Why it can't compile

Why this works

and Why it won't work

x = &mut s; does not what you probably think it does.
Since both x and s are &mut u32, x = &mut s is equivalent to x = &mut *s due to auto-dereferencing, thus reborrowing s in x. Therefore, after the exclusive reborrow, s is invalidated and thus cannot be borrowed again.

1 Like
#![allow(warnings)]
fn main() {
    let mut z = 4;

    //x:& 'x     mut u32 = & 'z mut z
    //x:& {8,20} mut u32 = & {8,20} mut z
    let mut x: &mut u32 = &mut z;

    //f:& 'f1     mut & 'z    mut u32= &'x mut x
    //f:& {13,20} mut & {}    mut u32= &{13,20}mut x
    //f:& {13,20} mut &{8,20} mut u32= &{13,20}mut  & {8,20} mut z
    let mut f: &mut &mut u32 = &mut x;

    let mut q = 44;

    //print: &'p      &'x mut      &'z mut u32 = &'f f
    //print: &{20,20} &{13,20}mut  &{8,20}mut =  &{20,20} &{13,20}mut  &{8,20}mut z
    println!("{}", f);

    //s:& 's      mut u32 = & 'q mut q
    //s:& {28,38} mut u32 = & {28,38} mut q
    let mut s: &mut u32 = &mut q;

   
    //f:& 'f     mut &  'q    mut u32=    &'s      mut  s
    //f:& {35,35} mut &  {}     mut u32=    &{35,35} mut  s
    //f:& {35,35} mut & {28,38} mut u32=    &{35,35} mut  &{28,38} mut s
   
    
    //f:& 'f1     mut & 'z    mut u32= &'x mut x
    //f:& {13,20} mut & {}    mut u32= &{13,20}mut x
    //f:& {13,20} mut &{8,20} mut u32= &{13,20}mut  & {8,20} mut z
   
   //x:&'z mut u32;
    x = &mut s;
   f = &mut s;
    // println!("{}",f);

    //x:& 'x      mut &{}mut u32= &'s mut s
    //x:& {40,40} mut &{28,38}mut u32= &{40,40}mut &{28,38} mut s
    // x= &mut s;
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `s` as mutable more than once at a time
  --> src/main.rs:36:8
   |
35 |     x = &mut s;
   |         ------ first mutable borrow occurs here
36 |    f = &mut s;
   |        ^^^^^^
   |        |
   |        second mutable borrow occurs here
   |        first borrow later used here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground` (bin "playground") due to 1 previous error

1 Like

This is a simplified explanation:

simplified code
fn main() {

    let mut x = &mut 4u32;
    let mut f = &mut x; // &mut &mut u32
    let mut s = &mut 44u32; // &mut u32

    x = &mut s;
    f = &mut s;
}
  1. Because let f=&mut x the compiler assumes that f alive means x alive.
  2. x = &mut s exclusively borrows s
  3. f exclusively borrows s but it keeps x alive.
  4. That means s has 2 mutable borrows alive and fails.

This is likely wrong in one or many ways, but it's the model I would currently use to understand it.

You could also simply use lifetimes' values to explain it but I find it hard to imagine.

By the way, it was also asked before by OP, or a very close variation of it,

https://users.rust-lang.org/t/why-this-code-wont-compile-it-compiles-until-x-using-case-but-problem-with-z-using-case

But it isn't an easy case; just linking BC that seems a complete explanation

    let mut z = 4;
    // 'a
    let mut x: &mut u32 = &mut z;
    // 'b 'a ('a: 'b)
    let mut f: &mut &mut u32 = &mut x;
    let mut q = 44;
    // 'c
    let mut s: &mut u32 = &mut q;
    // 'c: 'a
    x = &mut s;
    // 'c: 'b
    // 'c: 'a, 'a: 'c
    f = &mut s;

It's probably something like,

  • f being alive on the last line requires 'a be active
  • that requires 'c be active
  • that requires s still be borrowed
  • that conflicts with creating &mut s
  • borrow killing due to overwriting a reference doesn't apply due to the nested reference

Polonius accepts it.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.