about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-02-14 14:47:20 +0000
committerbors <bors@rust-lang.org>2022-02-14 14:47:20 +0000
commit52dd59ed2154f4158ae37e6994b678a6249a7bb0 (patch)
tree2594af77b745817febce8b91a847276a43cceb07
parentb321742c6c27494897a88cd5ac17ac20aa3469a1 (diff)
parentf2aea1ea6e5ae0aa7c8657caf02ec3f68f3ee945 (diff)
downloadrust-52dd59ed2154f4158ae37e6994b678a6249a7bb0.tar.gz
rust-52dd59ed2154f4158ae37e6994b678a6249a7bb0.zip
Auto merge of #93298 - lcnr:issue-92113, r=cjgillot
make `find_similar_impl_candidates` even fuzzier

continues the good work of `@BGR360` in #92223. I might have overshot a bit and we're now slightly too fuzzy :sweat_smile:

with this we can now also simplify `simplify_type`, which is nice :3
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs3
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs20
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs197
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs23
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs13
-rw-r--r--src/test/ui/associated-types/associated-types-path-2.stderr10
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-1.stderr2
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-object.stderr2
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr2
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr6
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr2
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr2
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr4
-rw-r--r--src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr2
-rw-r--r--src/test/ui/chalkify/chalk_initial_program.stderr3
-rw-r--r--src/test/ui/chalkify/impl_wf.stderr2
-rw-r--r--src/test/ui/chalkify/impl_wf_2.stderr2
-rw-r--r--src/test/ui/chalkify/type_wf.stderr1
-rw-r--r--src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr2
-rw-r--r--src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr3
-rw-r--r--src/test/ui/kindck/kindck-copy.stderr8
-rw-r--r--src/test/ui/specialization/default-associated-type-bound-1.stderr2
-rw-r--r--src/test/ui/suggestions/into-str.stderr6
-rw-r--r--src/test/ui/suggestions/issue-71394-no-from-impl.stderr3
-rw-r--r--src/test/ui/suggestions/issue-84973-negative.stderr2
-rw-r--r--src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr2
-rw-r--r--src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr2
-rw-r--r--src/test/ui/traits/issue-77982.stderr1
-rw-r--r--src/test/ui/traits/issue-79458.stderr2
-rw-r--r--src/test/ui/traits/suggest-deferences/issue-62530.stderr2
-rw-r--r--src/test/ui/try-trait/bad-interconversion.stderr3
35 files changed, 212 insertions, 153 deletions
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index c92b3b9434c..4d6b97eff24 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -26,7 +26,7 @@ use rustc_middle::mir::interpret;
 use rustc_middle::thir;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_serialize::{opaque, Encodable, Encoder};
@@ -2066,7 +2066,6 @@ impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplsVisitor<'tcx> {
                         self.tcx,
                         trait_ref.self_ty(),
                         SimplifyParams::No,
-                        StripReferences::No,
                     );
 
                     self.impls
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index daf9156a15f..983057bff95 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -54,12 +54,6 @@ pub enum SimplifyParams {
     No,
 }
 
-#[derive(PartialEq, Eq, Debug, Clone, Copy)]
-pub enum StripReferences {
-    Yes,
-    No,
-}
-
 /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
 ///
 /// The idea is to get something simple that we can use to quickly decide if two types could unify,
