@@ -223,60 +223,87 @@ enum Elaborate {
223223 None ,
224224}
225225
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.
226254fn extend_cause_with_original_assoc_item_obligation < ' tcx > (
227255 tcx : TyCtxt < ' tcx > ,
228- trait_ref : ty:: TraitRef < ' tcx > ,
229256 item : Option < & hir:: Item < ' tcx > > ,
230257 cause : & mut traits:: ObligationCause < ' tcx > ,
231258 pred : ty:: Predicate < ' tcx > ,
232259) {
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" ) ;
237261 let ( items, impl_def_id) = match item {
238262 Some ( hir:: Item { kind : hir:: ItemKind :: Impl ( impl_) , owner_id, .. } ) => {
239263 ( impl_. items , * owner_id)
240264 }
241265 _ => return ,
242266 } ;
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+ } ;
248280
249281 // It is fine to skip the binder as we don't care about regions here.
250282 match pred. kind ( ) . skip_binder ( ) {
251283 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)
265290 {
266291 cause. span = impl_item_span;
267292 }
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+ }
268301 }
302+
269303 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.
272305 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 ( ) ) {
280307 cause. span = impl_item_span;
281308 }
282309 }
@@ -355,9 +382,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
355382 traits:: ObligationCauseCode :: DerivedObligation ,
356383 ) ;
357384 }
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) ;
361386 traits:: Obligation :: with_depth ( tcx, cause, depth, param_env, predicate)
362387 } ;
363388
0 commit comments