Skip to content

Mutable borrow of field with autoref vs ref mut #67957

Open
@davidhewitt

Description

@davidhewitt

I've been playing around with a singly-linked-list. It turns out that this method, which I had hoped might compile with help of non-lexical-lifetimes, does not compile:

struct Recursive {
    child: Option<Box<Recursive>>
}

impl Recursive {
    fn mut_back(&mut self) -> &mut Self {
        let mut node = self;
        while let Some(child) = node.child.as_mut() {
            node = child
        }
        node
    }
}

The error is stating that the borrow for node.child overlaps with the returned borrow of node, as seen below:

error[E0499]: cannot borrow `*node` as mutable more than once at a time
  --> src/lib.rs:11:13
   |
6  |         fn mut_back(&mut self) -> &mut Self {
   |                     - let's call the lifetime of this reference `'1`
7  |             let mut node = self;
8  |             while let Some(child) = node.child.as_mut() {
   |                                     ---------- first mutable borrow occurs here
...
11 |             node
   |             ^^^^
   |             |
   |             second mutable borrow occurs here
   |             returning this value requires that `node.child` is borrowed for `'1`

error: aborting due to previous error

There is a very similar implementation of mut_back() which does compile:

impl Recursive {
    fn mut_back_good(&mut self) -> &mut Self {
        let mut node = self;
        while let Some(ref mut child) = node.child {
            node = child
        }
        node
    }
}

What I think is going on to cause the first implementation to fail is the call to child.as_mut(). Presumably due to autoref this creates a new unique borrow on node.child.

In the second case, I understand that the ref mut binding means we're also creating a unique borrow on node.child. But in this case the borrow checker doesn't think this new unique borrow is a problem.

It seems to me that the compiler should be able to treat these two implementations equally?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-NLLArea: Non-lexical lifetimes (NLL)A-lifetimesArea: Lifetimes / regionsNLL-completeWorking towards the "valid code works" goalNLL-poloniusIssues related for using Polonius in the borrow checkerT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions