From 8ba74369c210a0cdb1b1440c47f19f2145e1640f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Feb 2022 13:03:28 -0800 Subject: [PATCH 1/2] better ObligationCause for normalization errors in can_type_implement_copy --- compiler/rustc_lint/src/builtin.rs | 11 +++++-- .../rustc_trait_selection/src/traits/misc.rs | 4 +-- .../rustc_typeck/src/coherence/builtin.rs | 3 +- src/test/ui/issues/issue-50480.rs | 4 +-- src/test/ui/issues/issue-50480.stderr | 30 ++++++++++--------- .../ui/traits/copy-impl-cannot-normalize.rs | 25 ++++++++++++++++ .../traits/copy-impl-cannot-normalize.stderr | 14 +++++++++ .../src/needless_pass_by_value.rs | 2 +- 8 files changed, 71 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/traits/copy-impl-cannot-normalize.rs create mode 100644 src/test/ui/traits/copy-impl-cannot-normalize.stderr diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 30b5f9b34d099..0a218c2d25584 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -51,7 +51,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, MultiSpan, Span}; use rustc_target::abi::VariantIdx; -use rustc_trait_selection::traits::misc::can_type_implement_copy; +use rustc_trait_selection::traits::{self, misc::can_type_implement_copy}; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -764,7 +764,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) { return; } - if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() { + if can_type_implement_copy( + cx.tcx, + param_env, + ty, + traits::ObligationCause::misc(item.span, item.hir_id()), + ) + .is_ok() + { cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| { lint.build( "type could implement `Copy`; consider adding `impl \ diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index b23dce8a58130..dc72945af24e3 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -20,6 +20,7 @@ pub fn can_type_implement_copy<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, + cause: ObligationCause<'tcx>, ) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { @@ -49,9 +50,8 @@ pub fn can_type_implement_copy<'tcx>( continue; } let span = tcx.def_span(field.did); - let cause = ObligationCause::dummy_with_span(span); let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { + match traits::fully_normalize(&infcx, ctx, cause.clone(), param_env, ty) { Ok(ty) => { if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { infringing.push(field); diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index 401ba188728c1..a43f7f871167e 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -74,7 +74,8 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); - match can_type_implement_copy(tcx, param_env, self_type) { + let cause = traits::ObligationCause::misc(span, impl_hir_id); + match can_type_implement_copy(tcx, param_env, self_type, cause) { Ok(()) => {} Err(CopyImplementationError::InfrigingFields(fields)) => { let item = tcx.hir().expect_item(impl_did); diff --git a/src/test/ui/issues/issue-50480.rs b/src/test/ui/issues/issue-50480.rs index 10597caf5b2dc..ca81db023ec3b 100644 --- a/src/test/ui/issues/issue-50480.rs +++ b/src/test/ui/issues/issue-50480.rs @@ -1,17 +1,17 @@ #[derive(Clone, Copy)] //~^ ERROR the trait `Copy` may not be implemented for this type +//~| ERROR `i32` is not an iterator struct Foo(N, NotDefined, ::Item, Vec, String); //~^ ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope //~| ERROR cannot find type `N` in this scope -//~| ERROR `i32` is not an iterator #[derive(Clone, Copy)] //~^ ERROR the trait `Copy` may not be implemented for this type +//~| ERROR `i32` is not an iterator struct Bar(T, N, NotDefined, ::Item, Vec, String); //~^ ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope -//~| ERROR `i32` is not an iterator fn main() {} diff --git a/src/test/ui/issues/issue-50480.stderr b/src/test/ui/issues/issue-50480.stderr index 0bb1f9ae03500..48ec4aa434cd7 100644 --- a/src/test/ui/issues/issue-50480.stderr +++ b/src/test/ui/issues/issue-50480.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:3:12 + --> $DIR/issue-50480.rs:4:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -^ not found in this scope @@ -7,13 +7,13 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:3:15 + --> $DIR/issue-50480.rs:4:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:3:12 + --> $DIR/issue-50480.rs:4:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -^ not found in this scope @@ -21,7 +21,7 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:3:15 + --> $DIR/issue-50480.rs:4:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | - ^^^^^^^^^^ not found in this scope @@ -29,7 +29,7 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:12:18 + --> $DIR/issue-50480.rs:13:18 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | - ^ @@ -46,26 +46,27 @@ LL | struct Bar(T, N, NotDefined, ::Item, Vec, Strin | +++ error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:12:21 + --> $DIR/issue-50480.rs:13:21 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:3:27 + --> $DIR/issue-50480.rs:1:17 | -LL | struct Foo(N, NotDefined, ::Item, Vec, String); - | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator +LL | #[derive(Clone, Copy)] + | ^^^^ `i32` is not an iterator | = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/issue-50480.rs:1:17 | LL | #[derive(Clone, Copy)] | ^^^^ -LL | +... LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -------- ------ this field does not implement `Copy` | | @@ -74,20 +75,21 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:12:33 + --> $DIR/issue-50480.rs:10:17 | -LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); - | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator +LL | #[derive(Clone, Copy)] + | ^^^^ `i32` is not an iterator | = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/issue-50480.rs:10:17 | LL | #[derive(Clone, Copy)] | ^^^^ -LL | +... LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | -------- ------ this field does not implement `Copy` | | diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.rs b/src/test/ui/traits/copy-impl-cannot-normalize.rs new file mode 100644 index 0000000000000..a78ff046e97f9 --- /dev/null +++ b/src/test/ui/traits/copy-impl-cannot-normalize.rs @@ -0,0 +1,25 @@ +trait TraitFoo { + type Bar; +} + +struct Foo +where + T: TraitFoo, +{ + inner: T::Bar, +} + +impl Clone for Foo +where + T: TraitFoo, + T::Bar: Clone, +{ + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +impl Copy for Foo {} +//~^ ERROR the trait bound `T: TraitFoo` is not satisfied + +fn main() {} diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.stderr b/src/test/ui/traits/copy-impl-cannot-normalize.stderr new file mode 100644 index 0000000000000..cc540ea905a10 --- /dev/null +++ b/src/test/ui/traits/copy-impl-cannot-normalize.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `T: TraitFoo` is not satisfied + --> $DIR/copy-impl-cannot-normalize.rs:22:1 + | +LL | impl Copy for Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitFoo` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl Copy for Foo {} + | ++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index ebd4fb0bf51cc..d27e1383d012b 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let sugg = |diag: &mut DiagnosticBuilder<'_>| { if let ty::Adt(def, ..) = ty.kind() { if let Some(span) = cx.tcx.hir().span_if_local(def.did) { - if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() { + if can_type_implement_copy(cx.tcx, cx.param_env, ty, traits::ObligationCause::dummy_with_span(span)).is_ok() { diag.span_help(span, "consider marking this type as `Copy`"); } } From ee98dc8b3bdff99591630ca225f4769201100603 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Feb 2022 15:57:29 -0800 Subject: [PATCH 2/2] restore spans for issue-50480 --- .../rustc_trait_selection/src/traits/misc.rs | 15 +++++++++- src/test/ui/issues/issue-50480.rs | 4 +-- src/test/ui/issues/issue-50480.stderr | 30 +++++++++---------- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index dc72945af24e3..c293708dcc929 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -50,8 +50,21 @@ pub fn can_type_implement_copy<'tcx>( continue; } let span = tcx.def_span(field.did); + // FIXME(compiler-errors): This gives us better spans for bad + // projection types like in issue-50480. + // If the ADT has substs, point to the cause we are given. + // If it does not, then this field probably doesn't normalize + // to begin with, and point to the bad field's span instead. + let cause = if field + .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did)) + .has_param_types_or_consts() + { + cause.clone() + } else { + ObligationCause::dummy_with_span(span) + }; let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause.clone(), param_env, ty) { + match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { Ok(ty) => { if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { infringing.push(field); diff --git a/src/test/ui/issues/issue-50480.rs b/src/test/ui/issues/issue-50480.rs index ca81db023ec3b..10597caf5b2dc 100644 --- a/src/test/ui/issues/issue-50480.rs +++ b/src/test/ui/issues/issue-50480.rs @@ -1,17 +1,17 @@ #[derive(Clone, Copy)] //~^ ERROR the trait `Copy` may not be implemented for this type -//~| ERROR `i32` is not an iterator struct Foo(N, NotDefined, ::Item, Vec, String); //~^ ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope //~| ERROR cannot find type `N` in this scope +//~| ERROR `i32` is not an iterator #[derive(Clone, Copy)] //~^ ERROR the trait `Copy` may not be implemented for this type -//~| ERROR `i32` is not an iterator struct Bar(T, N, NotDefined, ::Item, Vec, String); //~^ ERROR cannot find type `NotDefined` in this scope //~| ERROR cannot find type `N` in this scope +//~| ERROR `i32` is not an iterator fn main() {} diff --git a/src/test/ui/issues/issue-50480.stderr b/src/test/ui/issues/issue-50480.stderr index 48ec4aa434cd7..0bb1f9ae03500 100644 --- a/src/test/ui/issues/issue-50480.stderr +++ b/src/test/ui/issues/issue-50480.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:4:12 + --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -^ not found in this scope @@ -7,13 +7,13 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:4:15 + --> $DIR/issue-50480.rs:3:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:4:12 + --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -^ not found in this scope @@ -21,7 +21,7 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:4:15 + --> $DIR/issue-50480.rs:3:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | - ^^^^^^^^^^ not found in this scope @@ -29,7 +29,7 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); | help: you might be missing a type parameter: `` error[E0412]: cannot find type `N` in this scope - --> $DIR/issue-50480.rs:13:18 + --> $DIR/issue-50480.rs:12:18 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | - ^ @@ -46,27 +46,26 @@ LL | struct Bar(T, N, NotDefined, ::Item, Vec, Strin | +++ error[E0412]: cannot find type `NotDefined` in this scope - --> $DIR/issue-50480.rs:13:21 + --> $DIR/issue-50480.rs:12:21 | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:1:17 + --> $DIR/issue-50480.rs:3:27 | -LL | #[derive(Clone, Copy)] - | ^^^^ `i32` is not an iterator +LL | struct Foo(N, NotDefined, ::Item, Vec, String); + | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator | = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/issue-50480.rs:1:17 | LL | #[derive(Clone, Copy)] | ^^^^ -... +LL | LL | struct Foo(N, NotDefined, ::Item, Vec, String); | -------- ------ this field does not implement `Copy` | | @@ -75,21 +74,20 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `i32` is not an iterator - --> $DIR/issue-50480.rs:10:17 + --> $DIR/issue-50480.rs:12:33 | -LL | #[derive(Clone, Copy)] - | ^^^^ `i32` is not an iterator +LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); + | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator | = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/issue-50480.rs:10:17 | LL | #[derive(Clone, Copy)] | ^^^^ -... +LL | LL | struct Bar(T, N, NotDefined, ::Item, Vec, String); | -------- ------ this field does not implement `Copy` | |