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

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.

Related

Lifetime issue for a borrowed value inside an async trait

I have this method
async fn insert<'a>(&mut self, params: &'a[&'a dyn QueryParameters<'a>]) {
let mut mapped_fields: String = String::new();
let values: &'a[&'a QueryParameters<'a>] = &[#(#insert_values),*];
// #insert_transaction
}
I would like to know why the compiler and the borrow checker complains about this:
^^^^^^^^^-
| | |
| | temporary value is freed at the end of this statement
| creates a temporary which is freed while still in use
| lifetime `'a` defined here
| type annotation requires that borrow lasts for `'a`
If I just remove the 'a lifetime annotation from the explicit type declaration, everything works. This piece of code is inside a derive proc-macro that it's marked as async-trait, so values is getting 'life0 (if I do not explicitly declare it's lifetime bound as 'a), which is the same as the &mut self.
But, I am confused. I make a new variable (values), as a slice array, but... that variable doesn't goes anywhere. I mean. I am just creating the slice on the let values assignment, but doing anything with it. So, Drop should come at the end of the method and cleaning up the variables for the current stack frame. Fine. But, I am doing nothing with that slice.
Can someone help me to understand better the borrow checker?
You can get a similar error with a simpler code:
fn test<'a>(x: &'a str) {
let p: &'a str = &String::new();
}
That results in:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:2:23
|
1 | fn test<'a>(x: &'a str) {
| -- lifetime `'a` defined here
2 | let p: &'a str = &String::new();
| ------- ^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'a`
3 | }
| - temporary value is freed at the end of this statement
The cause is that the 'a lifetime is a generic argument to the function, that is decided by the caller of that function, and that lifetime will certainly contain the whole execution of the function. For example if calling it with:
let z = String::from("foo");
test(&z);
Then 'a will be the lifetime of that z argument.
Now, when you use that lifetime to annotate a local value such as:
let p: &'a str = &String::new();
or equivalently:
let temp = String::new();
let p: &'a str = &temp;
you are requiring that this reference lives at least as long as 'a. But that is certainly impossible, because temp is a local value, it will never outlive the function itself.
This is precisely what the error is trying to say: you define a lifetime 'a as a generic argument, then you borrow a value that is required to live for 'a because of a type annotation, but that value is dropped sooner than it should be.
Naturally, if you use the argument of the function such as in:
let p: &'a str = &*x;
then all goes well, because *x is explicitly declared to live for 'a.
On the other hand, if you omit the lifetime annotation:
let p: &str = &temp;
then the compiler will just guess the lifetime of temp as a local lifetime and assign that to this reference. And all will go well, too.

