mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 01:04:03 +00:00
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.
This commit is contained in:
parent
8119d0853d
commit
9a64c3f5cb
@ -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<CandidateSource>,
|
||||
pub unsatisfied_predicates: Vec<ty::Predicate<'tcx>>,
|
||||
pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
|
||||
pub out_of_scope_traits: Vec<DefId>,
|
||||
pub lev_candidate: Option<ty::AssocItem>,
|
||||
pub mode: probe::Mode,
|
||||
@ -76,7 +76,7 @@ pub struct NoMatchData<'tcx> {
|
||||
impl<'tcx> NoMatchData<'tcx> {
|
||||
pub fn new(
|
||||
static_candidates: Vec<CandidateSource>,
|
||||
unsatisfied_predicates: Vec<ty::Predicate<'tcx>>,
|
||||
unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
|
||||
out_of_scope_traits: Vec<DefId>,
|
||||
lev_candidate: Option<ty::AssocItem>,
|
||||
mode: probe::Mode,
|
||||
|
@ -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<ty::Predicate<'tcx>>,
|
||||
unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
|
||||
|
||||
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<ty::Predicate<'tcx>>,
|
||||
possibly_unsatisfied_predicates: &mut Vec<(
|
||||
ty::Predicate<'tcx>,
|
||||
Option<ty::Predicate<'tcx>>,
|
||||
)>,
|
||||
unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>,
|
||||
) -> Option<PickResult<'tcx>>
|
||||
where
|
||||
@ -1342,7 +1345,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
probe: &Candidate<'tcx>,
|
||||
possibly_unsatisfied_predicates: &mut Vec<ty::Predicate<'tcx>>,
|
||||
possibly_unsatisfied_predicates: &mut Vec<(
|
||||
ty::Predicate<'tcx>,
|
||||
Option<ty::Predicate<'tcx>>,
|
||||
)>,
|
||||
) -> 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) => {
|
||||
// `<Foo as Iterator>::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::<Vec<_>>();
|
||||
.collect::<Vec<String>>();
|
||||
bound_list.sort();
|
||||
bound_list.dedup(); // #35677
|
||||
bound_spans.sort();
|
||||
|
@ -2,7 +2,10 @@ error[E0599]: no method named `clone` found for struct `Bar<NotClone>` in the cu
|
||||
--> $DIR/derive-assoc-type-not-impl.rs:18:30
|
||||
|
|
||||
LL | struct Bar<T: Foo> {
|
||||
| ------------------ method `clone` not found for this
|
||||
| ------------------
|
||||
| |
|
||||
| method `clone` not found for this
|
||||
| doesn't satisfy `Bar<NotClone>: std::clone::Clone`
|
||||
...
|
||||
LL | struct NotClone;
|
||||
| ---------------- doesn't satisfy `NotClone: std::clone::Clone`
|
||||
@ -11,7 +14,7 @@ LL | Bar::<NotClone> { x: 1 }.clone();
|
||||
| ^^^^^ method not found in `Bar<NotClone>`
|
||||
|
|
||||
= 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<NotClone>: 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`
|
||||
|
@ -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
|
||||
|
||||
|
@ -17,10 +17,13 @@ LL | .collect();
|
||||
|
|
||||
LL | pub struct Cloned<I> {
|
||||
| -------------------- 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`
|
||||
...
|
||||
LL | pub struct TakeWhile<I, P> {
|
||||
| -------------------------- 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 = &_`
|
||||
|
|
||||
= note: the method `collect` exists but the following trait bounds were not satisfied:
|
||||
`<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item = &_`
|
||||
`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`
|
||||
`<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`
|
||||
`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`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -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`
|
||||
|
@ -10,9 +10,9 @@ LL | pub struct Filter<I, P> {
|
||||
| ----------------------- 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`
|
||||
|
|
||||
= 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<std::iter::Fuse<std::iter::Once<&str>>, [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<std::iter::Fuse<std::iter::Once<&str>>, [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<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator`
|
||||
`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`
|
||||
|
||||
error[E0631]: type mismatch in closure arguments
|
||||
--> $DIR/issue-36053-2.rs:11:32
|
||||
|
@ -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<W: Write> {
|
||||
| ------------------------------ 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
|
||||
|
@ -11,7 +11,10 @@ error[E0599]: no method named `clone` found for union `U5<CloneNoCopy>` in the c
|
||||
--> $DIR/union-derive-clone.rs:37:15
|
||||
|
|
||||
LL | union U5<T> {
|
||||
| ----------- method `clone` not found for this
|
||||
| -----------
|
||||
| |
|
||||
| method `clone` not found for this
|
||||
| doesn't satisfy `U5<CloneNoCopy>: 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<CloneNoCopy>`
|
||||
|
|
||||
= 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<CloneNoCopy>: 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`
|
||||
|
@ -9,10 +9,15 @@ LL | trait Foo {
|
||||
...
|
||||
LL | let _z = y.clone();
|
||||
| ^^^^^ method not found in `std::boxed::Box<dyn Foo>`
|
||||
|
|
||||
::: $SRC_DIR/liballoc/boxed.rs:LL:COL
|
||||
|
|
||||
LL | pub struct Box<T: ?Sized>(Unique<T>);
|
||||
| ------------------------------------- doesn't satisfy `std::boxed::Box<dyn Foo>: 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<dyn Foo>: std::clone::Clone`
|
||||
`dyn Foo: std::marker::Sized` which is required by `std::boxed::Box<dyn Foo>: 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`
|
||||
|
@ -6,9 +6,14 @@ LL | struct R {
|
||||
...
|
||||
LL | let _j = i.clone();
|
||||
| ^^^^^ method not found in `std::boxed::Box<R>`
|
||||
|
|
||||
::: $SRC_DIR/liballoc/boxed.rs:LL:COL
|
||||
|
|
||||
LL | pub struct Box<T: ?Sized>(Unique<T>);
|
||||
| ------------------------------------- doesn't satisfy `std::boxed::Box<R>: 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<R>: 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`
|
||||
|
Loading…
Reference in New Issue
Block a user