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

Poor suggestions wrt closure type/lifetime inference #58525

Open
ijackson opened this issue Feb 17, 2019 · 2 comments
Open

Poor suggestions wrt closure type/lifetime inference #58525

ijackson opened this issue Feb 17, 2019 · 2 comments
Labels
A-closures Area: closures (`|args| { .. }`) A-diagnostics Area: Messages for errors, warnings, and lints A-inference Area: Type inference A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. C-enhancement Category: An issue proposing an enhancement or a PR with one. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@ijackson
Copy link
Contributor

Given the following code:

fn main() {
    let cl = |x| { x.split_at(0) };
    let (_x, _y) = cl("42");
}

rustc suggests:

3 |     let cl = |x| { x.split_at(0) };
  |               ^ consider giving this closure parameter a type

Unfortunately, specifying a closure parameter type casts the user from the frying pan into the fire:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
 --> src/main.rs:3:27
  |
3 |     let cl = |x:&str| { x.split_at(0) };
  |                           ^^^^^^^^
  |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 3:14...
 --> src/main.rs:3:14
  |
3 |     let cl = |x:&str| { x.split_at(0) };
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
 --> src/main.rs:3:25
  |
3 |     let cl = |x:&str| { x.split_at(0) };
  |                         ^
note: but, the lifetime must be valid for the call at 4:20...
 --> src/main.rs:4:20
  |
4 |     let (_x, _y) = cl("42");
  |                    ^^^^^^^^
note: ...so type `(&str, &str)` of expression is valid during the expression
 --> src/main.rs:4:20
  |
4 |     let (_x, _y) = cl("42");
  |                    ^^^^^^^^

Helpful contributors on #rust-beginners found #55526 #56537 and the following simple workaround:

fn main() {
    let cl = |x| { let x : &str = x; x.split_at(0) };
    let (_x, _y) = cl("42");
}

The underlying problem with lifetime inference in closures seems quite tricky and I guess it will remain like this for a while.

Under the circumstances, it would be nice if the compiler could make more helpful suggestions, including the trick with the let binding to nail the type.

Something like this maybe:

Consider removing the type specification for this closure parameter to allow lifetime inference. If the type specification is needed within the closure, a binding let VAR : TYPE = VAR at the start of the closure may help.

(for outputting, in addition to the other messages, in the more complicated lifetime problem case)

@Centril Centril added A-diagnostics Area: Messages for errors, warnings, and lints A-closures Area: closures (`|args| { .. }`) A-inference Area: Type inference A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. labels Feb 17, 2019
@estebank
Copy link
Contributor

Fur your own reference, the following code also works:

fn main() {
    let cl: for<'a> fn(&'a str) -> (&'a str, &'a str) = |x| { x.split_at(0) };
    let (_x, _y) = cl("42");
}

@estebank estebank added D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 6, 2019
@crlf0710 crlf0710 added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jun 11, 2020
@estebank
Copy link
Contributor

estebank commented Aug 3, 2023

Current output:

error[[E0282]](https://doc.rust-lang.org/stable/error_codes/E0282.html): type annotations needed
 --> src/main.rs:2:15
  |
2 |     let cl = |x| { x.split_at(0) };
  |               ^    - type must be known at this point
  |
help: consider giving this closure parameter an explicit type
  |
2 |     let cl = |x: /* Type */| { x.split_at(0) };
  |                ++++++++++++
error: lifetime may not live long enough
 --> src/main.rs:2:26
  |
2 |     let cl = |x: &str| { x.split_at(0) };
  |                  -   -   ^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
  |                  |   |
  |                  |   return type of closure is (&'2 str, &str)
  |                  let's call the lifetime of this reference `'1`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: closures (`|args| { .. }`) A-diagnostics Area: Messages for errors, warnings, and lints A-inference Area: Type inference A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. C-enhancement Category: An issue proposing an enhancement or a PR with one. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants