diff options
| author | Lukas Markeffsky <@> | 2024-02-08 16:56:47 +0100 |
|---|---|---|
| committer | Lukas Markeffsky <@> | 2024-03-04 21:06:52 +0100 |
| commit | 189e7843e80db90ee5283c82c2d2e0ee9fd7b6b5 (patch) | |
| tree | e28b90bc240b0d4cd036d4a51eb9aa1189c221e7 | |
| parent | 6fa58be8f463e25cc6b8219ea1db44a466cddc68 (diff) | |
| download | rust-189e7843e80db90ee5283c82c2d2e0ee9fd7b6b5.tar.gz rust-189e7843e80db90ee5283c82c2d2e0ee9fd7b6b5.zip | |
adjust obligation spans for super projections
6 files changed, 84 insertions, 52 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f03d0f8a885..17222922d3e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1294,8 +1294,9 @@ fn check_impl<'tcx>( // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. tcx.ensure().coherent_trait(trait_ref.def_id)?; + let trait_span = ast_trait_ref.path.span; let trait_ref = wfcx.normalize( - ast_trait_ref.path.span, + trait_span, Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), trait_ref, ); @@ -1306,12 +1307,21 @@ fn check_impl<'tcx>( wfcx.param_env, wfcx.body_def_id, trait_pred, - ast_trait_ref.path.span, + trait_span, item, ); for obligation in &mut obligations { + if obligation.cause.span != trait_span { + // We already have a better span. + continue; + } if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred() - && pred.self_ty().skip_binder() == trait_ref.self_ty() + && pred.skip_binder().self_ty() == trait_ref.self_ty() + { + obligation.cause.span = ast_self_ty.span; + } + if let Some(pred) = obligation.predicate.to_opt_poly_projection_pred() + && pred.skip_binder().self_ty() == trait_ref.self_ty() { obligation.cause.span = ast_self_ty.span; } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 15059bc6613..4cbdadac770 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -223,60 +223,84 @@ enum Elaborate { None, } +/// Points the cause span of a super predicate at the relevant associated type. +/// +/// Given a trait impl item: +/// +/// ```ignore (incomplete) +/// impl TargetTrait for TargetType { +/// type Assoc = SomeType; +/// } +/// ``` +/// +/// And a super predicate of `TargetTrait` that has any of the following forms: +/// +/// 1. `<OtherType as OtherTrait>::Assoc = <TargetType as TargetTrait>::Assoc` +/// 2. `<<TargetType as TargetTrait>::Assoc as OtherTrait>::Assoc = OtherType` +/// 3. `<TargetType as TargetTrait>::Assoc: OtherTrait` +/// +/// Replace the span of the cause with the span of the associated item: +/// +/// ```ignore (incomplete) +/// impl TargetTrait for TargetType { +/// type Assoc = SomeType; +/// // ^^^^^^^^ this span +/// } +/// ``` +/// +/// Note that bounds that can be expressed as associated item bounds are **not** +/// super predicates. This means that form 2 and 3 from above are only relevant if +/// the [`GenericArgsRef`] of the projection type are not its identity arguments. fn extend_cause_with_original_assoc_item_obligation<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, item: Option<&hir::Item<'tcx>>, cause: &mut traits::ObligationCause<'tcx>, pred: ty::Predicate<'tcx>, ) { - debug!( - "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}", - trait_ref, item, cause, pred - ); + debug!(?item, ?cause, ?pred, "extended_cause_with_original_assoc_item_obligation"); let (items, impl_def_id) = match item { Some(hir::Item { kind: hir::ItemKind::Impl(impl_), owner_id, .. }) => { (impl_.items, *owner_id) } _ => return, }; - let fix_span = - |impl_item_ref: &hir::ImplItemRef| match tcx.hir().impl_item(impl_item_ref.id).kind { - hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::Type(ty) => ty.span, - _ => impl_item_ref.span, - }; + + let ty_to_impl_span = |ty: Ty<'_>| { + if let ty::Alias(ty::Projection, projection_ty) = ty.kind() + && let Some(&impl_item_id) = + tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id) + && let Some(impl_item) = + items.iter().find(|item| item.id.owner_id.to_def_id() == impl_item_id) + { + Some(tcx.hir().impl_item(impl_item.id).expect_type().span) + } else { + None + } + }; // It is fine to skip the binder as we don't care about regions here. match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => { - // The obligation comes not from the current `impl` nor the `trait` being implemented, - // but rather from a "second order" obligation, where an associated type has a - // projection coming from another associated type. See - // `tests/ui/associated-types/point-at-type-on-obligation-failure.rs` and - // `traits-assoc-type-in-supertrait-bad.rs`. - if let Some(ty::Alias(ty::Projection, projection_ty)) = - proj.term.ty().map(|ty| ty.kind()) - && let Some(&impl_item_id) = - tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id) - && let Some(impl_item_span) = items - .iter() - .find(|item| item.id.owner_id.to_def_id() == impl_item_id) - .map(fix_span) + // Form 1: The obligation comes not from the current `impl` nor the `trait` being + // implemented, but rather from a "second order" obligation, where an associated + // type has a projection coming from another associated type. + // See `tests/ui/traits/assoc-type-in-superbad.rs` for an example. + if let Some(term_ty) = proj.term.ty() + && let Some(impl_item_span) = ty_to_impl_span(term_ty) { cause.span = impl_item_span; } + + // Form 2: A projection obligation for an associated item failed to be met. + if let Some(impl_item_span) = ty_to_impl_span(proj.self_ty()) { + cause.span = impl_item_span; + } } + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - // An associated item obligation born out of the `trait` failed to be met. An example - // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. + // Form 3: A trait obligation for an associated item failed to be met. debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); - if let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) = *pred.self_ty().kind() - && let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&def_id) - && let Some(impl_item_span) = items - .iter() - .find(|item| item.id.owner_id.to_def_id() == impl_item_id) - .map(fix_span) - { + if let Some(impl_item_span) = ty_to_impl_span(pred.self_ty()) { cause.span = impl_item_span; } } @@ -355,9 +379,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { traits::ObligationCauseCode::DerivedObligation, ); } - extend_cause_with_original_assoc_item_obligation( - tcx, trait_ref, item, &mut cause, predicate, - ); + extend_cause_with_original_assoc_item_obligation(tcx, item, &mut cause, predicate); traits::Obligation::with_depth(tcx, cause, depth, param_env, predicate) }; diff --git a/tests/ui/associated-types/hr-associated-type-projection-1.rs b/tests/ui/associated-types/hr-associated-type-projection-1.rs index 3df3f68ab1e..d7fc5d122c3 100644 --- a/tests/ui/associated-types/hr-associated-type-projection-1.rs +++ b/tests/ui/associated-types/hr-associated-type-projection-1.rs @@ -11,8 +11,8 @@ where } impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T { - //~^ type mismatch resolving `<T as Deref>::Target == T` type Item = T; + //~^ type mismatch resolving `<T as Deref>::Target == T` } pub fn main() { diff --git a/tests/ui/associated-types/hr-associated-type-projection-1.stderr b/tests/ui/associated-types/hr-associated-type-projection-1.stderr index 65221718ee6..b871bb51ae3 100644 --- a/tests/ui/associated-types/hr-associated-type-projection-1.stderr +++ b/tests/ui/associated-types/hr-associated-type-projection-1.stderr @@ -1,10 +1,10 @@ error[E0271]: type mismatch resolving `<T as Deref>::Target == T` - --> $DIR/hr-associated-type-projection-1.rs:13:33 + --> $DIR/hr-associated-type-projection-1.rs:14:17 | LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T { - | - ^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type - | | - | expected this type parameter + | - expected this type parameter +LL | type Item = T; + | ^ expected type parameter `T`, found associated type | = note: expected type parameter `T` found associated type `<T as Deref>::Target` diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.rs b/tests/ui/trait-bounds/super-assoc-mismatch.rs index 1cfcb5c8ceb..b701f0b3f88 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.rs +++ b/tests/ui/trait-bounds/super-assoc-mismatch.rs @@ -29,9 +29,9 @@ trait BoundOnGat where Self::Assoc<u8>: Sub { type Assoc<T>; } impl BoundOnGat for u8 { - //~^ ERROR type mismatch resolving `<() as Super>::Assoc == u16` type Assoc<T> = (); //~^ ERROR the trait bound `(): Sub` is not satisfied + //~| ERROR type mismatch resolving `<() as Super>::Assoc == u16` } fn trivial_bound() where (): Sub {} diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.stderr b/tests/ui/trait-bounds/super-assoc-mismatch.stderr index 278c655d0fd..bf19dd45193 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.stderr +++ b/tests/ui/trait-bounds/super-assoc-mismatch.stderr @@ -16,10 +16,10 @@ LL | trait BoundOnSelf: Sub {} | ^^^ required by this bound in `BoundOnSelf` error[E0271]: type mismatch resolving `<() as Super>::Assoc == u16` - --> $DIR/super-assoc-mismatch.rs:10:6 + --> $DIR/super-assoc-mismatch.rs:10:22 | LL | impl BoundOnSelf for () {} - | ^^^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == u16` + | ^^ type mismatch resolving `<() as Super>::Assoc == u16` | note: expected this to be `u16` --> $DIR/super-assoc-mismatch.rs:5:18 @@ -55,10 +55,10 @@ LL | trait BoundOnParam<T: Sub> {} | ^^^ required by this bound in `BoundOnParam` error[E0271]: type mismatch resolving `<() as Super>::Assoc == u16` - --> $DIR/super-assoc-mismatch.rs:15:6 + --> $DIR/super-assoc-mismatch.rs:15:27 | LL | impl BoundOnParam<()> for () {} - | ^^^^^^^^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == u16` + | ^^ type mismatch resolving `<() as Super>::Assoc == u16` | note: expected this to be `u16` --> $DIR/super-assoc-mismatch.rs:5:18 @@ -116,7 +116,7 @@ LL | type Assoc: Sub; | ^^^ required by this bound in `BoundOnAssoc::Assoc` error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:33:21 + --> $DIR/super-assoc-mismatch.rs:32:21 | LL | type Assoc<T> = (); | ^^ the trait `Sub` is not implemented for `()`, which is required by `<u8 as BoundOnGat>::Assoc<u8>: Sub` @@ -133,10 +133,10 @@ LL | trait BoundOnGat where Self::Assoc<u8>: Sub { | ^^^ required by this bound in `BoundOnGat` error[E0271]: type mismatch resolving `<() as Super>::Assoc == u16` - --> $DIR/super-assoc-mismatch.rs:31:6 + --> $DIR/super-assoc-mismatch.rs:32:21 | -LL | impl BoundOnGat for u8 { - | ^^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == u16` +LL | type Assoc<T> = (); + | ^^ type mismatch resolving `<() as Super>::Assoc == u16` | note: expected this to be `u16` --> $DIR/super-assoc-mismatch.rs:5:18 |
