From 97463da6194f77a96a1512fb905640cf5da35837 Mon Sep 17 00:00:00 2001 From: Ben Reeves Date: Thu, 23 Dec 2021 02:31:04 -0600 Subject: [PATCH 1/3] Make `find_similar_impl_candidates` a little fuzzier. --- .../src/traits/error_reporting/mod.rs | 144 ++++++++++++++---- .../error_reporting/on_unimplemented.rs | 3 +- .../associated-types-path-2.stderr | 10 ++ ...ypeck-default-trait-impl-precedence.stderr | 2 + .../defaults/rp_impl_trait_fail.stderr | 2 + .../issue-39802-show-5-trait-impls.stderr | 3 +- src/test/ui/kindck/kindck-copy.stderr | 8 + .../issue-71394-no-from-impl.stderr | 3 + src/test/ui/traits/issue-79458.stderr | 2 + .../ui/try-trait/bad-interconversion.stderr | 3 + 10 files changed, 147 insertions(+), 33 deletions(-) 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 0760f6268512..e89426feb9f5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -40,6 +40,21 @@ use suggestions::InferCtxtExt as _; pub use rustc_infer::traits::error_reporting::*; +// When outputting impl candidates, prefer showing those that are more similar. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum CandidateSimilarity { + Exact, + Simplified, + Fuzzy, + Unknown, +} + +#[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, @@ -1084,18 +1099,18 @@ 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>, strip_references: StripReferences) -> bool; 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<'_>, ); @@ -1389,7 +1404,7 @@ 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, a: Ty<'tcx>, b: Ty<'tcx>, strip_references: StripReferences) -> bool { /// 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 { @@ -1421,6 +1436,23 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } } + let strip_reference = |mut t: Ty<'tcx>| -> Ty<'tcx> { + loop { + match t.kind() { + ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => { + t = inner + } + _ => break t, + } + } + }; + + let (a, b) = if strip_references == StripReferences::Yes { + (strip_reference(a), strip_reference(b)) + } else { + (a, b) + }; + 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, @@ -1443,7 +1475,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn find_similar_impl_candidates( &self, trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Vec> { + ) -> Vec> { // We simplify params and strip references here. // // This both removes a lot of unhelpful suggestions, e.g. @@ -1461,32 +1493,67 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { 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 { + Some(simp) => { + all_impls + .filter_map(|def_id| { + if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { return None; } - } - if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { - return None; - } - Some(imp) - }) - .collect(), + + let imp = self.tcx.impl_trait_ref(def_id).unwrap(); + + // Check for exact match. + if trait_ref.skip_binder().self_ty() == imp.self_ty() { + return Some(ImplCandidate { + trait_ref: imp, + similarity: CandidateSimilarity::Exact, + }); + } + + // Check for match between simplified types. + 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 Some(ImplCandidate { + trait_ref: imp, + similarity: CandidateSimilarity::Simplified, + }); + } + } + + // Check for fuzzy match. + // Pass `StripReferences::Yes` because although we do want to + // be fuzzier than `simplify_type`, we don't want to be + // *too* fuzzy. + if self.fuzzy_match_tys( + trait_ref.skip_binder().self_ty(), + imp.self_ty(), + StripReferences::Yes, + ) { + return Some(ImplCandidate { + trait_ref: imp, + similarity: CandidateSimilarity::Fuzzy, + }); + } + + None + }) + .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) + self.tcx.impl_trait_ref(def_id).map(|trait_ref| ImplCandidate { + trait_ref, + similarity: CandidateSimilarity::Unknown, + }) }) .collect(), } @@ -1494,7 +1561,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn report_similar_impl_candidates( &self, - impl_candidates: Vec>, + impl_candidates: Vec>, err: &mut DiagnosticBuilder<'_>, ) { if impl_candidates.is_empty() { @@ -1518,13 +1585,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:{}{}", @@ -1688,7 +1766,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 1540725246b5..48adebb273fb 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 @@ -4,6 +4,7 @@ use super::{ use crate::infer::InferCtxt; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_middle::ty::fast_reject::StripReferences; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, GenericParamDefKind}; use rustc_span::symbol::sym; @@ -56,7 +57,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, StripReferences::No)) { fuzzy_match_impls.push(def_id); } 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 b3bb58f78142..f56631b12aa6 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/auto-traits/typeck-default-trait-impl-precedence.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr index 8ce70b1ac067..5755778fef26 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/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr index 8c8bfdc0e484..19813a491c96 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 5381a717dc3c..dff980301911 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 6977804708d5..dcee740a5561 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 8 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 8 others note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | 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 355f2038df88..797243777139 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/traits/issue-79458.stderr b/src/test/ui/traits/issue-79458.stderr index 3e83db142e08..b97001283731 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/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr index 80c5e6f529cd..6fc5f94f5f11 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 60 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` From 60930fcc81128e4982c517c8a87f87e078a9cab3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 25 Jan 2022 12:09:01 +0100 Subject: [PATCH 2/3] fuzzify `fuzzy_match_tys` --- .../src/traits/error_reporting/mod.rs | 137 +++++------------- .../error_reporting/on_unimplemented.rs | 3 +- .../hr-associated-type-bound-object.stderr | 2 - src/test/ui/block-result/issue-22645.stderr | 2 - src/test/ui/chalkify/type_inference.stderr | 3 - src/test/ui/chalkify/type_wf.stderr | 3 - src/test/ui/kindck/kindck-copy.stderr | 20 ++- .../mut-borrow-needed-by-trait.stderr | 12 ++ .../suggest-deferences/issue-62530.stderr | 2 + .../suggest-deferences/multiple-0.stderr | 2 + .../suggest-deferences/multiple-1.stderr | 2 + 11 files changed, 68 insertions(+), 120 deletions(-) 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 e89426feb9f5..83500ec37d79 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}; @@ -44,9 +43,7 @@ pub use rustc_infer::traits::error_reporting::*; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum CandidateSimilarity { Exact, - Simplified, Fuzzy, - Unknown, } #[derive(Debug, Clone, Copy)] @@ -1099,7 +1096,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { error: &MismatchedProjectionTypes<'tcx>, ); - fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>, strip_references: StripReferences) -> bool; + fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool; fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>; @@ -1404,7 +1401,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { }); } - fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>, strip_references: StripReferences) -> bool { + fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { /// 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 { @@ -1424,19 +1421,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { ty::Param(..) => 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, } } - let strip_reference = |mut t: Ty<'tcx>| -> Ty<'tcx> { + let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> { loop { match t.kind() { ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => { @@ -1447,16 +1440,14 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } }; - let (a, b) = if strip_references == StripReferences::Yes { - (strip_reference(a), strip_reference(b)) - } else { - (a, b) - }; - 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, + (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b, + _ if cat_a == cat_b => true, + (ty::Ref(..), _) | (_, ty::Ref(..)) => { + self.fuzzy_match_tys(strip_references(a), strip_references(b)) + } + _ => false, }, // infer and error can be equated to all types _ => true, @@ -1476,87 +1467,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { &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| { - if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { - return None; - } + 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(); + let imp = self.tcx.impl_trait_ref(def_id).unwrap(); - // Check for exact match. - if trait_ref.skip_binder().self_ty() == imp.self_ty() { - return Some(ImplCandidate { - trait_ref: imp, - similarity: CandidateSimilarity::Exact, - }); - } - - // Check for match between simplified types. - 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 Some(ImplCandidate { - trait_ref: imp, - similarity: CandidateSimilarity::Simplified, - }); - } - } + // Check for exact match. + if trait_ref.skip_binder().self_ty() == imp.self_ty() { + return Some(ImplCandidate { + trait_ref: imp, + similarity: CandidateSimilarity::Exact, + }); + } - // Check for fuzzy match. - // Pass `StripReferences::Yes` because although we do want to - // be fuzzier than `simplify_type`, we don't want to be - // *too* fuzzy. - if self.fuzzy_match_tys( - trait_ref.skip_binder().self_ty(), - imp.self_ty(), - StripReferences::Yes, - ) { - return Some(ImplCandidate { - trait_ref: imp, - similarity: CandidateSimilarity::Fuzzy, - }); - } + if self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty()) { + return Some(ImplCandidate { + trait_ref: imp, + similarity: CandidateSimilarity::Fuzzy, + }); + } - None - }) - .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).map(|trait_ref| ImplCandidate { - trait_ref, - similarity: CandidateSimilarity::Unknown, - }) - }) - .collect(), - } + None + }) + .collect() } fn report_similar_impl_candidates( 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 48adebb273fb..1540725246b5 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 @@ -4,7 +4,6 @@ use super::{ use crate::infer::InferCtxt; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::ty::fast_reject::StripReferences; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, GenericParamDefKind}; use rustc_span::symbol::sym; @@ -57,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, StripReferences::No)) + .all(|(u, v)| self.fuzzy_match_tys(u, v)) { fuzzy_match_impls.push(def_id); } 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 354f5ae45972..6d19186bde49 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/block-result/issue-22645.stderr b/src/test/ui/block-result/issue-22645.stderr index 397bdac60513..b869a70039c4 100644 --- a/src/test/ui/block-result/issue-22645.stderr +++ b/src/test/ui/block-result/issue-22645.stderr @@ -4,8 +4,6 @@ error[E0277]: the trait bound `{integer}: Scalar` is not satisfied LL | b + 3 | ^ the trait `Scalar` is not implemented for `{integer}` | - = help: the following implementations were found: - note: required because of the requirements on the impl of `Add<{integer}>` for `Bob` --> $DIR/issue-22645.rs:8:19 | diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index 14d43c1474c5..a05d8d6aa37d 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -6,9 +6,6 @@ LL | only_bar(x); | | | required by a bound introduced by this call | - = help: the following implementations were found: - - note: required by a bound in `only_bar` --> $DIR/type_inference.rs:12:16 | diff --git a/src/test/ui/chalkify/type_wf.stderr b/src/test/ui/chalkify/type_wf.stderr index 57902efa2015..d029eb2400b8 100644 --- a/src/test/ui/chalkify/type_wf.stderr +++ b/src/test/ui/chalkify/type_wf.stderr @@ -4,9 +4,6 @@ error[E0277]: the trait bound `{float}: Foo` is not satisfied 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/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr index dcee740a5561..607db0d11292 100644 --- a/src/test/ui/kindck/kindck-copy.stderr +++ b/src/test/ui/kindck/kindck-copy.stderr @@ -5,11 +5,11 @@ LL | assert_copy::<&'static mut isize>(); | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize` | = help: the following implementations were found: - + <&T as Copy> + <*const T as Copy> + <*mut T as Copy> - - - and 8 others + and 11 others note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | @@ -23,11 +23,11 @@ LL | assert_copy::<&'a mut isize>(); | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize` | = help: the following implementations were found: - + <&T as Copy> + <*const T as Copy> + <*mut T as Copy> - - - and 8 others + and 11 others note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | @@ -112,6 +112,10 @@ error[E0277]: the trait bound `&'a mut (dyn Dummy + Send + 'a): Copy` is not sat LL | assert_copy::<&'a mut (dyn Dummy + Send)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut (dyn Dummy + Send + 'a)` | + = help: the following implementations were found: + <&T as Copy> + <*const T as Copy> + <*mut T as Copy> note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index d121932c842e..6aaeafceb427 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -6,6 +6,12 @@ LL | let fp = BufWriter::new(fp); | | | required by a bound introduced by this call | + = help: the following implementations were found: + <&'a UnixStream as std::io::Write> + <&ChildStdin as std::io::Write> + <&File as std::io::Write> + <&Sink as std::io::Write> + and 5 others = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` note: required by a bound in `BufWriter::::new` --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL @@ -19,6 +25,12 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | + = help: the following implementations were found: + <&'a UnixStream as std::io::Write> + <&ChildStdin as std::io::Write> + <&File as std::io::Write> + <&Sink as std::io::Write> + and 5 others = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` note: required by a bound in `BufWriter` --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL diff --git a/src/test/ui/traits/suggest-deferences/issue-62530.stderr b/src/test/ui/traits/suggest-deferences/issue-62530.stderr index b77af7ddf474..299219431ef1 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/traits/suggest-deferences/multiple-0.stderr b/src/test/ui/traits/suggest-deferences/multiple-0.stderr index bf9f85f1b459..c629b06ba260 100644 --- a/src/test/ui/traits/suggest-deferences/multiple-0.stderr +++ b/src/test/ui/traits/suggest-deferences/multiple-0.stderr @@ -8,6 +8,8 @@ LL | foo(&baz); | | help: consider adding dereference here: `&***baz` | required by a bound introduced by this call | + = help: the following implementations were found: + <&LDM as Happy> note: required by a bound in `foo` --> $DIR/multiple-0.rs:30:26 | diff --git a/src/test/ui/traits/suggest-deferences/multiple-1.stderr b/src/test/ui/traits/suggest-deferences/multiple-1.stderr index 040fbb3e3e69..b18c297ed995 100644 --- a/src/test/ui/traits/suggest-deferences/multiple-1.stderr +++ b/src/test/ui/traits/suggest-deferences/multiple-1.stderr @@ -6,6 +6,8 @@ LL | foo(&mut baz); | | | required by a bound introduced by this call | + = help: the following implementations were found: + <&mut LDM as Happy> note: required by a bound in `foo` --> $DIR/multiple-1.rs:45:26 | From 7bd1b35e351c0f6dfc7a36eee6fcf02cad34c956 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 25 Jan 2022 12:50:00 +0100 Subject: [PATCH 3/3] fast_reject: remove `StripReferences` --- compiler/rustc_metadata/src/rmeta/encoder.rs | 3 +-- compiler/rustc_middle/src/ty/fast_reject.rs | 20 +--------------- compiler/rustc_middle/src/ty/trait_def.rs | 8 +++---- .../src/traits/coherence.rs | 6 ++--- .../src/traits/select/mod.rs | 11 +++------ .../traits/specialize/specialization_graph.rs | 23 ++++--------------- .../rustc_typeck/src/check/method/suggest.rs | 13 ++++------- 7 files changed, 19 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 809e5ee2c645..29943fba52a0 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 daf9156a15f3..983057bff95d 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 9f8053d4a4ea..96419bae4b8e 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; @@ -172,9 +172,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) { @@ -234,7 +232,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 80ed9023d969..3762c7a0983b 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -14,7 +14,7 @@ use crate::traits::{ PredicateObligations, SelectionContext, }; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -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}; @@ -80,8 +80,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/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ab4fb9607ca0..369295332ee6 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}; @@ -2174,14 +2174,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 3ac273fd19b6..8e8d2f268e27 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}; @@ -48,12 +48,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 { @@ -68,12 +63,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 { @@ -316,12 +306,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 96ab800afaff..4ceaffba13a0 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) }) {