Why is rustc's suggestion here wrong?

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`.

Why is "the temporary is part of an expression at the end of a block" an error?

This is likely a textbook case of me not understanding some of the technicalities of the borrow checker, but it would be nice if someone could clear this up for me.
I have this (incredibly simplified) chunk of code, which compiles perfectly fine.
pub struct Example(pub Vec<String>);
impl Example {
pub fn iter(&self) -> impl Iterator<Item=&String> {
self.0.iter()
}
}
pub fn some_condition(_: &str) -> bool {
// This is not important.
return false;
}
pub fn foo() -> bool {
let example = Example(vec!("foo".to_owned(), "bar".to_owned()));
let mut tmp = example.iter();
tmp.all(|x| some_condition(x))
}
pub fn main() {
println!("{}", foo());
}
However, the first thing that I tried (which, in my mind, should be equivalent to the above), was eliding the temporary variable tmp altogether, as follows
pub fn foo() -> bool {
let example = Example(vec!("foo".to_owned(), "bar".to_owned()));
example.iter().all(|x| some_condition(x))
}
But this version produces the following error.
error[E0597]: `example` does not live long enough
--> so_temporary.rs:23:3
|
23 | example.iter().all(|x| some_condition(x))
| ^^^^^^^-------
| |
| borrowed value does not live long enough
| a temporary with access to the borrow is created here ...
24 | }
| -
| |
| `example` dropped here while still borrowed
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `impl std::iter::Iterator`
|
= note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block.
Now, obviously, the note at the end of the error is an excellent suggestion, and it's why I introduced the temporary to fix the problem. But I don't understand why that fixes the problem. What's different about the lifetimes of my tmp variable versus example.iter() embedded into the expression directly, that makes one work and one fail?
This has essentially the same answer as Why do I get "does not live long enough" in a return value? and its somewhat explained in the error itself, but I'll elaborate. This behavior is the same with a normal block expression:
pub struct Example(pub Vec<String>);
impl Example {
pub fn iter(&self) -> impl Iterator<Item=&String> {
self.0.iter()
}
}
pub fn main() {
let foo = {
let example = Example(vec!("foo".to_owned(), "".to_owned()));
example.iter().all(String::is_empty)
};
println!("{}", foo);
}
error[E0597]: `example` does not live long enough
--> src/main.rs:12:9
|
12 | example.iter().all(String::is_empty)
| ^^^^^^^-------
| |
| borrowed value does not live long enough
| a temporary with access to the borrow is created here ...
13 | };
| -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `impl Iterator`
| |
| `example` dropped here while still borrowed
|
= note: the temporary is part of an expression at the end of a block;
consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
|
12 | let x = example.iter().all(String::is_empty); x
| ^^^^^^^ ^^^
The scope of temporary values is often the statement in which they were created. In the code above example is a variable and it is destroyed at the end of the block. However, example.iter() creates a temporary impl Iterator and its temporary scope is the full let foo = ... statement. So the steps when evaluating this are:
evaluate the result of example.iter().all(...)
drop example
assign result to foo
drop impl Iterator
You can probably see where this can go wrong. The reason introducing a variable works is because it forces any temporaries to be dropped sooner. The case is slightly different when talking about functions, but the effect is the same:
Temporaries that are created in the final expression of a function body are dropped after any named variables bound in the function body, as there is no smaller enclosing temporary scope.
Regarding the comments:
The reason it works when impl Iterator is replaced with std::slice::Iter<'_, i32> (in pretzelhammer's example) is because the drop checker knows that slice::Iter doesn't access example on drop whereas it has to assume that impl Iterator does.
The reason it works with fn my_all(mut self, ...) (in Peter Hall's example) is because all takes the iterator by reference but my_all takes it by value. The temporary impl Iterator is consumed and destroyed before the end of the expression.
From looking at various Rust issues relating to this, its clear that some would consider this a bug. Its definitely not obvious that { ...; EXPR } and { ...; let x = EXPR; x } could be different. However, since diagnostics and documentation have been added to reinforce and explain this behavior, I have to assume these temporary scoping rules allow for more reasonable code than not.

Cyclic reference of RefCell borrows in traversal

I'm learning Rust and tried coding a doubly-linked list. However, I'm stuck already at a typical iterative traversal implementation. I'm getting the impression that the borrow checker / drop checker is too strict and cannot infer the correct lifetime for the borrow when it crosses the function boundary from RefCell. I need to repeatedly set a variable binding (curr in this case) to the borrow of its current contents:
use std::cell::RefCell;
use std::rc::Rc;
pub struct LinkedList<T> {
head: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
struct LinkedNode<T> {
value: T,
next: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
impl<T> LinkedList<T> {
pub fn insert(&mut self, value: T, idx: usize) -> &mut LinkedList<T> {
// ... some logic ...
// This is the traversal that fails to compile.
let mut curr = self.head.as_ref().unwrap();
for _ in 1..idx {
curr = curr.borrow().next.as_ref().unwrap()
}
// I want to use curr here.
// ...
unimplemented!()
}
}
The compiler complains:
Without NLL
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^ temporary value does not live long enough
23 | }
| - temporary value dropped here while still borrowed
...
28 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
With NLL
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^
| |
| creates a temporary which is freed while still in use
| a temporary with access to the borrow is created here ...
23 | }
| -
| |
| temporary value is freed at the end of this statement
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, LinkedNode<T>>`
|
= note: consider using a `let` binding to create a longer lived value
= note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.
I would really appreciate a iterative solution (non-recursive) to this problem.
You can clone Rc to avoid lifetime issues:
let mut curr = self.head.as_ref().unwrap().clone();
for _ in 1..idx {
let t = curr.borrow().next.as_ref().unwrap().clone();
curr = t;
}
Here's a smaller reproduction that I believe shows the same problem:
use std::cell::RefCell;
fn main() {
let foo = RefCell::new(Some(42));
let x = foo.borrow().as_ref().unwrap();
}
As I read it:
foo.borrow() returns a cell::Ref, a type of smart pointer. In this case, the smart pointer acts like an &Option<i32>.
as_ref() creates an Option<&i32> where the inner reference has the same lifetime as the smart pointer.
The Option is discarded, yielding only an &i32, still with a lifetime of the smart pointer.
Notably, the smart pointer Ref only lasts for the statement, but the code attempts to return a reference into the Ref that would outlive the statement.
Generally, the solution would be to do something like this:
let foo_borrow = foo.borrow();
let x = foo_borrow.as_ref().unwrap();
This keeps the smart pointer around longer, allowing the lifetime of the reference to be valid for as long as foo_borrow (representing the borrow itself) exists.
In the case of a loop, there's not much you can do, as you essentially want to borrow every previous node until you get to the next one.

