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 ac7140ca2b67..cd0a62af72f3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -40,10 +40,13 @@ 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, - Fuzzy, + Exact { ignoring_lifetimes: bool }, + Fuzzy { ignoring_lifetimes: bool }, } #[derive(Debug, Clone, Copy)] @@ -1155,7 +1158,12 @@ 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>; @@ -1458,24 +1466,32 @@ 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(..) => Some(15), @@ -1497,17 +1513,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } }; - match (type_category(a), type_category(b)) { - (Some(cat_a), Some(cat_b)) => match (a.kind(), b.kind()) { + 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, - _ if cat_a == cat_b => true, - (ty::Ref(..), _) | (_, ty::Ref(..)) => { - self.fuzzy_match_tys(strip_references(a), strip_references(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() } - _ => false, - }, - // infer and error can be equated to all types - _ => true, + _ => true, + } + .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes }) + } else if ignoring_lifetimes { + None + } else { + self.fuzzy_match_tys(a, b, true) } } @@ -1533,22 +1565,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { 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, - }); - } - - if self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty()) { - return Some(ImplCandidate { - trait_ref: imp, - similarity: CandidateSimilarity::Fuzzy, - }); - } - - None + self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty(), false) + .map(|similarity| ImplCandidate { trait_ref: imp, similarity }) }) .collect() } 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 4e7a34d59511..4b6ffa8869db 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/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr index 4eed5c9a0083..ec28ca240be2 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-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr index 99f95c200511..e48ef8d17d1d 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 354caef1e41d..2fb3af38c0d9 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 9935445c3065..775f45ca8296 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 c26324ee6255..4e9b64ba832a 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 4c04d12a7147..d00abf30d3b0 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/block-result/issue-22645.stderr b/src/test/ui/block-result/issue-22645.stderr index b869a70039c4..397bdac60513 100644 --- a/src/test/ui/block-result/issue-22645.stderr +++ b/src/test/ui/block-result/issue-22645.stderr @@ -4,6 +4,8 @@ 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/chalk_initial_program.stderr b/src/test/ui/chalkify/chalk_initial_program.stderr index f8b792ae5363..7b0b3f85b391 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 95e320726aab..2bc9f077f028 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 80ec03d6221e..30cec80b036c 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_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index a05d8d6aa37d..14d43c1474c5 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -6,6 +6,9 @@ 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 d029eb2400b8..6abd8b28760d 100644 --- a/src/test/ui/chalkify/type_wf.stderr +++ b/src/test/ui/chalkify/type_wf.stderr @@ -4,6 +4,8 @@ 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: + 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 607db0d11292..e147366a2241 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 11 others + and 10 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 11 others + and 10 others note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | @@ -112,10 +112,6 @@ 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/specialization/default-associated-type-bound-1.stderr b/src/test/ui/specialization/default-associated-type-bound-1.stderr index 6680a29f9424..f88acfb2e793 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 0d9ecc32e08c..470c0bfcf73e 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-84973-negative.stderr b/src/test/ui/suggestions/issue-84973-negative.stderr index 1f33374eb29d..bacab64e2642 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/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index 6aaeafceb427..d121932c842e 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -6,12 +6,6 @@ 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 @@ -25,12 +19,6 @@ 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/associated_type_bound/check-trait-object-bounds-1.stderr b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr index 6333b4eb08cd..907a1bd75a06 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 9afae9a96383..b27f8d791a50 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 3c4a5d95c137..413225d45a62 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/suggest-deferences/multiple-0.stderr b/src/test/ui/traits/suggest-deferences/multiple-0.stderr index c629b06ba260..bf9f85f1b459 100644 --- a/src/test/ui/traits/suggest-deferences/multiple-0.stderr +++ b/src/test/ui/traits/suggest-deferences/multiple-0.stderr @@ -8,8 +8,6 @@ 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 b18c297ed995..040fbb3e3e69 100644 --- a/src/test/ui/traits/suggest-deferences/multiple-1.stderr +++ b/src/test/ui/traits/suggest-deferences/multiple-1.stderr @@ -6,8 +6,6 @@ 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 | diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr index 6fc5f94f5f11..171051156b7f 100644 --- a/src/test/ui/try-trait/bad-interconversion.stderr +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -10,9 +10,9 @@ LL | Ok(Err(123_i32)?) = help: the following implementations were found: > > - > - > - and 60 others + > + > + 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`