My naive understanding of borrow checking with NLL is that it could analyze the code flow graph rather then being tied to the lexical scope. I expected (wrongly) the follow code to be correct under that model, since we have branching control flow.
fn inner(i: &mut i32) -> Result<(), &i32> {
if i.is_positive() {
Err(i)
} else {
Ok(())
}
}
fn outer(i: &mut i32) -> Result<(), &i32> {
inner(i)?;
inner(i)
}
fn main() {
outer(&mut 1).unwrap();
}
However this fails to type check:
error[E0499]: cannot borrow `*i` as mutable more than once at a time
--> src/main.rs:11:11
|
9 | fn outer(i: &mut i32) -> Result<(), &i32> {
| - let's call the lifetime of this reference `'1`
10 | inner(i)?;
| ---------
| | |
| | first mutable borrow occurs here
| returning this value requires that `*i` is borrowed for `'1`
11 | inner(i)
| ^ second mutable borrow occurs here
I understand what the error is saying. It is saying that i
must be borrowed for the entire function, but that does not work with an early return, since the lifetime would have two sizes. However this seems like it should work with lifetimes analysis based on control flow.
Is this just limitation of the borrow checker, or is this preventing fundamental unsoundness? If it is a borrow checker limitation, why does NLL control-flow analysis not work with this?