Consider the following code:
#![allow(dead_code)]
fn f (x: &mut i32) -> &mut i32 { x }
fn id<T>(x: T ) -> T { x }
fn main() {
let mut x = 10;
let m = &mut x;
f(m);
*m = 11;
}
Note that f and id are identical, except that id replaces &mut i32 with
a type parameter.
As written, this code compiles. Although m is a &mut i32, which is not
Copy, the call to f does not move the reference out of m, because Rust
implicitly rewrites such calls to f(&mut *m). This allows the argument a lifetime
distinct from m's, one which ends immediately after the call.
However, if you change f(m) to id(m), the program no longer compiles: Rust
complains that the assignment to *m is trying to use m after it was moved,
and points out that &mut i32 is not Copy.
Finally, if you change id(m) to id::<&mut i32>, the program does compile.
This was a surprise to me. My guess is that inferring id's type parameter
unifies the T with m's type, so that T has the same lifetime as m, and
that Rust only introduces reborrows when the parameter and argument have
non-related lifetimes (the reborrow won't have any effect unless they do, anyway).