Skip to content

Commit 189e784

Browse files
author
Lukas Markeffsky
committed
adjust obligation spans for super projections
1 parent 6fa58be commit 189e784

File tree

6 files changed

+84
-52
lines changed

6 files changed

+84
-52
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,8 +1294,9 @@ fn check_impl<'tcx>(
12941294
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
12951295
// other `Foo` impls are incoherent.
12961296
tcx.ensure().coherent_trait(trait_ref.def_id)?;
1297+
let trait_span = ast_trait_ref.path.span;
12971298
let trait_ref = wfcx.normalize(
1298-
ast_trait_ref.path.span,
1299+
trait_span,
12991300
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
13001301
trait_ref,
13011302
);
@@ -1306,12 +1307,21 @@ fn check_impl<'tcx>(
13061307
wfcx.param_env,
13071308
wfcx.body_def_id,
13081309
trait_pred,
1309-
ast_trait_ref.path.span,
1310+
trait_span,
13101311
item,
13111312
);
13121313
for obligation in &mut obligations {
1314+
if obligation.cause.span != trait_span {
1315+
// We already have a better span.
1316+
continue;
1317+
}
13131318
if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred()
1314-
&& pred.self_ty().skip_binder() == trait_ref.self_ty()
1319+
&& pred.skip_binder().self_ty() == trait_ref.self_ty()
1320+
{
1321+
obligation.cause.span = ast_self_ty.span;
1322+
}
1323+
if let Some(pred) = obligation.predicate.to_opt_poly_projection_pred()
1324+
&& pred.skip_binder().self_ty() == trait_ref.self_ty()
13151325
{
13161326
obligation.cause.span = ast_self_ty.span;
13171327
}

compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -223,60 +223,84 @@ 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.
226254
fn 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+
if let Some(impl_item_span) = ty_to_impl_span(proj.self_ty()) {
296+
cause.span = impl_item_span;
297+
}
268298
}
299+
269300
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`.
301+
// Form 3: A trait obligation for an associated item failed to be met.
272302
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-
{
303+
if let Some(impl_item_span) = ty_to_impl_span(pred.self_ty()) {
280304
cause.span = impl_item_span;
281305
}
282306
}
@@ -355,9 +379,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
355379
traits::ObligationCauseCode::DerivedObligation,
356380
);
357381
}
358-
extend_cause_with_original_assoc_item_obligation(
359-
tcx, trait_ref, item, &mut cause, predicate,
360-
);
382+
extend_cause_with_original_assoc_item_obligation(tcx, item, &mut cause, predicate);
361383
traits::Obligation::with_depth(tcx, cause, depth, param_env, predicate)
362384
};
363385

tests/ui/associated-types/hr-associated-type-projection-1.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ where
1111
}
1212

1313
impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
14-
//~^ type mismatch resolving `<T as Deref>::Target == T`
1514
type Item = T;
15+
//~^ type mismatch resolving `<T as Deref>::Target == T`
1616
}
1717

1818
pub fn main() {

tests/ui/associated-types/hr-associated-type-projection-1.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
error[E0271]: type mismatch resolving `<T as Deref>::Target == T`
2-
--> $DIR/hr-associated-type-projection-1.rs:13:33
2+
--> $DIR/hr-associated-type-projection-1.rs:14:17
33
|
44
LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
5-
| - ^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type
6-
| |
7-
| expected this type parameter
5+
| - expected this type parameter
6+
LL | type Item = T;
7+
| ^ expected type parameter `T`, found associated type
88
|
99
= note: expected type parameter `T`
1010
found associated type `<T as Deref>::Target`

tests/ui/trait-bounds/super-assoc-mismatch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ trait BoundOnGat where Self::Assoc<u8>: Sub {
2929
type Assoc<T>;
3030
}
3131
impl BoundOnGat for u8 {
32-
//~^ ERROR type mismatch resolving `<() as Super>::Assoc == u16`
3332
type Assoc<T> = ();
3433
//~^ ERROR the trait bound `(): Sub` is not satisfied
34+
//~| ERROR type mismatch resolving `<() as Super>::Assoc == u16`
3535
}
3636

3737
fn trivial_bound() where (): Sub {}

tests/ui/trait-bounds/super-assoc-mismatch.stderr

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ LL | trait BoundOnSelf: Sub {}
1616
| ^^^ required by this bound in `BoundOnSelf`
1717

1818
error[E0271]: type mismatch resolving `<() as Super>::Assoc == u16`
19-
--> $DIR/super-assoc-mismatch.rs:10:6
19+
--> $DIR/super-assoc-mismatch.rs:10:22
2020
|
2121
LL | impl BoundOnSelf for () {}
22-
| ^^^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == u16`
22+
| ^^ type mismatch resolving `<() as Super>::Assoc == u16`
2323
|
2424
note: expected this to be `u16`
2525
--> $DIR/super-assoc-mismatch.rs:5:18
@@ -55,10 +55,10 @@ LL | trait BoundOnParam<T: Sub> {}
5555
| ^^^ required by this bound in `BoundOnParam`
5656

5757
error[E0271]: type mismatch resolving `<() as Super>::Assoc == u16`
58-
--> $DIR/super-assoc-mismatch.rs:15:6
58+
--> $DIR/super-assoc-mismatch.rs:15:27
5959
|
6060
LL | impl BoundOnParam<()> for () {}
61-
| ^^^^^^^^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == u16`
61+
| ^^ type mismatch resolving `<() as Super>::Assoc == u16`
6262
|
6363
note: expected this to be `u16`
6464
--> $DIR/super-assoc-mismatch.rs:5:18
@@ -116,7 +116,7 @@ LL | type Assoc: Sub;
116116
| ^^^ required by this bound in `BoundOnAssoc::Assoc`
117117

118118
error[E0277]: the trait bound `(): Sub` is not satisfied
119-
--> $DIR/super-assoc-mismatch.rs:33:21
119+
--> $DIR/super-assoc-mismatch.rs:32:21
120120
|
121121
LL | type Assoc<T> = ();
122122
| ^^ 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 {
133133
| ^^^ required by this bound in `BoundOnGat`
134134

135135
error[E0271]: type mismatch resolving `<() as Super>::Assoc == u16`
136-
--> $DIR/super-assoc-mismatch.rs:31:6
136+
--> $DIR/super-assoc-mismatch.rs:32:21
137137
|
138-
LL | impl BoundOnGat for u8 {
139-
| ^^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == u16`
138+
LL | type Assoc<T> = ();
139+
| ^^ type mismatch resolving `<() as Super>::Assoc == u16`
140140
|
141141
note: expected this to be `u16`
142142
--> $DIR/super-assoc-mismatch.rs:5:18

0 commit comments

Comments
 (0)