Borrow checker error in loop with early return - shouldn't NLL handle this case?

⚓ Rust    📅 2025-08-10    👤 surdeus    👁️ 4      

surdeus

Hi everyone,

I'm encountering a borrow checker error that I believe should be resolved by Non-Lexical Lifetimes (NLL), but it's failing to compile in Rust 1.88 (2024 Edition). I'd appreciate some insight into whether this is expected behavior or if I'm missing something.

Minimal reproducing example:

struct Test {
    current: Option<(Vec<u8>, usize)>,
}

impl Test {
    fn peek(&mut self) -> Option<&[u8]> {
        loop {
            match &self.current {
                Some((bytes, pos)) => {
                    if *pos < bytes.len() {
                        return Some(&bytes[*pos..]);  // immutable borrow here
                    }
                }
                None => return None,
            }
            self.next(); // ERROR: cannot borrow `*self` as mutable
        }
    }
  
    fn next(&mut self) {
        self.current = None;
    }
}

Compiler error:

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable

My understanding:

According to NLL, the immutable borrow &bytes[*pos..] should end at the return statement, so self.next() should be able to mutably borrow self since the immutable borrow is no longer live.

Questions:

  1. Is this expected behavior, or should NLL handle this case?
  2. If this is a limitation, is there a specific reason why the borrow checker can't prove safety here?
  3. Are there any known issues or discussions about this pattern?

I've tried various workarounds, but I'm curious about the fundamental reason why this doesn't compile and whether it's considered a soundness issue or just a limitation of the current borrow checker.

Thanks for any insights!

3 posts - 2 participants

Read full topic

🏷️ Rust_feed