Skip to content

Commit 70e8240

Browse files
committed
Point at impl blocks when they introduce unmet obligations
Group obligations by `impl` block that introduced them.
1 parent a6b31eb commit 70e8240

File tree

9 files changed

+184
-59
lines changed

9 files changed

+184
-59
lines changed

compiler/rustc_typeck/src/check/method/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub use self::CandidateSource::*;
1212
pub use self::MethodError::*;
1313

1414
use crate::check::FnCtxt;
15+
use crate::ObligationCause;
1516
use rustc_data_structures::sync::Lrc;
1617
use rustc_errors::{Applicability, DiagnosticBuilder};
1718
use rustc_hir as hir;
@@ -71,7 +72,8 @@ pub enum MethodError<'tcx> {
7172
#[derive(Debug)]
7273
pub struct NoMatchData<'tcx> {
7374
pub static_candidates: Vec<CandidateSource>,
74-
pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
75+
pub unsatisfied_predicates:
76+
Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
7577
pub out_of_scope_traits: Vec<DefId>,
7678
pub lev_candidate: Option<ty::AssocItem>,
7779
pub mode: probe::Mode,
@@ -80,7 +82,11 @@ pub struct NoMatchData<'tcx> {
8082
impl<'tcx> NoMatchData<'tcx> {
8183
pub fn new(
8284
static_candidates: Vec<CandidateSource>,
83-
unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
85+
unsatisfied_predicates: Vec<(
86+
ty::Predicate<'tcx>,
87+
Option<ty::Predicate<'tcx>>,
88+
Option<ObligationCause<'tcx>>,
89+
)>,
8490
out_of_scope_traits: Vec<DefId>,
8591
lev_candidate: Option<ty::AssocItem>,
8692
mode: probe::Mode,

compiler/rustc_typeck/src/check/method/probe.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ struct ProbeContext<'a, 'tcx> {
7878

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

8384
is_suggestion: IsSuggestion,
8485

@@ -1268,6 +1269,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12681269
possibly_unsatisfied_predicates: &mut Vec<(
12691270
ty::Predicate<'tcx>,
12701271
Option<ty::Predicate<'tcx>>,
1272+
Option<ObligationCause<'tcx>>,
12711273
)>,
12721274
unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>,
12731275
) -> Option<PickResult<'tcx>>
@@ -1412,6 +1414,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14121414
possibly_unsatisfied_predicates: &mut Vec<(
14131415
ty::Predicate<'tcx>,
14141416
Option<ty::Predicate<'tcx>>,
1417+
Option<ObligationCause<'tcx>>,
14151418
)>,
14161419
) -> ProbeResult {
14171420
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
@@ -1423,8 +1426,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14231426
.sup(probe.xform_self_ty, self_ty)
14241427
{
14251428
Ok(InferOk { obligations, value: () }) => obligations,
1426-
Err(_) => {
1427-
debug!("--> cannot relate self-types");
1429+
Err(err) => {
1430+
debug!("--> cannot relate self-types {:?}", err);
14281431
return ProbeResult::NoMatch;
14291432
}
14301433
};
@@ -1473,7 +1476,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14731476
let o = self.resolve_vars_if_possible(o);
14741477
if !self.predicate_may_hold(&o) {
14751478
result = ProbeResult::NoMatch;
1476-
possibly_unsatisfied_predicates.push((o.predicate, None));
1479+
possibly_unsatisfied_predicates.push((
1480+
o.predicate,
1481+
None,
1482+
Some(o.cause),
1483+
));
14771484
}
14781485
}
14791486
}
@@ -1519,16 +1526,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
15191526
} else {
15201527
Some(predicate)
15211528
};
1522-
possibly_unsatisfied_predicates
1523-
.push((nested_predicate, p));
1529+
possibly_unsatisfied_predicates.push((
1530+
nested_predicate,
1531+
p,
1532+
Some(obligation.cause.clone()),
1533+
));
15241534
}
15251535
}
15261536
}
15271537
_ => {
15281538
// Some nested subobligation of this predicate
15291539
// failed.
15301540
let predicate = self.resolve_vars_if_possible(predicate);
1531-
possibly_unsatisfied_predicates.push((predicate, None));
1541+
possibly_unsatisfied_predicates.push((predicate, None, None));
15321542
}
15331543
}
15341544
false
@@ -1547,7 +1557,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
15471557
let o = self.resolve_vars_if_possible(o);
15481558
if !self.predicate_may_hold(&o) {
15491559
result = ProbeResult::NoMatch;
1550-
possibly_unsatisfied_predicates.push((o.predicate, None));
1560+
possibly_unsatisfied_predicates.push((o.predicate, None, Some(o.cause)));
15511561
}
15521562
}
15531563

