I recently encountered something weird and I condensed it into the following snippet:
use std::cell::RefCell;
fn main() {
let x_vec = RefCell::new(vec![5u32, 8u32, 2u32]);
// borrow `x_vec` mutably in the while-head
while let Some(x) = x_vec.borrow_mut().pop() {
// borrow it again in the body.
// ERROR: apparently the cell was not released
let rem_count = x_vec.borrow().len();
println!("x = {}, remaining = {}", x, rem_count);
}
}
Apparently drop() for RefMut gets not executed in time before the loop body starts? pop() does not return a reference, so there should not be a need to keep a mutable reference.
I'm guessing this is related to lexical borrows, and how this also interacts with temporaries that extend the lifetime of the borrow. RefCell::borrow_mut takes &mut self but must be moving that mutable borrow into the returned RefMut; that RefMut temporary must be having its scope extended (unnecessarily). Indeed, if I write a slimmed down version of this code using my own types, Rust Playground, you'll see that "Inside loop" is printed before "Dropped" - no surprise given what you're seeing with RefCell. If you uncomment the two lines in the loop, you get a borrowck error, suggesting it understands that it's still borrowed from loop header. If you add the workaround that @jethrogb suggested, then you'll see the "Dropped" before the loop body starts - again, no surprise but just reaffirms that something's fishy.
I recommend you open a github issue, pointing to this thread. I think it's probably a known issue, but doesn't hurt to report it (if nothing else, as possibly another example of the known problem).