Repository: rust
Issue: Moving mutable borrows in/out of inferred types results in the compiler thinking they are moved as if they were owned values
Labels: A-borrow-checker,C-discussion

<!--
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.
-->

Apologies for the slightly long title, but I'm not sure how to best summarize this issue. The problem is as follows: I have some code that uses a stack of sorts (`VecDeque` in my case, but the exact type isn't relevant) and pops data from it. It then does something with the data, and optionally pushes it back onto the stack. Crucially, the data is a _mutable borrow_ of something, i.e. `&mut Whatever`. The code roughly looks like this:

```rust
let mut work = VecDeque::new();

...

while let Some((module, node)) = work.pop_front() {
    if pass.run(module, node) {
        resolved = true;
    } else {
        work.push_back((module, node));
    }
}

...
```

Here `node` is a `&mut Something`. The problem I'm running into is that type-checking this code results in the following error:

```
   --> compiler/src/type_check/expressions.rs:632:45
    |
628 |             while let Some((module, node)) = work.pop_front() {
    |                                     ---- move occurs because `node` has type `&mut hir::DefineConstant`, which does not implement the `Copy` trait
629 |                 if pass.run(module, node) {
    |                                     ---- value moved here
...
632 |                     work.push_back((module, node));
    |                                             ^^^^ value borrowed here after move
    |
note: consider changing this parameter type in method `run` to borrow instead if owning the value isn't necessary
   --> compiler/src/type_check/expressions.rs:659:15
    |
656 |     fn run(
    |        --- in this method
...
659 |         node: &mut hir::DefineConstant,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^ this parameter takes ownership of the value

For more information about this error, try `rustc --explain E0382`.
error: could not compile `compiler` (lib) due to 1 previous error
```

In other words, it seems that the compiler treats `node` as if it were an owned value and thus applies move semantics to it, but it's a borrow instead.

This issue _can_ in fact be resolved by giving `work` an explicit type annotation like so:

```rust
let mut work: VecDeque<(ModuleId, &mut hir::DefineConstant)> = VecDeque::new();
```

This suggests the issue is potentially due to type inference not inferring the correct type or ownership.

A very easy way to reproduce this is the following snippet:

```rust
struct Person {}

fn main() {
    let mut work = Vec::new();

    while let Some(person) = work.pop() {
        run(person);
        work.push(person);
    }
}

fn run(_person: &mut Person) {}
```

I expected to see this happen: it should just work, because `person` is a borrow

Instead, this happened: the compiler produces the following error:

```
    Checking playground v0.1.0 (/var/home/yorickpeterse/Projects/rust/playground)
error[E0382]: borrow of moved value: `person`
  --> src/main.rs:8:19
   |
6  |     while let Some(person) = work.pop() {
   |                    ------ move occurs because `person` has type `&mut Person`, which does not implement the `Copy` trait
7  |         run(person);
   |             ------ value moved here
8  |         work.push(person);
   |                   ^^^^^^ value borrowed here after move
   |
note: consider changing this parameter type in function `run` to borrow instead if owning the value isn't necessary
  --> src/main.rs:12:17
   |
12 | fn run(_person: &mut Person) {}
   |    ---          ^^^^^^^^^^^ this parameter takes ownership of the value
   |    |
   |    in this function
help: consider cloning the value if the performance cost is acceptable
   |
7  |         run(person).clone();
   |                    ++++++++

For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` (bin "playground") due to 1 previous error
```

Like with my actual code, one can prevent this error by defining `work` as `let mut work: Vec<&mut Person> = Vec::new();` instead of relying on type inference.

### 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.80.1 (3f5fd8dd4 2024-08-06)
binary: rustc
commit-hash: 3f5fd8dd41153bc5fdca9427e9e05be2c767ba23
commit-date: 2024-08-06
host: x86_64-unknown-linux-gnu
release: 1.80.1
LLVM version: 18.1.7
```