Hello!
I am wrestling with the borrow checker and I could use some advice. I think what I'm trying to do is safe, but I don't know how to convince the borrow checker that it is valid. From my understanding, an omniscient borrow checker would know that the two calls to f
in the following code are safe:
use std::marker::PhantomData;
struct Inner<'a> {
_phantom: PhantomData<&'a ()>,
}
impl<'a> Inner<'a> {
fn do_a_thing(&mut self) {}
}
struct Outer<'a> {
x: &'a mut Inner<'a>,
}
impl<'a> Outer<'a> {
fn act_on_inner(&mut self) {
self.x.do_a_thing();
}
}
fn f<'a>(x: &'a mut Inner<'a>) {
let mut outer = Outer { x: x };
outer.act_on_inner();
}
fn main() {
let mut x = Inner {
_phantom: PhantomData,
};
f(&mut x);
f(&mut x);
}
However, the error is:
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> src/main.rs:29:12
|
28 | f(&mut x);
| - first mutable borrow occurs here
29 | f(&mut x);
| ^ second mutable borrow occurs here
30 | }
| - first borrow ends here
The most unusual part of the above code's style would be the use of the struct Outer
to wrap the Inner
in the body of f
. I did that for developer ergonomics (I'm writing an API).
I've tried a number of things, including enabling non-lexical lifetimes in the nightly compiler, but no fix seems to keep all functionality. I did manage to get the code to typecheck by adding multiple lifetimes to the arguments of f
, and deleting its function body:
fn f2<'a, 'b>(x: &'a mut Inner<'b>) {
// let mut outer = Outer { x: x };
// outer.act_on_inner();
}
But, as soon as I uncommented the function body, I got this error:
error[E0623]: lifetime mismatch
--> src/main.rs:25:36
|
24 | fn f2<'a, 'b>(x: &'a mut Inner<'b>) {
| -----------------
| |
| these two types are declared with different lifetimes...
25 | let mut outer = Outer { x: x };
| ^ ...but data from `x` flows into `x` here
I've also experimented with adding lifetime bounds to various parameters, but nothing has worked. (Which is not surprising, since it seems that my mental model is missing a key concept.)
My best educated guess about what is happening (in the original code) is that the struct Outer
has a mutable reference to Inner
that is living longer than the duration of the function f
.
Any help would be greatly appreciated. Thank you!
P.S. Is there any way to turn on debug output to see all lifetimes, included elided ones?
Here is a playground link: Rust Playground