Skip to content

Commit ca554ef

Browse files
Improve spans of non-WF implied bound types
1 parent fa51fc0 commit ca554ef

22 files changed

+134
-153
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+21-37
Original file line numberDiff line numberDiff line change
@@ -1489,54 +1489,38 @@ fn check_fn_or_method<'tcx>(
14891489
def_id: LocalDefId,
14901490
) {
14911491
let tcx = wfcx.tcx();
1492-
let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
1492+
let mut sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
14931493

14941494
// Normalize the input and output types one at a time, using a different
14951495
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
14961496
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
14971497
// for each type, preventing the HIR wf check from generating
14981498
// a nice error message.
1499-
let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig;
1500-
inputs_and_output = tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| {
1501-
wfcx.normalize(
1502-
span,
1503-
Some(WellFormedLoc::Param {
1504-
function: def_id,
1505-
// Note that the `param_idx` of the output type is
1506-
// one greater than the index of the last input type.
1507-
param_idx: i.try_into().unwrap(),
1508-
}),
1509-
ty,
1510-
)
1511-
}));
1512-
// Manually call `normalize_associated_types_in` on the other types
1513-
// in `FnSig`. This ensures that if the types of these fields
1514-
// ever change to include projections, we will start normalizing
1515-
// them automatically.
1516-
let sig = ty::FnSig {
1517-
inputs_and_output,
1518-
c_variadic: wfcx.normalize(span, None, c_variadic),
1519-
unsafety: wfcx.normalize(span, None, unsafety),
1520-
abi: wfcx.normalize(span, None, abi),
1521-
};
1499+
let arg_span =
1500+
|idx| hir_decl.inputs.get(idx).map_or(hir_decl.output.span(), |arg: &hir::Ty<'_>| arg.span);
1501+
1502+
sig.inputs_and_output =
1503+
tcx.mk_type_list(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| {
1504+
wfcx.normalize(
1505+
arg_span(idx),
1506+
Some(WellFormedLoc::Param {
1507+
function: def_id,
1508+
// Note that the `param_idx` of the output type is
1509+
// one greater than the index of the last input type.
1510+
param_idx: idx.try_into().unwrap(),
1511+
}),
1512+
ty,
1513+
)
1514+
}));
15221515

1523-
for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() {
1516+
for (idx, ty) in sig.inputs_and_output.iter().enumerate() {
15241517
wfcx.register_wf_obligation(
1525-
ty.span,
1526-
Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }),
1527-
input_ty.into(),
1518+
arg_span(idx),
1519+
Some(WellFormedLoc::Param { function: def_id, param_idx: idx.try_into().unwrap() }),
1520+
ty.into(),
15281521
);
15291522
}
15301523

1531-
wfcx.register_wf_obligation(
1532-
hir_decl.output.span(),
1533-
Some(WellFormedLoc::Param {
1534-
function: def_id,
1535-
param_idx: sig.inputs().len().try_into().unwrap(),
1536-
}),
1537-
sig.output().into(),
1538-
);
1539-
15401524
check_where_clauses(wfcx, span, def_id);
15411525

15421526
check_return_position_impl_trait_in_trait_bounds(

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ rustc_queries! {
803803
///
804804
/// Note that we've liberated the late bound regions of function signatures, so
805805
/// this can not be used to check whether these types are well formed.
806-
query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> {
806+
query assumed_wf_types(key: DefId) -> &'tcx [(Ty<'tcx>, Span)] {
807807
desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
808808
}
809809

compiler/rustc_trait_selection/src/traits/engine.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,8 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
191191
let assumed_wf_types = tcx.assumed_wf_types(def_id);
192192
let mut implied_bounds = FxIndexSet::default();
193193
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
194-
let cause = ObligationCause::misc(span, hir_id);
195-
for ty in assumed_wf_types {
194+
for &(ty, ty_span) in assumed_wf_types {
195+
let span = if ty_span.is_dummy() { span } else { ty_span };
196196
// FIXME(@lcnr): rustc currently does not check wf for types
197197
// pre-normalization, meaning that implied bounds are sometimes
198198
// incorrect. See #100910 for more details.
@@ -205,7 +205,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
205205
// sound and then uncomment this line again.
206206

207207
// implied_bounds.insert(ty);
208-
let normalized = self.normalize(&cause, param_env, ty);
208+
let normalized = self.normalize(&ObligationCause::misc(span, hir_id), param_env, ty);
209209
implied_bounds.insert(normalized);
210210
}
211211
implied_bounds

compiler/rustc_ty_utils/src/implied_bounds.rs

+57-10
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,80 @@
11
use crate::rustc_middle::ty::DefIdTree;
2-
use rustc_hir::{def::DefKind, def_id::DefId};
2+
use rustc_hir::{self as hir, def::DefKind, def_id::DefId};
33
use rustc_middle::ty::{self, Ty, TyCtxt};
4+
use rustc_span::{Span, DUMMY_SP};
45

56
pub fn provide(providers: &mut ty::query::Providers) {
67
*providers = ty::query::Providers { assumed_wf_types, ..*providers };
78
}
89

9-
fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
10+
fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &[(Ty<'_>, Span)] {
1011
match tcx.def_kind(def_id) {
1112
DefKind::Fn => {
1213
let sig = tcx.fn_sig(def_id);
1314
let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
14-
liberated_sig.inputs_and_output
15+
if let Some(node) = tcx.hir().get_if_local(def_id)
16+
&& let Some(decl) = node.fn_decl()
17+
{
18+
assert_eq!(decl.inputs.len(), liberated_sig.inputs().len());
19+
tcx.arena.alloc_from_iter(std::iter::zip(
20+
liberated_sig.inputs_and_output,
21+
decl.inputs.iter().map(|ty| ty.span).chain([decl.output.span()]),
22+
))
23+
} else {
24+
tcx.arena.alloc_from_iter(
25+
liberated_sig.inputs_and_output.iter().map(|ty| (ty, DUMMY_SP)),
26+
)
27+
}
1528
}
1629
DefKind::AssocFn => {
1730
let sig = tcx.fn_sig(def_id);
1831
let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
19-
let mut assumed_wf_types: Vec<_> =
20-
tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into();
21-
assumed_wf_types.extend(liberated_sig.inputs_and_output);
22-
tcx.intern_type_list(&assumed_wf_types)
32+
let assumed_wf_types = tcx.assumed_wf_types(tcx.parent(def_id));
33+
if let Some(node) = tcx.hir().get_if_local(def_id)
34+
&& let Some(decl) = node.fn_decl()
35+
{
36+
assert_eq!(decl.inputs.len(), liberated_sig.inputs().len());
37+
tcx.arena.alloc_from_iter(assumed_wf_types.iter().copied().chain(std::iter::zip(
38+
liberated_sig.inputs_and_output,
39+
decl.inputs.iter().map(|ty| ty.span).chain([decl.output.span()]),
40+
)))
41+
} else {
42+
tcx.arena.alloc_from_iter(assumed_wf_types.iter().copied().chain(
43+
liberated_sig.inputs_and_output.iter().map(|ty| (ty, DUMMY_SP)),
44+
))
45+
}
2346
}
2447
DefKind::Impl => match tcx.impl_trait_ref(def_id) {
2548
Some(trait_ref) => {
2649
let types: Vec<_> = trait_ref.substs.types().collect();
27-
tcx.intern_type_list(&types)
50+
let self_span = if let Some(hir::Node::Item(hir::Item {
51+
kind: hir::ItemKind::Impl(impl_),
52+
..
53+
})) = tcx.hir().get_if_local(def_id)
54+
{
55+
impl_.self_ty.span
56+
} else {
57+
DUMMY_SP
58+
};
59+
tcx.arena.alloc_from_iter(std::iter::zip(
60+
types,
61+
// FIXME: reliable way of getting trait ref substs...
62+
[self_span].into_iter().chain(std::iter::repeat(DUMMY_SP)),
63+
))
2864
}
2965
// Only the impl self type
30-
None => tcx.intern_type_list(&[tcx.type_of(def_id)]),
66+
None => {
67+
let span = if let Some(hir::Node::Item(hir::Item {
68+
kind: hir::ItemKind::Impl(impl_),
69+
..
70+
})) = tcx.hir().get_if_local(def_id)
71+
{
72+
impl_.self_ty.span
73+
} else {
74+
DUMMY_SP
75+
};
76+
tcx.arena.alloc_from_iter([(tcx.type_of(def_id), span)])
77+
}
3178
},
3279
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
3380
DefKind::Mod
@@ -56,6 +103,6 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
56103
| DefKind::LifetimeParam
57104
| DefKind::GlobalAsm
58105
| DefKind::Closure
59-
| DefKind::Generator => ty::List::empty(),
106+
| DefKind::Generator => &[],
60107
}
61108
}

src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the trait bound `Self: Get` is not satisfied
2-
--> $DIR/associated-types-for-unimpl-trait.rs:10:5
2+
--> $DIR/associated-types-for-unimpl-trait.rs:10:40
33
|
44
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
5+
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
66
|
77
help: consider further restricting `Self`
88
|

src/test/ui/associated-types/associated-types-no-suitable-bound.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the trait bound `T: Get` is not satisfied
2-
--> $DIR/associated-types-no-suitable-bound.rs:11:5
2+
--> $DIR/associated-types-no-suitable-bound.rs:11:21
33
|
44
LL | fn uhoh<T>(foo: <T as Get>::Value) {}
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
5+
| ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
66
|
77
help: consider restricting type parameter `T`
88
|

src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the trait bound `Self: Get` is not satisfied
2-
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
2+
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40
33
|
44
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
5+
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
66
|
77
help: consider further restricting `Self`
88
|

src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
error[E0277]: the trait bound `(T, U): Get` is not satisfied
2-
--> $DIR/associated-types-no-suitable-supertrait.rs:22:5
2+
--> $DIR/associated-types-no-suitable-supertrait.rs:22:40
33
|
44
LL | fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
5+
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
66

77
error[E0277]: the trait bound `Self: Get` is not satisfied
8-
--> $DIR/associated-types-no-suitable-supertrait.rs:17:5
8+
--> $DIR/associated-types-no-suitable-supertrait.rs:17:40
99
|
1010
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
11+
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
1212
|
1313
help: consider further restricting `Self`
1414
|

src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the trait bound `Self: Get` is not satisfied
2-
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
2+
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40
33
|
44
LL | fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
5+
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
66
|
77
help: consider further restricting `Self`
88
|

src/test/ui/associated-types/issue-59324.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ pub trait ThriftService<Bug: NotFoo>:
1515
{
1616
fn get_service(
1717
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
18-
//~| ERROR the trait bound `Bug: Foo` is not satisfied
1918
&self,
2019
) -> Self::AssocType;
20+
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
2121
}
2222

2323
fn with_factory<H>(factory: dyn ThriftService<()>) {}

src/test/ui/associated-types/issue-59324.stderr

+6-11
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | |
2020
LL | |
2121
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
2222
... |
23-
LL | | ) -> Self::AssocType;
23+
LL | |
2424
LL | | }
2525
| |_^ the trait `Foo` is not implemented for `Bug`
2626
|
@@ -34,7 +34,6 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied
3434
|
3535
LL | / fn get_service(
3636
LL | |
37-
LL | |
3837
LL | | &self,
3938
LL | | ) -> Self::AssocType;
4039
| |_________________________^ the trait `Foo` is not implemented for `Bug`
@@ -45,20 +44,16 @@ LL | pub trait ThriftService<Bug: NotFoo + Foo>:
4544
| +++++
4645

4746
error[E0277]: the trait bound `(): Foo` is not satisfied
48-
--> $DIR/issue-59324.rs:23:1
47+
--> $DIR/issue-59324.rs:23:29
4948
|
5049
LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
51-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
50+
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
5251

5352
error[E0277]: the trait bound `Bug: Foo` is not satisfied
54-
--> $DIR/issue-59324.rs:16:5
53+
--> $DIR/issue-59324.rs:19:10
5554
|
56-
LL | / fn get_service(
57-
LL | |
58-
LL | |
59-
LL | | &self,
60-
LL | | ) -> Self::AssocType;
61-
| |_________________________^ the trait `Foo` is not implemented for `Bug`
55+
LL | ) -> Self::AssocType;
56+
| ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
6257
|
6358
help: consider further restricting this bound
6459
|

