diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 96aae3bd70cd..f1c7c1ea852a 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -628,6 +628,7 @@ impl Trait for X { assoc_substs, ty, msg, + false, ) { return true; } @@ -646,6 +647,7 @@ impl Trait for X { assoc_substs, ty, msg, + false, ); } } @@ -771,13 +773,24 @@ fn foo(&self) -> Self::T { String::new() } ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() { - self.constrain_associated_type_structured_suggestion( + let opaque_local_def_id = def_id.expect_local(); + let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id); + let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind { + hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, + _ => bug!("The HirId comes from a `ty::Opaque`"), + }; + + let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); + + self.constrain_generic_bound_associated_type_structured_suggestion( db, - self.def_span(def_id), - &assoc, - proj_ty.trait_ref_and_own_substs(self).1, + &trait_ref, + opaque_hir_ty.bounds, + assoc, + assoc_substs, ty, - &msg, + msg, + true, ) } else { false @@ -899,6 +912,11 @@ fn foo(&self) -> Self::T { String::new() } /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` /// requirement, provide a structured suggestion to constrain it to a given type `ty`. + /// + /// `is_bound_surely_present` indicates whether we know the bound we're looking for is + /// inside `bounds`. If that's the case then we can consider `bounds` containing only one + /// trait bound as the one we're looking for. This can help in cases where the associated + /// type is defined on a supertrait of the one present in the bounds. fn constrain_generic_bound_associated_type_structured_suggestion( self, db: &mut DiagnosticBuilder<'_>, @@ -908,23 +926,30 @@ fn foo(&self) -> Self::T { String::new() } assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, msg: &str, + is_bound_surely_present: bool, ) -> bool { // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. - bounds.iter().any(|bound| match bound { - hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => { - // Relate the type param against `T` in `::Foo`. - ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id) - && self.constrain_associated_type_structured_suggestion( - db, - ptr.span, - assoc, - assoc_substs, - ty, - msg, - ) - } - _ => false, - }) + + let trait_bounds = bounds.iter().filter_map(|bound| match bound { + hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr), + _ => None, + }); + + let matching_trait_bounds = trait_bounds + .clone() + .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)) + .collect::>(); + + let span = match &matching_trait_bounds[..] { + &[ptr] => ptr.span, + &[] if is_bound_surely_present => match &trait_bounds.collect::>()[..] { + &[ptr] => ptr.span, + _ => return false, + }, + _ => return false, + }; + + self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg) } /// Given a span corresponding to a bound, provide a structured suggestion to set an