Possible bug in the borrow checker

I encountered in my code a situation where all the immutable references to an object have been dropped, but the borrow checker still complained the object could not be mut borrowed.

I tried to create simpler self-contained demonstration of the issue, but it didn't happen until I made it almost as complex as the real code.

In the gist bellow, I have one while let and a loop, both identical in function, but in the while let the borrow checker complains and provides a wrong suggestion on how to fix, in the loop it compiles just fine.

Is there some hidden semantic that make the code invalid with while let but valid with loop that I am unaware about? Is this some bug or improvement request that is worth reporting somewhere else?

Haven't digged deep yet, but note that your desugaring of while let is incorrect - the real one is (and it gives the same error):

loop {
    if let Some((x, mut y)) = c.a.get(&c.b) {
        println!("{:#?}, {:#?}", x.v, y.iter.next());

        // There should be no more immutable references to c after this drop:
        drop(y);

        c.inf(2);
    } else {
        break;
    };
}

And it has an impact on temporaries lifetimes.

Here's a much smaller repro, although it doesn't print the nonsensical suggestion (I suspect the suggestion comes from some part in the compiler not considering the desugaring and suggests as if this was actual code, btw).

Even smaller one: Rust Playground. It seems borrowck doesn't pay attention to drops/moves with drop-implementing types with temporaries/partial moves.

Edit: Here's another one that I think is the same, but without if let: Rust Playground.

I think the borrow checker cannot recognize partial moves that prevent destructors from running. Interestingly, it does work with destructuring.

Unfortunately, It is not a bug.

It is documented..

give some useful discussion (not my post, but someone who against me shows lots of really useful reasons.)

1 Like

The problem here is not the lifetime of the temporary, it that we drop() it and thus the borrow checker should realize it doesn't live anymore.

this is another question: drop(a.0) not equals to drop(a)

if you wrote drop(a), things are fine

but even you wrote

if let var=c.get(){
    drop(var);
    c.get_mut()
}

error (may) still exists (i've not tested yet, but it should be)

That is the issue, and that's why I said the issue seems to be borrowck doesn't account for partial moves.

IIRC I checked that and the error is not present.

Edit: Yes, I was correct: Rust Playground.

1 Like