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

Terrible error message when trying to use borrowed self in move closure #45634

Closed
cramertj opened this issue Oct 30, 2017 · 6 comments
Closed
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-diagnostics Working group: Diagnostics

Comments

@cramertj
Copy link
Member

cramertj commented Oct 30, 2017

The code:

struct Foo {
    name: String,
}

impl Foo {
    fn foo(&self) -> Box<Fn()> {
        Box::new(move || println!("{}", self.name))
    }
}

Expected behavior: prints error that looks something like this:

self.name
^^^^ cannot use self in 'static move closure because `self` is borrowed

Actual behavior: prints this error message:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
 --> src/main.rs:8:9
  |
8 |         Box::new(move || println!("{}", self.name))
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 7:5...
 --> src/main.rs:7:5
  |
7 | /     fn foo(&self) -> Box<Fn()> {
8 | |         Box::new(move || println!("{}", self.name))
9 | |     }
  | |_____^
note: ...so that the type `[closure@src/main.rs:8:18: 8:51 self:&Foo]` will meet its required lifetime bounds
 --> src/main.rs:8:9
  |
8 |         Box::new(move || println!("{}", self.name))
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<std::ops::Fn() + 'static>, found std::boxed::Box<std::ops::Fn()>)
 --> src/main.rs:8:9
  |
8 |         Box::new(move || println!("{}", self.name))
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@cramertj cramertj changed the title Terrible error message when trying to use self in move closure Terrible error message when trying to use borrored self in move closure Oct 30, 2017
@cramertj cramertj changed the title Terrible error message when trying to use borrored self in move closure Terrible error message when trying to use borrowed self in move closure Oct 30, 2017
@cramertj
Copy link
Member Author

cramertj commented Oct 30, 2017

This issue isn't limited to self, either, but this was the case in which the error originally occurred. While I understand it might be difficult to identify exactly which variable in the closure has too short of a lifetime, it should be possible to at least give a better error message like "value with non-'static lifetime referenced in static closure" and provide the name of the lifetime (if there is one).

@Mark-Simulacrum Mark-Simulacrum added A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. WG-diagnostics Working group: Diagnostics labels Oct 30, 2017
@estebank
Copy link
Contributor

Triage: very little change:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
 --> src/main.rs:7:9
  |
7 |         Box::new(move || println!("{}", self.name))
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5...
 --> src/main.rs:6:5
  |
6 | /     fn foo(&self) -> Box<Fn()> {
7 | |         Box::new(move || println!("{}", self.name))
8 | |     }
  | |_____^
note: ...so that the type `[closure@src/main.rs:7:18: 7:51 self:&Foo]` will meet its required lifetime bounds
 --> src/main.rs:7:9
  |
7 |         Box::new(move || println!("{}", self.name))
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = note: but, the lifetime must be valid for the static lifetime...
  = note: ...so that the expression is assignable:
          expected std::boxed::Box<std::ops::Fn() + 'static>
             found std::boxed::Box<std::ops::Fn()>

Error should point at self inside the closure, and to the closure.

@estebank
Copy link
Contributor

Ast output:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
 --> file.rs:7:18
  |
7 |         Box::new(move || println!("{}", self.name))
  |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5...
 --> file.rs:6:5
  |
6 | /     fn foo(&self) -> Box<Fn()> {
7 | |         Box::new(move || println!("{}", self.name))
8 | |     }
  | |_____^
  = note: ...so that the types are compatible:
          expected &Foo
             found &Foo
  = note: but, the lifetime must be valid for the static lifetime...
  = note: ...so that the expression is assignable:
          expected std::boxed::Box<(dyn std::ops::Fn() + 'static)>
             found std::boxed::Box<dyn std::ops::Fn()>

MIR output:

error: lifetime may not live long enough
 --> file.rs:7:9
  |
6 |     fn foo(&self) -> Box<Fn()> {
  |            - let's call the lifetime of this reference `'1`
7 |         Box::new(move || println!("{}", self.name))
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`

@estebank
Copy link
Contributor

No change in the output. The compiler should suggest a signature of fn foo(&self) -> Box<dyn Fn() + '_> when we infer a 'static lifetime, as it is rarely what we desire. We already provide that suggestion for impl Traits in the return type.

@cramertj
Copy link
Member Author

@estebank FWIW in the case this was originally minimized from, the solution was actually to call self.name.clone() and then move the resulting name into the closure, rather than moving self in . I don't think a suggestion is what's needed here-- I think the primary thing that would help would be a hint that the use of self.name in the closure is what's causing the lifetime to be restricted to '1.

@estebank estebank added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Feb 14, 2020
@estebank
Copy link
Contributor

estebank commented Jan 10, 2023

Closing in favor of the newer ticket, which will be closed by #106641.

Looking at the code it now compiles (after applying some suggested changes), and the new suggestion will not help for closures being returned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-diagnostics Working group: Diagnostics
Projects
None yet
Development

No branches or pull requests

3 participants