How to retrieve a user-defined type from a for loop?

I defined an Attribute type and I have a Vec<Attribute> that I am looping over to retrieve the "best" one. This was similar to my first attempt:
#[derive(Debug)]
struct Attribute;
impl Attribute {
fn new() -> Self {
Self
}
}
fn example(attrs: Vec<Attribute>, root: &mut Attribute) {
let mut best_attr = &Attribute::new();
for a in attrs.iter() {
if is_best(a) {
best_attr = a;
}
}
*root = *best_attr;
}
// simplified for example
fn is_best(_: &Attribute) -> bool {
true
}
I had the following compile error:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:17:13
|
17 | *root = *best_attr;
| ^^^^^^^^^^ cannot move out of borrowed content
After some searching for a solution, I resolved the error by doing the following:
Adding a #[derive(Clone)] attribute to my Attribute struct
Replacing the final statement with *root = best_attr.clone();
I don't fully understand why this works, and I feel like this is a rough solution to the problem I was having. How does this resolve the error, and is this the correct way to solve this problem?
You are experiencing the basis of the Rust memory model:
every object can (and must!) be owned by only exactly one other object
most types are never implicitly copied and always moved (there are some exceptions: types that implement Copy)
Take this code for example:
let x = String::new();
let y = x;
println!("{}", x);
it generates the error:
error[E0382]: borrow of moved value: `x`
--> src/main.rs:4:20
|
3 | let y = x;
| - value moved here
4 | println!("{}", x);
| ^ value borrowed here after move
|
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
x, of type String, is not implicitly copyable, and thus has been moved into y. x cannot be used any longer.
In your code, when you write *root = *best_attr, you are first dereferencing the reference best_attr, then assigning the dereferenced value to *root. Your Attribute type is not Copy, thus this assignment should be a move.
Then, the compiler complains:
cannot move out of borrowed content
Indeed, best_attr is an immutable reference, which does not allow you to take ownership of the value behind it (it doesn't even allow modifying it). Allowing such a move would put the object owning the value behind the reference in an undefined state, which is exactly what Rust aims to prevent.
In this case, your best option is indeed to create a new object with the same value as the first one, which is exactly what the trait Clone is made for.
#[derive(Clone)] allows you to mark your structs as Clone-able, as long as all of their fields are Clone. In more complex cases, you'll have to implement the trait by hand.

Resources