Skip to content

Iterating a vector that needs to have mutable references error is a bit cryptic and leads down wrong path #114311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
drebbe-intrepid opened this issue Jul 31, 2023 · 0 comments · Fixed by #115147
Labels
A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@drebbe-intrepid
Copy link

drebbe-intrepid commented Jul 31, 2023

Code

struct Test {
    a: u32
}

impl Test {
    pub fn add(&mut self, value: u32) {
        self.a += value;
    }
    
    pub fn print_value(&self) {
        println!("Value of a is: {}", self.a);
    }
}

fn main() {
    let mut tests = Vec::new();
    // fill the vector with some Test structs
    for i in 0..=10 {
        tests.push(Test {a: i});
    }
    
    /*
    // First Error: error[E0596]: cannot borrow `test` as mutable, as it is not declared as mutable
    for test in tests {
        test.add(2);
    }
    */
    
    /*
    // Second Error: error[E0382]: borrow of moved value: `tests`
    for mut test in tests {
        test.add(2);
    }
    */
    
    /*
    // Third Error: error[E0596]: cannot borrow `*test` as mutable, as it is behind a `&` reference
    for mut test in &tests {
        test.add(2);
    }
    */
    
    /*
    // Another dead end: error[E0596]: cannot borrow `*test` as mutable, as it is behind a `&` reference
    for test in &tests {
        test.add(2);
    }
    */
    
    // error above should have a recommendation to make tests a mutable reference
    for test in &mut tests {
        test.add(2);
    }

    
    for test in &tests {
        test.print_value();
    }
}

Current output

First Error:

error[E0596]: cannot borrow `test` as mutable, as it is not declared as mutable
  --> src/main.rs:25:9
   |
25 |         test.add(2);
   |         ^^^^^^^^^^^ cannot borrow as mutable
   |
help: consider changing this to be mutable
   |
24 |     for mut test in tests {
   |         +++

Second Error:

error[E0382]: borrow of moved value: `tests`
  --> src/main.rs:51:17
   |
16 |     let mut tests = Vec::new();
   |         --------- move occurs because `tests` has type `Vec<Test>`, which does not implement the `Copy` trait
...
31 |     for mut test in tests {
   |                     ----- `tests` moved due to this implicit call to `.into_iter()`
...
51 |     for test in &mut tests {
   |                 ^^^^^^^^^^ value borrowed here after move
   |
note: `into_iter` takes ownership of the receiver `self`, which moves `tests`
  --> /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/iter/traits/collect.rs:271:18
help: consider iterating over a slice of the `Vec<Test>`'s content to avoid moving into the `for` loop
   |
31 |     for mut test in &tests {
   |                     +

Third Error:

warning: variable does not need to be mutable
  --> src/main.rs:38:9
   |
38 |     for mut test in &tests {
   |         ----^^^^
   |         |
   |         help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

error[E0596]: cannot borrow `*test` as mutable, as it is behind a `&` reference
  --> src/main.rs:39:9
   |
38 |     for mut test in &tests {
   |                     ------ this iterator yields `&` references
39 |         test.add(2);
   |         ^^^^^^^^^^^ `test` is a `&` reference, so the data it refers to cannot be borrowed as mutable

Another dead-end:

error[E0596]: cannot borrow `*test` as mutable, as it is behind a `&` reference
  --> src/main.rs:46:9
   |
45 |     for test in &tests {
   |                 ------ this iterator yields `&` references
46 |         test.add(2);
   |         ^^^^^^^^^^^ `test` is a `&` reference, so the data it refers to cannot be borrowed as mutable

Desired output

error[E0596]: cannot borrow `test` as mutable, as it is not declared as mutable
  --> src/main.rs:25:9
   |
25 |         test.add(2);
   |         ^^^^^^^^^^^ cannot borrow as mutable
   |
help: consider changing this to be a `&` mutable reference
   |
24 |     for mut test in &mut tests {
   |                     ++++

Rationale and extra context

The first error compiler messages leads to the second error, which in turn leads to the third error which ends up not solving the actual issue.

I'm not sure if the desired output is the best way to go but I believe I would have fixed the issue a lot faster if I had that instead.

Other cases

No response

Anything else?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e7a08793435e70676d81d98c826b0286

@drebbe-intrepid drebbe-intrepid added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 31, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jul 31, 2023
@saethlin saethlin removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 1, 2023
estebank added a commit to estebank/rust that referenced this issue Aug 23, 2023
```
error[E0596]: cannot borrow `*test` as mutable, as it is behind a `&` reference
  --> $DIR/suggest-mut-iterator.rs:22:9
   |
LL |     for test in &tests {
   |                 ------ this iterator yields `&` references
LL |         test.add(2);
   |         ^^^^ `test` is a `&` reference, so the data it refers to cannot be borrowed as mutable
   |
help: use a mutable iterator instead
   |
LL |     for test in &mut tests {
   |                  +++
```

Address rust-lang#114311.
@bors bors closed this as completed in aa5dbee Aug 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants