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 whichlvis 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?