compiler/rustc_typeck/src/check/method/suggest.rs

Lines changed: 105 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use rustc_span::lev_distance;
1717
use rustc_span::symbol::{kw, sym, Ident};
1818
use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
1919
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
20-
use rustc_trait_selection::traits::{FulfillmentError, Obligation};
20+
use rustc_trait_selection::traits::{
21+
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
22+
};
2123

2224
use std::cmp::Ordering;
2325
use std::iter;
@@ -787,9 +789,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
787789
_ => None,
788790
}
789791
};
792+
793+
// Find all the requirements that come from a local `impl` block.
794+
let mut skip_list: FxHashSet<_> = Default::default();
795+
let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
796+
for (data, p, parent_p) in unsatisfied_predicates
797+
.iter()
798+
.filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
799+
.filter_map(|(p, parent, c)| match c.code {
800+
ObligationCauseCode::ImplDerivedObligation(ref data) => {
801+
Some((data, p, parent))
802+
}
803+
_ => None,
804+
})
805+
{
806+
let parent_trait_ref = data.parent_trait_ref;
807+
let parent_def_id = parent_trait_ref.def_id();
808+
let path = parent_trait_ref.print_only_trait_path();
809+
let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
810+
let mut candidates = vec![];
811+
self.tcx.for_each_relevant_impl(
812+
parent_def_id,
813+
parent_trait_ref.self_ty().skip_binder(),
814+
|impl_def_id| match self.tcx.hir().get_if_local(impl_def_id) {
815+
Some(Node::Item(hir::Item {
816+
kind: hir::ItemKind::Impl(hir::Impl { .. }),
817+
..
818+
})) => {
819+
candidates.push(impl_def_id);
820+
}
821+
_ => {}
822+
},
823+
);
824+
if let [def_id] = &candidates[..] {
825+
match self.tcx.hir().get_if_local(*def_id) {
826+
Some(Node::Item(hir::Item {
827+
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
828+
..
829+
})) => {
830+
if let Some(pred) = parent_p {
831+
// Done to add the "doesn't satisfy" `span_label`.
832+
let _ = format_pred(*pred);
833+
}
834+
skip_list.insert(p);
835+
let mut spans = Vec::with_capacity(2);
836+
if let Some(trait_ref) = of_trait {
837+
spans.push(trait_ref.path.span);
838+
}
839+
spans.push(self_ty.span);
840+
let entry = spanned_predicates.entry(spans.into());
841+
entry
842+
.or_insert_with(|| (path, tr_self_ty, Vec::new()))
843+
.2
844+
.push(p);
845+
}
846+
_ => {}
847+
}
848+
}
849+
}
850+
for (span, (path, self_ty, preds)) in spanned_predicates {
851+
err.span_note(
852+
span,
853+
&format!(
854+
"the following trait bounds were not satisfied because of the \
855+
requirements of the implementation of `{}` for `{}`:\n{}",
856+
path,
857+
self_ty,
858+
preds
859+
.into_iter()
860+
// .map(|pred| format!("{:?}", pred))
861+
.filter_map(|pred| format_pred(*pred))
862+
.map(|(p, _)| format!("`{}`", p))
863+
.collect::<Vec<_>>()
864+
.join("\n"),
865+
),
866+
);
867+
}
868+
869+
// The requirements that didn't have an `impl` span to show.
790870
let mut bound_list = unsatisfied_predicates
791871
.iter()
792-
.filter_map(|(pred, parent_pred)| {
872+
.filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred))
873+
.filter_map(|(pred, parent_pred, _cause)| {
793874
format_pred(*pred).map(|(p, self_ty)| match parent_pred {
794875
None => format!("`{}`", &p),
795876
Some(parent_pred) => match format_pred(*parent_pred) {
@@ -832,7 +913,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
832913
for (span, msg) in bound_spans.into_iter() {
833914
err.span_label(span, &msg);
834915
}
835-
if !bound_list.is_empty() {
916+
if !bound_list.is_empty() || !skip_list.is_empty() {
836917
let bound_list = bound_list
837918
.into_iter()
838919
.map(|(_, path)| path)
@@ -842,9 +923,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
842923
err.set_primary_message(&format!(
843924
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
844925
));
845-
err.note(&format!(
846-
"the following trait bounds were not satisfied:\n{bound_list}"
847-
));
926+
if !bound_list.is_empty() {
927+
err.note(&format!(
928+
"the following trait bounds were not satisfied:\n{bound_list}"
929+
));
930+
}
848931
self.suggest_derive(&mut err, &unsatisfied_predicates);
849932

850933
unsatisfied_bounds = true;
@@ -1058,18 +1141,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10581141
err.span_note(spans, &msg);
10591142
}
10601143

1061-
let preds: Vec<_> = errors.iter().map(|e| (e.obligation.predicate, None)).collect();
1144+
let preds: Vec<_> = errors
1145+
.iter()
1146+
.map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
1147+
.collect();
10621148
self.suggest_derive(err, &preds);
10631149
}
10641150

10651151
fn suggest_derive(
10661152
&self,
10671153
err: &mut DiagnosticBuilder<'_>,
1068-
unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
1154+
unsatisfied_predicates: &Vec<(
1155+
ty::Predicate<'tcx>,
1156+
Option<ty::Predicate<'tcx>>,
1157+
Option<ObligationCause<'tcx>>,
1158+
)>,
10691159
) {
10701160
let mut derives = Vec::<(String, Span, String)>::new();
10711161
let mut traits = Vec::<Span>::new();
1072-
for (pred, _) in unsatisfied_predicates {
1162+
for (pred, _, _) in unsatisfied_predicates {
10731163
let trait_pred = match pred.kind().skip_binder() {
10741164
ty::PredicateKind::Trait(trait_pred) => trait_pred,
10751165
_ => continue,
@@ -1260,7 +1350,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12601350
item_name: Ident,
12611351
source: SelfSource<'tcx>,
12621352
valid_out_of_scope_traits: Vec<DefId>,
1263-
unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
1353+
unsatisfied_predicates: &[(
1354+
ty::Predicate<'tcx>,
1355+
Option<ty::Predicate<'tcx>>,
1356+
Option<ObligationCause<'tcx>>,
1357+
)],
12641358
unsatisfied_bounds: bool,
12651359
) {
12661360
let mut alt_rcvr_sugg = false;
@@ -1376,7 +1470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13761470
// this isn't perfect (that is, there are cases when
13771471
// implementing a trait would be legal but is rejected
13781472
// here).
1379-
unsatisfied_predicates.iter().all(|(p, _)| {
1473+
unsatisfied_predicates.iter().all(|(p, _, _)| {
13801474
match p.kind().skip_binder() {
13811475
// Hide traits if they are present in predicates as they can be fixed without
13821476
// having to implement them.

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ LL | struct NotClone;
1313
LL | Bar::<NotClone> { x: 1 }.clone();
1414
| ^^^^^ method cannot be called on `Bar<NotClone>` due to unsatisfied trait bounds
1515
|
16-
= note: the following trait bounds were not satisfied:
17-
`NotClone: Clone`
18-
which is required by `Bar<NotClone>: Clone`
16+
note: the following trait bounds were not satisfied because of the requirements of the implementation of `Clone` for `_`:
17+
`NotClone: Clone`
18+
--> $DIR/derive-assoc-type-not-impl.rs:6:10
19+
|
20+
LL | #[derive(Clone)]
21+
| ^^^^^
1922
= help: items from traits can only be used if the trait is implemented and in scope
2023
= note: the following trait defines an item `clone`, perhaps you need to implement it:
2124
candidate #1: `Clone`
25+
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
2226
help: consider annotating `NotClone` with `#[derive(Clone)]`
2327
|
2428
LL | #[derive(Clone)]

src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ trait M {
1212
}
1313

1414
impl<T: X<Y<i32> = i32>> M for T {}
15+
//~^ NOTE the following trait bounds were not satisfied
1516

1617
struct S;
1718
//~^ NOTE method `f` not found for this
@@ -26,7 +27,6 @@ fn f(a: S) {
2627
a.f();
2728
//~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied
2829
//~| NOTE method cannot be called on `S` due to unsatisfied trait bounds
29-
//~| NOTE the following trait bounds were not satisfied:
3030
}
3131

3232
fn main() {}

src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
2-
--> $DIR/method-unsatified-assoc-type-predicate.rs:26:7
2+
--> $DIR/method-unsatified-assoc-type-predicate.rs:27:7
33
|
44
LL | struct S;
55
| ---------
@@ -11,9 +11,12 @@ LL | struct S;
1111
LL | a.f();
1212
| ^ method cannot be called on `S` due to unsatisfied trait bounds
1313
|
14-
= note: the following trait bounds were not satisfied:
15-
`<S as X>::Y<i32> = i32`
16-
which is required by `S: M`
14+
note: the following trait bounds were not satisfied because of the requirements of the implementation of `M` for `_`:
15+
`<S as X>::Y<i32> = i32`
16+
--> $DIR/method-unsatified-assoc-type-predicate.rs:14:26
17+
|
18+
LL | impl<T: X<Y<i32> = i32>> M for T {}
19+
| ^ ^
1720

1821
error: aborting due to previous error
1922

0 commit comments

Comments
 (0)