diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index fd85397760a..b09522bbd33 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -67,7 +67,7 @@ pub enum MethodError<'tcx> { // could lead to matches if satisfied, and a list of not-in-scope traits which may work. pub struct NoMatchData<'tcx> { pub static_candidates: Vec, - pub unsatisfied_predicates: Vec>, + pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>)>, pub out_of_scope_traits: Vec, pub lev_candidate: Option, pub mode: probe::Mode, @@ -76,7 +76,7 @@ pub struct NoMatchData<'tcx> { impl<'tcx> NoMatchData<'tcx> { pub fn new( static_candidates: Vec, - unsatisfied_predicates: Vec>, + unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>)>, out_of_scope_traits: Vec, lev_candidate: Option, mode: probe::Mode, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 4f729c593cb..3e2826907b8 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -77,7 +77,7 @@ struct ProbeContext<'a, 'tcx> { /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used /// for error reporting - unsatisfied_predicates: Vec>, + unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>)>, is_suggestion: IsSuggestion, } @@ -1223,7 +1223,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, self_ty: Ty<'tcx>, probes: ProbesIter, - possibly_unsatisfied_predicates: &mut Vec>, + possibly_unsatisfied_predicates: &mut Vec<( + ty::Predicate<'tcx>, + Option>, + )>, unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>, ) -> Option> where @@ -1342,7 +1345,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>, - possibly_unsatisfied_predicates: &mut Vec>, + possibly_unsatisfied_predicates: &mut Vec<( + ty::Predicate<'tcx>, + Option>, + )>, ) -> ProbeResult { debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe); @@ -1409,20 +1415,25 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if !self.predicate_may_hold(&obligation) { result = ProbeResult::NoMatch; let o = self.resolve_vars_if_possible(obligation); - possibly_unsatisfied_predicates.push(o.predicate); + let predicate = + self.resolve_vars_if_possible(&predicate); + let p = if predicate == o.predicate { + // Avoid "`MyStruct: Foo` which is required by + // `MyStruct: Foo`" in E0599. + None + } else { + Some(predicate) + }; + possibly_unsatisfied_predicates.push((o.predicate, p)); } } } _ => { // Some nested subobligation of this predicate // failed. - // - // FIXME: try to find the exact nested subobligation - // and point at it rather than reporting the entire - // trait-ref? result = ProbeResult::NoMatch; let predicate = self.resolve_vars_if_possible(&predicate); - possibly_unsatisfied_predicates.push(predicate); + possibly_unsatisfied_predicates.push((predicate, None)); } } false @@ -1447,7 +1458,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let o = self.resolve_vars_if_possible(&o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; - possibly_unsatisfied_predicates.push(o.predicate); + possibly_unsatisfied_predicates.push((o.predicate, None)); } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 6edceeb15b3..973f8208f16 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -538,9 +538,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let def_span = |def_id| self.tcx.sess.source_map().def_span(self.tcx.def_span(def_id)); let mut bound_spans = vec![]; - let mut bound_list = unsatisfied_predicates - .iter() - .filter_map(|pred| match pred { + let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str| { + match &self_ty.kind { + ty::Adt(def, _) => { + // Point at the type that couldn't satisfy the bound. + bound_spans.push(( + def_span(def.did), + format!("doesn't satisfy {}", obligation), + )); + } + ty::Dynamic(preds, _) => { + // Point at the trait object that couldn't satisfy the bound. + for pred in *preds.skip_binder() { + match pred { + ty::ExistentialPredicate::Trait(tr) => bound_spans.push(( + def_span(tr.def_id), + format!("doesn't satisfy {}", obligation), + )), + ty::ExistentialPredicate::Projection(_) + | ty::ExistentialPredicate::AutoTrait(_) => {} + } + } + } + _ => {} + } + }; + let mut format_pred = |pred| { + match pred { ty::Predicate::Projection(pred) => { // `::Item = String`. let trait_ref = @@ -549,44 +573,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .associated_item(pred.skip_binder().projection_ty.item_def_id); let ty = pred.skip_binder().ty; - Some(format!("`{}::{} = {}`", trait_ref, assoc.ident, ty)) + let obligation = + format!("`{}::{} = {}`", trait_ref, assoc.ident, ty); + bound_span_label(trait_ref.self_ty(), &obligation); + Some(obligation) } ty::Predicate::Trait(poly_trait_ref, _) => { let p = poly_trait_ref.skip_binder().trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); - match &self_ty.kind { - ty::Adt(def, _) => { - // Point at the type that couldn't satisfy the bound. - bound_spans.push(( - def_span(def.did), - format!("doesn't satisfy `{}: {}`", self_ty, path), - )); - } - ty::Dynamic(preds, _) => { - // Point at the trait object that couldn't satisfy the bound. - for pred in *preds.skip_binder() { - match pred { - ty::ExistentialPredicate::Trait(tr) => bound_spans - .push(( - def_span(tr.def_id), - format!( - "doesn't satisfy `{}: {}`", - self_ty, path - ), - )), - ty::ExistentialPredicate::Projection(_) - | ty::ExistentialPredicate::AutoTrait(_) => {} - } - } - } - _ => {} - } - Some(format!("`{}: {}`", self_ty, path)) + let obligation = format!("`{}: {}`", self_ty, path); + bound_span_label(self_ty, &obligation); + Some(obligation) } _ => None, + } + }; + let mut bound_list = unsatisfied_predicates + .iter() + .filter_map(|(pred, parent_pred)| { + format_pred(*pred).map(|pred| match parent_pred { + None => pred, + Some(parent_pred) => match format_pred(*parent_pred) { + None => pred, + Some(parent_pred) => { + format!("{} which is required by {}", pred, parent_pred) + } + }, + }) }) - .collect::>(); + .collect::>(); bound_list.sort(); bound_list.dedup(); // #35677 bound_spans.sort(); diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr index 3ed726dea35..e837c7721af 100644 --- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr +++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr @@ -2,7 +2,10 @@ error[E0599]: no method named `clone` found for struct `Bar` in the cu --> $DIR/derive-assoc-type-not-impl.rs:18:30 | LL | struct Bar { - | ------------------ method `clone` not found for this + | ------------------ + | | + | method `clone` not found for this + | doesn't satisfy `Bar: std::clone::Clone` ... LL | struct NotClone; | ---------------- doesn't satisfy `NotClone: std::clone::Clone` @@ -11,7 +14,7 @@ LL | Bar:: { x: 1 }.clone(); | ^^^^^ method not found in `Bar` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `NotClone: std::clone::Clone` + `NotClone: std::clone::Clone` which is required by `Bar: std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone` diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr index 10b634b4603..bbd16618049 100644 --- a/src/test/ui/issues/issue-21596.stderr +++ b/src/test/ui/issues/issue-21596.stderr @@ -7,7 +7,7 @@ LL | println!("{}", z.to_string()); = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior = note: the method `to_string` exists but the following trait bounds were not satisfied: - `*const u8: std::fmt::Display` + `*const u8: std::fmt::Display` which is required by `*const u8: std::string::ToString` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index d5e3cf48f38..9100f2c3a93 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -17,10 +17,13 @@ LL | .collect(); | LL | pub struct Cloned { | -------------------- doesn't satisfy `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` +... +LL | pub struct TakeWhile { + | -------------------------- doesn't satisfy `, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item = &_` | = note: the method `collect` exists but the following trait bounds were not satisfied: - `, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item = &_` - `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` + `, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item = &_` which is required by `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` + `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` which is required by `&mut std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index b0d747d201d..b4e54ab7783 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -44,7 +44,7 @@ LL | .take() | ^^^^ method not found in `Foo` | = note: the method `take` exists but the following trait bounds were not satisfied: - `Foo: std::iter::Iterator` + `Foo: std::iter::Iterator` which is required by `&mut Foo: std::iter::Iterator` = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `take`, perhaps you need to implement one of them: candidate #1: `std::io::Read` diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index 5f3353c89cc..5899dfffa41 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -10,9 +10,9 @@ LL | pub struct Filter { | ----------------------- doesn't satisfy `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` | = note: the method `count` exists but the following trait bounds were not satisfied: - `<[closure@$DIR/issue-36053-2.rs:11:39: 11:53] as std::ops::FnOnce<(&&str,)>>::Output = bool` - `[closure@$DIR/issue-36053-2.rs:11:39: 11:53]: std::ops::FnMut<(&&str,)>` - `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` + `<[closure@$DIR/issue-36053-2.rs:11:39: 11:53] as std::ops::FnOnce<(&&str,)>>::Output = bool` which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` + `[closure@$DIR/issue-36053-2.rs:11:39: 11:53]: std::ops::FnMut<(&&str,)>` which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` + `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` which is required by `&mut std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` error[E0631]: type mismatch in closure arguments --> $DIR/issue-36053-2.rs:11:32 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 3a9fddc474a..5d297728eca 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -30,9 +30,14 @@ error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<& | LL | writeln!(fp, "hello world").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>` + | + ::: $SRC_DIR/libstd/io/buffered.rs:LL:COL + | +LL | pub struct BufWriter { + | ------------------------------ doesn't satisfy `std::io::BufWriter<&dyn std::io::Write>: std::io::Write` | = note: the method `write_fmt` exists but the following trait bounds were not satisfied: - `&dyn std::io::Write: std::io::Write` + `&dyn std::io::Write: std::io::Write` which is required by `std::io::BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index 2051ea33391..456e1cd83ef 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -11,7 +11,10 @@ error[E0599]: no method named `clone` found for union `U5` in the c --> $DIR/union-derive-clone.rs:37:15 | LL | union U5 { - | ----------- method `clone` not found for this + | ----------- + | | + | method `clone` not found for this + | doesn't satisfy `U5: std::clone::Clone` ... LL | struct CloneNoCopy; | ------------------- doesn't satisfy `CloneNoCopy: std::marker::Copy` @@ -20,7 +23,7 @@ LL | let w = u.clone(); | ^^^^^ method not found in `U5` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `CloneNoCopy: std::marker::Copy` + `CloneNoCopy: std::marker::Copy` which is required by `U5: std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone` diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index f230d0d14d2..c3be38e1cf1 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -9,10 +9,15 @@ LL | trait Foo { ... LL | let _z = y.clone(); | ^^^^^ method not found in `std::boxed::Box` + | + ::: $SRC_DIR/liballoc/boxed.rs:LL:COL + | +LL | pub struct Box(Unique); + | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `dyn Foo: std::clone::Clone` - `dyn Foo: std::marker::Sized` + `dyn Foo: std::clone::Clone` which is required by `std::boxed::Box: std::clone::Clone` + `dyn Foo: std::marker::Sized` which is required by `std::boxed::Box: std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone` diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index 12d719a1027..fb2f4c01b63 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -6,9 +6,14 @@ LL | struct R { ... LL | let _j = i.clone(); | ^^^^^ method not found in `std::boxed::Box` + | + ::: $SRC_DIR/liballoc/boxed.rs:LL:COL + | +LL | pub struct Box(Unique); + | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `R: std::clone::Clone` + `R: std::clone::Clone` which is required by `std::boxed::Box: std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone`