rustreferenceborrow-checkerborrowing

Nested method calls with existing mutable references


The following code compiles successfully:

let mut v = vec![1];
let r = &mut v;
r.push(r.len());

while this one fails:

let mut v = vec![1];
let r = &mut v;
r.push(v.len());

with error:

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
    |
    |     let r = &mut v;
    |             ------ mutable borrow occurs here
    |     r.push(v.len());
    |            ^ immutable borrow occurs here
    |     r.push(r.len());
    |     - mutable borrow later used here

I suspect that in the first example there are no errors because the compiler does not create intermediate references and it uses the same reference: r so that there are not multiple borrows. However, if that is the case, why the following code fails to compile

let mut v = vec![1];
let r = &mut v;
r.push({r.push(0);1});

Solution

  • 1st example:

    let mut v = vec![1];
    let r = &mut v;
    r.push(r.len());
    

    Without the 2-phase borrows the code will not compile because the outer call creates a reborrow of r: &mut *r, and the inner call a new immutable reborrow of the same value: &*r.

    With 2-phase borrows, the first reborrow is converted to &mut2 *r and later activated when the second reborrow is out of scope.

    2nd example:

    let mut v = vec![1];
    let r = &mut v;
    r.push(v.len());
    

    Even with the 2-phase borrows it does not compile.

    The inner call causes a reborrow of v: &mut v that clashes with r.

    3rd example:

    let mut v = vec![1];
    let r = &mut v;
    r.push({r.push(0);0});
    

    Even with the 2-phase borrows it does not compile.

    The inner call requires a &mut2 reborrows of *r that is not allowed by the 2-phase borrows since the outer call already created a &mut2 reborrows of *r.

    References: