Skip to content

NLL issue when using DerefMut to access fields through a Pin, causing multiple mutable borrow error #63993

Open
@dialtone

Description

@dialtone

The code below doesn't compile due to multiple mutable borrows, however the exact same code without the std::pin::Pin compiles fine actually. My expectation is however that the code would obviously compile fine in both cases.

use std::pin::Pin;
use slab;

struct Entry {
    complete: u64
}

struct Ctx {}
impl Ctx {
    fn new() -> Self {
        Ctx{}
    }
    fn pread<T>(&mut self, _key: T) -> std::io::Result<()> {
        Ok(())
    }
}

struct Foo {
    ctx: Ctx,
    handles: slab::Slab<Entry>
}
impl Foo {
    fn new() -> Self {
        Foo {ctx: Ctx::new(),
             handles: slab::Slab::with_capacity(20)}
    }
    
    fn blah(mut self: Pin<&mut Self>) {
        let v = self.handles.vacant_entry();
        let key = v.key();
        match self.ctx.pread(key) {
            Ok(()) => {
                v.insert(Entry{complete:123});
            },
            Err(_) => {
                
            }
        }
        
    }
}

fn main() {
    Pin::new(&mut Foo::new()).blah();
}

The exception raised is:

error[E0499]: cannot borrow `self` as mutable more than once at a time
  --> src/main.rs:31:15
   |
29 |         let v = self.handles.vacant_entry();
   |                 ---- first mutable borrow occurs here
30 |         let key = v.key();
31 |         match self.ctx.pread(key) {
   |               ^^^^ second mutable borrow occurs here
32 |             Ok(()) => {
33 |                 v.insert(Entry{complete:123});
   |                 - first borrow later used here

error: aborting due to previous error

I'm able to get the code to compile also by creating additional scopes around the areas where I'm supposedly borrowing self like this:

let key = {
    let entry = self.handles.vacant_entry();
    entry.key()
};
match self.ctx.pread(key) {
    Ok(()) => {
        *self.handles.get_mut(key).unwrap() =
            Entry { complete: 123 };
    }

Although obviously that's pretty awkward. I'm told that this could possibly be a bug in the NLL, but I'm pretty new to the language so I'm just reporting this with a short reproducible example.

Hope it helps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-enhancementCategory: An issue proposing an enhancement or a PR with one.NLL-completeWorking towards the "valid code works" goal

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions