diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c92b3b9434c2b..4d6b97eff24fe 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 daf9156a15f34..983057bff95d6 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 { 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 9e32c0162e617..597f7dd95a211 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 + '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`, `Vec`, `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 21775a5c49f09..ed1bf433c2c15 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 f80fad19528da..cd0a62af72f32 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; fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>; fn find_similar_impl_candidates( &self, trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Vec>; + ) -> Vec>; fn report_similar_impl_candidates( &self, - impl_candidates: Vec>, + impl_candidates: Vec>, 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 { /// 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 { + fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option { 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> { - // 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> { + 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>, + impl_candidates: Vec>, 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::>(); - - // 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::>(); + normalized_impl_candidates_and_similarities.sort(); + + let normalized_impl_candidates = normalized_impl_candidates_and_similarities + .into_iter() + .map(|(_, normalized)| normalized) + .collect::>(); 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 4e7a34d595111..4b6ffa8869dba 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 47427395b93b3..ee21eb029a888 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 5ee8b45e66b5c..497ac207bbe4f 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; - 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 8aa22852a6ffd..55dce71bdfbd4 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 b3bb58f78142a..f56631b12aa67 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: + 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: + 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: + 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: + 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 4eed5c9a0083c..ec28ca240be2b 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: + 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 354f5ae459729..6d19186bde49a 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> >::U: Clone` is not satisfied LL | fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { | ^^^^^ the trait `for<'b> Clone` is not implemented for `>::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 99f95c200511a..e48ef8d17d1de 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: + 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 354caef1e41d8..2fb3af38c0d9b 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: + 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: + 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: + 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 9935445c30658..775f45ca82965 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: + 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 c26324ee62554..4e9b64ba832ad 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: + 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 4c04d12a71470..d00abf30d3b05 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: + 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: + 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 8ce70b1ac0677..5755778fef266 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: + 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 f8b792ae5363c..7b0b3f85b3915 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::(); | ^^^ the trait `Foo` is not implemented for `f32` | + = help: the following implementations were found: + + 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 95e320726aab0..2bc9f077f0285 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 for f32 { } | ^^^^^^^^ the trait `Foo` is not implemented for `f32` | + = help: the following implementations were found: + 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 80ec03d6221e8..30cec80b036c6 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: + 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 57902efa2015c..6abd8b28760d8 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: - 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 8c8bfdc0e4847..19813a491c96e 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() -> impl Traitor { | = help: the following implementations were found: > + > 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: > + > 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 5381a717dc3cf..dff980301911c 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::::bar(&1i8); > > > - > + and 5 others error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 @@ -26,6 +26,7 @@ LL | Foo::::bar(&1u8); > > > + and 5 others error[E0277]: the trait bound `bool: Foo` 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 6977804708d5e..e147366a22410 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: + + + + 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: + + + + 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 6680a29f94245..f88acfb2e793e 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: + 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 0d9ecc32e08cd..470c0bfcf73e5 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: + > + > + > + >> + 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 355f2038df889..7972437771399 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>> + <[bool; LANES] as From>> = 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 1f33374eb29db..bacab64e2642c 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 6333b4eb08cd5..907a1bd75a064 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::>(); | ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + 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 9afae9a963834..b27f8d791a50f 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::>(); | ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + 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 3c4a5d95c137e..413225d45a62c 100644 --- a/src/test/ui/traits/issue-77982.stderr +++ b/src/test/ui/traits/issue-77982.stderr @@ -44,6 +44,7 @@ LL | opts.get(>::as_ref(opt)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | opts.get(>::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 3e83db142e087..b970012837313 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 b77af7ddf4746..299219431ef11 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 80c5e6f529cd6..171051156b7f2 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: > > + > + > + and 71 others = note: required because of the requirements on the impl of `FromResidual>` for `Result` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`