Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 63 additions & 2 deletions compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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<'_>,
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/associated-types/param-env-shadowing-issue-149910.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
trait Trait {
type Assoc;
}

impl<T> Trait for T {
type Assoc = T;
}

fn foo<T: Trait>(x: T) -> T::Assoc {
x
//~^ ERROR mismatched types
}

fn main() {}
21 changes: 21 additions & 0 deletions tests/ui/associated-types/param-env-shadowing-issue-149910.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0308]: mismatched types
--> $DIR/issue-149910.rs:10:5
|
LL | fn foo<T: Trait>(x: T) -> T::Assoc {
| - -------- expected `<T as Trait>::Assoc` because of return type
| |
| found this type parameter
LL | x
| ^ expected associated type, found type parameter `T`
|
= note: expected associated type `<T as Trait>::Assoc`
found type parameter `T`
= note: the associated type `<T as Trait>::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<T: Trait<Assoc = T>>(x: T) -> T::Assoc {
| +++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
Loading