@@ -73,8 +67,6 @@ pub enum StripReferences {
 /// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections²,
 /// the reasoning for this can be seen at the places doing this.
 ///
-/// For diagnostics we strip references with `StripReferences::Yes`. This is currently the best
-/// way to skip some unhelpful suggestions.
 ///
 /// ¹ meaning that if two outermost layers are different, then the whole types are also different.
 /// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during
@@ -87,7 +79,6 @@ pub fn simplify_type(
     tcx: TyCtxt<'_>,
     ty: Ty<'_>,
     can_simplify_params: SimplifyParams,
-    strip_references: StripReferences,
 ) -> Option<SimplifiedType> {
     match *ty.kind() {
         ty::Bool => Some(BoolSimplifiedType),
@@ -106,16 +97,7 @@ pub fn simplify_type(
             }
             _ => Some(MarkerTraitObjectSimplifiedType),
         },
-        ty::Ref(_, ty, mutbl) => {
-            if strip_references == StripReferences::Yes {
-                // For diagnostics, when recommending similar impls we want to
-                // recommend impls even when there is a reference mismatch,
-                // so we treat &T and T equivalently in that case.
-                simplify_type(tcx, ty, can_simplify_params, strip_references)
-            } else {
-                Some(RefSimplifiedType(mutbl))
-            }
-        }
+        ty::Ref(_, _, mutbl) => Some(RefSimplifiedType(mutbl)),
         ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)),
         ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)),
         ty::GeneratorWitness(ref tys) => {
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 9e32c0162e6..597f7dd95a2 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,5 +1,5 @@
 use crate::traits::specialization_graph;
-use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
 use crate::ty::fold::TypeFoldable;
 use crate::ty::{Ident, Ty, TyCtxt};
 use rustc_hir as hir;
@@ -150,9 +150,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self_ty: Ty<'tcx>,
     ) -> impl Iterator<Item = DefId> + 'tcx {
         let impls = self.trait_impls_of(def_id);
-        if let Some(simp) =
-            fast_reject::simplify_type(self, self_ty, SimplifyParams::No, StripReferences::No)
-        {
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::No) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 return impls.iter().copied();
             }
@@ -189,9 +187,7 @@ impl<'tcx> TyCtxt<'tcx> {
         // whose outer level is not a parameter or projection. Especially for things like
         // `T: Clone` this is incredibly useful as we would otherwise look at all the impls
         // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
-        if let Some(simp) =
-            fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes, StripReferences::No)
-        {
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
                     if let result @ Some(_) = f(impl_def_id) {
@@ -251,7 +247,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
         }
 
         if let Some(simplified_self_ty) =
-            fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No, StripReferences::No)
+            fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No)
         {
             impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
         } else {
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 21775a5c49f..ed1bf433c2c 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -15,7 +15,7 @@ use crate::traits::{
 };
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::traits::specialization_graph::OverlapMode;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifyParams};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -82,8 +82,8 @@ where
         impl2_ref.iter().flat_map(|tref| tref.substs.types()),
     )
     .any(|(ty1, ty2)| {
-        let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No, StripReferences::No);
-        let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No, StripReferences::No);
+        let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No);
+        let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No);
 
         if let (Some(t1), Some(t2)) = (t1, t2) {
             // Simplified successfully
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index f80fad19528..cd0a62af72f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -21,10 +21,9 @@ use rustc_hir::Item;
 use rustc_hir::Node;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{
-    self, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    self, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_session::DiagnosticMessageId;
 use rustc_span::symbol::{kw, sym};
@@ -40,6 +39,22 @@ use suggestions::InferCtxtExt as _;
 
 pub use rustc_infer::traits::error_reporting::*;
 
+// When outputting impl candidates, prefer showing those that are more similar.
+//
+// We also compare candidates after skipping lifetimes, which has a lower
+// priority than exact matches.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum CandidateSimilarity {
+    Exact { ignoring_lifetimes: bool },
+    Fuzzy { ignoring_lifetimes: bool },
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct ImplCandidate<'tcx> {
+    pub trait_ref: ty::TraitRef<'tcx>,
+    pub similarity: CandidateSimilarity,
+}
+
 pub trait InferCtxtExt<'tcx> {
     fn report_fulfillment_errors(
         &self,
@@ -1143,18 +1158,23 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
         error: &MismatchedProjectionTypes<'tcx>,
     );
 
-    fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool;
+    fn fuzzy_match_tys(
+        &self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        ignoring_lifetimes: bool,
+    ) -> Option<CandidateSimilarity>;
 
     fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>;
 
     fn find_similar_impl_candidates(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Vec<ty::TraitRef<'tcx>>;
+    ) -> Vec<ImplCandidate<'tcx>>;
 
     fn report_similar_impl_candidates(
         &self,
-        impl_candidates: Vec<ty::TraitRef<'tcx>>,
+        impl_candidates: Vec<ImplCandidate<'tcx>>,
         err: &mut DiagnosticBuilder<'_>,
     );
 
@@ -1446,45 +1466,80 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
         });
     }
 
-    fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+    fn fuzzy_match_tys(
+        &self,
+        mut a: Ty<'tcx>,
+        mut b: Ty<'tcx>,
+        ignoring_lifetimes: bool,
+    ) -> Option<CandidateSimilarity> {
         /// returns the fuzzy category of a given type, or None
         /// if the type can be equated to any type.
-        fn type_category(t: Ty<'_>) -> Option<u32> {
+        fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
             match t.kind() {
                 ty::Bool => Some(0),
                 ty::Char => Some(1),
                 ty::Str => Some(2),
-                ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3),
-                ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4),
+                ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did) => Some(2),
+                ty::Int(..)
+                | ty::Uint(..)
+                | ty::Float(..)
+                | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4),
                 ty::Ref(..) | ty::RawPtr(..) => Some(5),
                 ty::Array(..) | ty::Slice(..) => Some(6),
                 ty::FnDef(..) | ty::FnPtr(..) => Some(7),
                 ty::Dynamic(..) => Some(8),
                 ty::Closure(..) => Some(9),
                 ty::Tuple(..) => Some(10),
-                ty::Projection(..) => Some(11),
-                ty::Param(..) => Some(12),
+                ty::Param(..) => Some(11),
+                ty::Projection(..) => Some(12),
                 ty::Opaque(..) => Some(13),
                 ty::Never => Some(14),
-                ty::Adt(adt, ..) => match adt.adt_kind() {
-                    AdtKind::Struct => Some(15),
-                    AdtKind::Union => Some(16),
-                    AdtKind::Enum => Some(17),
-                },
-                ty::Generator(..) => Some(18),
-                ty::Foreign(..) => Some(19),
-                ty::GeneratorWitness(..) => Some(20),
+                ty::Adt(..) => Some(15),
+                ty::Generator(..) => Some(16),
+                ty::Foreign(..) => Some(17),
+                ty::GeneratorWitness(..) => Some(18),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
 
