`impl Trait` Lifetime Elision
cramertj opened this issue · 3 comments
The following ICEs:
fn foo(x: &bool) -> impl Into<&bool> { x }
The message is: error: internal compiler error: /checkout/src/librustc_typeck/check/mod.rs:618: escaping regions in predicate Obligation(predicate=Binder(TraitPredicate(<_ as std::convert::Into<&bool>>)),depth=0) --> src/main.rs:6:21
.
Should we explicitly disallow lifetime elision in impl Trait
?
The ICE should not be fixed, but rather elision be disabled, unless someone can point me to an accepted RFC allowing this kind of elision. cc @rust-lang/lang
So @cramertj and I discussed this over IRC today. The plan is to support elision as follows:
- Lifetimes can be elided, but if you just write
impl Trait
it does not capture&self
. To capture, you must writeimpl Trait + '_
. - We will effectively desugar by mapping
'_
to an add'l lifetime parameter on theabstract type
that is being created. So we would have:
fn foo(x: &u32) -> impl Trait<'_> { ... }
desugaring to something like:
abstract type Foo<'a>: Trait<'a>;
fn foo(x: &u32) -> Foo<'_> { ... }
To implement this, we have to first modify HIR lowerring to detect elided lifetimes when it is scraping the impl trait bounds for additional parameters. We can then add a special parameter (perhaps naming it '_
?).
Then we have to modify name resolution as follows. When we are lifetime-resolving the trait bounds (Trait<'a>
in the above example):
rust/src/librustc/middle/resolve_lifetime.rs
Line 496 in 833785b
we would insert an elision scope:
rust/src/librustc/middle/resolve_lifetime.rs
Lines 248 to 253 in 833785b
with Elide::Exact
set to a reference to this (early-bound) extra parameter:
rust/src/librustc/middle/resolve_lifetime.rs
Lines 271 to 272 in 833785b
We will also insert a reference to the elided lifetime into the Foo<'_>
reference, which can just resolve as normal.
An example from #46565:
struct Parent
{
children: Option<Vec<String>>
}
impl Parent {
pub fn children() -> impl Iterator<Item=&str> {
self.children.unwrap_or(Vec::new()).iter()
}
}