@@ -223,60 +223,87 @@ enum Elaborate {
223
223
None ,
224
224
}
225
225
226
+ /// Points the cause span of a super predicate at the relevant associated type.
227
+ ///
228
+ /// Given a trait impl item:
229
+ ///
230
+ /// ```ignore (incomplete)
231
+ /// impl TargetTrait for TargetType {
232
+ /// type Assoc = SomeType;
233
+ /// }
234
+ /// ```
235
+ ///
236
+ /// And a super predicate of `TargetTrait` that has any of the following forms:
237
+ ///
238
+ /// 1. `<OtherType as OtherTrait>::Assoc == <TargetType as TargetTrait>::Assoc`
239
+ /// 2. `<<TargetType as TargetTrait>::Assoc as OtherTrait>::Assoc == OtherType`
240
+ /// 3. `<TargetType as TargetTrait>::Assoc: OtherTrait`
241
+ ///
242
+ /// Replace the span of the cause with the span of the associated item:
243
+ ///
244
+ /// ```ignore (incomplete)
245
+ /// impl TargetTrait for TargetType {
246
+ /// type Assoc = SomeType;
247
+ /// // ^^^^^^^^ this span
248
+ /// }
249
+ /// ```
250
+ ///
251
+ /// Note that bounds that can be expressed as associated item bounds are **not**
252
+ /// super predicates. This means that form 2 and 3 from above are only relevant if
253
+ /// the [`GenericArgsRef`] of the projection type are not its identity arguments.
226
254
fn extend_cause_with_original_assoc_item_obligation < ' tcx > (
227
255
tcx : TyCtxt < ' tcx > ,
228
- trait_ref : ty:: TraitRef < ' tcx > ,
229
256
item : Option < & hir:: Item < ' tcx > > ,
230
257
cause : & mut traits:: ObligationCause < ' tcx > ,
231
258
pred : ty:: Predicate < ' tcx > ,
232
259
) {
233
- debug ! (
234
- "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}" ,
235
- trait_ref, item, cause, pred
236
- ) ;
260
+ debug ! ( ?item, ?cause, ?pred, "extended_cause_with_original_assoc_item_obligation" ) ;
237
261
let ( items, impl_def_id) = match item {
238
262
Some ( hir:: Item { kind : hir:: ItemKind :: Impl ( impl_) , owner_id, .. } ) => {
239
263
( impl_. items , * owner_id)
240
264
}
241
265
_ => return ,
242
266
} ;
243
- let fix_span =
244
- |impl_item_ref : & hir:: ImplItemRef | match tcx. hir ( ) . impl_item ( impl_item_ref. id ) . kind {
245
- hir:: ImplItemKind :: Const ( ty, _) | hir:: ImplItemKind :: Type ( ty) => ty. span ,
246
- _ => impl_item_ref. span ,
247
- } ;
267
+
268
+ let ty_to_impl_span = |ty : Ty < ' _ > | {
269
+ if let ty:: Alias ( ty:: Projection , projection_ty) = ty. kind ( )
270
+ && let Some ( & impl_item_id) =
271
+ tcx. impl_item_implementor_ids ( impl_def_id) . get ( & projection_ty. def_id )
272
+ && let Some ( impl_item) =
273
+ items. iter ( ) . find ( |item| item. id . owner_id . to_def_id ( ) == impl_item_id)
274
+ {
275
+ Some ( tcx. hir ( ) . impl_item ( impl_item. id ) . expect_type ( ) . span )
276
+ } else {
277
+ None
278
+ }
279
+ } ;
248
280
249
281
// It is fine to skip the binder as we don't care about regions here.
250
282
match pred. kind ( ) . skip_binder ( ) {
251
283
ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( proj) ) => {
252
- // The obligation comes not from the current `impl` nor the `trait` being implemented,
253
- // but rather from a "second order" obligation, where an associated type has a
254
- // projection coming from another associated type. See
255
- // `tests/ui/associated-types/point-at-type-on-obligation-failure.rs` and
256
- // `traits-assoc-type-in-supertrait-bad.rs`.
257
- if let Some ( ty:: Alias ( ty:: Projection , projection_ty) ) =
258
- proj. term . ty ( ) . map ( |ty| ty. kind ( ) )
259
- && let Some ( & impl_item_id) =
260
- tcx. impl_item_implementor_ids ( impl_def_id) . get ( & projection_ty. def_id )
261
- && let Some ( impl_item_span) = items
262
- . iter ( )
263
- . find ( |item| item. id . owner_id . to_def_id ( ) == impl_item_id)
264
- . map ( fix_span)
284
+ // Form 1: The obligation comes not from the current `impl` nor the `trait` being
285
+ // implemented, but rather from a "second order" obligation, where an associated
286
+ // type has a projection coming from another associated type.
287
+ // See `tests/ui/traits/assoc-type-in-superbad.rs` for an example.
288
+ if let Some ( term_ty) = proj. term . ty ( )
289
+ && let Some ( impl_item_span) = ty_to_impl_span ( term_ty)
265
290
{
266
291
cause. span = impl_item_span;
267
292
}
293
+
294
+ // Form 2: A projection obligation for an associated item failed to be met.
295
+ // We overwrite the span from above to ensure that a bound like
296
+ // `Self::Assoc1: Trait<OtherAssoc = Self::Assoc2>` gets the same
297
+ // span for both obligations that it is lowered to.
298
+ if let Some ( impl_item_span) = ty_to_impl_span ( proj. self_ty ( ) ) {
299
+ cause. span = impl_item_span;
300
+ }
268
301
}
302
+
269
303
ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( pred) ) => {
270
- // An associated item obligation born out of the `trait` failed to be met. An example
271
- // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
304
+ // Form 3: A trait obligation for an associated item failed to be met.
272
305
debug ! ( "extended_cause_with_original_assoc_item_obligation trait proj {:?}" , pred) ;
273
- if let ty:: Alias ( ty:: Projection , ty:: AliasTy { def_id, .. } ) = * pred. self_ty ( ) . kind ( )
274
- && let Some ( & impl_item_id) = tcx. impl_item_implementor_ids ( impl_def_id) . get ( & def_id)
275
- && let Some ( impl_item_span) = items
276
- . iter ( )
277
- . find ( |item| item. id . owner_id . to_def_id ( ) == impl_item_id)
278
- . map ( fix_span)
279
- {
306
+ if let Some ( impl_item_span) = ty_to_impl_span ( pred. self_ty ( ) ) {
280
307
cause. span = impl_item_span;
281
308
}
282
309
}
@@ -355,9 +382,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
355
382
traits:: ObligationCauseCode :: DerivedObligation ,
356
383
) ;
357
384
}
358
- extend_cause_with_original_assoc_item_obligation (
359
- tcx, trait_ref, item, & mut cause, predicate,
360
- ) ;
385
+ extend_cause_with_original_assoc_item_obligation ( tcx, item, & mut cause, predicate) ;
361
386
traits:: Obligation :: with_depth ( tcx, cause, depth, param_env, predicate)
362
387
} ;
363
388
0 commit comments