Skip to content

Commit 9a7345b

Browse files
committed
Show information of chain of bound obligations
When the obligation that couldn't be fulfilled is specific to a nested obligation, maintain both the nested and parent obligations around for more accurate and detailed error reporting.
1 parent 1b4c5b5 commit 9a7345b

File tree

12 files changed

+111
-60
lines changed

12 files changed

+111
-60
lines changed

src/librustc_typeck/check/method/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub enum MethodError<'tcx> {
6767
// could lead to matches if satisfied, and a list of not-in-scope traits which may work.
6868
pub struct NoMatchData<'tcx> {
6969
pub static_candidates: Vec<CandidateSource>,
70-
pub unsatisfied_predicates: Vec<ty::Predicate<'tcx>>,
70+
pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
7171
pub out_of_scope_traits: Vec<DefId>,
7272
pub lev_candidate: Option<ty::AssocItem>,
7373
pub mode: probe::Mode,
@@ -76,7 +76,7 @@ pub struct NoMatchData<'tcx> {
7676
impl<'tcx> NoMatchData<'tcx> {
7777
pub fn new(
7878
static_candidates: Vec<CandidateSource>,
79-
unsatisfied_predicates: Vec<ty::Predicate<'tcx>>,
79+
unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
8080
out_of_scope_traits: Vec<DefId>,
8181
lev_candidate: Option<ty::AssocItem>,
8282
mode: probe::Mode,

src/librustc_typeck/check/method/probe.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ struct ProbeContext<'a, 'tcx> {
7777

7878
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
7979
/// for error reporting
80-
unsatisfied_predicates: Vec<ty::Predicate<'tcx>>,
80+
unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
8181

8282
is_suggestion: IsSuggestion,
8383
}
@@ -1223,7 +1223,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12231223
&self,
12241224
self_ty: Ty<'tcx>,
12251225
probes: ProbesIter,
1226-
possibly_unsatisfied_predicates: &mut Vec<ty::Predicate<'tcx>>,
1226+
possibly_unsatisfied_predicates: &mut Vec<(
1227+
ty::Predicate<'tcx>,
1228+
Option<ty::Predicate<'tcx>>,
1229+
)>,
12271230
unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>,
12281231
) -> Option<PickResult<'tcx>>
12291232
where
@@ -1342,7 +1345,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13421345
&self,
13431346
self_ty: Ty<'tcx>,
13441347
probe: &Candidate<'tcx>,
1345-
possibly_unsatisfied_predicates: &mut Vec<ty::Predicate<'tcx>>,
1348+
possibly_unsatisfied_predicates: &mut Vec<(
1349+
ty::Predicate<'tcx>,
1350+
Option<ty::Predicate<'tcx>>,
1351+
)>,
13461352
) -> ProbeResult {
13471353
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
13481354

@@ -1409,20 +1415,25 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14091415
if !self.predicate_may_hold(&obligation) {
14101416
result = ProbeResult::NoMatch;
14111417
let o = self.resolve_vars_if_possible(obligation);
1412-
possibly_unsatisfied_predicates.push(o.predicate);
1418+
let predicate =
1419+
self.resolve_vars_if_possible(&predicate);
1420+
let p = if predicate == o.predicate {
1421+
// Avoid "`MyStruct: Foo` which is required by
1422+
// `MyStruct: Foo`" in E0599.
1423+
None
1424+
} else {
1425+
Some(predicate)
1426+
};
1427+
possibly_unsatisfied_predicates.push((o.predicate, p));
14131428
}
14141429
}
14151430
}
14161431
_ => {
14171432
// Some nested subobligation of this predicate
14181433
// failed.
1419-
//
1420-
// FIXME: try to find the exact nested subobligation
1421-
// and point at it rather than reporting the entire
1422-
// trait-ref?
14231434
result = ProbeResult::NoMatch;
14241435
let predicate = self.resolve_vars_if_possible(&predicate);
1425-
possibly_unsatisfied_predicates.push(predicate);
1436+
possibly_unsatisfied_predicates.push((predicate, None));
14261437
}
14271438
}
14281439
false
@@ -1447,7 +1458,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14471458
let o = self.resolve_vars_if_possible(&o);
14481459
if !self.predicate_may_hold(&o) {
14491460
result = ProbeResult::NoMatch;
1450-
possibly_unsatisfied_predicates.push(o.predicate);
1461+
possibly_unsatisfied_predicates.push((o.predicate, None));
14511462
}
14521463
}
14531464

