Skip to content

Shouldn't lifetime elision apply to closure return type annotation? #56537

Closed
@pnkfelix

Description

@pnkfelix

(Spawned off of #55526.)

Consider the following code (play):

fn foo(input: &str) -> &str {
    let id = |x: &str| -> &str { x };
    id(input)
}

The above does not compile today.

Error diagnostic:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
 --> src/main.rs:2:27
  |
2 |     let id = |x: &str| -> &str { x };
  |                           ^
  |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 2:14...
 --> src/main.rs:2:14
  |
2 |     let id = |x: &str| -> &str { x };
  |              ^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
 --> src/main.rs:2:34
  |
2 |     let id = |x: &str| -> &str { x };
  |                                  ^
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 1:1...
 --> src/main.rs:1:1
  |
1 | / fn foo(input: &str) -> &str {
2 | |     let id = |x: &str| -> &str { x };
3 | |     id(input)
4 | | }
  | |_^
note: ...so that reference does not outlive borrowed content
 --> src/main.rs:3:5
  |
3 |     id(input)
  |     ^^^^^^^^^

However, discussions with @nikomatsakis lead us to wonder why lifetime elision is not being applied to the type annotation attached to the closure. Since there is a single input argument type and a single return type, it seems reasonable to apply lifetime elision, yielding the type for <'r> (&'r str) -> &'r str.

I believe fixing this is actually pretty trivial, based on some initial experimentation with the code here:

// Everything else (only closures?) doesn't
// actually enjoy elision in return types.
_ => {
self.visit_ty(output);
return;
}

(The question will only be whether there are unintended consequences of the fix; I'm still looking into that.)

(This might require an RFC, not sure yet.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-lifetimesArea: Lifetimes / regionsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions