Tell Borrow Checker To Unborrow

Is there a way to tell rust's borrow checker that a variable (with shared reference type) should be dropped and the thing it borrows should be unborrowed?

I have a code below. I'm trying to call fetch once. If the result is Some, I want to return it, but if it's None, I want to call fill and re-call fetch again. But, for some reason, in the else block, Rust still consider result as alive, and foo.buff is still borrowed. Is there a way to tell Rust's borrow checker that in the else block result is no longer valid, should be dropped, and the foo.buff should be unborrowed?

struct Foo {
    buff: Vec<u8>,
}

fn get<'a>(foo: &'a mut Foo) -> &'a u8 {
    let result = fetch(&foo.buff);
    if let Some(val) = result {
        val
    } else {
        // How do I tell the borrow checker that result should be dropped here
        // and `foo.buff` is no longer borrowed here?
        fill(foo);
        fetch(&foo.buff).unwrap()
    }
}

fn fetch(_a: &[u8]) -> Option<&u8> {
    panic!("not implemented");
}

fn fill(_a: &mut Foo) {}

(Playground)

I tried to isolate the result in a separate scope, but it doesn't work:

struct Foo {
    buff: Vec<u8>,
}

fn get<'a>(foo: &'a mut Foo) -> &'a u8 {
    {
        let result = fetch(&foo.buff);
        if let Some(val) = result {
            return val;
        }
    }
    
    // I don't know why, but for some reason, foo.buff is still considered as
    // borrowed here.
    fill(foo);
    fetch(&foo.buff).unwrap()
}

fn fetch(_a: &[u8]) -> Option<&u8> {
    panic!("not implemented");
}

fn fill(_a: &mut Foo) {}

This looks like the classic Borrow checker extends borrow range in code with early return · Issue #54663 · rust-lang/rust · GitHub, a shortcoming of the current borrow checker. You could use polonius-the-crab to work around this I believe.

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.