src/librustc_typeck/check/method/suggest.rs

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -538,9 +538,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
538538
let def_span =
539539
|def_id| self.tcx.sess.source_map().def_span(self.tcx.def_span(def_id));
540540
let mut bound_spans = vec![];
541-
let mut bound_list = unsatisfied_predicates
542-
.iter()
543-
.filter_map(|pred| match pred {
541+
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str| {
542+
match &self_ty.kind {
543+
ty::Adt(def, _) => {
544+
// Point at the type that couldn't satisfy the bound.
545+
bound_spans.push((
546+
def_span(def.did),
547+
format!("doesn't satisfy {}", obligation),
548+
));
549+
}
550+
ty::Dynamic(preds, _) => {
551+
// Point at the trait object that couldn't satisfy the bound.
552+
for pred in *preds.skip_binder() {
553+
match pred {
554+
ty::ExistentialPredicate::Trait(tr) => bound_spans.push((
555+
def_span(tr.def_id),
556+
format!("doesn't satisfy {}", obligation),
557+
)),
558+
ty::ExistentialPredicate::Projection(_)
559+
| ty::ExistentialPredicate::AutoTrait(_) => {}
560+
}
561+
}
562+
}
563+
_ => {}
564+
}
565+
};
566+
let mut format_pred = |pred| {
567+
match pred {
544568
ty::Predicate::Projection(pred) => {
545569
// `<Foo as Iterator>::Item = String`.
546570
let trait_ref =
@@ -549,44 +573,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
549573
.tcx
550574
.associated_item(pred.skip_binder().projection_ty.item_def_id);
551575
let ty = pred.skip_binder().ty;
552-
Some(format!("`{}::{} = {}`", trait_ref, assoc.ident, ty))
576+
let obligation =
577+
format!("`{}::{} = {}`", trait_ref, assoc.ident, ty);
578+
bound_span_label(trait_ref.self_ty(), &obligation);
579+
Some(obligation)
553580
}
554581
ty::Predicate::Trait(poly_trait_ref, _) => {
555582
let p = poly_trait_ref.skip_binder().trait_ref;
556583
let self_ty = p.self_ty();
557584
let path = p.print_only_trait_path();
558-
match &self_ty.kind {
559-
ty::Adt(def, _) => {
560-
// Point at the type that couldn't satisfy the bound.
561-
bound_spans.push((
562-
def_span(def.did),
563-
format!("doesn't satisfy `{}: {}`", self_ty, path),
564-
));
565-
}
566-
ty::Dynamic(preds, _) => {
567-
// Point at the trait object that couldn't satisfy the bound.
568-
for pred in *preds.skip_binder() {
569-
match pred {
570-
ty::ExistentialPredicate::Trait(tr) => bound_spans
571-
.push((
572-
def_span(tr.def_id),
573-
format!(
574-
"doesn't satisfy `{}: {}`",
575-
self_ty, path
576-
),
577-
)),
578-
ty::ExistentialPredicate::Projection(_)
579-
| ty::ExistentialPredicate::AutoTrait(_) => {}
580-
}
581-
}
582-
}
583-
_ => {}
584-
}
585-
Some(format!("`{}: {}`", self_ty, path))
585+
let obligation = format!("`{}: {}`", self_ty, path);
586+
bound_span_label(self_ty, &obligation);
587+
Some(obligation)
586588
}
587589
_ => None,
590+
}
591+
};
592+
let mut bound_list = unsatisfied_predicates
593+
.iter()
594+
.filter_map(|(pred, parent_pred)| {
595+
format_pred(*pred).map(|pred| match parent_pred {
596+
None => pred,
597+
Some(parent_pred) => match format_pred(*parent_pred) {
598+
None => pred,
599+
Some(parent_pred) => {
600+
format!("{} which is required by {}", pred, parent_pred)
601+
}
602+
},
603+
})
588604
})
589-
.collect::<Vec<_>>();
605+
.collect::<Vec<String>>();
590606
bound_list.sort();
591607
bound_list.dedup(); // #35677
592608
bound_spans.sort();

src/test/ui/derives/derive-assoc-type-not-impl.stderr

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error[E0599]: no method named `clone` found for struct `Bar<NotClone>` in the cu
22
--> $DIR/derive-assoc-type-not-impl.rs:18:30
33
|
44
LL | struct Bar<T: Foo> {
5-
| ------------------ method `clone` not found for this
5+
| ------------------
6+
| |
7+
| method `clone` not found for this
8+
| doesn't satisfy `Bar<NotClone>: std::clone::Clone`
69
...
710
LL | struct NotClone;
811
| ---------------- doesn't satisfy `NotClone: std::clone::Clone`
@@ -11,7 +14,7 @@ LL | Bar::<NotClone> { x: 1 }.clone();
1114
| ^^^^^ method not found in `Bar<NotClone>`
1215
|
1316
= note: the method `clone` exists but the following trait bounds were not satisfied:
14-
`NotClone: std::clone::Clone`
17+
`NotClone: std::clone::Clone` which is required by `Bar<NotClone>: std::clone::Clone`
1518
= help: items from traits can only be used if the trait is implemented and in scope
1619
= note: the following trait defines an item `clone`, perhaps you need to implement it:
1720
candidate #1: `std::clone::Clone`

src/test/ui/issues/issue-21596.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | println!("{}", z.to_string());
77
= 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
88
= note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior
99
= note: the method `to_string` exists but the following trait bounds were not satisfied:
10-
`*const u8: std::fmt::Display`
10+
`*const u8: std::fmt::Display` which is required by `*const u8: std::string::ToString`
1111

1212
error: aborting due to previous error
1313

src/test/ui/issues/issue-31173.stderr

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ LL | .collect();
1717
|
1818
LL | pub struct Cloned<I> {
1919
| -------------------- doesn't satisfy `std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator`
20+
...
21+
LL | pub struct TakeWhile<I, P> {
22+
| -------------------------- doesn't satisfy `<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item = &_`
2023
|
2124
= note: the method `collect` exists but the following trait bounds were not satisfied:
22-
`<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item = &_`
23-
`std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator`
25+
`<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item = &_` which is required by `std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator`
26+
`std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` which is required by `&mut std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator`
2427

2528
error: aborting due to 2 previous errors
2629

src/test/ui/methods/method-call-err-msg.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ LL | .take()
4444
| ^^^^ method not found in `Foo`
4545
|
4646
= note: the method `take` exists but the following trait bounds were not satisfied:
47-
`Foo: std::iter::Iterator`
47+
`Foo: std::iter::Iterator` which is required by `&mut Foo: std::iter::Iterator`
4848
= help: items from traits can only be used if the trait is implemented and in scope
4949
= note: the following traits define an item `take`, perhaps you need to implement one of them:
5050
candidate #1: `std::io::Read`

src/test/ui/mismatched_types/issue-36053-2.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ LL | pub struct Filter<I, P> {
1010
| ----------------------- doesn't satisfy `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator`
1111
|
1212
= note: the method `count` exists but the following trait bounds were not satisfied:
13-
`<[closure@$DIR/issue-36053-2.rs:11:39: 11:53] as std::ops::FnOnce<(&&str,)>>::Output = bool`
14-
`[closure@$DIR/issue-36053-2.rs:11:39: 11:53]: std::ops::FnMut<(&&str,)>`
15-
`std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator`
13+
`<[closure@$DIR/issue-36053-2.rs:11:39: 11:53] as std::ops::FnOnce<(&&str,)>>::Output = bool` which is required by `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator`
14+
`[closure@$DIR/issue-36053-2.rs:11:39: 11:53]: std::ops::FnMut<(&&str,)>` which is required by `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator`
15+
`std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` which is required by `&mut std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator`
1616

1717
error[E0631]: type mismatch in closure arguments
1818
--> $DIR/issue-36053-2.rs:11:32

src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,14 @@ error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<&
3030
|
3131
LL | writeln!(fp, "hello world").unwrap();
3232
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>`
33+
|
34+
::: $SRC_DIR/libstd/io/buffered.rs:LL:COL
35+
|
36+
LL | pub struct BufWriter<W: Write> {
37+
| ------------------------------ doesn't satisfy `std::io::BufWriter<&dyn std::io::Write>: std::io::Write`
3338
|
3439
= note: the method `write_fmt` exists but the following trait bounds were not satisfied:
35-
`&dyn std::io::Write: std::io::Write`
40+
`&dyn std::io::Write: std::io::Write` which is required by `std::io::BufWriter<&dyn std::io::Write>: std::io::Write`
3641
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
3742

3843
error: aborting due to 4 previous errors

src/test/ui/union/union-derive-clone.stderr

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ error[E0599]: no method named `clone` found for union `U5<CloneNoCopy>` in the c
1111
--> $DIR/union-derive-clone.rs:37:15
1212
|
1313
LL | union U5<T> {
14-
| ----------- method `clone` not found for this
14+
| -----------
15+
| |
16+
| method `clone` not found for this
17+
| doesn't satisfy `U5<CloneNoCopy>: std::clone::Clone`
1518
...
1619
LL | struct CloneNoCopy;
1720
| ------------------- doesn't satisfy `CloneNoCopy: std::marker::Copy`
@@ -20,7 +23,7 @@ LL | let w = u.clone();
2023
| ^^^^^ method not found in `U5<CloneNoCopy>`
2124
|
2225
= note: the method `clone` exists but the following trait bounds were not satisfied:
23-
`CloneNoCopy: std::marker::Copy`
26+
`CloneNoCopy: std::marker::Copy` which is required by `U5<CloneNoCopy>: std::clone::Clone`
2427
= help: items from traits can only be used if the trait is implemented and in scope
2528
= note: the following trait defines an item `clone`, perhaps you need to implement it:
2629
candidate #1: `std::clone::Clone`

src/test/ui/unique-object-noncopyable.stderr

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@ LL | trait Foo {
99
...
1010
LL | let _z = y.clone();
1111
| ^^^^^ method not found in `std::boxed::Box<dyn Foo>`
12+
|
13+
::: $SRC_DIR/liballoc/boxed.rs:LL:COL
14+
|
15+
LL | pub struct Box<T: ?Sized>(Unique<T>);
16+
| ------------------------------------- doesn't satisfy `std::boxed::Box<dyn Foo>: std::clone::Clone`
1217
|
1318
= note: the method `clone` exists but the following trait bounds were not satisfied:
14-
`dyn Foo: std::clone::Clone`
15-
`dyn Foo: std::marker::Sized`
19+
`dyn Foo: std::clone::Clone` which is required by `std::boxed::Box<dyn Foo>: std::clone::Clone`
20+
`dyn Foo: std::marker::Sized` which is required by `std::boxed::Box<dyn Foo>: std::clone::Clone`
1621
= help: items from traits can only be used if the trait is implemented and in scope
1722
= note: the following trait defines an item `clone`, perhaps you need to implement it:
1823
candidate #1: `std::clone::Clone`

src/test/ui/unique-pinned-nocopy.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ LL | struct R {
66
...
77
LL | let _j = i.clone();
88
| ^^^^^ method not found in `std::boxed::Box<R>`
9+
|
10+
::: $SRC_DIR/liballoc/boxed.rs:LL:COL
11+
|
12+
LL | pub struct Box<T: ?Sized>(Unique<T>);
13+
| ------------------------------------- doesn't satisfy `std::boxed::Box<R>: std::clone::Clone`
914
|
1015
= note: the method `clone` exists but the following trait bounds were not satisfied:
11-
`R: std::clone::Clone`
16+
`R: std::clone::Clone` which is required by `std::boxed::Box<R>: std::clone::Clone`
1217
= help: items from traits can only be used if the trait is implemented and in scope
1318
= note: the following trait defines an item `clone`, perhaps you need to implement it:
1419
candidate #1: `std::clone::Clone`

0 commit comments

Comments
 (0)