Skip to content

Commit 3a58b83

Browse files
authored
Rollup merge of rust-lang#119350 - fmease:lazy-ty-aliases-implied-bounds, r=compiler-errors
Imply outlives-bounds on lazy type aliases Fixes rust-lang#118479. r? types
2 parents cf4d1c3 + 90d6fe2 commit 3a58b83

File tree

5 files changed

+211
-97
lines changed

5 files changed

+211
-97
lines changed

compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs

+108-71
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ pub(super) fn infer_predicates(
5959
}
6060
}
6161

62+
DefKind::TyAlias if tcx.type_alias_is_lazy(item_did) => {
63+
insert_required_predicates_to_be_wf(
64+
tcx,
65+
tcx.type_of(item_did).instantiate_identity(),
66+
tcx.def_span(item_did),
67+
&global_inferred_outlives,
68+
&mut item_required_predicates,
69+
&mut explicit_map,
70+
);
71+
}
72+
6273
_ => {}
6374
};
6475

@@ -88,78 +99,41 @@ pub(super) fn infer_predicates(
8899

89100
fn insert_required_predicates_to_be_wf<'tcx>(
90101
tcx: TyCtxt<'tcx>,
91-
field_ty: Ty<'tcx>,
92-
field_span: Span,
102+
ty: Ty<'tcx>,
103+
span: Span,
93104
global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
94105
required_predicates: &mut RequiredPredicates<'tcx>,
95106
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
96107
) {
97-
for arg in field_ty.walk() {
98-
let ty = match arg.unpack() {
108+
for arg in ty.walk() {
109+
let leaf_ty = match arg.unpack() {
99110
GenericArgKind::Type(ty) => ty,
100111

101112
// No predicates from lifetimes or constants, except potentially
102113
// constants' types, but `walk` will get to them as well.
103114
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
104115
};
105116

106-
match *ty.kind() {
107-
// The field is of type &'a T which means that we will have
108-
// a predicate requirement of T: 'a (T outlives 'a).
109-
//
110-
// We also want to calculate potential predicates for the T
117+
match *leaf_ty.kind() {
111118
ty::Ref(region, rty, _) => {
119+
// The type is `&'a T` which means that we will have
120+
// a predicate requirement of `T: 'a` (`T` outlives `'a`).
121+
//
122+
// We also want to calculate potential predicates for the `T`.
112123
debug!("Ref");
113-
insert_outlives_predicate(tcx, rty.into(), region, field_span, required_predicates);
124+
insert_outlives_predicate(tcx, rty.into(), region, span, required_predicates);
114125
}
115126

116-
// For each Adt (struct/enum/union) type `Foo<'a, T>`, we
117-
// can load the current set of inferred and explicit
118-
// predicates from `global_inferred_outlives` and filter the
119-
// ones that are TypeOutlives.
120127
ty::Adt(def, args) => {
121-
// First check the inferred predicates
122-
//
123-
// Example 1:
124-
//
125-
// struct Foo<'a, T> {
126-
// field1: Bar<'a, T>
127-
// }
128-
//
129-
// struct Bar<'b, U> {
130-
// field2: &'b U
131-
// }
132-
//
133-
// Here, when processing the type of `field1`, we would
134-
// request the set of implicit predicates computed for `Bar`
135-
// thus far. This will initially come back empty, but in next
136-
// round we will get `U: 'b`. We then apply the substitution
137-
// `['b => 'a, U => T]` and thus get the requirement that `T:
138-
// 'a` holds for `Foo`.
128+
// For ADTs (structs/enums/unions), we check inferred and explicit predicates.
139129
debug!("Adt");
140-
if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) {
141-
for (unsubstituted_predicate, &span) in
142-
unsubstituted_predicates.as_ref().skip_binder()
143-
{
144-
// `unsubstituted_predicate` is `U: 'b` in the
145-
// example above. So apply the substitution to
146-
// get `T: 'a` (or `predicate`):
147-
let predicate = unsubstituted_predicates
148-
.rebind(*unsubstituted_predicate)
149-
.instantiate(tcx, args);
150-
insert_outlives_predicate(
151-
tcx,
152-
predicate.0,
153-
predicate.1,
154-
span,
155-
required_predicates,
156-
);
157-
}
158-
}
159-
160-
// Check if the type has any explicit predicates that need
161-
// to be added to `required_predicates`
162-
// let _: () = args.region_at(0);
130+
check_inferred_predicates(
131+
tcx,
132+
def.did(),
133+
args,
134+
global_inferred_outlives,
135+
required_predicates,
136+
);
163137
check_explicit_predicates(
164138
tcx,
165139
def.did(),
@@ -170,13 +144,31 @@ fn insert_required_predicates_to_be_wf<'tcx>(
170144
);
171145
}
172146

147+
ty::Alias(ty::Weak, alias) => {
148+
// This corresponds to a type like `Type<'a, T>`.
149+
// We check inferred and explicit predicates.
150+
debug!("Weak");
151+
check_inferred_predicates(
152+
tcx,
153+
alias.def_id,
154+
alias.args,
155+
global_inferred_outlives,
156+
required_predicates,
157+
);
158+
check_explicit_predicates(
159+
tcx,
160+
alias.def_id,
161+
alias.args,
162+
required_predicates,
163+
explicit_map,
164+
None,
165+
);
166+
}
167+
173168
ty::Dynamic(obj, ..) => {
174169
// This corresponds to `dyn Trait<..>`. In this case, we should
175170
// use the explicit predicates as well.
176-
177171
debug!("Dynamic");
178-
debug!("field_ty = {}", &field_ty);
179-
debug!("ty in field = {}", &ty);
180172
if let Some(ex_trait_ref) = obj.principal() {
181173
// Here, we are passing the type `usize` as a
182174
// placeholder value with the function
@@ -198,41 +190,44 @@ fn insert_required_predicates_to_be_wf<'tcx>(
198190
}
199191
}
200192

201-
ty::Alias(ty::Projection, obj) => {
202-
// This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
203-
// explicit predicates as well.
193+
ty::Alias(ty::Projection, alias) => {
194+
// This corresponds to a type like `<() as Trait<'a, T>>::Type`.
195+
// We only use the explicit predicates of the trait but
196+
// not the ones of the associated type itself.
204197
debug!("Projection");
205198
check_explicit_predicates(
206199
tcx,
207-
tcx.parent(obj.def_id),
208-
obj.args,
200+
tcx.parent(alias.def_id),
201+
alias.args,
209202
required_predicates,
210203
explicit_map,
211204
None,
212205
);
213206
}
214207

215-
// FIXME(inherent_associated_types): Handle this case properly.
208+
// FIXME(inherent_associated_types): Use the explicit predicates from the parent impl.
216209
ty::Alias(ty::Inherent, _) => {}
217210

218211
_ => {}
219212
}
220213
}
221214
}
222215

223-
/// We also have to check the explicit predicates
224-
/// declared on the type.
216+
/// Check the explicit predicates declared on the type.
217+
///
218+
/// ### Example
219+
///
225220
/// ```ignore (illustrative)
226-
/// struct Foo<'a, T> {
227-
/// field1: Bar<T>
221+
/// struct Outer<'a, T> {
222+
/// field: Inner<T>,
228223
/// }
229224
///
230-
/// struct Bar<U> where U: 'static, U: Foo {
231-
/// ...
225+
/// struct Inner<U> where U: 'static, U: Outer {
226+
/// // ...
232227
/// }
233228
/// ```
234229
/// Here, we should fetch the explicit predicates, which
235-
/// will give us `U: 'static` and `U: Foo`. The latter we
230+
/// will give us `U: 'static` and `U: Outer`. The latter we
236231
/// can ignore, but we will want to process `U: 'static`,
237232
/// applying the substitution as above.
238233
fn check_explicit_predicates<'tcx>(
@@ -303,3 +298,45 @@ fn check_explicit_predicates<'tcx>(
303298
insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates);
304299
}
305300
}
301+
302+
/// Check the inferred predicates declared on the type.
303+
///
304+
/// ### Example
305+
///
306+
/// ```ignore (illustrative)
307+
/// struct Outer<'a, T> {
308+
/// outer: Inner<'a, T>,
309+
/// }
310+
///
311+
/// struct Inner<'b, U> {
312+
/// inner: &'b U,
313+
/// }
314+
/// ```
315+
///
316+
/// Here, when processing the type of field `outer`, we would request the
317+
/// set of implicit predicates computed for `Inner` thus far. This will
318+
/// initially come back empty, but in next round we will get `U: 'b`.
319+
/// We then apply the substitution `['b => 'a, U => T]` and thus get the
320+
/// requirement that `T: 'a` holds for `Outer`.
321+
fn check_inferred_predicates<'tcx>(
322+
tcx: TyCtxt<'tcx>,
323+
def_id: DefId,
324+
args: ty::GenericArgsRef<'tcx>,
325+
global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
326+
required_predicates: &mut RequiredPredicates<'tcx>,
327+
) {
328+
// Load the current set of inferred and explicit predicates from `global_inferred_outlives`
329+
// and filter the ones that are `TypeOutlives`.
330+
331+
let Some(predicates) = global_inferred_outlives.get(&def_id) else {
332+
return;
333+
};
334+
335+
for (&predicate, &span) in predicates.as_ref().skip_binder() {
336+
// `predicate` is `U: 'b` in the example above.
337+
// So apply the substitution to get `T: 'a`.
338+
let ty::OutlivesPredicate(arg, region) =
339+
predicates.rebind(predicate).instantiate(tcx, args);
340+
insert_outlives_predicate(tcx, arg, region, span, required_predicates);
341+
}
342+
}

compiler/rustc_hir_analysis/src/outlives/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
2121
let crate_map = tcx.inferred_outlives_crate(());
2222
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
2323
}
24+
DefKind::TyAlias if tcx.type_alias_is_lazy(item_def_id) => {
25+
let crate_map = tcx.inferred_outlives_crate(());
26+
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
27+
}
2428
DefKind::AnonConst if tcx.features().generic_const_exprs => {
2529
let id = tcx.local_def_id_to_hir_id(item_def_id);
2630
if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
@@ -47,8 +51,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
4751
}
4852

4953
fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
50-
// Compute a map from each struct/enum/union S to the **explicit**
51-
// outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
54+
// Compute a map from each ADT (struct/enum/union) and lazy type alias to
55+
// the **explicit** outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
5256
// Typically there won't be many of these, except in older code where
5357
// they were mandatory. Nonetheless, we have to ensure that every such
5458
// predicate is satisfied, so they form a kind of base set of requirements

tests/ui/associated-type-bounds/duplicate.stderr

+24-24
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,30 @@ LL | struct SI1<T: Iterator<Item: Copy, Item: Send>> {
66
| |
77
| `Item` bound here first
88

9+
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
10+
--> $DIR/duplicate.rs:255:40
11+
|
12+
LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
13+
| ---------- ^^^^^^^^^^ re-bound here
14+
| |
15+
| `Item` bound here first
16+
17+
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
18+
--> $DIR/duplicate.rs:257:44
19+
|
20+
LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
21+
| ---------- ^^^^^^^^^^ re-bound here
22+
| |
23+
| `Item` bound here first
24+
25+
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
26+
--> $DIR/duplicate.rs:259:43
27+
|
28+
LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
29+
| ------------- ^^^^^^^^^^^^^ re-bound here
30+
| |
31+
| `Item` bound here first
32+
933
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
1034
--> $DIR/duplicate.rs:11:36
1135
|
@@ -490,30 +514,6 @@ LL | Self: Iterator<Item: 'static, Item: 'static>,
490514
|
491515
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
492516

493-
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
494-
--> $DIR/duplicate.rs:255:40
495-
|
496-
LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
497-
| ---------- ^^^^^^^^^^ re-bound here
498-
| |
499-
| `Item` bound here first
500-
501-
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
502-
--> $DIR/duplicate.rs:257:44
503-
|
504-
LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
505-
| ---------- ^^^^^^^^^^ re-bound here
506-
| |
507-
| `Item` bound here first
508-
509-
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
510-
--> $DIR/duplicate.rs:259:43
511-
|
512-
LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
513-
| ------------- ^^^^^^^^^^^^^ re-bound here
514-
| |
515-
| `Item` bound here first
516-
517517
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
518518
--> $DIR/duplicate.rs:243:34
519519
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/implied-outlives-bounds.rs:21:12
3+
|
4+
LL | fn env0<'any>() {
5+
| ---- lifetime `'any` defined here
6+
LL | let _: TypeOutlives<'static, &'any ()>;
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`
8+
9+
error: lifetime may not live long enough
10+
--> $DIR/implied-outlives-bounds.rs:26:12
11+
|
12+
LL | fn env1<'any>() {
13+
| ---- lifetime `'any` defined here
14+
LL | let _: RegionOutlives<'static, 'any>;
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`
16+
17+
error: lifetime may not live long enough
18+
--> $DIR/implied-outlives-bounds.rs:31:12
19+
|
20+
LL | fn env2<'any>() {
21+
| ---- lifetime `'any` defined here
22+
LL | let _: Outer0<'static, &'any ()>;
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`
24+
25+
error: lifetime may not live long enough
26+
--> $DIR/implied-outlives-bounds.rs:36:12
27+
|
28+
LL | fn env3<'any>() {
29+
| ---- lifetime `'any` defined here
30+
LL | let _: Outer1<'static, &'any ()>;
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`
32+
33+
error: aborting due to 4 previous errors
34+

0 commit comments

Comments
 (0)