Repository: rust
Issue: fixed-by-polonius loops/functions have very bad diagnostics
Labels: A-diagnostics,A-borrow-checker,T-compiler,D-confusing,D-terse,fixed-by-polonius

### Code

```Rust
struct Command(Vec<String>);
impl Command {
    fn find_subcommand_mut(&mut self, _name: &str) -> Option<&mut Self> {
        None
    }
}

fn foo(app: &mut Command) {
    let alias_definition = vec!["submodule", "status"];
    let mut cmd = app;
    for arg in alias_definition {
        if let Some(next) = cmd.find_subcommand_mut(arg) {
            cmd = next;
        } else {
            break;
        }
    }
    dbg!(&cmd.0);
}
```


### Current output

```Shell
error[E0502]: cannot borrow `cmd.0` as immutable because it is also borrowed as mutable
  --> src/lib.rs:18:10
   |
12 |         if let Some(next) = cmd.find_subcommand_mut(arg) {
   |                             --- mutable borrow occurs here
...
18 |     dbg!(&cmd.0);
   |          ^^^^^^
   |          |
   |          immutable borrow occurs here
   |          mutable borrow later used here
```


### Desired output

```Shell
"use -Zpolonius lol"
```


### Rationale and extra context

"immutable borrow used here" *pointing at the same span* as "mutable borrow used here" is very unhelpful. the only case this could possibly make sense is when the code is in a loop, which this is not.

i originally ran into this problem inside of an (unrelated) loop, making the diagnostic even more confusing.

### Other cases

removing `break` makes the error a *little* better, but it still would be nice to say "this is a limitation of lifetimes" instead of "your code is broken"
```Rust
fn foo(app: &mut Command) {
    let alias_definition = vec!["submodule", "status"];
    let mut cmd = app;
    for arg in alias_definition {
        if let Some(next) = cmd.find_subcommand_mut(arg) {
            cmd = next;
        }
    }
}
```
```
error[E0499]: cannot borrow `*cmd` as mutable more than once at a time
  --> src/lib.rs:12:29
   |
12 |         if let Some(next) = cmd.find_subcommand_mut(arg) {
   |                             ^^^
   |                             |
   |                             `*cmd` was mutably borrowed here in the previous iteration of the loop
   |                             first borrow used here, in later iteration of loop

```
the recursive case is also pretty confusing, although it looks more like a "traditional" polonius error so maybe it's easier to recognize
```rust
use clap::Command; // 4.5.4

fn find_nested_cmd<'a, 'b, 'c>(cmd: &'a mut Command, query: &'b [&'c str]) -> (&'a mut Command, &'b [&'c str]) {
    // let next = query.first().and_then(|arg| cmd.find_subcommand_mut(arg));
    if let Some(arg) = query.first() {
        if let Some(next) = cmd.find_subcommand_mut(arg) {
            return find_nested_cmd(next, &query[1..]);
        }
    }
    (cmd, query)
}

fn foo(app: &mut Command) {
    let alias_definition = vec!["submodule", "status"];
    let (subcmd, args) = find_nested_cmd(app, &alias_definition);
    dbg!(subcmd.get_bin_name());
}
```
```
error[E0499]: cannot borrow `*cmd` as mutable more than once at a time
  --> src/lib.rs:10:6
   |
3  | fn find_nested_cmd<'a, 'b, 'c>(cmd: &'a mut Command, query: &'b [&'c str]) -> (&'a mut Command, &'b [&'c str]) {
   |                    -- lifetime `'a` defined here
...
6  |         if let Some(next) = cmd.find_subcommand_mut(arg) {
   |                             --- first mutable borrow occurs here
7  |             return find_nested_cmd(next, &query[1..]);
   |                    ---------------------------------- returning this value requires that `*cmd` is borrowed for `'a`
...
10 |     (cmd, query)
   |      ^^^ second mutable borrow occurs here
```

another workaround is to add an extra unwrap() so it doesn't look to the compiler like the lifetimes are related:
```rust
    for arg in alias_definition {
        if let Some(next) = cmd.find_subcommand_mut(arg) {
            cmd = cmd.find_subcommand_mut(arg).unwrap();
        }
    }
```


### Rust Version

```Shell
rustc 1.80.0-nightly (8c127df75 2024-05-16)
binary: rustc
commit-hash: 8c127df75fde3d5ad8ef9af664962a7676288b52
commit-date: 2024-05-16
host: x86_64-unknown-linux-gnu
release: 1.80.0-nightly
LLVM version: 18.1.4
```


### Anything else?

@rustbot label fixed-by-polonius