Why does the `f1` fail to compile while `f2` is ok?

fn f1() {
    let mut a = 1;
    let b = &mut a;
    let c = b;
    println!("{}", b);
}

fn f2() {
    let mut a = 1;
    let b = &mut a;
    let c: &mut i32 = b;
    println!("{}", b);
}

According to Rust Analyzer, the c in these two functions have the same type &mut i32, but one is ok while another is not,

Can I reproduce the error in f1 by manually annotating the types? Or reproduce the result of f2 with automatic type inference?

The reason this happens is automatic reborrowing, which is not well-documented.

Automatic reborrowing only happens when no type inference is required[1], which is the case only when you explicitly provide a type annotation, like in f2.

Alternatively, you can do manual reborrowing, which works without annotation too:

fn f1() {
    let mut a = 1;
    let b = &mut a;
    let c = &mut *b; // what you wrote is sugar for this
    println!("{}", b);
}

  1. it is enough if the outer &mut is known without inference, so an annotation like let c: &mut _ = b is enough to make it work ↩ī¸Ž

4 Likes

Forgot about reborrowing limitations.

Thanks!

BTW, can I annotate the type of c in f1 manually if I want to transfer the ownership (without triggering the reborrowing)?

It's possible if you put enough indirection between the annotation and the actual &mut _, like so. But I'm unaware of just some simple syntactic way to inhibit the reborrow when it would be automatic.

2 Likes