Borrow checker on else branch

Why the borrow checker doesn’t allow such code?:

#[derive(Default)]
struct X(Vec<u32>);

impl X {
    fn get_iter(&self) -> Option<impl Iterator<Item = &u32>> {
        Some(self.0.iter())
    }
    
    fn push(&mut self, x: u32) {
        self.0.push(x);
    }
}

fn main() {
    let mut tmp = X::default();

    if let Some(xx) = tmp.get_iter() { // `xx` holds the reference to `tmp`
        for t in xx {
            println!("{:?}", t);
        }

        // but here `xx` is dropped
    } else {
        tmp.push(1); // ERROR: cannot borrow `tmp` as mutable because it is also borrowed as immutable
        // why tmp is still borrowed here?
    };
}

I thought that nll should break such limitations, but with #![feature(nll)] it does not work either.

There seems to be some unfortunate interaction between NLL and impl Trait. I don’t understand why, but replacing impl Iterator with the concrete type std::slice::Iter<'_, u32> works. (Playground)

In that case it seems to be a bug of NLL (or impl Trait)

I couldn’t find an issue relating to this. It would be a good idea to go to the issue tracker and create one.

Yep, #53528

1 Like