Repository: rust
Issue: Compiler warning unused_mut suggests removing mut keyword, but it would break compilation
Labels: A-lints,T-compiler,C-bug,A-suggestion-diagnostics,D-invalid-suggestion,L-unused_mut

The Rust compiler gives a warning the `mut` keyword on a pattern is not needed, and suggests removing it. However, removing `mut` makes the code invalid and it then fails to compile.

I tried this code:

([Rust Playground Link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=145e868db895f4d5c6143e4de7769d3f))
```rust
use std::mem::replace;

fn main() {
    let mut state = State::Waiting { start_at: 1 };
    handle_event(&mut state, 0); // waiting
    handle_event(&mut state, 1); // start
    handle_event(&mut state, 2); // running
}

#[derive(Debug)]
enum State {
    Waiting { start_at: u64 },
    Running { started_at: u64 },
}

fn handle_event(state: &mut State, current_time: u64) {
    println!("time: {current_time}: state: {state:?} - event triggered");
    match state {
        // How to handle the matching of "start_at"?
        // Would like to match as a value, not a reference. Is there a way to do this without using mut?
        State::Waiting { mut start_at } => {
            if current_time >= start_at {
                println!("... Starting at {current_time}");
                let _ = replace(
                    state,
                    State::Running {
                        started_at: start_at,
                    },
                );
            } else {
                println!("... Waiting until {start_at}");
            }
        }
        State::Running { started_at } => {
            println!("... Running at {current_time} since {started_at}")
        }
    }
}
```

I expected to see this happen: if the code compiles successfully, a warning and its suggested fix should not break the code so it then fails to compile.

Instead, this happened: 

```text
warning: variable does not need to be mutable
  --> src/main.rs:21:26
   |
21 |         State::Waiting { mut start_at } => {
   |                          ----^^^^^^^^
   |                          |
   |                          help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

warning: `rust-mut-warning` (bin "rust-mut-warning") generated 1 warning (run `cargo fix --bin "rust-mut-warning"` to apply 1 suggestion)
```

And if we remove `mut` from `{ mut start_at }` in the code, the compilation fails:

```text
   Compiling rust-mut-warning v0.1.0 (/Code/rust-mut-warning)
error[E0308]: mismatched types
  --> src/main.rs:22:32
   |
22 |             if current_time >= start_at {
   |                ------------    ^^^^^^^^ expected `u64`, found `&mut u64`
   |                |
   |                expected because this is `u64`
   |
help: consider dereferencing the borrow
   |
22 |             if current_time >= *start_at {
   |                                +

error[E0308]: mismatched types
  --> src/main.rs:27:37
   |
27 |                         started_at: start_at,
   |                                     ^^^^^^^^ expected `u64`, found `&mut u64`
   |
help: consider dereferencing the borrow
   |
27 |                         started_at: *start_at,
   |                                     +

For more information about this error, try `rustc --explain E0308`.
error: could not compile `rust-mut-warning` (bin "rust-mut-warning") due to 2 previous errors
```

Or, we could use the `cargo fix` feature, and it results in the same issue:

```text
cargo fix --bin "rust-mut-warning"
    Checking rust-mut-warning v0.1.0 (/Code/rust-mut-warning)
warning: failed to automatically apply fixes suggested by rustc to crate `rust_mut_warning`

after fixes were automatically applied the compiler reported errors within these files:

  * src/main.rs

This likely indicates a bug in either rustc or cargo itself,
and we would appreciate a bug report! You're likely to see 
a number of compiler warnings after this message which cargo
attempted to fix but failed. If you could open an issue at
https://github.com/rust-lang/rust/issues
quoting the full output of this command we'd be very appreciative!
Note that you may be able to make some more progress in the near-term
fixing code with the `--broken-code` flag

The following errors were reported:
error[E0308]: mismatched types
  --> src/main.rs:22:32
   |
22 |             if current_time >= start_at {
   |                ------------    ^^^^^^^^ expected `u64`, found `&mut u64`
   |                |
   |                expected because this is `u64`
   |
help: consider dereferencing the borrow
   |
22 |             if current_time >= *start_at {
   |                                +

error[E0308]: mismatched types
  --> src/main.rs:27:37
   |
27 |                         started_at: start_at,
   |                                     ^^^^^^^^ expected `u64`, found `&mut u64`
   |
help: consider dereferencing the borrow
   |
27 |                         started_at: *start_at,
   |                                     +

error: aborting due to 2 previous errors
```

### Goal of the sample code

The code that was used (and generates an `unused_mut` warning) was trying to match on a `Copy` type (in this case `u64`). We want to use it by value, and adding the `mut` keyword to the pattern was used in order to bind by value instead of by reference.

There may be a better way to implement the sample code -- that is perhaps a related issue. It is true that the `mut` is unneeded. The bound variable is only used to read the value. But it must be matched by value and not by reference, and adding `mut` is the only way I know to do that.

(There is the alternative of matching by shared reference and adding an immediately following statement `let start_at = *start_at;` to rebind it by value (it is `Copy`), but that is also an ugly hack.)

### Meta

Occurs on both 1.70 stable and 1.72 nightly:

`rustc --version --verbose`:
```
rustc 1.70.0 (90c541806 2023-05-31)
binary: rustc
commit-hash: 90c541806f23a127002de5b4038be731ba1458ca
commit-date: 2023-05-31
host: x86_64-apple-darwin
release: 1.70.0
LLVM version: 16.0.2

rustc 1.72.0-nightly (85bf07972 2023-07-06)
binary: rustc
commit-hash: 85bf07972a1041b9e25393b803d0e006bec3eaaf
commit-date: 2023-07-06
host: x86_64-apple-darwin
release: 1.72.0-nightly
LLVM version: 16.0.5
```