@nikomatsakis 's post 5 years ago explained the resonale behind late bound lifetimes:
I will call this a late-bound lifetime parameter , because we don’t need to substitute a specific lifetime right away, but rather we can wait until the function is called.
- Lifetime parameters on fns or methods that appear within a type bound are considered early bound . Those that do not are considered late bound .
The following recently found example code that causes ICE
trait Lt<'a> {
type T;
}
impl<'a> Lt<'a> for () {
type T = ();
}
fn main() {
let _:fn(<() as Lt<'_>>::T) = |()| {};
}
however, put a serious question in front of us:
If the function were called, but no lifetime can be concluded, what should the compiler do?
Specifically, in the example above, <() as Lt<'_>>::T
is late bound because the lifetime '_
cannot be bound until we know ()
must be a supertype of <() as Lt<'_>>::T
. But even then, we don't know what '_
should be.
Right now, the compiler cannot handle this case and get confused: "<() as Lt<'_>>::T
have no relation with ()
and this should be rejected earlier" whiles the decision was just being postponed.
As this is ICE in STABLE we now have to make a decision:
What should we do?
EDIT
trait Lt<'a> {
type T;
}
impl<'a> Lt<'a> for () {
type T = ();
}
fn test<'a>() {
let _:fn(<() as Lt<'a>>::T) = |()| {};
}
fn main() {
test();
}
Is working!, however if we remove the 'a
lifetime from test
and replace Lt<'a>
with Lt<'_>
it triggers ICE. I think this means the code to justify "<() as Lt<'_>>::T
is a subtype of ()
" failed to pick up a brand new lifetime parameter, so it didn't fall back to the case above.