Too strict lifetime inference in `if let` statement?

Compiler denies the following code:

struct Foo {
    a: usize,
}
impl Foo {
    fn foo(&mut self) -> &usize {
        if let Some(b) = Some(&self.a) {
            b
        } else {
            self.a = 10;
            &self.a
        }
    }
}

fn main() {}
error[E0506]: cannot assign to `self.a` because it is borrowed
 --> src/main.rs:9:13
  |
5 |     fn foo(&mut self) -> &usize {
  |            - let's call the lifetime of this reference `'1`
6 |         if let Some(a) = Some(&self.a) {
  |                               ------- borrow of `self.a` occurs here
7 |             a
  |             - returning this value requires that `self.a` is borrowed for `'1`
8 |         } else {
9 |             self.a = 10;
  |             ^^^^^^^^^^^ assignment to borrowed `self.a` occurs here

error: aborting due to previous error

playground

The variable b is block-scoped in if let statement, and cannot be used in else block.
So I think there is no restriction for self.a = 10.
How to solve this problem? Or is it a compiler's bug?

I believe this is the same as https://users.rust-lang.org/t/compiler-claims-mutable-reference-being-borrowed-twice.

3 Likes