src/test/ui/issues/issue-18611.stderr

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
error[E0277]: the trait bound `isize: HasState` is not satisfied
2-
--> $DIR/issue-18611.rs:1:1
2+
--> $DIR/issue-18611.rs:1:18
33
|
4-
LL | / fn add_state(op: <isize as HasState>::State) {
5-
LL | |
6-
LL | | }
7-
| |_^ the trait `HasState` is not implemented for `isize`
4+
LL | fn add_state(op: <isize as HasState>::State) {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize`
86

97
error: aborting due to previous error
108

src/test/ui/issues/issue-20831-debruijn.stderr

+6-18
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
2-
--> $DIR/issue-20831-debruijn.rs:28:5
2+
--> $DIR/issue-20831-debruijn.rs:28:33
33
|
4-
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
5-
LL | | // Not obvious, but there is an implicit lifetime here -------^
6-
LL | |
7-
LL | | //
8-
... |
9-
LL | | self.sub = t;
10-
LL | | }
11-
| |_____^
4+
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
126
|
137
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
148
--> $DIR/issue-20831-debruijn.rs:28:58
@@ -21,16 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined he
2115
LL | impl<'a> Publisher<'a> for MyStruct<'a> {
2216
| ^^
2317
note: ...so that the types are compatible
24-
--> $DIR/issue-20831-debruijn.rs:28:5
18+
--> $DIR/issue-20831-debruijn.rs:28:33
2519
|
26-
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
27-
LL | | // Not obvious, but there is an implicit lifetime here -------^
28-
LL | |
29-
LL | | //
30-
... |
31-
LL | | self.sub = t;
32-
LL | | }
33-
| |_____^
20+
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3422
= note: expected `<MyStruct<'a> as Publisher<'_>>`
3523
found `<MyStruct<'_> as Publisher<'_>>`
3624

src/test/ui/issues/issue-35570.rs

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ trait Trait2<'a> {
77

88
fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
99
//~^ ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied
10-
//~| ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied
1110
let _e: (usize, usize) = unsafe{mem::transmute(param)};
1211
}
1312

0 commit comments

Comments
 (0)