diff options
| author | Manish Goregaokar <manishsmail@gmail.com> | 2022-11-08 21:03:51 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-08 21:03:51 -0500 |
| commit | f162e3a1b1e8025435c177bc0659155bab50ad92 (patch) | |
| tree | 18ceabcaed776fd527cc9fac65dc2b764c078d93 /compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | |
| parent | 8d36948b1519c77a54867523453fef3e0c3a648b (diff) | |
| parent | 983a90d7160b5e6054827f42c0ecf9aa52cebcd4 (diff) | |
| download | rust-f162e3a1b1e8025435c177bc0659155bab50ad92.tar.gz rust-f162e3a1b1e8025435c177bc0659155bab50ad92.zip | |
Rollup merge of #100508 - BoxyUwU:make_less_things_late_bound, r=nikomatsakis
avoid making substs of type aliases late bound when used as fn args
fixes #47511
fixes #85533
(although I did not know theses issues existed when i was working on this :upside_down_face:)
currently `Alias<...>` is treated the same as `Struct<...>` when deciding if generics should be late bound or early bound but this is not correct as `Alias` might normalize to a projection which does not constrain the generics.
I think this needs more tests before merging
more explanation of PR [here](https://hackmd.io/v44a-QVjTIqqhK9uretyQg?view)
Hackmd inline for future readers:
---
This assumes reader is familiar with the concept of early/late bound lifetimes. There's a section on rustc-dev-guide if not (although i think some details are a bit out of date)
## problem & background
Not all lifetimes on a fn can be late bound:
```rust
fn foo<'a>() -> &'a ();
impl<'a> Fn<()> for FooFnDef {
type Output = &'a (); // uh oh unconstrained lifetime
}
```
so we make make them early bound
```rust
fn foo<'a>() -> &'a ();
impl<'a> Fn<()> for FooFnDef<'a> {// wow look at all that lifetimey
type Output = &'a ();
}
```
(Closures have the same constraint however it is not enforced leading to soundness bugs, [#84385](https://github.com/rust-lang/rust/pull/84385) implements this "downgrading late bound to early bound" for closures)
lifetimes on fn items are only late bound when they are "constrained" by the fn args:
```rust
fn foo<'a>(_: &'a ()) -> &'a ();
// late bound, not present on `FooFnItem`
// vv
impl<'a> Trait<(&'a (),)> for FooFnItem {
type Output = &'a ();
}
// projections do not constrain inputs
fn bar<'a, T: Trait>(_: <T as Trait<'a>>::Assoc) -> &'a (); // early bound
// vv
impl<'a, T: Trait> Fn<(<T as Trait<'a>>::Assoc,)> for BarFnItem<'a, T> {
type Output = &'a ();
}
```
current logic for determining if inputs "constrain" a lifetime works off of HIR so does not normalize aliases. It also assumes that any path with no self type constrains all its substs (i.e. `Foo<'a, u32>` has no self type but `T::Assoc` does). This falls apart for top level type aliases (see linked issues):
```rust
type Alias<'a, T> = <T as Trait<'a>>::Assoc;
// wow look its a path with no self type uwu
// i bet that constrains `'a` so it should be latebound
// vvvvvvvvvvv
fn foo<'a, T: Trait>(_: Alias<'a, T>) -> &'a ();
// `Alias` normalized to make things clearer
// vvvvvvvvvvvvvvvvvvvvvvv
impl<'a, T: Trait> Fn<(<T as Trait<'a>>::Assoc,)> for FooFnDef<T> {
type Output = &'a ();
// oh no `'a` isnt constrained wah wah waaaah *trumbone noises*
// i think, idk what musical instrument that is
}
```
## solution
The PR solves this by having the hir visitor that checks for lifetimes in constraining uses check if the path is a `DefKind::Alias`. If it is we ""normalize"" it by calling `type_of` and walking the returned type. This is a bit hacky as it requires a mapping between the substs on the path in hir, and the generics of the `type Alias<...>` which is on the ty layer.
Alternative solutions may involve calculating the "late boundness" of lifetimes after/during astconv rather than relying on hir at all. We already have code to determine whether a lifetime SHOULD be late bound or not as this is currently how the error for `fn foo<'a, T: Trait>(_: Alias<'a, T>) -> &'a ();` gets emitted.
It is probably not possible to do this right now, late boundness is used by `generics_of` and `gather_explicit_predicates_of` as we currently do not put late bound lifetimes in `Generics`. Although this seems sus to me as the long term goal is to make all generics late bound which would result in `generics_of(function)` being empty? [#103448](https://github.com/rust-lang/rust/pull/103448) places all lifetimes in `Generics` regardless of late boundness so that may be a good step towards making this possible.
Diffstat (limited to 'compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp')
0 files changed, 0 insertions, 0 deletions
