Skip to content

Bad suggestion when implicit loop .iter() should be made mutable #94060

Open
@edmorley

Description

@edmorley

Given the following code:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=b3ca40d8d38fae14b7bab120a85b2b8a
(From AoC, in case it wasn't obvious 😆)

fn winning_losing_game_scores(bingo_game: BingoGame) -> (Option<u64>, Option<u64>) {
    let mut scores = Vec::new();

    for number in bingo_game.numbers_to_be_drawn {
        for card in bingo_game.cards {
            if card.still_playing && card.mark_number(number) {
                // (removed)
            }
        }
    }

    let winning_score = scores.first();
    let losing_score = scores.last();
    (winning_score.copied(), losing_score.copied())
}

struct BingoGame {
    numbers_to_be_drawn: Vec<u64>,
    cards: Vec<BingoCard>,
}

struct BingoCard {
    still_playing: bool,
    // (removed)
}

impl BingoCard {
    fn mark_number(&mut self, _number: u64) -> bool {
        // (removed)
        false
    }
}

The current output is:

error[[E0382]](https://doc.rust-lang.org/nightly/error-index.html#E0382): use of moved value: `bingo_game.cards`
   [--> src/lib.rs:5:21
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=eda0bc06b2047145bfbda74c962a5e91#)    |
5   |         for card in bingo_game.cards {
    |                     ^^^^^^^^^^^^^^^^
    |                     |
    |                     `bingo_game.cards` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
    |                     help: consider borrowing to avoid moving into the for loop: `&bingo_game.cards`
    |
note: this function takes ownership of the receiver `self`, which moves `bingo_game.cards`
    = note: move occurs because `bingo_game.cards` has type `Vec<BingoCard>`, which does not implement the `Copy` trait

error[[E0596]](https://doc.rust-lang.org/nightly/error-index.html#E0596): cannot borrow `card` as mutable, as it is not declared as mutable
 [--> src/lib.rs:6:38
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=eda0bc06b2047145bfbda74c962a5e91#)  |
5 |         for card in bingo_game.cards {
  |             ---- help: consider changing this to be mutable: `mut card`
6 |             if card.still_playing && card.mark_number(number) {
  |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

Ideally the output should look like:

error[[E0596]](https://doc.rust-lang.org/nightly/error-index.html#E0596): cannot borrow `card` as mutable, as it is not declared as mutable
 [--> src/lib.rs:6:38
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=eda0bc06b2047145bfbda74c962a5e91#)  |
5 |         for card in bingo_game.cards {
  |                     ---------------- help: help: consider changing this to: `&mut bingo_game.cards`
6 |             if card.still_playing && card.mark_number(number) {
  |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

ie: To suggest changing the implicit loop iteration for card in bingo_game.cards to either for card in &mut bingo_game.cards or else for card in bingo_game.cards.iter_mut().

CC #62387, #82081. (I've filed a new issue since the #62387 uses closures, and #82081 is about E0594 not E0596)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions