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)
Not all lifetimes on a fn can be late bound:
fn foo<'a>() -> &'a ();
impl<'a> Fn<()> for FooFnDef {
type Output = &'a (); // uh oh unconstrained lifetime
}
so we make make them early bound
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 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:
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):
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
}
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 places all lifetimes in Generics
regardless of late boundness so that may be a good step towards making this possible.
or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Syncing