Skip to content

diagnostics: suggest iter_mut() where trying to modify .iter()'ed vector elements inplace #62387

@matthiaskrgr

Description

@matthiaskrgr
Member

code:

#[derive(Debug)]
struct A {
    a: i32,
}

impl A {
    fn double(&mut self) {
        self.a += self.a
    }
}

fn main() {
    let mut v = [A { a: 4 }];
    v.iter().for_each(|a| a.double());
    println!("{:?}", v);
}

The code gives the following not-very-helpful warning:

error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
  --> src/main.rs:14:27
   |
14 |     v.iter().for_each(|a| a.double());
   |                        -  ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
   |                        |
   |                        help: consider changing this to be a mutable reference: `&mut A`

warning: variable does not need to be mutable
  --> src/main.rs:13:9
   |
13 |     let mut v = [A { a: 4 }];
   |         ----^
   |         |
   |         help: remove this `mut`
   |
   = note: #[warn(unused_mut)] on by default

error: aborting due to previous error

trying to use

v.iter().for_each(|&mut a| a.double());

and a none-mutable vector just causes more errors

error[E0308]: mismatched types
  --> src/main.rs:14:24
   |
14 |     v.iter().for_each(|&mut a| a.double());
   |                        ^^^^^^ types differ in mutability
   |
   = note: expected type `&A`
              found type `&mut _`
   = help: did you mean `mut a: &&A`?

The actual fix is to use iter_mut() instead of just iter():

#[derive(Debug)]
struct A {
    a: i32,
}

impl A {
    fn double(&mut self) {
        self.a += self.a
    }
}

fn main() {
    let mut v = [A { a: 4 }];
    v.iter_mut().for_each(|a| a.double());
    println!("{:?}", v);
}

It would be very helpful the compiler could suggest iter_mut()!

Activity

matthiaskrgr

matthiaskrgr commented on Jul 4, 2019

@matthiaskrgr
MemberAuthor

@rustbot modify labels: A-diagnostics

rustbot

rustbot commented on Jul 4, 2019

@rustbot
Collaborator

Error: Parsing label command in comment failed: ...ify labels|error: must have : or to as label starter at >| A-diagnos...

Please let @rust-lang/release know if you're having trouble with this bot.

added
C-enhancementCategory: An issue proposing an enhancement or a PR with one.
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on Jun 11, 2020
matthiaskrgr

matthiaskrgr commented on Aug 28, 2020

@matthiaskrgr
MemberAuthor

Urgh I just ran into this AGAIN. 😭

My code was something like this:

use std::path::PathBuf;

struct Container {
    things: Vec<PathBuf>,
}

impl Container {
    fn things(&mut self) -> &[PathBuf] {
        &self.things
    }
}

// contains containers
struct ContainerContainer {
    contained: Vec<Container>
}

impl ContainerContainer {
    fn contained(&self ) -> &[Container] {
        &self.contained
    }

    fn all_the_things(&mut self) -> &[PathBuf]
    {
       let a = &self.contained().iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
        unimplemented!();
    }
}

pub fn main() {}

The error shown:

error[E0596]: cannot borrow `*container` as mutable, as it is behind a `&` reference
  --> src/main.rs:25:62
   |
25 |        let a = &self.contained().iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>();
   |                                                   ---------  ^^^^^^^^^ `container` is a `&` reference, so the data it refers to cannot be borrowed as mutable
   |                                                   |
   |                                                   help: consider changing this to be a mutable reference: `&mut Container`

error: aborting due to previous error; 1 warning emitted

So I changed it to |&mut container| and was greeted with

error[E0308]: mismatched types
  --> src/main.rs:25:51
   |
25 |        let a = &self.contained().iter().flat_map(|&mut container| container.things()).cloned().collect::<Vec<PathBuf>>();
   |                                                   ^^^^^----------
   |                                                   |    |
   |                                                   |    expected due to this
   |                                                   types differ in mutability
   |                                                   help: did you mean `container`: `&&Container`
   |
   = note:      expected reference `&Container`
           found mutable reference `&mut _`

which made me wonder if I was better off with the origin |container|.

I really wish rust could somehow detect the .iter().bla(|x| fn_that_requires_mut(x) pattern and suggest to use iter_mut() :(

added
D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.
on Aug 3, 2023
self-assigned this
on Aug 27, 2023
added a commit that references this issue on Sep 11, 2023
added a commit that references this issue on Sep 11, 2023
93464a1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsC-enhancementCategory: An issue proposing an enhancement or a PR with one.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.T-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

    Participants

    @chenyukang@crlf0710@matthiaskrgr@estebank@rustbot

    Issue actions

      diagnostics: suggest iter_mut() where trying to modify .iter()'ed vector elements inplace · Issue #62387 · rust-lang/rust