An example sourced from Polonius update | Inside Rust Blog
struct Thing;
impl Thing {
fn maybe_next(&mut self) -> Option<&mut Self> { None }
}
fn main() {
let mut temp = &mut Thing;
loop {
match temp.maybe_next() {
Some(v) => { temp = v; }
None => { }
}
}
}
The borrowing checker reports an error
error[E0499]: cannot borrow `*temp` as mutable more than once at a time
I tried to simplify above example for researching
struct Thing;
impl Thing {
fn next(&mut self) -> &mut Self {
self
}
}
fn main() {
let mut temp = &mut Thing;
loop {
let r = temp.next();
temp = r;
}
}
This code is compiled. What's the difference here? By using NIL to analysis the first example
fn main() {
let mut temp = &/* 'tmp */ mut Thing;
loop {
/* &'ln mut (*temp) */
/* loan ('ln, mut, *temp) */
match temp.maybe_next() {
Some(v) => { temp = v; }
None => { }
}
}
}
Assuming the control flow repeatedly steps into the Some
branch several times. According to reborrowing constraints: 'tmp :'l1 :'l2 ...
Since v
is assigned to v
(i.e. 'l1:'tmp
, 'l2:'l1
, ...), 'tmp == 'l1 == 'l2 ...
. However, because of the assignment to temp
, the following rules applies to this example:
For a statement at point P in the graph, we define the “transfer function” – that is, which loans it brings into or out of scope – as follows:
- [...]
- if this is an assignment
lv = <rvalue>
, then any loan for some path P of whichlv
is a prefix is killed.
So, any former in 'l1 == 'l2 ...
is killed after temp = v
as if it were to look like:
let mut temp = &'tmp mut Thing;
let v = &'l1 mut *temp; // ('l1, mut, *temp) #1
temp = v; // kill ('l1, mut, *temp)
//#1 is not a relevant borrowing here
let v = &'l2 mut *temp; // ('l2, mut, *temp)
temp = v; // kill ('l2, mut, *temp)
// ...
This is why I thought the first example is equivalent to the second one, however, the second example is compiled. Is there something I misunderstood?