Why this code can't be compiled

#[test]
fn b() {
    let mut s = "1".to_owned();
    let z = {
        let mut s1 = &mut s;
        let s2 = &mut s1;
        &mut **s2
    };
    println!("{}", z)
}

but

#[test]
fn b() {
    let mut s = "1".to_owned();
    let z = {
        let mut s1 = &mut s;
        &mut *s1
    };
    println!("{}", z)
}

is ok

1 Like

Not as you said, the following passes

#[test]
fn b() {
    let mut s = "1".to_owned();
    let mut s1 = &mut s;
    let z = {
        let s2 = &mut s1;
        &mut **s2
    };
    println!("{}", z)
}
#[test]
fn b() {
    let mut s = "1".to_owned();
    let mut s1 = &mut s;
    let z = &mut *s1;
    drop(s1);
    println!("{}", z);
}

fails, because z must have a shorter life than s1;

but,

#[test]
fn b() {
    let mut s = "1".to_owned();
    let z = {
        let mut s1 = &mut s;
        &mut *s1
    };
    println!("{}", z)
}

compiles, and z lives longer than s1................

I think it's a limitation of reborrowing.

An examination of a bunch of variations

This is no problem:

Whereas with this one:

fn b() {
    let mut s = "1".to_owned();
    let z = {
        let mut s1 = &mut s;
        let s2 = &mut s1;
        &mut **s2
//            ^^^ s1
//      ^^^^^^ reborrow of s1
//      But reborrows must be shorter than the original borrow
//      And s1 doesn't last longer than this block
//      So the reborrow can't escape this block
//      `&mut *s2` fails with the same error
    };
    println!("{}", z);
}

Making this, I believe, a special-case for reborrowing:

fn b() {
    let mut s = "1".to_owned();
    let z = {
        let s1 = &mut s;
        &mut *s1
//      ^^^^^^^^ Reborrow of s1 that lasts beyond the block
    };
    println!("{}", z)
}

Why allow this? Consider the version without reborrowing:

fn b() {
    let mut s = "1".to_owned();
    let z = {
        let s1 = &mut s;
        // As a "return" of the block, the lifetime can be greater
        // than the block: `s1` gets moved to `z`
        s1
    };
    println!("{}", z)
}

And contrast:

fn b() {
    let mut s = "1".to_owned();
    let z = {
        let mut s1 = &mut s;
        let s2 = &mut s1;
        // error[E0507]: cannot move out of `*s2` which is behind a mutable reference
        *s2
    };
    println!("{}", z)
}

But reborrows aren't well documented, so I'm not 100% on this, and that's all the time I have for it at the moment. (It may not even be a special case; perhaps the move of s1 out of the block happens before the reborrow, and as shown, *s2 can't be moved.)

1 Like

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.