@@ -22,11 +22,14 @@ pub fn obligations<'a, 'tcx>(
22
22
ty : Ty < ' tcx > ,
23
23
span : Span ,
24
24
) -> 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
+ } ;
30
33
if wf. compute ( ty) {
31
34
debug ! ( "wf::obligations({:?}, body_id={:?}) = {:?}" , ty, body_id, wf. out) ;
32
35
let result = wf. normalize ( ) ;
@@ -47,8 +50,9 @@ pub fn trait_obligations<'a, 'tcx>(
47
50
body_id : hir:: HirId ,
48
51
trait_ref : & ty:: TraitRef < ' tcx > ,
49
52
span : Span ,
53
+ item : Option < & ' tcx hir:: Item > ,
50
54
) -> 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 } ;
52
56
wf. compute_trait_ref ( trait_ref, Elaborate :: All ) ;
53
57
wf. normalize ( )
54
58
}
@@ -60,7 +64,7 @@ pub fn predicate_obligations<'a, 'tcx>(
60
64
predicate : & ty:: Predicate < ' tcx > ,
61
65
span : Span ,
62
66
) -> 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 } ;
64
68
65
69
// (*) ok to skip binders, because wf code is prepared for it
66
70
match * predicate {
@@ -107,6 +111,7 @@ struct WfPredicates<'a, 'tcx> {
107
111
body_id : hir:: HirId ,
108
112
span : Span ,
109
113
out : Vec < traits:: PredicateObligation < ' tcx > > ,
114
+ item : Option < & ' tcx hir:: Item > ,
110
115
}
111
116
112
117
/// Controls whether we "elaborate" supertraits and so forth on the WF
@@ -157,33 +162,162 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
157
162
. collect ( )
158
163
}
159
164
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`.
162
166
fn compute_trait_ref ( & mut self , trait_ref : & ty:: TraitRef < ' tcx > , elaborate : Elaborate ) {
167
+ let tcx = self . infcx . tcx ;
163
168
let obligations = self . nominal_obligations ( trait_ref. def_id , trait_ref. substs ) ;
164
169
165
170
let cause = self . cause ( traits:: MiscObligation ) ;
166
171
let param_env = self . param_env ;
167
172
173
+ let item = & self . item ;
174
+ let extend_cause_with_original_assoc_item_obligation = |
175
+ cause : & mut traits:: ObligationCause < ' _ > ,
176
+ pred : & ty:: Predicate < ' _ > ,
177
+ trait_assoc_items : ty:: AssocItemsIterator < ' _ > ,
178
+ | {
179
+ let item_span = item. map( |i| tcx. sess. source_map( ) . def_span( i. span) ) ;
180
+ match pred {
181
+ ty : : Predicate :: Projection ( proj) => {
182
+ // The obligation comes not from the current `impl` nor the `trait` being
183
+ // implemented, but rather from a "second order" obligation, like in
184
+ // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`:
185
+ //
186
+ // error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
187
+ // --> $DIR/point-at-type-on-obligation-failure.rs:13:5
188
+ // |
189
+ // LL | type Ok;
190
+ // | -- associated type defined here
191
+ // ...
192
+ // LL | impl Bar for Foo {
193
+ // | ---------------- in this `impl` item
194
+ // LL | type Ok = ();
195
+ // | ^^^^^^^^^^^^^ expected u32, found ()
196
+ // |
197
+ // = note: expected type `u32`
198
+ // found type `()`
199
+ //
200
+ // FIXME: we would want to point a span to all places that contributed to this
201
+ // obligation. In the case above, it should be closer to:
202
+ //
203
+ // error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
204
+ // --> $DIR/point-at-type-on-obligation-failure.rs:13:5
205
+ // |
206
+ // LL | type Ok;
207
+ // | -- associated type defined here
208
+ // LL | type Sibling: Bar2<Ok=Self::Ok>;
209
+ // | -------------------------------- obligation set here
210
+ // ...
211
+ // LL | impl Bar for Foo {
212
+ // | ---------------- in this `impl` item
213
+ // LL | type Ok = ();
214
+ // | ^^^^^^^^^^^^^ expected u32, found ()
215
+ // ...
216
+ // LL | impl Bar2 for Foo2 {
217
+ // | ---------------- in this `impl` item
218
+ // LL | type Ok = u32;
219
+ // | -------------- obligation set here
220
+ // |
221
+ // = note: expected type `u32`
222
+ // found type `()`
223
+ if let Some ( hir:: ItemKind :: Impl ( .., impl_items) ) = item. map ( |i| & i. kind ) {
224
+ let trait_assoc_item = tcx. associated_item ( proj. projection_def_id ( ) ) ;
225
+ if let Some ( impl_item) = impl_items. iter ( ) . filter ( |item| {
226
+ item. ident == trait_assoc_item. ident
227
+ } ) . next ( ) {
228
+ cause. span = impl_item. span ;
229
+ cause. code = traits:: AssocTypeBound (
230
+ item_span,
231
+ trait_assoc_item. ident . span ,
232
+ ) ;
233
+ }
234
+ }
235
+ }
236
+ ty:: Predicate :: Trait ( proj) => {
237
+ // An associated item obligation born out of the `trait` failed to be met.
238
+ // Point at the `impl` that failed the obligation, the associated item that
239
+ // needed to meet the obligation, and the definition of that associated item,
240
+ // which should hold the obligation in most cases. An example can be seen in
241
+ // `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`:
242
+ //
243
+ // error[E0277]: the trait bound `bool: Bar` is not satisfied
244
+ // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
245
+ // |
246
+ // LL | type Assoc: Bar;
247
+ // | ----- associated type defined here
248
+ // ...
249
+ // LL | impl Foo for () {
250
+ // | --------------- in this `impl` item
251
+ // LL | type Assoc = bool;
252
+ // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
253
+ //
254
+ // FIXME: if the obligation comes from the where clause in the `trait`, we
255
+ // should point at it:
256
+ //
257
+ // error[E0277]: the trait bound `bool: Bar` is not satisfied
258
+ // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
259
+ // |
260
+ // | trait Foo where <Self as Foo>>::Assoc: Bar {
261
+ // | -------------------------- obligation set here
262
+ // LL | type Assoc;
263
+ // | ----- associated type defined here
264
+ // ...
265
+ // LL | impl Foo for () {
266
+ // | --------------- in this `impl` item
267
+ // LL | type Assoc = bool;
268
+ // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
269
+ if let (
270
+ ty:: Projection ( ty:: ProjectionTy { item_def_id, .. } ) ,
271
+ Some ( hir:: ItemKind :: Impl ( .., impl_items) ) ,
272
+ ) = ( & proj. skip_binder ( ) . self_ty ( ) . kind , item. map ( |i| & i. kind ) ) {
273
+ if let Some ( ( impl_item, trait_assoc_item) ) = trait_assoc_items
274
+ . filter ( |i| i. def_id == * item_def_id)
275
+ . next ( )
276
+ . and_then ( |trait_assoc_item| impl_items. iter ( )
277
+ . filter ( |i| i. ident == trait_assoc_item. ident )
278
+ . next ( )
279
+ . map ( |impl_item| ( impl_item, trait_assoc_item) ) )
280
+ {
281
+ cause. span = impl_item. span ;
282
+ cause. code = traits:: AssocTypeBound (
283
+ item_span,
284
+ trait_assoc_item. ident . span ,
285
+ ) ;
286
+ }
287
+ }
288
+ }
289
+ _ => { }
290
+ }
291
+ } ;
292
+
168
293
if let Elaborate :: All = elaborate {
294
+ let trait_assoc_items = tcx. associated_items ( trait_ref. def_id ) ;
295
+
169
296
let predicates = obligations. iter ( )
170
- . map ( |obligation| obligation. predicate . clone ( ) )
171
- . collect ( ) ;
172
- let implied_obligations = traits:: elaborate_predicates ( self . infcx . tcx , predicates) ;
297
+ . map ( |obligation| obligation. predicate . clone ( ) )
298
+ . collect ( ) ;
299
+ let implied_obligations = traits:: elaborate_predicates ( tcx, predicates) ;
173
300
let implied_obligations = implied_obligations. map ( |pred| {
174
- traits:: Obligation :: new ( cause. clone ( ) , param_env, pred)
301
+ let mut cause = cause. clone ( ) ;
302
+ extend_cause_with_original_assoc_item_obligation (
303
+ & mut cause,
304
+ & pred,
305
+ trait_assoc_items. clone ( ) ,
306
+ ) ;
307
+ traits:: Obligation :: new ( cause, param_env, pred)
175
308
} ) ;
176
309
self . out . extend ( implied_obligations) ;
177
310
}
178
311
179
312
self . out . extend ( obligations) ;
180
313
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) ) ) ) ;
314
+ self . out . extend ( trait_ref. substs . types ( )
315
+ . filter ( |ty| !ty. has_escaping_bound_vars ( ) )
316
+ . map ( |ty| traits:: Obligation :: new (
317
+ cause. clone ( ) ,
318
+ param_env,
319
+ ty:: Predicate :: WellFormed ( ty) ,
320
+ ) ) ) ;
187
321
}
188
322
189
323
/// Pushes the obligations required for `trait_ref::Item` to be WF
0 commit comments