Strangeness in pattern matching mutable references in nested structs

There is a stackoverflow question that asks what the difference between matching with let Some(next) = &mut and let Some(ref mut next) = is.

I looked into binding modes and move/binding semantics of patterns but for life of my I can not figure out why one of these functions compiles but the other doesn't.

struct Node {
    next: Option<Box<Node>>,

fn node_matched<'a>(mut node: &'a mut Node)  {
    if let Some(next) = &mut {
        node = next;
    // here the compiler thinks is still borrowed = None;

fn node_reffed<'a>(mut node: &'a mut Node) {
    if let Some(ref mut next) = {
        node = next;
    // here the compiler thinks is not borrowed anymore = None;

I have been experimenting with different patterns and scenarios to figure this out and this only seems to happen with mutable references but I might be wrong.. Maybe its a bug maybe it is just some interested mechanism that isn't very well known but after spending quite some time trying to answer that stackoverflow question I really really itch to know what is going on.

1 Like

There's another bug report related to this, similar to the one linked in that StackOverflow thread but with a bit more discussion: if/while Some(n) = &mut foo sugar will leak a temporary mutable borrow to current scope in particular situation · Issue #62013 · rust-lang/rust · GitHub

I didn't follow all of the details, but I believe the difference in behavior here is unintentional and will be fixed eventually. When compiling with the next-generation borrow checker Polonius, both functions compile successfully.


Isn't the first example a mutable borrow of an Option, while the second is a mutable reference to a value inside an option? It kind of makes sense to me the compiler would think the first borrow was still alive.