Reputation: 1180
I'm trying to understand a lifetime error. I've reduced the code to this short, albeit nonsensical playground:
type Value = Vec<i32>;
type MemberList<'a> = Box<dyn Iterator<Item = &'a i32> + 'a>;
pub fn traverse<'a, F>(input: &'a Value, f: F) -> MemberList<'a>
where
F: Fn(&'a i32) -> MemberList<'a> + 'a,
{
Box::new(
input
.into_iter()
.flat_map(move |v| traverse::<'a>(input, &f)),
)
}
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/lib.rs:12:54
|
12 | .flat_map(move |v| traverse::<'a>(input, &f)),
| ^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
--> src/lib.rs:12:23
|
12 | .flat_map(move |v| traverse::<'a>(input, &f)),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that closure can access `f`
--> src/lib.rs:12:54
|
12 | .flat_map(move |v| traverse::<'a>(input, &f)),
| ^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/lib.rs:5:17
|
5 | pub fn traverse<'a, F>(input: &'a Value, f: F) -> MemberList<'a>
| ^^
note: ...so that the type `&F` will meet its required lifetime bounds...
--> src/lib.rs:12:32
|
12 | .flat_map(move |v| traverse::<'a>(input, &f)),
| ^^^^^^^^^^^^^^
note: ...that is required by this bound
--> src/lib.rs:7:40
|
7 | F: Fn(&'a i32) -> MemberList<'a> + 'a,
| ^^
This seems to be saying that if the lifetime of the borrow expression &f
outlived the lifetime of the closure, then the closure wouldn't be able to access f
. But I would have thought it was the other way round: the borrow expression needs to live at least as long as the closure in order for the closure to access the expression.
How should I interpret these error messages?
Similar questions have been raised before:
These are focussed on fixing, rather than questioning the validity of, the error messages.
Upvotes: 1
Views: 105
Reputation: 1180
Thanks to bstrie who answered on Zulip, it turns out that the error messages have recently been improved and compiling on nightly, as in this playground, produces the following messages:
error: lifetime may not live long enough
--> src/lib.rs:7:48
|
5 | pub fn traverse<'a, F>(input: &'a Value, f: F) -> MemberList<'a>
| -- lifetime `'a` defined here
6 | where F: Fn(&'a i32) -> MemberList<'a> + 'a {
7 | Box::new(input.into_iter().flat_map(move |v| traverse::<'a>(input, &f)))
| -------- ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`
| |
| lifetime `'1` represents this closure's body
|
= note: closure implements `FnMut`, so references to captured variables can't escape the closure
The experimental Polonius borrow checker on nightly gives even more context to the explanation:
error: lifetime may not live long enough
--> someguy.rs:7:48
|
5 | pub fn traverse<'a, F>(input: &'a Value, f: F) -> MemberList<'a>
| -- lifetime `'a` defined here
6 | where F: Fn(&'a i32) -> MemberList<'a> + 'a {
7 | Box::new(input.into_iter().flat_map(move |_| traverse::<'a>(input, &f)))
| -------- ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`
| |
| lifetime `'1` represents this closure's body
|
= note: closure implements `FnMut`, so references to captured variables can't escape the closure
error: captured variable cannot escape `FnMut` closure body
--> someguy.rs:7:48
|
5 | pub fn traverse<'a, F>(input: &'a Value, f: F) -> MemberList<'a>
| - variable defined here
6 | where F: Fn(&'a i32) -> MemberList<'a> + 'a {
7 | Box::new(input.into_iter().flat_map(move |_| traverse::<'a>(input, &f)))
| - ^^^^^^^^^^^^^^^^^^^^^^^-^
| | | |
| | | variable captured here
| | returns a reference to a captured variable which escapes the closure body
| inferred to be a `FnMut` closure
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
This answers my question as the error is about a reference to a captured variable escaping the closure which was far from clear in the original messages.
Upvotes: 1