Repository: rust-lang/rust
File: compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs (Rust)

Code before:

                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<'_>,
        cause: &ObligationCause<'tcx>,
        exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
        terr: TypeError<'tcx>,
        param_env: Option<ParamEnv<'tcx>>,
    ) {
        match *cause.code() {
            ObligationCauseCode::Pattern {
                origin_expr: Some(origin_expr),
                span: Some(span),
                root_ty,
            } => {
                let expected_ty = self.resolve_vars_if_possible(root_ty);
                if !matches!(

Review comment (suggestion):
cc @rust-lang/types unsure about this note. I think it's certainly useful. Ideally we'd link to some reference section or github issue explaining impl shadowing.

I think it's easiest to write a special github issue for this quickly explaining why this happens, what they can do about it, and how this may change in the future

Code after:
        let obligation =
            Obligation::new(tcx, ObligationCause::dummy(), param_env, ty::Binder::dummy(trait_ref));

        let applicable_impls = compute_applicable_impls_for_diagnostics(self.infcx, &obligation);

        for candidate in applicable_impls {
            let impl_def_id = match candidate {
                CandidateSource::DefId(did) => did,
                CandidateSource::ParamEnv(_) => continue,
            };

            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 let Err(_) = self.infcx.at(&ObligationCause::dummy(), param_env).eq(
                    DefineOpaqueTypes::No,
                    expected_trait_ref,
                    impl_trait_ref,
                ) {
                    return false;
                }

                let leaf_def = match specialization_graph::assoc_def(tcx, impl_def_id, alias.def_id)
                {
                    Ok(leaf) => leaf,
                    Err(_) => return false,
                };

                let trait_def_id = alias.trait_def_id(tcx);
                let rebased_args = alias.args.rebase_onto(tcx, trait_def_id, impl_substs);

                let impl_item_def_id = leaf_def.item.def_id;
                let impl_assoc_ty = tcx.type_of(impl_item_def_id).instantiate(tcx, rebased_args);

                self.infcx.can_eq(param_env, impl_assoc_ty, concrete)
            });

            if is_shadowed {
                diag.note(format!(
                    "the associated type `{}` is defined as `{}` in the implementation, \
                    but the where-bound `{}` shadows this definition\n\
                    see issue #152409 <https://github.com/rust-lang/rust/issues/152409> for more information",
                    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;
            }