Skip to content

Make lifetime elision rules for closures consistent with lifetime elision rules for functions #86921

Open
@bstrie

Description

@bstrie

The following code does not compile:

fn function(x: &i32) -> &i32 { x } // ok
let closure = |x: &i32| -> &i32 { x }; // fails

Output:

error: lifetime may not live long enough
 --> src/main.rs:3:35
  |
3 | let closure = |x: &i32| -> &i32 { x };
  |                   -        -      ^ returning this value requires that `'1` must outlive `'2`
  |                   |        |
  |                   |        let's call the lifetime of this reference `'2`
  |                   let's call the lifetime of this reference `'1`

For function, the lifetime of the return type is properly inferred to be equal to the only input lifetime, as per the lifetime elision rules:

If there is exactly one lifetime used in the parameters (elided or not), that lifetime is assigned to all elided output lifetimes.

However, for closure this is not done, and the return type is assigned a distinct lifetime from the input. AFAIK it is only an accident of history that closures do not have the same lifetime elision rules as functions. This would be a breaking change to fix, but should be able to be done over an edition.


Here's a simplified example of code that compiles today that might break if the function elision rules were applied to closures:

fn foo(s: &str) -> &str {
    let bar = |_| { s };
    bar(&String::new())
}

See #56537 for prior discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-inferenceArea: Type inferenceA-lifetimesArea: Lifetimes / regionsA-maybe-future-editionSomething we may consider for a future edition.T-langRelevant to the language team

    Type

    No type

    Projects

    Status

    Idea

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions