Why is the mutable reference not moved here?

There might actually be a good reason for this.

&mut T isn’t actually a type: all borrows are parametrized by some (potentially inexpressible) lifetime.

When one writes

fn move_try(val: &mut ()) {
    { let new = val; }
    *val
}

fn main() {
    move_try(&mut ());
}

the type inference engine infers typeof new == typeof val, so they share the original lifetime. This means the borrow from new does not end until the borrow from val does.

This means it’s equivalent to

fn move_try<'a>(val: &'a mut ()) {
    { let new: &'a mut _ = val; }
    *val
}

fn main() {
    move_try(&mut ());
}

However, when you write

fn move_try(val: &mut ()) {
    { let new: &mut _ = val; }
    *val
}

fn main() {
    move_try(&mut ());
}

a cast happens – the same kind of thing that lets you cast away pointer mutability. This means that the lifetime is some (seemingly unspecifiable) 'b < 'a. This involves a cast, and thus a reborrow, and so the reborrow is able to fall out of scope.

An always-reborrow rule would probably be nicer, but explicit declaration isn’t too problematic.

Leave a Comment