Borrow checker, slices, and Copy

Why does the borrow checker reject the following code?

fn foo(a: &mut u32, b: u32) {
    *a += b;
}

fn main() {
    let mut x = Vec::new();
    x.push(0);
    x.push(1);
    for i in 2..10 {
        x.push(x[i - 1]);
        foo(&mut x[i], x[i - 2]);
    }
    dbg!(&x);
}

Using rustc 1.39.0, I see the error

error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
  --> src/main.rs:11:24
   |
11 |         foo(&mut x[i], x[i - 2]);
   |         ---      -     ^ immutable borrow occurs here
   |         |        |
   |         |        mutable borrow occurs here
   |         mutable borrow later used by call

In general, can a function take a mutable reference to an element of a slice if it also takes a copy of another element from the same slice?

You need to split up your code for the borrow checker to be happy.

fn foo(a: &mut u32, b: u32) {
    *a += b;
}

fn main() {
    let mut x = Vec::new();
    x.push(0);
    x.push(1);
    for i in 2..10 {
        x.push(x[i - 1]);
        let bar = x[i - 2];
        foo(&mut x[i], bar);
    }
    dbg!(&x);
}

The borrow checker looks in right to left order to try and find where borrows overlap. So, &mut x[i] overlaps with x[i - 2], because it's borrow only ends after the function foo returns

Thank you for explaining this. Reversing the order of arguments works as well:

fn foo(b: u32, a: &mut u32) {
    *a += b;
}

fn main() {
    let mut x = Vec::new();
    x.push(0);
    x.push(1);
    for i in 2..10 {
        x.push(x[i - 1]);
        foo(x[i - 2], &mut x[i]);
    }
    dbg!(&x);
}
1 Like

Why does the Rust compiler allow x.push(x[i - 1])? Doesn't this mutably borrow x before evaluating the function arguments?

This is likely due to how $x.$method($args) is desugared, and I don't know enough of the subtleties of this desugaring to give an answer. It may just be special cased to work.

1 Like

I don't know if this is current, but there's some discussion about nested method calls (and "two-phase borrows") here:

http://smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/

This was just an idea, not something that was implemented

1 Like