Skip to content

Commit ae5f58d

Browse files
Check elaborated projections from dyn don't mention unconstrained late bound lifetimes
1 parent 14f303b commit ae5f58d

File tree

5 files changed

+86
-14
lines changed

5 files changed

+86
-14
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs

+50
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
174174
// Include projections defined on supertraits.
175175
projection_bounds.push((pred, span));
176176
}
177+
178+
self.check_elaborated_projection_mentions_input_lifetimes(pred, span);
177179
}
178180
_ => (),
179181
}
@@ -360,6 +362,54 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
360362

361363
Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
362364
}
365+
366+
/// Check that elaborating the principal of a trait ref doesn't lead to projections
367+
/// that are unconstrained. This can happen because an otherwise unconstrained
368+
/// *type variable* can be substituted with a type that has late-bound regions. See
369+
/// `elaborated-predicates-unconstrained-late-bound.rs` for a test.
370+
fn check_elaborated_projection_mentions_input_lifetimes(
371+
&self,
372+
pred: ty::PolyProjectionPredicate<'tcx>,
373+
span: Span,
374+
) {
375+
let tcx = self.tcx();
376+
377+
// Find any late-bound regions declared in `ty` that are not
378+
// declared in the trait-ref or assoc_item. These are not well-formed.
379+
//
380+
// Example:
381+
//
382+
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
383+
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
384+
let late_bound_in_projection_term =
385+
tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term));
386+
let late_bound_in_term =
387+
tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term));
388+
debug!(?late_bound_in_projection_term);
389+
debug!(?late_bound_in_term);
390+
391+
// FIXME: point at the type params that don't have appropriate lifetimes:
392+
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
393+
// ---- ---- ^^^^^^^
394+
// NOTE(associated_const_equality): This error should be impossible to trigger
395+
// with associated const equality constraints.
396+
self.validate_late_bound_regions(
397+
late_bound_in_projection_term,
398+
late_bound_in_term,
399+
|br_name| {
400+
let item_name = tcx.item_name(pred.projection_def_id());
401+
struct_span_code_err!(
402+
self.dcx(),
403+
span,
404+
E0582,
405+
"binding for associated type `{}` references {}, \
406+
which does not appear in the trait input types",
407+
item_name,
408+
br_name
409+
)
410+
},
411+
);
412+
}
363413
}
364414

365415
fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Make sure that when elaborating the principal of a dyn trait for projection predicates
2+
// we don't end up in a situation where we have an unconstrained late-bound lifetime in
3+
// the output of a projection.
4+
5+
// Fix for <https://github.com/rust-lang/rust/issues/130347>.
6+
7+
trait A<T>: B<T = T> {}
8+
9+
trait B {
10+
type T;
11+
}
12+
13+
struct Erase<T: ?Sized + B>(T::T);
14+
15+
fn main() {
16+
let x = {
17+
let x = String::from("hello");
18+
19+
Erase::<dyn for<'a> A<&'a _>>(x.as_str())
20+
//~^ ERROR binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types
21+
};
22+
23+
dbg!(x.0);
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0582]: binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types
2+
--> $DIR/elaborated-predicates-unconstrained-late-bound.rs:19:21
3+
|
4+
LL | Erase::<dyn for<'a> A<&'a _>>(x.as_str())
5+
| ^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0582`.

tests/ui/traits/object/pretty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ trait SuperGeneric<'a> {
1313
}
1414
trait AnyGeneric<'a>: SuperGeneric<'a> {}
1515
trait FixedGeneric1<'a>: SuperGeneric<'a, Assoc2 = &'a u8> {}
16-
trait FixedGeneric2<'a>: Super<Assoc = &'a u8> {}
16+
// trait FixedGeneric2<'a>: Super<Assoc = &'a u8> {} // Unsound!
1717
trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {}
1818
trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {}
1919
trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super<Assoc = u8> {}
@@ -32,7 +32,7 @@ fn dyn_fixed_static(x: &dyn FixedStatic) { x } //~ERROR mismatched types
3232
fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types
3333
fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types
3434
fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } //~ERROR mismatched types
35-
fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } //~ERROR mismatched types
35+
// fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } // Unsound!
3636
fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } //~ERROR mismatched types
3737
fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types
3838
fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } //~ERROR mismatched types

tests/ui/traits/object/pretty.stderr

+1-12
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,6 @@ LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x }
106106
= note: expected unit type `()`
107107
found reference `&dyn for<'a> FixedGeneric1<'a>`
108108

109-
error[E0308]: mismatched types
110-
--> $DIR/pretty.rs:35:60
111-
|
112-
LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x }
113-
| - ^ expected `()`, found `&dyn FixedGeneric2<'a>`
114-
| |
115-
| help: try adding a return type: `-> &dyn for<'a> FixedGeneric2<'a>`
116-
|
117-
= note: expected unit type `()`
118-
found reference `&dyn for<'a> FixedGeneric2<'a>`
119-
120109
error[E0308]: mismatched types
121110
--> $DIR/pretty.rs:36:79
122111
|
@@ -172,6 +161,6 @@ LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
172161
= note: expected unit type `()`
173162
found reference `&dyn HasGat<u8, Assoc<bool> = ()>`
174163

175-
error: aborting due to 15 previous errors; 1 warning emitted
164+
error: aborting due to 14 previous errors; 1 warning emitted
176165

177166
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)