Repository: rust
Issue: Bug in borrow checker with 'while let'
Labels: P-medium,A-borrow-checker,T-compiler,C-bug

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->

I tried to simplify a `loop` and `match` combination using a `while let` expression, but the result fails to compile while the behavior should be the same.

I tried this code:

```rust
pub fn remove_elements(
    mut head: Option<Box<ListNode>>, val: i32
) -> Option<Box<ListNode>> {        
    let mut current = &mut head;
    while let Some(node) = current {
        if node.val == val {
            *current = node.next.take();
        } else {
            current = &mut node.next;
        }
    }
    head
}
```

I expected to see this happen: it compiles.

Instead, this happened: it does not compile, with the compilation errors:
```
error[E0503]: cannot use `*current` because it was mutably borrowed
  --> src/main.rs:21:15
   |
21 |     while let Some(node) = current {
   |               ^^^^^----^
   |               |    |
   |               |    borrow of `current.0` occurs here
   |               use of borrowed `current.0`
   |               borrow later used here

error[E0499]: cannot borrow `current.0` as mutable more than once at a time
  --> src/main.rs:21:20
   |
21 |     while let Some(node) = current {
   |                    ^^^^ mutable borrow starts here in previous iteration of loop

error[E0506]: cannot assign to `*current` because it is borrowed
  --> src/main.rs:23:13
   |
21 |     while let Some(node) = current {
   |                    ---- borrow of `*current` occurs here
22 |         if node.val == val {
23 |             *current = node.next.take();
   |             ^^^^^^^^
   |             |
   |             assignment to borrowed `*current` occurs here
   |             borrow later used here

error: aborting due to 3 previous errors
```

The original `loop` and `match` code, which does compile, is:
```rust
pub fn remove_elements(
    mut head: Option<Box<ListNode>>, val: i32
) -> Option<Box<ListNode>> {
    let mut current = &mut head;
    loop {
        match current {
            None => break,
            Some(node) if node.val == val => {
                *current = node.next.take();
            },
            Some(node) => {
                current = &mut node.next;
            }
        }
    }
    head
}
```

For completeness, `ListNode` is defined and implemented as:
```rust
#[derive(PartialEq, Eq, Clone, Debug)]                                          
pub struct ListNode {                                                           
    pub val: i32,                                                               
    pub next: Option<Box<ListNode>>                                             
}                                                                               
                                                                                
impl ListNode {                                                                 
    #[inline]                                                                   
    fn new(val: i32) -> Self {                                                  
        ListNode {                                                              
            next: None,                                                         
            val                                                                 
        }                                                                       
    }                                                                           
}
```

### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->

`rustc --version --verbose`:
```
rustc 1.50.0-nightly (0f6f2d681 2020-12-06)
binary: rustc
commit-hash: 0f6f2d681b39c5f95459cd09cb936b6ceb27cd82
commit-date: 2020-12-06
host: x86_64-apple-darwin
release: 1.50.0-nightly
```