Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

impl Trait Lifetime Elision #43396

Closed
cramertj opened this issue Jul 21, 2017 · 3 comments
Closed

impl Trait Lifetime Elision #43396

cramertj opened this issue Jul 21, 2017 · 3 comments
Labels
C-bug Category: This is a bug. I-needs-decision Issue: In need of a decision. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@cramertj
Copy link
Member

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?

@eddyb
Copy link
Member

eddyb commented Jul 21, 2017

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

@nikomatsakis
Copy link
Contributor

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 write impl Trait + '_.
  • We will effectively desugar by mapping '_ to an add'l lifetime parameter on the abstract 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):

self.with(scope, |_old_scope, this| {

we would insert an elision scope:

/// A scope which either determines unspecified lifetimes or errors
/// on them (e.g. due to ambiguity). For more details, see `Elide`.
Elision {
elide: Elide,
s: ScopeRef<'a>
},

with Elide::Exact set to a reference to this (early-bound) extra parameter:

/// Always use this one lifetime.
Exact(Region),

We will also insert a reference to the elided lifetime into the Foo<'_> reference, which can just resolve as normal.

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Dec 7, 2017

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()
    }
}

bors added a commit that referenced this issue Dec 13, 2017
Implement impl Trait lifetime elision

Fixes #43396.

There's one weird ICE in the interaction with argument-position `impl Trait`. I'm still debugging it-- I've left a test for it commented out with a FIXME.

Also included a FIXME to ensure that `impl Trait` traits are caught under the lint in #45992.

r? @nikomatsakis
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. I-needs-decision Issue: In need of a decision. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants