Eliminating double mutable borrow in method [duplicate] - struct

Why is the following invalid and what should I do instead to make it work?
struct Foo;
impl Foo {
fn mutable1(&mut self) -> Result<(), &str> {
Ok(())
}
fn mutable2(&mut self) -> Result<(), &str> {
self.mutable1()?;
self.mutable1()?;
Ok(())
}
}
This code yields:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:10:9
|
8 | fn mutable2(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
9 | self.mutable1()?;
| ---- - returning this value requires that `*self` is borrowed for `'1`
| |
| first mutable borrow occurs here
10 | self.mutable1()?;
| ^^^^ second mutable borrow occurs here
There are many questions already with the same error but I cannot use them to address this one as it's the presence of the implicit return provided by ? that causes the problem, without ? the code compiles successfully, yet with warnings.
Playground

This is the same problem discussed in Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?. Through lifetime elision, the lifetime of the &str is tied to the lifetime of &self. The compiler isn't aware that the borrow won't be used in the condition that an Ok is returned. It's overly conservative and disallows this code. This is a limitation of the current borrow checker implementation.
If you did need the lifetime of the Err variant to be tied to the lifetime of the Foo instance, there's not much to be done in safe Rust (unsafe Rust is another story). In your case, however, it seems unlikely that your &str is intended to be tied to the lifetime of self, so you can use explicit lifetimes to avoid the problem. For example, a &'static str is a common basic error type:
impl Foo {
fn mutable1(&mut self) -> Result<(), &'static str> {
Ok(())
}
fn mutable2(&mut self) -> Result<(), &'static str> {
self.mutable1()?;
self.mutable1()?;
Ok(())
}
}
as it's the presence of the implicit return provided by ?
Not really, as the same code with explicit returns has the same problem:
fn mutable2(&mut self) -> Result<(), &str> {
if let Err(e) = self.mutable1() {
return Err(e);
}
if let Err(e) = self.mutable1() {
return Err(e);
}
Ok(())
}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:12:25
|
8 | fn mutable2(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
9 | if let Err(e) = self.mutable1() {
| ---- first mutable borrow occurs here
10 | return Err(e);
| ------ returning this value requires that `*self` is borrowed for `'1`
11 | }
12 | if let Err(e) = self.mutable1() {
| ^^^^ second mutable borrow occurs here

Current limitation of the Rust borrow checker, we have to rewrite the corresponding methods to static method, for example
fn mutable2(&mut self) -> Result<(), &str> {
...
if let Err(e) = Self::mutable1(&a, &b, &c) {
return Err(e);
}
if let Err(e) = Self::mutable1(&e, &f, &g) {
return Err(e);
}
Ok(())
}

Related

Why does using ? on Result<_, &str> cause a lifetime error?

I have this code that doesn't compile:
impl BytePacketBuffer {
fn read(&mut self) -> Result<u8, &str> {
if self.pos >= 512 {
return Err("End of buffer".into());
}
let res = self.buf[self.pos];
self.pos += 1;
Ok(res)
}
fn read_u16(&mut self) -> Result<u16, &str> {
let res = ((self.read()? as u16) << 8) | (self.read()? as u16);
Ok(res)
}
}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/byte_packet_buffer.rs:53:51
|
52 | fn read_u16(&mut self) -> Result<u16, &str> {
| - let's call the lifetime of this reference `'1`
53 | let res = ((self.read()? as u16) << 8) | (self.read()? as u16);
| ------------ ^^^^^^^^^^^ second mutable borrow occurs here
| |
| first mutable borrow occurs here
| returning this value requires that `*self` is borrowed for `'1`
But if I modify the return type from &str to String, it compiles without error. Can anybody explain why I get an error when returning &str but not when returning String?
Because you did not specify any lifetimes Rust will infer them according to the elision rules to be this:
fn read<'a>(&'a mut self) -> Result<u8, &'a str>
which means it will infer self to be borrowed for as long as you keep the Result or anything it contained around.
To fix it you could just specify the lifetime of the returned str because it's always static anyways.
fn read(&mut self) -> Result<u8, &'static str>
#cafce25 explained well how lifetime elision leads to incorrect lifetime, but this still does not explain why this fails. Even with the incorrect lifetimes, when we borrow self for the &str it is the error case, and the error case is immediately returning from the function and thus does not borrow self further.
Well, this is because the ? operators desugars roughly into (simplified, but the actual desugaring doesn't matter here):
match expr {
Ok(v) => v,
Err(e) => return Err(From::from(e)),
}
And it is well known that the borrow checker is overly conservative w.r.t. branches. It extends borrow in return expression to the rest of the function, causing the &str to live even when it cannot really live.
If you compile it with Polonius (cargo +nightly rustc -- -Zpolonius), it compiles successfully.

How too loop over a function that requires a mutable refrence?

I am quite new to rust and I have a problem with the borrow checker.
I have a function like this:
impl<'a> DFA<'a> {
fn solve_next(&mut self, c: Option<char>) -> Option<TokenType> {
let node = self.state.unwrap_or_else(|| &self.start_node);
let checks: Vec<char> = node.connections.iter().map(|x| x.1).collect();
let mut position = None;
if let Some(c) = c {
position = checks.iter().position(|x| *x == c);
}
if let Some(i) = position {
let node = &node.connections[i].0;
self.state = Some(node);
None
} else {
if node.is_end {
return Some(TokenType::Keyword);
}
panic!("Invalid charter for current set");
}
}
}
This function either returns a TokenType (which is a enum) when the loop is complete or None when it is not.
its is on this struct:
struct DFA<'a> {
state: Option<&'a Node>,
start_node: Node,
}
Node is:
struct Node {
connections: Vec<(Node, char)>,
is_end: bool,
token_type: TokenType,
}
with the method
fn insert(&mut self, _match: char, end: bool) -> &mut Node {
which creates and return a new node and adds this node into its own connections.
So when I wanted to loop over the solve next function I tried:
impl<'a> Lexer<'a> {
fn next_char(&self) -> Option<char> {
let mut r: Option<char> = None;
for c in &self.chars {
match c {
' ' | '\n' | '\r' => {
continue;
}
_ => {
r = Some(c.clone());
break;
}
}
}
return r;
}
fn next_token(&'a mut self) {
let somechar = 'c';
let mut x = self.dfa.solve_next(self.next_char());
while let None = x {
x = self.dfa.solve_next(self.next_char());
}
}
}
which is a method of
struct Lexer<'a> {
//the output of the lexer
pub tokens: Vec<Token>,
chars: Vec<char>,
dfa: DFA<'a>,
}
the compile error's with
error[E0499]: cannot borrow `self.dfa` as mutable more than once at a time
--> src/main.rs:177:17
|
146 | impl<'a> Lexer<'a> {
| -- lifetime `'a` defined here
...
175 | let mut x = self.dfa.solve_next(self.next_char());
| -------------------------------------
| |
| first mutable borrow occurs here
| argument requires that `self.dfa` is borrowed for `'a`
176 | while let None = x {
177 | x = self.dfa.solve_next(self.next_char());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/main.rs:177:37
|
146 | impl<'a> Lexer<'a> {
| -- lifetime `'a` defined here
...
175 | let mut x = self.dfa.solve_next(self.next_char());
| -------------------------------------
| |
| mutable borrow occurs here
| argument requires that `self.dfa` is borrowed for `'a`
176 | while let None = x {
177 | x = self.dfa.solve_next(self.next_char());
| ^^^^^^^^^^^^^^^^ immutable borrow occurs here
So is their any way I can use solve_next in this loop? as I would not know how to make a function that can be used like this without having it take a mutable refrence.
The actual error you get with your code is the following (playground):
error: lifetime may not live long enough
--> src/lib.rs:27:49
|
25 | impl<'a> DFA<'a> {
| -- lifetime `'a` defined here
26 | fn solve_next(&mut self, c: Option<char>) -> Option<TokenType> {
| - let's call the lifetime of this reference `'1`
27 | let node = self.state.unwrap_or_else(|| &self.start_node);
| ^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
This is actually complaining about the reference to self.start_node not living long enough, that is for at least 'a.
The reason for that is that your local variable node, that is of type &'x Node, being the lifetime 'x the shorter of that of self.state.unwrap() and &self.start_node. The first one is 'a and the second one is the unnamed lifetime of &self (from now on 's).
But by the rules of Rust lifetimes, 'a outlives DFA<'a> and Self outlives 's, and Self is equal to DFA<'a>, then we conclude that 'a outlives 's. So the lifetime of the local node is actually 's.
Now, the other key line is this one:
self.state = Some(node);
being self.state of type Option<&'a Node>, that requires that the lifetime of node, that is 's, outlives 'a. But that cannot be, we already determined that it is the other way around: 'a outlives 's. Thus a compiler error.
In a nutshell, you are trying to write a self-referential struct, storing in one field a reference to the other field. And that is well known to be impossible.
In the original version of your question, you tried to solve it adding an extra lifetime to the solve_next() function:
fn solve_next(&'a mut self, c: Option<char>) -> Option<TokenType>
Doing that you force the 's from my explanation above to be exactly equal to 'a, so the body of this function is actually correct. Unfortunately if you try to call it normally with:
fn next_token(&mut self) {
let mut x = self.dfa.solve_next(self.next_char());
}
It fails with:
error: lifetime may not live long enough
--> src/lib.rs:63:21
|
46 | impl<'a> Lexer<'a> {
| -- lifetime `'a` defined here
...
62 | fn next_token(&mut self) {
| - let's call the lifetime of this reference `'1`
63 | let mut x = self.dfa.solve_next(self.next_char());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`
Exactly for the same reason as above: the anonymous lifetime of self must outlive 'a but the compiler deduces it the other way around.
Naturally you can fix it the same way:
fn next_token(&'a mut self) {
And that will compile... as long as you do not try to call solve_next() twice.
I'm not sure why calling solve_next() once it compiles, but calling it twice fails with. But it does not actually matter because even if this function worked, with this extra &'a mut self you'd still have the same problem calling this function from the external code.
What about the solution? Well, I think you need to refactor the code so that you never try to add a reference start_node in the same struct.
For example, you can store the start_node outside this struct:
struct DFA<'a> {
state: Option<&'a Node>,
start_node: &'a Node,
}
This, and remove all the lifetime annotations from &'a self and it will just compile (playground).

Rust borrow checker and early returns

Rust-lang Playground link
struct Foo {
val: i32
}
impl Foo {
pub fn maybe_get(&mut self) -> Option<&mut i32> {
Some(&mut self.val)
}
pub fn definitely_get(&mut self) -> &mut i32 {
{ // Add closure to ensure things have a chance to get dropped
if let Some(val) = self.maybe_get() {
// Explicit return to avoid potential scope sharing with an else block or a match arms.
return val;
}
}
// One would think any mutable references would not longer be at play at this point
&mut self.val
}
}
I have some code that's similar but more complicated than what is provided above that I've been fighting with for quite a while. The borrow checker is unhappy with the implementation of definitely_get and has the following error
error[E0499]: cannot borrow `self.val` as mutable more than once at a time
--> src/main.rs:19:9
|
10 | pub fn definitely_get(&mut self) -> &mut i32 {
| - let's call the lifetime of this reference `'1`
11 | {
12 | if let Some(val) = self.maybe_get() {
| ---------------- first mutable borrow occurs here
13 | return val;
| --- returning this value requires that `*self` is borrowed for `'1`
...
19 | &mut self.val
| ^^^^^^^^^^^^^ second mutable borrow occurs here
It seems unreasonable for there to be no way to implement fallback logic with a mutable reference in Rust so I can't imagine there isn't a way.
I've managed to fix this with an unfortunately expensive alternative implementation due to how maybe_get is implemented in my non-trivial example.
impl Foo {
pub fn has_maybe_val(&self) -> bool {
// Non-trivial lookup...
true
}
pub fn maybe_get(&mut self) -> Option<&mut i32> {
// Same non-trivial lookup...
Some(&mut self.val)
}
pub fn definitely_get(&mut self) -> &mut i32 {
if self.has_maybe_val() {
self.maybe_get().unwrap() // Ouch!
} else {
&mut self.val
}
}
}

How can we solve this lifetime error occuring when conditionally returning a string slice?

The desired behaviour is if you can cut off 4 bytes cut and return 4 bytes, else if you can cut off 2 bytes cut and return 2 bytes, else return an error.
The methods cut, cut_alternative and cut_alternative_1 try to achieve this. The compiler error messages are listed below.
Why do all of these example methods fail to compile? In cut_alternative_1 the borrows are separated from each other while the error message is the same.
Can you give a workaround?
Playground link
struct StrWrapper<'s> {
content: &'s str,
}
impl<'s> StrWrapper<'s> {
fn cut(&mut self) -> Result<&str, ()> {
self.cut4()
.or(self.cut2())
}
fn cut_alternative(&mut self) -> Result<&str, ()> {
if let Ok(part) = self.cut4() {
Ok(part)
} else if let Ok(part) = self.cut2() {
Ok(part)
} else {
Err(())
}
}
fn cut_alternative_1(&'s mut self) -> Result<&'s str, ()> {
{
let part = self.cut4();
if part.is_ok() {
return part;
}
}
{
let part = self.cut2();
if part.is_ok() {
return part;
}
}
Err(())
}
fn cut2(&mut self) -> Result<&str, ()> {
if self.content.len() >= 2 {
let part = &self.content[..2];
self.content = &self.content[2..];
Ok(part)
} else {
Err(())
}
}
fn cut4(&mut self) -> Result<&str, ()> {
if self.content.len() >= 4 {
let part = &self.content[..4];
self.content = &self.content[4..];
Ok(part)
} else {
Err(())
}
}
}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/parser.rs:210:17
|
208 | fn cut(&mut self) -> Result<&str, ()> {
| - let's call the lifetime of this reference `'1`
209 | self.cut4()
| ----
| |
| _________first mutable borrow occurs here
| |
210 | | .or(self.cut2())
| |_________________^^^^_______- returning this value requires that `*self` is borrowed for `'1`
| |
| second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/parser.rs:216:34
|
213 | fn cut_alternative(&mut self) -> Result<&str, ()> {
| - let's call the lifetime of this reference `'1`
214 | if let Ok(part) = self.cut4() {
| ---- first mutable borrow occurs here
215 | Ok(part)
| -------- returning this value requires that `*self` is borrowed for `'1`
216 | } else if let Ok(part) = self.cut2() {
| ^^^^ second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/parser.rs:230:24
|
207 | impl<'s> StrWrapper<'s> {
| -- lifetime `'s` defined here
...
224 | let part = self.cut4();
| ---- first mutable borrow occurs here
225 | if part.is_ok() {
226 | return part;
| ---- returning this value requires that `*self` is borrowed for `'s`
...
230 | let part = self.cut2();
| ^^^^ second mutable borrow occurs here
#Shepmaster commented a link to a similar question: Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
This question differs in two ways:
There are multiple mutable borrows instead of one unmutable and one mutable borrow.
I am unable to apply the workarounds in the answer to this problem right now. A workaround would be much appreciated.
The secret sauce in the HashMap solution is the use of contains_key(), which returns a bool that just doesn't carry the lifetime baggage. Likewise, the Vec solution involves using indices instead of slices in strategic places.
In your case the equivalent adaptation requires changing the signatures cut4() and cut2() to return Result<Range<usize>, ()>. Then you'd be able to write something like this:
fn cut(&mut self) -> Result<&str, ()> {
if let Ok(part) = self.cut4() {
Ok(&self.content[part])
} else if let Ok(part) = self.cut2() {
Ok(&self.content[part])
} else {
Err(())
}
}
fn cut2(&mut self) -> Result<Range<usize>, ()> {
if self.content.len() >= 2 {
let part = 0..2;
self.content = &self.content[2..];
Ok(part)
} else {
Err(())
}
}
// likewise for cut4
Playground
Another option would be to use interior mutability and make all of the functions accept &self:
use std::cell::Cell;
struct StrWrapper<'s> {
content: Cell<&'s str>,
}
impl<'s> StrWrapper<'s> {
fn cut(&self) -> Result<&str, ()> {
if let Ok(part) = self.cut4() {
Ok(part)
} else if let Ok(part) = self.cut2() {
Ok(part)
} else {
Err(())
}
}
fn cut2(&self) -> Result<&str, ()> {
if self.content.get().len() >= 2 {
let part = &self.content.get()[..2];
self.content.set(&self.content.get()[2..]);
Ok(part)
} else {
Err(())
}
}
// likewise for cut4
}
Playground (I was honestly surprised that this compiled, I've never tried to put a reference inside a Cell before.)
Finally, if neither of the above options is palatable for you, there is always unsafe:
fn cut(&mut self) -> Result<&str, ()> {
// Safety: slices returned by cut4() and cut2() must live at least as
// long as `self` (because the lifetime of `&str` returned is tied to the
// lifetime of `&self`). This is the case because cut2() and cut4() are
// bound by their signatures to return sub-slices of `self`, and we don't
// modify `self` between a successful call to cut*() and the return.
unsafe {
if let Ok((ptr, len)) = self.cut4().map(|s| (s.as_ptr(), s.len())) {
Ok(std::str::from_utf8(std::slice::from_raw_parts(ptr, len)).unwrap())
} else if let Ok((ptr, len)) = self.cut2().map(|s| (s.as_ptr(), s.len())) {
Ok(std::str::from_utf8(std::slice::from_raw_parts(ptr, len)).unwrap())
} else {
Err(())
}
}
}
Playground
If the unsafe voodoo looks scary, good - it should. The compiler won't help you if you slip up and make a mistake, so that kind of thing should be used only as a last resort. I think the above code is correct because it basically works the same way as the range version, it just converts the slices to their constituent parts after they've been created. But any time someone refactors the code you'll be wondering if a crash or, worse, a silent UB is lurking around the corner.
In case it's not already obvious, my recommendation would be approach #1.

Cannot borrow `*self` as mutable more than once at a time when returning a Result containing a reference

Why is the following invalid and what should I do instead to make it work?
struct Foo;
impl Foo {
fn mutable1(&mut self) -> Result<(), &str> {
Ok(())
}
fn mutable2(&mut self) -> Result<(), &str> {
self.mutable1()?;
self.mutable1()?;
Ok(())
}
}
This code yields:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:10:9
|
8 | fn mutable2(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
9 | self.mutable1()?;
| ---- - returning this value requires that `*self` is borrowed for `'1`
| |
| first mutable borrow occurs here
10 | self.mutable1()?;
| ^^^^ second mutable borrow occurs here
There are many questions already with the same error but I cannot use them to address this one as it's the presence of the implicit return provided by ? that causes the problem, without ? the code compiles successfully, yet with warnings.
Playground
This is the same problem discussed in Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?. Through lifetime elision, the lifetime of the &str is tied to the lifetime of &self. The compiler isn't aware that the borrow won't be used in the condition that an Ok is returned. It's overly conservative and disallows this code. This is a limitation of the current borrow checker implementation.
If you did need the lifetime of the Err variant to be tied to the lifetime of the Foo instance, there's not much to be done in safe Rust (unsafe Rust is another story). In your case, however, it seems unlikely that your &str is intended to be tied to the lifetime of self, so you can use explicit lifetimes to avoid the problem. For example, a &'static str is a common basic error type:
impl Foo {
fn mutable1(&mut self) -> Result<(), &'static str> {
Ok(())
}
fn mutable2(&mut self) -> Result<(), &'static str> {
self.mutable1()?;
self.mutable1()?;
Ok(())
}
}
as it's the presence of the implicit return provided by ?
Not really, as the same code with explicit returns has the same problem:
fn mutable2(&mut self) -> Result<(), &str> {
if let Err(e) = self.mutable1() {
return Err(e);
}
if let Err(e) = self.mutable1() {
return Err(e);
}
Ok(())
}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:12:25
|
8 | fn mutable2(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
9 | if let Err(e) = self.mutable1() {
| ---- first mutable borrow occurs here
10 | return Err(e);
| ------ returning this value requires that `*self` is borrowed for `'1`
11 | }
12 | if let Err(e) = self.mutable1() {
| ^^^^ second mutable borrow occurs here
Current limitation of the Rust borrow checker, we have to rewrite the corresponding methods to static method, for example
fn mutable2(&mut self) -> Result<(), &str> {
...
if let Err(e) = Self::mutable1(&a, &b, &c) {
return Err(e);
}
if let Err(e) = Self::mutable1(&e, &f, &g) {
return Err(e);
}
Ok(())
}

Resources