Skip to content

Commit 1b4c5b5

Browse files
committed
Track all predicates in errors, not just trait obligations
Surface associated type projection bounds that could not be fulfilled in E0599 errors. Always present the list of unfulfilled trait bounds, regardless of whether we're pointing at the ADT or trait that didn't satisfy it.
1 parent 2e8399d commit 1b4c5b5

19 files changed

+134
-103
lines changed

src/librustc/traits/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,20 @@ impl<'tcx, N> Vtable<'tcx, N> {
579579
}
580580
}
581581

582+
pub fn borrow_nested_obligations(&self) -> &[N] {
583+
match &self {
584+
VtableImpl(i) => &i.nested[..],
585+
VtableParam(n) => &n[..],
586+
VtableBuiltin(i) => &i.nested[..],
587+
VtableAutoImpl(d) => &d.nested[..],
588+
VtableClosure(c) => &c.nested[..],
589+
VtableGenerator(c) => &c.nested[..],
590+
VtableObject(d) => &d.nested[..],
591+
VtableFnPointer(d) => &d.nested[..],
592+
VtableTraitAlias(d) => &d.nested[..],
593+
}
594+
}
595+
582596
pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M>
583597
where
584598
F: FnMut(N) -> M,

src/librustc_typeck/check/method/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::check::FnCtxt;
1414
use rustc::ty::subst::Subst;
1515
use rustc::ty::subst::{InternalSubsts, SubstsRef};
1616
use rustc::ty::GenericParamDefKind;
17-
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable, WithConstness};
17+
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness};
1818
use rustc_data_structures::sync::Lrc;
1919
use rustc_errors::{Applicability, DiagnosticBuilder};
2020
use rustc_hir as hir;
@@ -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<TraitRef<'tcx>>,
70+
pub unsatisfied_predicates: Vec<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<TraitRef<'tcx>>,
79+
unsatisfied_predicates: Vec<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: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use rustc::session::config::nightly_options;
1414
use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
1515
use rustc::ty::GenericParamDefKind;
1616
use rustc::ty::{
17-
self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
18-
WithConstness,
17+
self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
1918
};
2019
use rustc_data_structures::fx::FxHashSet;
2120
use rustc_data_structures::sync::Lrc;
@@ -78,7 +77,7 @@ struct ProbeContext<'a, 'tcx> {
7877

7978
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
8079
/// for error reporting
81-
unsatisfied_predicates: Vec<TraitRef<'tcx>>,
80+
unsatisfied_predicates: Vec<ty::Predicate<'tcx>>,
8281

8382
is_suggestion: IsSuggestion,
8483
}
@@ -1224,7 +1223,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12241223
&self,
12251224
self_ty: Ty<'tcx>,
12261225
probes: ProbesIter,
1227-
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>,
1226+
possibly_unsatisfied_predicates: &mut Vec<ty::Predicate<'tcx>>,
12281227
unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>,
12291228
) -> Option<PickResult<'tcx>>
12301229
where
@@ -1343,7 +1342,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13431342
&self,
13441343
self_ty: Ty<'tcx>,
13451344
probe: &Candidate<'tcx>,
1346-
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>,
1345+
possibly_unsatisfied_predicates: &mut Vec<ty::Predicate<'tcx>>,
13471346
) -> ProbeResult {
13481347
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
13491348

@@ -1398,47 +1397,40 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13981397
let predicate = trait_ref.without_const().to_predicate();
13991398
let obligation = traits::Obligation::new(cause, self.param_env, predicate);
14001399
if !self.predicate_may_hold(&obligation) {
1401-
if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) {
1400+
if self.probe(|_| {
1401+
match self.select_trait_candidate(trait_ref) {
1402+
Err(_) => return true,
1403+
Ok(Some(vtable))
1404+
if !vtable.borrow_nested_obligations().is_empty() =>
1405+
{
1406+
for obligation in vtable.borrow_nested_obligations() {
1407+
// Determine exactly which obligation wasn't met, so
1408+
// that we can give more context in the error.
1409+
if !self.predicate_may_hold(&obligation) {
1410+
result = ProbeResult::NoMatch;
1411+
let o = self.resolve_vars_if_possible(obligation);
1412+
possibly_unsatisfied_predicates.push(o.predicate);
1413+
}
1414+
}
1415+
}
1416+
_ => {
1417+
// Some nested subobligation of this predicate
1418+
// failed.
1419+
//
1420+
// FIXME: try to find the exact nested subobligation
1421+
// and point at it rather than reporting the entire
1422+
// trait-ref?
1423+
result = ProbeResult::NoMatch;
1424+
let predicate = self.resolve_vars_if_possible(&predicate);
1425+
possibly_unsatisfied_predicates.push(predicate);
1426+
}
1427+
}
1428+
false
1429+
}) {
14021430
// This candidate's primary obligation doesn't even
14031431
// select - don't bother registering anything in
14041432
// `potentially_unsatisfied_predicates`.
14051433
return ProbeResult::NoMatch;
1406-
} else {
1407-
self.probe(|_| {
1408-
match self.select_trait_candidate(trait_ref) {
1409-
Ok(Some(traits::VtableImpl(traits::VtableImplData {
1410-
nested,
1411-
..
1412-
}))) if !nested.is_empty() => {
1413-
for obligation in nested {
1414-
// Determine exactly which obligation wasn't met, so
1415-
// that we can give more context in the error.
1416-
if !self.predicate_may_hold(&obligation) {
1417-
result = ProbeResult::NoMatch;
1418-
if let Some(poly_trait_ref) =
1419-
obligation.predicate.to_opt_poly_trait_ref()
1420-
{
1421-
let trait_ref = poly_trait_ref.clone();
1422-
let trait_ref = trait_ref.skip_binder();
1423-
possibly_unsatisfied_predicates
1424-
.push(*trait_ref);
1425-
}
1426-
}
1427-
}
1428-
}
1429-
_ => {
1430-
// Some nested subobligation of this predicate
1431-
// failed.
1432-
//
1433-
// FIXME: try to find the exact nested subobligation
1434-
// and point at it rather than reporting the entire
1435-
// trait-ref?
1436-
result = ProbeResult::NoMatch;
1437-
let trait_ref = self.resolve_vars_if_possible(&trait_ref);
1438-
possibly_unsatisfied_predicates.push(trait_ref);
1439-
}
1440-
}
1441-
});
14421434
}
14431435
}
14441436
vec![]
@@ -1455,9 +1447,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14551447
let o = self.resolve_vars_if_possible(&o);
14561448
if !self.predicate_may_hold(&o) {
14571449
result = ProbeResult::NoMatch;
1458-
if let &ty::Predicate::Trait(ref pred, _) = &o.predicate {
1459-
possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref);
1460-
}
1450+
possibly_unsatisfied_predicates.push(o.predicate);
14611451
}
14621452
}
14631453

