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 2da4c86a58e9..65e2554a6f22 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2,10 +2,11 @@ pub mod on_unimplemented; pub mod suggestions; use super::{ - EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode, - MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode, - OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, - PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe, + DerivedObligationCause, EvaluationResult, FulfillmentContext, FulfillmentError, + FulfillmentErrorCode, ImplDerivedObligationCause, MismatchedProjectionTypes, Obligation, + ObligationCause, ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, + OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError, + TraitNotObjectSafe, }; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; @@ -654,11 +655,77 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } else if !suggested { // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_ref); - self.report_similar_impl_candidates( + if !self.report_similar_impl_candidates( impl_candidates, trait_ref, &mut err, - ); + ) { + // This is *almost* equivalent to + // `obligation.cause.code().peel_derives()`, but it gives us the + // trait predicate for that corresponding root obligation. This + // lets us get a derived obligation from a type parameter, like + // when calling `string.strip_suffix(p)` where `p` is *not* an + // implementer of `Pattern<'_>`. + let mut code = obligation.cause.code(); + let mut trait_pred = trait_predicate; + let mut peeled = false; + loop { + match &*code { + ObligationCauseCode::FunctionArgumentObligation { + parent_code, + .. + } => { + code = &parent_code; + } + ObligationCauseCode::ImplDerivedObligation( + box ImplDerivedObligationCause { + derived: + DerivedObligationCause { + parent_code, + parent_trait_pred, + }, + .. + }, + ) + | ObligationCauseCode::BuiltinDerivedObligation( + DerivedObligationCause { + parent_code, + parent_trait_pred, + }, + ) + | ObligationCauseCode::DerivedObligation( + DerivedObligationCause { + parent_code, + parent_trait_pred, + }, + ) => { + peeled = true; + code = &parent_code; + trait_pred = *parent_trait_pred; + } + _ => break, + }; + } + let def_id = trait_pred.def_id(); + // Mention *all* the `impl`s for the *top most* obligation, the + // user might have meant to use one of them, if any found. We skip + // auto-traits or fundamental traits that might not be exactly what + // the user might expect to be presented with. Instead this is + // useful for less general traits. + if peeled + && !self.tcx.trait_is_auto(def_id) + && !self.tcx.lang_items().items().contains(&Some(def_id)) + { + let trait_ref = trait_pred.to_poly_trait_ref(); + let impl_candidates = + self.find_similar_impl_candidates(trait_ref); + self.report_similar_impl_candidates( + impl_candidates, + trait_ref, + &mut err, + ); + } + } } // Changing mutability doesn't make a difference to whether we have diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr index 4202cbae7eb2..27f5dce9fb26 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr @@ -6,6 +6,7 @@ LL | writes_to_specific_path(&cap); | | | required by a bound introduced by this call | + = help: the trait `Delegates` is implemented for `T` note: required because of the requirements on the impl of `Contains<(), true>` for `&C` --> $DIR/issue-85848.rs:21:12 | diff --git a/src/test/ui/impl-trait/cross-return-site-inference.stderr b/src/test/ui/impl-trait/cross-return-site-inference.stderr index 06afb938c5fa..d458c7be783d 100644 --- a/src/test/ui/impl-trait/cross-return-site-inference.stderr +++ b/src/test/ui/impl-trait/cross-return-site-inference.stderr @@ -7,6 +7,7 @@ LL | Err("whoops")?; | ^ the trait `From<&str>` is not implemented for `impl Debug` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the trait `FromResidual>` is implemented for `Result` = note: required because of the requirements on the impl of `FromResidual>` for `Result<(), impl Debug>` error[E0277]: the trait bound `impl Debug: From<&str>` is not satisfied diff --git a/src/test/ui/impl-trait/nested_impl_trait.stderr b/src/test/ui/impl-trait/nested_impl_trait.stderr index 26b48c7cdf71..bb4ae5e82825 100644 --- a/src/test/ui/impl-trait/nested_impl_trait.stderr +++ b/src/test/ui/impl-trait/nested_impl_trait.stderr @@ -52,6 +52,7 @@ error[E0277]: the trait bound `impl Debug: From>` is not satisfie LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug` | + = help: the trait `Into` is implemented for `T` = note: required because of the requirements on the impl of `Into` for `impl Into` error[E0277]: the trait bound `impl Debug: From>` is not satisfied @@ -60,6 +61,7 @@ error[E0277]: the trait bound `impl Debug: From>` is not satisfie LL | fn bad(x: impl Into) -> impl Into { x } | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug` | + = help: the trait `Into` is implemented for `T` = note: required because of the requirements on the impl of `Into` for `impl Into` error: aborting due to 8 previous errors diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index b4c3f148e32b..ed5addcbec51 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -7,6 +7,7 @@ LL | Err(5)?; | ^ the trait `From<{integer}>` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the trait `FromResidual>` is implemented for `Result` = note: required because of the requirements on the impl of `FromResidual>` for `Result` error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr index 3558f0c9e629..64bbc841b330 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.stderr @@ -80,6 +80,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied LL | let a = t as Box>; | ^ the trait `Copy` is not implemented for `String` | + = help: the trait `Gettable` is implemented for `S` note: required because of the requirements on the impl of `Gettable` for `S` --> $DIR/kindck-impl-type-params.rs:14:32 | @@ -93,6 +94,7 @@ error[E0277]: the trait bound `Foo: Copy` is not satisfied LL | let a: Box> = t; | ^ the trait `Copy` is not implemented for `Foo` | + = help: the trait `Gettable` is implemented for `S` note: required because of the requirements on the impl of `Gettable` for `S` --> $DIR/kindck-impl-type-params.rs:14:32 | diff --git a/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.rs b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.rs new file mode 100644 index 000000000000..2720f94a3c19 --- /dev/null +++ b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.rs @@ -0,0 +1,12 @@ +fn strip_lf(s: &str) -> &str { + s.strip_suffix(b'\n').unwrap_or(s) + //~^ ERROR expected a `FnMut<(char,)>` closure, found `u8` + //~| NOTE expected an `FnMut<(char,)>` closure, found `u8` + //~| NOTE required by a bound introduced by this call + //~| HELP the trait `FnMut<(char,)>` is not implemented for `u8` + //~| HELP the following other types implement trait `Pattern<'_>`: + //~| NOTE required because of the requirements on the impl of `Pattern<'_>` for `u8` + +} + +fn main() {} diff --git a/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr new file mode 100644 index 000000000000..37cba4189d72 --- /dev/null +++ b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -0,0 +1,23 @@ +error[E0277]: expected a `FnMut<(char,)>` closure, found `u8` + --> $DIR/assoc-fn-bound-root-obligation.rs:2:20 + | +LL | s.strip_suffix(b'\n').unwrap_or(s) + | ------------ ^^^^^ expected an `FnMut<(char,)>` closure, found `u8` + | | + | required by a bound introduced by this call + | + = help: the trait `FnMut<(char,)>` is not implemented for `u8` + = help: the following other types implement trait `Pattern<'_>`: + &'b String + &'b [char; N] + &'b [char] + &'b str + &'c &'b str + [char; N] + char + pattern::MultiCharEqPattern + = note: required because of the requirements on the impl of `Pattern<'_>` for `u8` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.