-        match (type_category(a), type_category(b)) {
-            (Some(cat_a), Some(cat_b)) => match (a.kind(), b.kind()) {
-                (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b,
-                _ => cat_a == cat_b,
-            },
-            // infer and error can be equated to all types
-            _ => true,
+        let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> {
+            loop {
+                match t.kind() {
+                    ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => {
+                        t = inner
+                    }
+                    _ => break t,
+                }
+            }
+        };
+
+        if !ignoring_lifetimes {
+            a = strip_references(a);
+            b = strip_references(b);
+        }
+
+        let cat_a = type_category(self.tcx, a)?;
+        let cat_b = type_category(self.tcx, b)?;
+        if a == b {
+            Some(CandidateSimilarity::Exact { ignoring_lifetimes })
+        } else if cat_a == cat_b {
+            match (a.kind(), b.kind()) {
+                (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,
+                // Matching on references results in a lot of unhelpful
+                // suggestions, so let's just not do that for now.
+                //
+                // We still upgrade successful matches to `ignoring_lifetimes: true`
+                // to prioritize that impl.
+                (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => {
+                    self.fuzzy_match_tys(a, b, true).is_some()
+                }
+                _ => true,
+            }
+            .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes })
+        } else if ignoring_lifetimes {
+            None
+        } else {
+            self.fuzzy_match_tys(a, b, true)
         }
     }
 
@@ -1500,58 +1555,25 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
     fn find_similar_impl_candidates(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Vec<ty::TraitRef<'tcx>> {
-        // We simplify params and strip references here.
-        //
-        // This both removes a lot of unhelpful suggestions, e.g.
-        // when searching for `&Foo: Trait` it doesn't suggestion `impl Trait for &Bar`,
-        // while also suggesting impls for `&Foo` when we're looking for `Foo: Trait`.
-        //
-        // The second thing isn't necessarily always a good thing, but
-        // any other simple setup results in a far worse output, so 🤷
-        let simp = fast_reject::simplify_type(
-            self.tcx,
-            trait_ref.skip_binder().self_ty(),
-            SimplifyParams::Yes,
-            StripReferences::Yes,
-        );
-        let all_impls = self.tcx.all_impls(trait_ref.def_id());
-
-        match simp {
-            Some(simp) => all_impls
-                .filter_map(|def_id| {
-                    let imp = self.tcx.impl_trait_ref(def_id).unwrap();
-                    let imp_simp = fast_reject::simplify_type(
-                        self.tcx,
-                        imp.self_ty(),
-                        SimplifyParams::Yes,
-                        StripReferences::Yes,
-                    );
-                    if let Some(imp_simp) = imp_simp {
-                        if simp != imp_simp {
-                            return None;
-                        }
-                    }
-                    if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
-                        return None;
-                    }
-                    Some(imp)
-                })
-                .collect(),
-            None => all_impls
-                .filter_map(|def_id| {
-                    if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
-                        return None;
-                    }
-                    self.tcx.impl_trait_ref(def_id)
-                })
-                .collect(),
-        }
+    ) -> Vec<ImplCandidate<'tcx>> {
+        self.tcx
+            .all_impls(trait_ref.def_id())
+            .filter_map(|def_id| {
+                if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
+                    return None;
+                }
+
+                let imp = self.tcx.impl_trait_ref(def_id).unwrap();
+
+                self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty(), false)
+                    .map(|similarity| ImplCandidate { trait_ref: imp, similarity })
+            })
+            .collect()
     }
 
     fn report_similar_impl_candidates(
         &self,
-        impl_candidates: Vec<ty::TraitRef<'tcx>>,
+        impl_candidates: Vec<ImplCandidate<'tcx>>,
         err: &mut DiagnosticBuilder<'_>,
     ) {
         if impl_candidates.is_empty() {
@@ -1575,13 +1597,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
         };
 
         // Sort impl candidates so that ordering is consistent for UI tests.
-        let mut normalized_impl_candidates =
-            impl_candidates.iter().copied().map(normalize).collect::<Vec<String>>();
-
-        // Sort before taking the `..end` range,
         // because the ordering of `impl_candidates` may not be deterministic:
         // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
-        normalized_impl_candidates.sort();
+        //
+        // Prefer more similar candidates first, then sort lexicographically
+        // by their normalized string representation.
+        let mut normalized_impl_candidates_and_similarities = impl_candidates
+            .into_iter()
+            .map(|ImplCandidate { trait_ref, similarity }| {
+                let normalized = normalize(trait_ref);
+                (similarity, normalized)
+            })
+            .collect::<Vec<_>>();
+        normalized_impl_candidates_and_similarities.sort();
+
+        let normalized_impl_candidates = normalized_impl_candidates_and_similarities
+            .into_iter()
+            .map(|(_, normalized)| normalized)
+            .collect::<Vec<_>>();
 
         err.help(&format!(
             "the following implementations were found:{}{}",
@@ -1744,7 +1777,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                     return;
                 }
 
-                let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+                let impl_candidates = self
+                    .find_similar_impl_candidates(trait_ref)
+                    .into_iter()
+                    .map(|candidate| candidate.trait_ref)
+                    .collect();
                 let mut err = self.emit_inference_failure_err(
                     body_id,
                     span,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 4e7a34d5951..4b6ffa8869d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -56,7 +56,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     trait_ref.substs.types().skip(1),
                     impl_trait_ref.substs.types().skip(1),
                 )
-                .all(|(u, v)| self.fuzzy_match_tys(u, v))
+                .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
                 {
                     fuzzy_match_impls.push(def_id);
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 47427395b93..ee21eb029a8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -36,7 +36,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifyParams};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
@@ -2172,14 +2172,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             self.tcx(),
                             obligation_ty,
                             SimplifyParams::Yes,
-                            StripReferences::No,
-                        );
-                        let simplified_impl_ty = fast_reject::simplify_type(
-                            self.tcx(),
-                            impl_ty,
-                            SimplifyParams::No,
-                            StripReferences::No,
                         );
+                        let simplified_impl_ty =
+                            fast_reject::simplify_type(self.tcx(), impl_ty, SimplifyParams::No);
 
                         simplified_obligation_ty.is_some()
                             && simplified_impl_ty.is_some()
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 5ee8b45e66b..497ac207bbe 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -2,7 +2,7 @@ use super::OverlapError;
 
 use crate::traits;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 
@@ -49,12 +49,7 @@ impl ChildrenExt<'_> for Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
-        if let Some(st) = fast_reject::simplify_type(
-            tcx,
-            trait_ref.self_ty(),
-            SimplifyParams::No,
-            StripReferences::No,
-        ) {
+        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) {
             debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
             self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
         } else {
@@ -69,12 +64,7 @@ impl ChildrenExt<'_> for Children {
     fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let vec: &mut Vec<DefId>;
-        if let Some(st) = fast_reject::simplify_type(
-            tcx,
-            trait_ref.self_ty(),
-            SimplifyParams::No,
-            StripReferences::No,
-        ) {
+        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) {
             debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
             vec = self.non_blanket_impls.get_mut(&st).unwrap();
         } else {
@@ -322,12 +312,7 @@ impl GraphExt for Graph {
 
         let mut parent = trait_def_id;
         let mut last_lint = None;
-        let simplified = fast_reject::simplify_type(
-            tcx,
-            trait_ref.self_ty(),
-            SimplifyParams::No,
-            StripReferences::No,
-        );
+        let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No);
 
         // Descend the specialization tree, where `parent` is the current parent node.
         loop {
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 8aa22852a6f..55dce71bdfb 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -9,7 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams};
 use rustc_middle::ty::print::with_crate_prefix;
 use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_span::lev_distance;
@@ -1748,8 +1748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // FIXME: Even though negative bounds are not implemented, we could maybe handle
                 // cases where a positive bound implies a negative impl.
                 (candidates, Vec::new())
-            } else if let Some(simp_rcvr_ty) =
-                simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes, StripReferences::No)
+            } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes)
             {
                 let mut potential_candidates = Vec::new();
                 let mut explicitly_negative = Vec::new();
@@ -1763,12 +1762,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         })
                         .any(|imp_did| {
                             let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
-                            let imp_simp = simplify_type(
-                                self.tcx,
-                                imp.self_ty(),
-                                SimplifyParams::Yes,
-                                StripReferences::No,
-                            );
+                            let imp_simp =
+                                simplify_type(self.tcx, imp.self_ty(), SimplifyParams::Yes);
                             imp_simp.map_or(false, |s| s == simp_rcvr_ty)
                         })
                     {
diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr
index b3bb58f7814..f56631b12aa 100644
--- a/src/test/ui/associated-types/associated-types-path-2.stderr
+++ b/src/test/ui/associated-types/associated-types-path-2.stderr
@@ -15,6 +15,8 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied
 LL |     f1(2u32, 4u32);
    |     ^^ the trait `Foo` is not implemented for `u32`
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
 note: required by a bound in `f1`
   --> $DIR/associated-types-path-2.rs:13:14
    |
@@ -26,6 +28,9 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied
    |
 LL |     f1(2u32, 4u32);
    |              ^^^^ the trait `Foo` is not implemented for `u32`
+   |
+   = help: the following implementations were found:
+             <i32 as Foo>
 
 error[E0277]: the trait bound `u32: Foo` is not satisfied
   --> $DIR/associated-types-path-2.rs:35:8
@@ -35,6 +40,8 @@ LL |     f1(2u32, 4i32);
    |     |
    |     required by a bound introduced by this call
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
 note: required by a bound in `f1`
   --> $DIR/associated-types-path-2.rs:13:14
    |
@@ -46,6 +53,9 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied
    |
 LL |     f1(2u32, 4i32);
    |              ^^^^ the trait `Foo` is not implemented for `u32`
+   |
+   = help: the following implementations were found:
+             <i32 as Foo>
 
 error[E0308]: mismatched types
   --> $DIR/associated-types-path-2.rs:41:18
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr
index 4eed5c9a008..ec28ca240be 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-1.rs:3:33
    |
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr
index 354f5ae4597..6d19186bde4 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr
@@ -4,8 +4,6 @@ error[E0277]: the trait bound `for<'b> <T as X<'b>>::U: Clone` is not satisfied
 LL | fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) {
    |             ^^^^^ the trait `for<'b> Clone` is not implemented for `<T as X<'b>>::U`
    |
-   = help: the following implementations were found:
-             <&T as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-object.rs:3:33
    |
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr
index 99f95c20051..e48ef8d17d1 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type V = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `Y`
   --> $DIR/hr-associated-type-bound-param-1.rs:4:36
    |
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
index 354caef1e41..2fb3af38c0d 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     T: Z<'a, u16>,
    |        ^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `Z`
   --> $DIR/hr-associated-type-bound-param-2.rs:6:35
    |
@@ -19,6 +21,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     T: Z<'a, u16>,
    |        ^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `Z`
   --> $DIR/hr-associated-type-bound-param-2.rs:6:35
    |
@@ -34,6 +38,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type W = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `Z`
   --> $DIR/hr-associated-type-bound-param-2.rs:6:35
    |
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr
index 9935445c306..775f45ca829 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-param-3.rs:4:33
    |
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr
index c26324ee625..4e9b64ba832 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-param-4.rs:4:36
    |
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
index 4c04d12a714..d00abf30d3b 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-param-5.rs:17:45
    |
@@ -19,6 +21,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-param-5.rs:17:45
    |
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
index 8ce70b1ac06..5755778fef2 100644
--- a/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
+++ b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `u32: Signed` is not satisfied
 LL |     is_defaulted::<&'static u32>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`
    |
+   = help: the following implementations were found:
+             <i32 as Signed>
 note: required because of the requirements on the impl of `Defaulted` for `&'static u32`
   --> $DIR/typeck-default-trait-impl-precedence.rs:10:19
    |
diff --git a/src/test/ui/chalkify/chalk_initial_program.stderr b/src/test/ui/chalkify/chalk_initial_program.stderr
index f8b792ae536..7b0b3f85b39 100644
--- a/src/test/ui/chalkify/chalk_initial_program.stderr
+++ b/src/test/ui/chalkify/chalk_initial_program.stderr
@@ -4,6 +4,9 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied
 LL |     gimme::<f32>();
    |             ^^^ the trait `Foo` is not implemented for `f32`
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
+             <u32 as Foo>
 note: required by a bound in `gimme`
   --> $DIR/chalk_initial_program.rs:9:13
    |
diff --git a/src/test/ui/chalkify/impl_wf.stderr b/src/test/ui/chalkify/impl_wf.stderr
index 95e320726aa..2bc9f077f02 100644
--- a/src/test/ui/chalkify/impl_wf.stderr
+++ b/src/test/ui/chalkify/impl_wf.stderr
@@ -17,6 +17,8 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied
 LL | impl Baz<f32> for f32 { }
    |      ^^^^^^^^ the trait `Foo` is not implemented for `f32`
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
 note: required by a bound in `Baz`
   --> $DIR/impl_wf.rs:18:31
    |
diff --git a/src/test/ui/chalkify/impl_wf_2.stderr b/src/test/ui/chalkify/impl_wf_2.stderr
index 80ec03d6221..30cec80b036 100644
--- a/src/test/ui/chalkify/impl_wf_2.stderr
+++ b/src/test/ui/chalkify/impl_wf_2.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied
 LL |     type Item = f32;
    |                 ^^^ the trait `Foo` is not implemented for `f32`
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
 note: required by a bound in `Bar::Item`
   --> $DIR/impl_wf_2.rs:8:16
    |
diff --git a/src/test/ui/chalkify/type_wf.stderr b/src/test/ui/chalkify/type_wf.stderr
index 57902efa201..6abd8b28760 100644
--- a/src/test/ui/chalkify/type_wf.stderr
+++ b/src/test/ui/chalkify/type_wf.stderr
@@ -5,7 +5,6 @@ LL |     let s = S {
    |             ^ the trait `Foo` is not implemented for `{float}`
    |
    = help: the following implementations were found:
-             <Option<T> as Foo>
              <i32 as Foo>
 note: required by a bound in `S`
   --> $DIR/type_wf.rs:6:13
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
index 8c8bfdc0e48..19813a491c9 100644
--- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
+++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
@@ -15,6 +15,7 @@ LL | fn uwu<const N: u8>() -> impl Traitor<N> {
    |
    = help: the following implementations were found:
              <u32 as Traitor<N, 2_u8>>
+             <u64 as Traitor<1_u8, 2_u8>>
 
 error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
   --> $DIR/rp_impl_trait_fail.rs:22:13
@@ -24,6 +25,7 @@ LL | fn owo() -> impl Traitor {
    |
    = help: the following implementations were found:
              <u64 as Traitor<1_u8, 2_u8>>
+             <u32 as Traitor<N, 2_u8>>
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr
index 5381a717dc3..dff98030191 100644
--- a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr
+++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr
@@ -11,7 +11,7 @@ LL |     Foo::<i32>::bar(&1i8);
              <i8 as Foo<u16>>
              <i8 as Foo<u32>>
              <i8 as Foo<u64>>
-             <i8 as Foo<u8>>
+           and 5 others
 
 error[E0277]: the trait bound `u8: Foo<i32>` is not satisfied
   --> $DIR/issue-39802-show-5-trait-impls.rs:25:21
@@ -26,6 +26,7 @@ LL |     Foo::<i32>::bar(&1u8);
              <u8 as Foo<u16>>
              <u8 as Foo<u32>>
              <u8 as Foo<u64>>
+           and 5 others
 
 error[E0277]: the trait bound `bool: Foo<i32>` is not satisfied
   --> $DIR/issue-39802-show-5-trait-impls.rs:26:21
diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr
index 6977804708d..e147366a224 100644
--- a/src/test/ui/kindck/kindck-copy.stderr
+++ b/src/test/ui/kindck/kindck-copy.stderr
@@ -6,6 +6,10 @@ LL |     assert_copy::<&'static mut isize>();
    |
    = help: the following implementations were found:
              <isize as Copy>
+             <f32 as Copy>
+             <f64 as Copy>
+             <i128 as Copy>
+           and 10 others
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
    |
@@ -20,6 +24,10 @@ LL |     assert_copy::<&'a mut isize>();
    |
    = help: the following implementations were found:
              <isize as Copy>
+             <f32 as Copy>
+             <f64 as Copy>
+             <i128 as Copy>
+           and 10 others
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
    |
diff --git a/src/test/ui/specialization/default-associated-type-bound-1.stderr b/src/test/ui/specialization/default-associated-type-bound-1.stderr
index 6680a29f942..f88acfb2e79 100644
--- a/src/test/ui/specialization/default-associated-type-bound-1.stderr
+++ b/src/test/ui/specialization/default-associated-type-bound-1.stderr
@@ -14,6 +14,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     default type U = str;
    |                      ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X::U`
   --> $DIR/default-associated-type-bound-1.rs:8:13
    |
diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr
index 0d9ecc32e08..470c0bfcf73 100644
--- a/src/test/ui/suggestions/into-str.stderr
+++ b/src/test/ui/suggestions/into-str.stderr
@@ -7,6 +7,12 @@ LL |     foo(String::new());
    |     required by a bound introduced by this call
    |
    = note: to coerce a `String` into a `&str`, use `&*` as a prefix
+   = help: the following implementations were found:
+             <String as From<&String>>
+             <String as From<&mut str>>
+             <String as From<&str>>
+             <String as From<Box<str>>>
+           and 2 others
    = note: required because of the requirements on the impl of `Into<&str>` for `String`
 note: required by a bound in `foo`
   --> $DIR/into-str.rs:1:31
diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr
index 355f2038df8..79724377713 100644
--- a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr
+++ b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr
@@ -4,6 +4,9 @@ error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied
 LL |     let _: &[i8] = data.into();
    |                         ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`
    |
+   = help: the following implementations were found:
+             <[T; LANES] as From<Simd<T, LANES>>>
+             <[bool; LANES] as From<Mask<T, LANES>>>
    = note: required because of the requirements on the impl of `Into<&[i8]>` for `&[u8]`
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/issue-84973-negative.stderr b/src/test/ui/suggestions/issue-84973-negative.stderr
index 1f33374eb29..bacab64e264 100644
--- a/src/test/ui/suggestions/issue-84973-negative.stderr
+++ b/src/test/ui/suggestions/issue-84973-negative.stderr
@@ -6,6 +6,8 @@ LL |     bar(a);
    |     |
    |     required by a bound introduced by this call
    |
+   = help: the following implementations were found:
+             <&f32 as Tr>
 note: required by a bound in `bar`
   --> $DIR/issue-84973-negative.rs:5:11
    |
diff --git a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr
index 6333b4eb08c..907a1bd75a0 100644
--- a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr
+++ b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     f::<dyn X<Y = str>>();
    |     ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `f`
   --> $DIR/check-trait-object-bounds-1.rs:7:9
    |
diff --git a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr
index 9afae9a9638..b27f8d791a5 100644
--- a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr
+++ b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     f::<dyn X<Y = str>>();
    |     ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `f`
   --> $DIR/check-trait-object-bounds-4.rs:10:9
    |
diff --git a/src/test/ui/traits/issue-77982.stderr b/src/test/ui/traits/issue-77982.stderr
index 3c4a5d95c13..413225d45a6 100644
--- a/src/test/ui/traits/issue-77982.stderr
+++ b/src/test/ui/traits/issue-77982.stderr
@@ -44,6 +44,7 @@ LL |     opts.get(<String as AsRef<[u8]>>::as_ref(opt));
    |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     opts.get(<String as AsRef<str>>::as_ref(opt));
    |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+     and 4 other candidates
 
 error[E0283]: type annotations needed
   --> $DIR/issue-77982.rs:13:44
diff --git a/src/test/ui/traits/issue-79458.stderr b/src/test/ui/traits/issue-79458.stderr
index 3e83db142e0..b9700128373 100644
--- a/src/test/ui/traits/issue-79458.stderr
+++ b/src/test/ui/traits/issue-79458.stderr
@@ -9,6 +9,8 @@ LL |     bar: &'a mut T
    |
    = help: the following implementations were found:
              <&T as Clone>
+             <*const T as Clone>
+             <*mut T as Clone>
    = note: `Clone` is implemented for `&T`, but not for `&mut T`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/traits/suggest-deferences/issue-62530.stderr b/src/test/ui/traits/suggest-deferences/issue-62530.stderr
index b77af7ddf47..299219431ef 100644
--- a/src/test/ui/traits/suggest-deferences/issue-62530.stderr
+++ b/src/test/ui/traits/suggest-deferences/issue-62530.stderr
@@ -8,6 +8,8 @@ LL |     takes_type_parameter(&string);  // Error
    |     |                    help: consider adding dereference here: `&*string`
    |     required by a bound introduced by this call
    |
+   = help: the following implementations were found:
+             <&str as SomeTrait>
 note: required by a bound in `takes_type_parameter`
   --> $DIR/issue-62530.rs:4:44
    |
diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr
index 80c5e6f529c..171051156b7 100644
--- a/src/test/ui/try-trait/bad-interconversion.stderr
+++ b/src/test/ui/try-trait/bad-interconversion.stderr
@@ -10,6 +10,9 @@ LL |     Ok(Err(123_i32)?)
    = help: the following implementations were found:
              <u8 as From<NonZeroU8>>
              <u8 as From<bool>>
+             <f32 as From<i16>>
+             <f32 as From<i8>>
+           and 71 others
    = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, i32>>` for `Result<u64, u8>`
 
 error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`