-
Notifications
You must be signed in to change notification settings - Fork 13.8k
Description
The following program, when compiled, gives rise to a misleading and unhelpful error message:
use std::io;
enum Error<'a> {
Invalid(&'a [u8]),
Io(io::Error),
}
struct Thing {
counter: usize
}
enum Result<'a> {
Done,
Error(Error<'a>),
Value(usize)
}
impl Thing {
fn new() -> Self {
Self { counter: 0 }
}
fn process(&mut self) -> Result {
self.counter += 1;
Result::Done // for now
}
}
fn main() {
let mut thing = Thing::new();
loop {
let result = thing.process();
match result {
Result::Done => {
break;
}
Result::Error(e) => panic!(e),
Result::Value(v) => {
println!("{}", v);
}
}
}
}
The message is:
Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `thing` as mutable more than once at a time
--> src/lib.rs:32:22
|
32 | let result = thing.process();
| ^^^^^ mutable borrow starts here in previous iteration of loop
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
However, the mutable borrow complaint appears remote from the true reason for the error.
The key to determining the problem, as analysed by Daniel Keep here, is the exact language of the error message:
note: borrowed value must be valid for the static lifetime...
At first glance, there are no static borrows anywhere in the code. But what's actually happening is that when there's the panic!(e)
, e
is being used as the literal panic payload. In order for that to work, e
itself must live forever. But, as Error
contains a borrow, that borrow must live forever.
But the 'a
lifetime of that Error
borrow is tied to the 'a
lifetime in Result
. And that lifetime is tied to the lifetime of self
, which is in turn the required lifetime of the thing
variable.
So thing
has to be 'static
, but it cannot be 'static
because it’s on the stack.
It's not immediately obvious how best to improve the error message, but the current message isn't helpful, because it points to the borrow in the loop.
Apparently Polonius doesn't give any better message.
Links which may be useful:
The sample in Rust Playground
Discussion on users.rust-lang.org