Skip to content

Commit 4c3d9fa

Browse files
committed
Point at associated type for some obligations
1 parent 58b5491 commit 4c3d9fa

10 files changed

+90
-39
lines changed

src/librustc/traits/error_reporting.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2027,6 +2027,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
20272027
);
20282028
}
20292029
}
2030+
ObligationCauseCode::AssocTypeBound(impl_span, orig) => {
2031+
err.span_label(orig, "associated type defined here");
2032+
if let Some(sp) = impl_span {
2033+
err.span_label(sp, "in this `impl` item");
2034+
}
2035+
}
20302036
}
20312037
}
20322038

src/librustc/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ pub enum ObligationCauseCode<'tcx> {
268268

269269
/// #[feature(trivial_bounds)] is not enabled
270270
TrivialBound,
271+
272+
AssocTypeBound(/*impl*/ Option<Span>, /*original*/ Span),
271273
}
272274

273275
// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.

src/librustc/traits/structural_impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
544544
super::MethodReceiver => Some(super::MethodReceiver),
545545
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
546546
super::TrivialBound => Some(super::TrivialBound),
547+
super::AssocTypeBound(impl_sp, sp) => Some(super::AssocTypeBound(impl_sp, sp)),
547548
}
548549
}
549550
}

src/librustc/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3133,6 +3133,7 @@ impl<'tcx> TyCtxt<'tcx> {
31333133
}
31343134
}
31353135

3136+
#[derive(Clone)]
31363137
pub struct AssocItemsIterator<'tcx> {
31373138
tcx: TyCtxt<'tcx>,
31383139
def_ids: &'tcx [DefId],

src/librustc/ty/wf.rs

+45-19
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ pub fn obligations<'a, 'tcx>(
2222
ty: Ty<'tcx>,
2323
span: Span,
2424
) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
25-
let mut wf = WfPredicates { infcx,
26-
param_env,
27-
body_id,
28-
span,
29-
out: vec![] };
25+
let mut wf = WfPredicates {
26+
infcx,
27+
param_env,
28+
body_id,
29+
span,
30+
out: vec![],
31+
item: None,
32+
};
3033
if wf.compute(ty) {
3134
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
3235
let result = wf.normalize();
@@ -47,8 +50,9 @@ pub fn trait_obligations<'a, 'tcx>(
4750
body_id: hir::HirId,
4851
trait_ref: &ty::TraitRef<'tcx>,
4952
span: Span,
53+
item: Option<&'tcx hir::Item>,
5054
) -> Vec<traits::PredicateObligation<'tcx>> {
51-
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
55+
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item };
5256
wf.compute_trait_ref(trait_ref, Elaborate::All);
5357
wf.normalize()
5458
}
@@ -60,7 +64,7 @@ pub fn predicate_obligations<'a, 'tcx>(
6064
predicate: &ty::Predicate<'tcx>,
6165
span: Span,
6266
) -> Vec<traits::PredicateObligation<'tcx>> {
63-
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
67+
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
6468

6569
// (*) ok to skip binders, because wf code is prepared for it
6670
match *predicate {
@@ -107,6 +111,7 @@ struct WfPredicates<'a, 'tcx> {
107111
body_id: hir::HirId,
108112
span: Span,
109113
out: Vec<traits::PredicateObligation<'tcx>>,
114+
item: Option<&'tcx hir::Item>,
110115
}
111116

112117
/// Controls whether we "elaborate" supertraits and so forth on the WF
@@ -157,33 +162,54 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
157162
.collect()
158163
}
159164

160-
/// Pushes the obligations required for `trait_ref` to be WF into
161-
/// `self.out`.
165+
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
162166
fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
163167
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
164-
168+
let assoc_items = self.infcx.tcx.associated_items(trait_ref.def_id);
165169
let cause = self.cause(traits::MiscObligation);
166170
let param_env = self.param_env;
167171

168172
if let Elaborate::All = elaborate {
169173
let predicates = obligations.iter()
170-
.map(|obligation| obligation.predicate.clone())
171-
.collect();
174+
.map(|obligation| obligation.predicate.clone())
175+
.collect();
172176
let implied_obligations = traits::elaborate_predicates(self.infcx.tcx, predicates);
177+
let item_span: Option<Span> = self.item.map(|i| i.span);
178+
let item = &self.item;
173179
let implied_obligations = implied_obligations.map(|pred| {
174-
traits::Obligation::new(cause.clone(), param_env, pred)
180+
let mut cause = cause.clone();
181+
if let ty::Predicate::Trait(proj) = &pred {
182+
if let (
183+
ty::Projection(ty::ProjectionTy { item_def_id, .. }),
184+
Some(hir::ItemKind::Impl(.., bounds)),
185+
) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind)) {
186+
if let Some((bound, assoc_item)) = assoc_items.clone()
187+
.filter(|i| i.def_id == *item_def_id)
188+
.next()
189+
.and_then(|assoc_item| bounds.iter()
190+
.filter(|b| b.ident == assoc_item.ident)
191+
.next()
192+
.map(|bound| (bound, assoc_item)))
193+
{
194+
cause.span = bound.span;
195+
cause.code = traits::AssocTypeBound(item_span, assoc_item.ident.span);
196+
}
197+
}
198+
}
199+
traits::Obligation::new(cause, param_env, pred)
175200
});
176201
self.out.extend(implied_obligations);
177202
}
178203

