Why is rustc's suggestion here wrong? - rust

I'm trying to implement the following trait, where the <'baz> is required for a later impl<'baz> Baz<'baz> for T where T: OtherTrait†.
trait Baz<'baz>: Clone {
fn baz(&'baz mut self);
fn bazzed(&self) -> Self {
let mut x = self.clone();
x.baz();
x
}
}
Rustc understandably fails:
Compiling playground v0.0.1 (/playground)
error[E0309]: the parameter type `Self` may not live long enough
--> src/lib.rs:6:9
|
6 | x.baz();
| ^
|
= help: consider adding an explicit lifetime bound `Self: 'baz`...
= note: ...so that the type `Self` is not borrowed for too long
error[E0309]: the parameter type `Self` may not live long enough
--> src/lib.rs:6:11
|
6 | x.baz();
| ^^^
|
= help: consider adding an explicit lifetime bound `Self: 'baz`...
= note: ...so that the reference type `&'baz mut Self` does not outlive the data it points at
For more information about this error, try `rustc --explain E0309`.
error: could not compile `playground` due to 2 previous errors
So I follow its suggestion:
trait Baz<'baz>: Clone {
fn baz(&'baz mut self);
fn bazzed(&self) -> Self
where
Self: 'baz
{
let mut x = self.clone();
x.baz();
x
}
}
And I don't quite understand what it's not liking now...
Compiling playground v0.0.1 (/playground)
error[E0597]: `x` does not live long enough
--> src/lib.rs:9:9
|
1 | trait Baz<'baz>: Clone {
| ---- lifetime `'baz` defined here
...
9 | x.baz();
| ^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `x` is borrowed for `'baz`
10 | x
11 | }
| - `x` dropped here while still borrowed
error[E0505]: cannot move out of `x` because it is borrowed
--> src/lib.rs:10:9
|
1 | trait Baz<'baz>: Clone {
| ---- lifetime `'baz` defined here
...
9 | x.baz();
| -------
| |
| borrow of `x` occurs here
| argument requires that `x` is borrowed for `'baz`
10 | x
| ^ move out of `x` occurs here
Some errors have detailed explanations: E0505, E0597.
For more information about an error, try `rustc --explain E0505`.
error: could not compile `playground` due to 2 previous errors
I tried making Self: 'static too but that did not help either. What am I missing here?
† The <'baz> I need for another trait, that looks roughly like:
trait ReturnIteratorMut<'item> {
type IterType: Iterator<Item = &'item mut Thing>;
fn iterator<'slf: 'item>(&'slf mut self) -> Self::IterType;
}
I want to implement Baz for all of these by applying baz() to every item in the iterator, so I need 'baz: 'item. This works fine with just the baz() method, it's only the bazzed() that it starts to complain at.

Let's first try to understand what's wrong with this code, without the compiler's help.
x.baz() requires x to live for 'baz. Since 'baz can be any lifetime this means x has to live for 'static. It does not - it is a local variable, and this is an error (you might want HRTB, but you said you want to focus on the compiler errors so I don't deal with the solution).
The compiler's second errors are just that - x does not live long enough, or, if we look at the opposite angle, x is borrowed for 'static and so we cannot move it (the compiler shows both errors in order to maximize displayed errors - sometimes it works, sometimes, like in this case, it leads to confusing errors being shown).
The first error(s) is a negligible result of this constraint, but it hides the actual error (for what it's worth, on nightly they're all shown together): x needs to live for 'static, but not just it does not, sometimes it is impossible for any variable of its type to be. Suppose Self is &'some_short_lifetime i32 - it cannot live for 'static, since it contains a shorter lifetime. This is the reason "Self may not live long enough`.

Related

How to interpret Rust error E0495 on the lifetimes of a closure and a variable borrowed by the closure

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:
What does the Rust error code E0495 mean?
How do I work around closures causing error[E0495]: cannot infer an appropriate lifetime
Rust: error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
Rust: error[E0495]: cannot infer an appropriate lifetime for autorefdue to conflicting requirements in closure
These are focussed on fixing, rather than questioning the validity of, the error messages.
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.

Access variable after it was borrowed

I am assigning data to properties of a struct, but the following error appears:
error[E0382]: borrow of partially moved value: `super_hero`
--> src/main.rs:16:22
|
13 | for mut chunk in super_hero.description_chunks.unwrap() {
| -------- `super_hero.description_chunks` partially moved due to this method call
...
16 | println!("{:?}", &super_hero);
| ^^^^^^^ value borrowed here after partial move
|
note: this function takes ownership of the receiver `self`, which moves `super_hero.description_chunks`
--> /Users/someuser/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:752:25
|
752 | pub const fn unwrap(self) -> T {
| ^^^^
= note: partial move occurs because `super_hero.description_chunks` has type `std::option::Option<Vec<Chunk>>`, which does not implement the `Copy` trait
help: consider calling `.as_ref()` to borrow the type's contents
|
13 | for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
The following is the code where I am assigning data to properties of a struct:
let super_hero_description = "several years ago.";
let mut super_hero = SuperHero::new(super_hero_description);
super_hero.description_chunks = Option::from(super_hero.get_decription_chunks(DescriptionTypes::NotVillan));
for mut chunk in super_hero.description_chunks.unwrap() {
chunk.data = Option::from(chunk.get_data(DescriptionTypes::NotVillan).await);
}
println!("{:?}", &super_hero);
The error does not happen until I try to print the super_hero at the end.
Oh, and if I follow the recommendation rust gives me
for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
I end up with another error:
error[E0594]: cannot assign to `chunk.data`, which is behind a `&` reference
--> src/main.rs:14:9
|
13 | for mut subdivision in super_hero.description_chunks.as_ref().unwrap() {
| ------------------------------------- this iterator yields `&` references
14 | chunk.data = Option::from(chunk.get_data()(DescriptionTypes::NotVillan).await);
| ^^^^^^^^^^^^ `chunk` is a `&` reference, so the data it refers to cannot be written
rustc is correct, it just needs a little adjustment: instead of as_ref() use as_mut(), that converts &mut Option<T> to Option<&mut T> instead of &Option<T> to Option<&T>.
The problem is that unwrap() requires an owned Option: see Reference to unwrapped property fails: use of partially moved value: `self`.

solving "argument requires that `x` is borrowed for `'y`"

tl;dr blocked by "argument requires that `x` is borrowed for `'y`"; how can I coerce variable x to lifetime 'y?
Given the following code, I'm blocked when trying to create the Box pointer pointing to a reference. I know the referenced object instance lives long enough. However, the rust compiler is concerned it does not.
How do I tell the rust compiler that Box::new(&thing) is valid for the lifetime of the containing struct instance?
Code example
This code is essentially:
Things (a Vec), holding multiple Things
counter of Things (a HashMap), holding multiple Box pointers to different &Thing as keys, a u64 count as values
(My best attempt at) a minimal example (rust playground):
use std::collections::HashMap;
type Thing<'a> = (&'a str, usize);
type Things<'a> = Vec<Thing<'a>>;
type ThingsCounterKey<'a> = Box<&'a Thing<'a>>;
type ThingsCounter<'a> = HashMap<ThingsCounterKey<'a>, u64>;
pub struct Struct1<'struct1> {
things1: Things<'struct1>,
thingscounter1: ThingsCounter<'struct1>,
}
impl<'struct1> Struct1<'struct1> {
pub fn new() -> Struct1<'struct1> {
Struct1{
things1: Things::new(),
thingscounter1: ThingsCounter::new(),
}
}
fn things_update(&mut self, thing_: Thing<'struct1>) {
self.things1.push(thing_);
let counter = self.thingscounter1.entry(
ThingsCounterKey::new(&thing_)
).or_insert(0);
*counter += 1;
}
}
fn main() {
let mut s1 = Struct1::new();
for (x, y) in [("a", 1 as usize), ("b", 2 as usize)] {
s1.things_update((x, y));
}
}
This results in compiler error:
error[E0597]: `thing_` does not live long enough
--> src/main.rs:24:35
|
14 | impl<'struct1> Struct1<'struct1> {
| -------- lifetime `'struct1` defined here
...
24 | ThingsCounterKey::new(&thing_)
| ----------------------^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `thing_` is borrowed for `'struct1`
...
27 | }
| - `thing_` dropped here while still borrowed
For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error
How can I tell the rust compiler "&thing_ has the lifetime of 'struct1"?
Similar questions
Before this Question is marked as duplicate, these questions are similar but not quite the same. These Questions address 'static lifetimes or other slightly different scenarios.
Argument requires that value is borrowed for 'static not working for non copy value
Argument requires that _ is borrowed for 'static - how do I work round this?
"argument requires that record is borrowed for 'static" when using belonging_to associations with tokio-diesel
(tokio::spawn) borrowed value does not live long enough -- argument requires that sleepy is borrowed for 'static
Rust lifetime syntax when borrowing variables
Borrow data out of a mutex "borrowed value does not live long enough"
Rust: argument requires that borrow lasts for 'static
thing_ is passed by value. Its lifetime ends at the end of things_update. That means, the reference to thing_ becomes invalid after the end of the function but still be held by the struct, which is certainly should be rejected.
Like many times, actually the compiler is right and you were wrong. The compiler prevented you from use-after-free.
thing_ doesn't live long enough: you pushed a copy of it into the vector. It was clear if you'd used a type that isn't Copy:
type Thing<'a> = (&'a str, String);
// ...
Besides the previous error, now you also get:
error[E0382]: borrow of moved value: `thing_`
--> src/main.rs:24:35
|
21 | fn things_update(&mut self, thing_: Thing<'struct1>) {
| ------ move occurs because `thing_` has type `(&str, String)`, which does not implement the `Copy` trait
22 | self.things1.push(thing_);
| ------ value moved here
23 | let counter = self.thingscounter1.entry(
24 | ThingsCounterKey::new(&thing_)
| ^^^^^^^ value borrowed here after move
Playground.
In other case, you would have to first push the item into the vector and then retrieve a reference to the pushed item there, like:
self.things1.push(thing_);
let counter = self.thingscounter1.entry(
ThingsCounterKey::new(self.things1.last().unwrap())
).or_insert(0);
But in this case it will not work, and you'll get a long "cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements" error. This is because you're essentially trying to do the impossible: create a self-referential struct. See Why can't I store a value and a reference to that value in the same struct? for more about this problem and how to solve it.

Rust: Why does the binding of the closure to a variable change the type?

I have this (most simplified) piece of code:
fn returns_closure() -> Box<dyn Fn(&u64)> {
let closure = |_| ();
Box::new(closure)
}
This does not compile with a rather unhelpful error message:
error[E0308]: mismatched types
--> src/main.rs:3:5
|
3 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `FnOnce<(&u64,)>`
found type `FnOnce<(&u64,)>`
However, when I don't bind the closure to a variable first, and create it directly in the constructor of the Box, it does compile:
fn returns_closure() -> Box<dyn Fn(&u64)> {
Box::new(|_| ())
}
Why does the first one fail to compile, and what is the difference between the two?
Edit:
Emouns answer seems to be correct.
I compiled the exact same code with the nightly toolchain (1.52.0), and got a better error:
error: implementation of `FnOnce` is not general enough
--> src/main.rs:3:5
|
3 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 u64)` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2`
As #frankenapps pointed out, if you use let closure = |_: &u64|(); then you don't get this error. So what is going on?
To try to figure this out I made the following edits that use explicit lifetimes (instead of having the compiler elide them for us) in an effort to get the same error message:
fn returns_closure<'a>() -> Box<dyn Fn(&'_ u64)> {
let closure = |_: &'a u64| ();
Box::new(closure)
}
Running this code gives us the following error message:
rror[E0308]: mismatched types
--> src/lib.rs:4:5
|
4 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `for<'r> Fn<(&'r u64,)>`
found type `Fn<(&'a u64,)>`
note: this closure does not fulfill the lifetime requirements
--> src/lib.rs:3:19
|
3 | let closure = |_: &'a u64| ();
| ^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> src/lib.rs:4:5
|
4 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `FnOnce<(&u64,)>`
found type `FnOnce<(&'a u64,)>`
note: this closure does not fulfill the lifetime requirements
--> src/lib.rs:3:19
|
3 | let closure = |_: &'a u64| ();
| ^^^^^^^^^^^^^^^
The error message is not the exact same, since we are using explicit lifetimes, but the type of error is still one type is more general than the other.
So what we see here might be an error in lifetime elision.
You can see that I have given the closure the same lifetime as the function ('a), however the function returns dyn Fn(&'_ u64). Here notice the '_ which is a stand-in for any lifetime, not just 'a.
Therefore, the return type &'_ u64is more general (accepts more lifetimes) than the closure (&'a u64) and we get the error.
I tried other lifetime combinations, but this one was the only one to give this type of error. But whether this is actually what is going on I cannot say.

Borrow checker complains for closure inside loop if type not provided explicitly

I have this code, for which borrow checker shows error:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=55d050b6f25410ce0e17ef9e844b048d
fn f1(v: &str) {
}
fn main() {
let c = |v| f1(v);
for _ in 0..1 {
let s = String::new();
c(&s);
}
}
|
10 | c(&s);
| - ^^ borrowed value does not live long enough
| |
| borrow later used here
11 | }
| - `s` dropped here while still borrowed
But if I add explicit type to closure, code compiles let c = |v: &str| f1(v);
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=54ca20dff5bdf1831ec705481e4936bb
Can someone explain why it works in second case and not in first, as I understand rust correctly infers same type in first example (as it works if I run closure outside of loop)?

Resources