@@ -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,162 @@ 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 ) {
167+ let tcx = self . infcx . tcx ;
163168 let obligations = self . nominal_obligations ( trait_ref. def_id , trait_ref. substs ) ;
164169
165170 let cause = self . cause ( traits:: MiscObligation ) ;
166171 let param_env = self . param_env ;
167172
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+
168293 if let Elaborate :: All = elaborate {
294+ let trait_assoc_items = tcx. associated_items ( trait_ref. def_id ) ;
295+
169296 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) ;
173300 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)
175308 } ) ;
176309 self . out . extend ( implied_obligations) ;
177310 }
178311
179312 self . out . extend ( obligations) ;
180313
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+ ) ) ) ;
187321 }
188322
189323 /// Pushes the obligations required for `trait_ref::Item` to be WF
0 commit comments