src/librustc_typeck/check/method/suggest.rs

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -535,57 +535,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
535535
}
536536

537537
if !unsatisfied_predicates.is_empty() {
538+
let def_span =
539+
|def_id| self.tcx.sess.source_map().def_span(self.tcx.def_span(def_id));
538540
let mut bound_spans = vec![];
539541
let mut bound_list = unsatisfied_predicates
540542
.iter()
541-
.filter_map(|p| {
542-
let self_ty = p.self_ty();
543-
match &self_ty.kind {
544-
ty::Adt(def, _) => {
545-
bound_spans.push((
546-
self.tcx
547-
.sess
548-
.source_map()
549-
.def_span(self.tcx.def_span(def.did)),
550-
format!(
551-
"the method `{}` exists but this type doesn't satisfy \
552-
the bound `{}: {}`",
553-
item_name,
554-
p.self_ty(),
555-
p.print_only_trait_path()
556-
),
557-
));
558-
None
559-
}
560-
ty::Dynamic(preds, _) => {
561-
for pred in *preds.skip_binder() {
562-
match pred {
563-
ty::ExistentialPredicate::Trait(tr) => bound_spans
564-
.push((
565-
self.tcx
566-
.sess
567-
.source_map()
568-
.def_span(self.tcx.def_span(tr.def_id)),
569-
format!(
570-
"the method `{}` exists but this trait \
571-
doesn't satisfy the bound `{}: {}`",
572-
item_name,
573-
p.self_ty(),
574-
p.print_only_trait_path()
575-
),
576-
)),
577-
ty::ExistentialPredicate::Projection(_)
578-
| ty::ExistentialPredicate::AutoTrait(_) => {}
543+
.filter_map(|pred| match pred {
544+
ty::Predicate::Projection(pred) => {
545+
// `<Foo as Iterator>::Item = String`.
546+
let trait_ref =
547+
pred.skip_binder().projection_ty.trait_ref(self.tcx);
548+
let assoc = self
549+
.tcx
550+
.associated_item(pred.skip_binder().projection_ty.item_def_id);
551+
let ty = pred.skip_binder().ty;
552+
Some(format!("`{}::{} = {}`", trait_ref, assoc.ident, ty))
553+
}
554+
ty::Predicate::Trait(poly_trait_ref, _) => {
555+
let p = poly_trait_ref.skip_binder().trait_ref;
556+
let self_ty = p.self_ty();
557+
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+
}
579581
}
580582
}
581-
None
583+
_ => {}
582584
}
583-
_ => Some(format!(
584-
"`{}: {}`",
585-
p.self_ty(),
586-
p.print_only_trait_path()
587-
)),
585+
Some(format!("`{}: {}`", self_ty, path))
588586
}
587+
_ => None,
589588
})
590589
.collect::<Vec<_>>();
591590
bound_list.sort();

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ LL | struct Bar<T: Foo> {
55
| ------------------ method `clone` not found for this
66
...
77
LL | struct NotClone;
8-
| ---------------- the method `clone` exists but this type doesn't satisfy the bound `NotClone: std::clone::Clone`
8+
| ---------------- doesn't satisfy `NotClone: std::clone::Clone`
99
...
1010
LL | Bar::<NotClone> { x: 1 }.clone();
1111
| ^^^^^ method not found in `Bar<NotClone>`
1212
|
13+
= note: the method `clone` exists but the following trait bounds were not satisfied:
14+
`NotClone: std::clone::Clone`
1315
= help: items from traits can only be used if the trait is implemented and in scope
1416
= note: the following trait defines an item `clone`, perhaps you need to implement it:
1517
candidate #1: `std::clone::Clone`

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ LL | .collect();
1616
::: $SRC_DIR/libcore/iter/adapters/mod.rs:LL:COL
1717
|
1818
LL | pub struct Cloned<I> {
19-
| -------------------- the method `collect` exists but this type doesn't satisfy the bound `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`
19+
| -------------------- 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+
= 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`
2024

2125
error: aborting due to 2 previous errors
2226

src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | let _result = &Some(42).as_deref();
55
| ^^^^^^^^ help: there is a method with a similar name: `as_ref`
66
|
77
= note: the method `as_deref` exists but the following trait bounds were not satisfied:
8+
`<{integer} as std::ops::Deref>::Target = _`
89
`{integer}: std::ops::Deref`
910

1011
error: aborting due to previous error

src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | let _result = &mut Some(42).as_deref_mut();
55
| ^^^^^^^^^^^^ method not found in `std::option::Option<{integer}>`
66
|
77
= note: the method `as_deref_mut` exists but the following trait bounds were not satisfied:
8+
`<{integer} as std::ops::Deref>::Target = _`
89
`{integer}: std::ops::DerefMut`
910

1011
error: aborting due to previous error

src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | let _result = &Ok(42).as_deref();
55
| ^^^^^^^^ help: there is a method with a similar name: `as_ref`
66
|
77
= note: the method `as_deref` exists but the following trait bounds were not satisfied:
8+
`<{integer} as std::ops::Deref>::Target = _`
89
`{integer}: std::ops::Deref`
910

1011
error: aborting due to previous error

src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | let _result = &Err(41).as_deref_err();
55
| ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut`
66
|
77
= note: the method `as_deref_err` exists but the following trait bounds were not satisfied:
8+
`<{integer} as std::ops::Deref>::Target = _`
89
`{integer}: std::ops::Deref`
910

1011
error: aborting due to previous error

src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | let _result = &mut Ok(42).as_deref_mut();
55
| ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_err`
66
|
77
= note: the method `as_deref_mut` exists but the following trait bounds were not satisfied:
8+
`<{integer} as std::ops::Deref>::Target = _`
89
`{integer}: std::ops::DerefMut`
910

1011
error: aborting due to previous error

src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | let _result = &mut Err(41).as_deref_mut_err();
55
| ^^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut`
66
|
77
= note: the method `as_deref_mut_err` exists but the following trait bounds were not satisfied:
8+
`<{integer} as std::ops::Deref>::Target = _`
89
`{integer}: std::ops::DerefMut`
910

1011
error: aborting due to previous error

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ LL | pub struct Foo;
3838
| ---------------
3939
| |
4040
| method `take` not found for this
41-
| the method `take` exists but this type doesn't satisfy the bound `Foo: std::iter::Iterator`
41+
| doesn't satisfy `Foo: std::iter::Iterator`
4242
...
4343
LL | .take()
4444
| ^^^^ method not found in `Foo`
4545
|
46+
= note: the method `take` exists but the following trait bounds were not satisfied:
47+
`Foo: std::iter::Iterator`
4648
= help: items from traits can only be used if the trait is implemented and in scope
4749
= note: the following traits define an item `take`, perhaps you need to implement one of them:
4850
candidate #1: `std::io::Read`

0 commit comments

Comments
 (0)