179204
self.out.extend(obligations);
180205

181-
self.out.extend(
182-
trait_ref.substs.types()
183-
.filter(|ty| !ty.has_escaping_bound_vars())
184-
.map(|ty| traits::Obligation::new(cause.clone(),
185-
param_env,
186-
ty::Predicate::WellFormed(ty))));
206+
self.out.extend(trait_ref.substs.types()
207+
.filter(|ty| !ty.has_escaping_bound_vars())
208+
.map(|ty| traits::Obligation::new(
209+
cause.clone(),
210+
param_env,
211+
ty::Predicate::WellFormed(ty),
212+
)));
187213
}
188214

189215
/// Pushes the obligations required for `trait_ref::Item` to be WF

src/librustc_typeck/check/wfcheck.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ fn check_item_type(
430430

431431
fn check_impl<'tcx>(
432432
tcx: TyCtxt<'tcx>,
433-
item: &hir::Item,
433+
item: &'tcx hir::Item,
434434
ast_self_ty: &hir::Ty,
435435
ast_trait_ref: &Option<hir::TraitRef>,
436436
) {
@@ -445,15 +445,18 @@ fn check_impl<'tcx>(
445445
// therefore don't need to be WF (the trait's `Self: Trait` predicate
446446
// won't hold).
447447
let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
448-
let trait_ref =
449-
fcx.normalize_associated_types_in(
450-
ast_trait_ref.path.span, &trait_ref);
451-
let obligations =
452-
ty::wf::trait_obligations(fcx,
453-
fcx.param_env,
454-
fcx.body_id,
455-
&trait_ref,
456-
ast_trait_ref.path.span);
448+
let trait_ref = fcx.normalize_associated_types_in(
449+
ast_trait_ref.path.span,
450+
&trait_ref,
451+
);
452+
let obligations = ty::wf::trait_obligations(
453+
fcx,
454+
fcx.param_env,
455+
fcx.body_id,
456+
&trait_ref,
457+
ast_trait_ref.path.span,
458+
Some(item),
459+
);
457460
for obligation in obligations {
458461
fcx.register_predicate(obligation);
459462
}

src/test/ui/issues/issue-43784-associated-type.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ impl<T> Partial<T> for T::Assoc where
1010
{
1111
}
1212

13-
impl<T> Complete for T { //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied
14-
type Assoc = T;
13+
impl<T> Complete for T {
14+
type Assoc = T; //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied
1515
}
1616

1717
fn main() {}

src/test/ui/issues/issue-43784-associated-type.stderr

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
2-
--> $DIR/issue-43784-associated-type.rs:13:9
2+
--> $DIR/issue-43784-associated-type.rs:14:5
33
|
4-
LL | impl<T> Complete for T {
5-
| ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
4+
LL | type Assoc: Partial<Self>;
5+
| ----- associated type defined here
6+
...
7+
LL | / impl<T> Complete for T {
8+
LL | | type Assoc = T;
9+
| | ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
10+
LL | | }
11+
| |_- in this `impl` item
612
|
713
= help: consider adding a `where T: std::marker::Copy` bound
814

src/test/ui/traits/cycle-cache-err-60010.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ struct SalsaStorage {
2727
_parse: <ParseQuery as Query<RootDatabase>>::Data, //~ ERROR overflow
2828
}
2929

30-
impl Database for RootDatabase { //~ ERROR overflow
31-
type Storage = SalsaStorage;
30+
impl Database for RootDatabase {
31+
type Storage = SalsaStorage; //~ ERROR overflow
3232
}
3333
impl HasQueryGroup for RootDatabase {}
3434
impl<DB> Query<DB> for ParseQuery

src/test/ui/traits/cycle-cache-err-60010.stderr

+9-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@ LL | _parse: <ParseQuery as Query<RootDatabase>>::Data,
77
= note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
88

99
error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
10-
--> $DIR/cycle-cache-err-60010.rs:30:6
10+
--> $DIR/cycle-cache-err-60010.rs:31:5
1111
|
12-
LL | impl Database for RootDatabase {
13-
| ^^^^^^^^
12+
LL | type Storage;
13+
| ------- associated type defined here
14+
...
15+
LL | / impl Database for RootDatabase {
16+
LL | | type Storage = SalsaStorage;
17+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
LL | | }
19+
| |_- in this `impl` item
1420
|
1521
= note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
1622
= note: required because it appears within the type `SalsaStorage`

0 commit comments

Comments
 (0)