Why would this variable lose ownership?

fn test1(_: &mut String) {
}

fn test2<T>(_: T) {
}

// OK Pattern1
let mut a = "hoge".to_string();
let mut b = &mut a;
test1(b);
println!("{}", b);

// OK Pattern2
let mut a = "hoge".to_string();
let mut b = &mut a;
test2::<&mut String>(b);
println!("{}", b);

// NG Pattern
let mut a = "hoge".to_string();
let mut b = &mut a;
test2(b);	// 'b'  moved here
println!("{}", b);	// "Error" because `b` after moved

Why does 'b' lose its ownership in NG Pattern?
In test2(), the compiler seems to infer T as '&mut String', so I thought test2() was borrowing 'b'.

In test1(), the compiler sees a &mut and inserts a reborrow on the call, as an exception to the normal rule, since that is usually what is meant when a function takes a &mut reference. That doesn't apply when you have a generic, since it could be called with something that isn't &mut and the special case there would create an inconsistency with what happens in other instantiations of the generic, so test2() always takes ownership. Since &mut is not Copy, that means b can't be used afterwards. The solution would be to insert an explicit extra borrow or reborrow of b on the call of test2().

1 Like

It is borrowing a. The error message isn't about moving a, it's about moving b, which does indeed happen. The mutable rererence itself is being moved to test2.

Thank you for your answer.

I don't understand the 'inserts a reborrow on the call' part, what exactly does that mean?

It means that this:

test1(b);

is internally transformed by the compiler into this:

test1(&mut *b);

i.e. the original value b is not moved; a new, distinct reference is created from the pointed value *b, so that b is left intact.

4 Likes

Oh, I see. Thank you very much!!

But test2 is 'generic', so no such conversion occurs, and "&mut" itself is moved, right?