diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 47810e2578df..cfe5b1f42556 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -149,11 +149,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { actual: Ty<'tcx>, err: TypeError<'tcx>, ) -> Diag<'a> { - self.report_and_explain_type_error( + let mut diag = self.report_and_explain_type_error( TypeTrace::types(cause, expected, actual), param_env, err, - ) + ); + + self.suggest_param_env_shadowing(&mut diag, expected, actual); + + diag } pub fn report_mismatched_consts( @@ -240,6 +244,63 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false } + fn suggest_param_env_shadowing( + &self, + diag: &mut Diag<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + let (alias, concrete) = match (expected.kind(), found.kind()) { + (ty::Alias(ty::Projection, proj), _) => (proj, found), + (_, ty::Alias(ty::Projection, proj)) => (proj, expected), + _ => return, + }; + + let tcx = self.tcx; + let trait_def_id = alias.trait_def_id(tcx); + let impls = tcx.trait_impls_of(trait_def_id); + + let all_impls = + impls.blanket_impls().iter().chain(impls.non_blanket_impls().values().flatten()); + + for &impl_def_id in all_impls { + let is_shadowed = self.infcx.probe(|_| { + let impl_substs = self.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); + + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate(tcx, impl_substs); + + let expected_trait_ref = alias.trait_ref(tcx); + + if self.infcx.can_eq(ty::ParamEnv::empty(), expected_trait_ref, impl_trait_ref) { + let name = tcx.item_name(alias.def_id); + let assoc_item = tcx + .associated_items(impl_def_id) + .filter_by_name_unhygienic(name) + .find(|item| matches!(item.kind, ty::AssocKind::Type { .. })); + + if let Some(item) = assoc_item { + let impl_assoc_ty = tcx.type_of(item.def_id).instantiate(tcx, impl_substs); + if self.infcx.can_eq(ty::ParamEnv::empty(), impl_assoc_ty, concrete) { + return true; + } + } + } + false + }); + + if is_shadowed { + diag.note(format!( + "the associated type `{}` is defined as `{}` in the implementation, \ + but the generic bound `{}` hides this definition", + self.ty_to_string(tcx.mk_ty_from_kind(ty::Alias(ty::Projection, *alias))), + self.ty_to_string(concrete), + self.ty_to_string(alias.self_ty()) + )); + return; + } + } + } + fn note_error_origin( &self, err: &mut Diag<'_>, diff --git a/tests/ui/associated-types/param-env-shadowing-issue-149910.rs b/tests/ui/associated-types/param-env-shadowing-issue-149910.rs new file mode 100644 index 000000000000..bd4df859dc07 --- /dev/null +++ b/tests/ui/associated-types/param-env-shadowing-issue-149910.rs @@ -0,0 +1,14 @@ +trait Trait { + type Assoc; +} + +impl Trait for T { + type Assoc = T; +} + +fn foo(x: T) -> T::Assoc { + x + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-types/param-env-shadowing-issue-149910.stderr b/tests/ui/associated-types/param-env-shadowing-issue-149910.stderr new file mode 100644 index 000000000000..57eaaee9906b --- /dev/null +++ b/tests/ui/associated-types/param-env-shadowing-issue-149910.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/issue-149910.rs:10:5 + | +LL | fn foo(x: T) -> T::Assoc { + | - -------- expected `::Assoc` because of return type + | | + | found this type parameter +LL | x + | ^ expected associated type, found type parameter `T` + | + = note: expected associated type `::Assoc` + found type parameter `T` + = note: the associated type `::Assoc` is defined as `T` in the implementation, but the generic bound `T` hides this definition +help: consider further restricting this bound + | +LL | fn foo>(x: T) -> T::Assoc { + | +++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`.