Skip to content

Confusing compilation error when forgetting to deref_mut in a chain of iterators #105337

Description

@robinmoussu

This doesn’t compile:

fn foo(items: &mut [u8]) -> u8 {
    // The centent of this function isn’t important
    items.sort();
    42
}

fn main() {
    let mut x: Vec<Vec<u8>> = vec![
        vec![0, 1, 2],
        vec![3, 4, 5],
    ];
    let x = x
        .iter_mut()
        .map(foo) // <-- this line
    println!("{:?}", x);
}
error[[E0631]](https://doc.rust-lang.org/stable/error-index.html#E0631): type mismatch in function arguments
  --> src/main.rs:20:14
   |
1  | fn foo(items: &mut [u8]) -> u8 {
   | ------------------------------ found signature defined here
...
20 |         .map(foo);
   |          --- ^^^ expected due to this
   |          |
   |          required by a bound introduced by this call
   |
   = note: expected function signature `fn(&mut Vec<u8>) -> _`
              found function signature `for<'r> fn(&'r mut [u8]) -> _`
note: required by a bound in `map`

For more information about this error, try `rustc --explain E0631`.

The solution is either to call first deref

.map(std::ops::DerefMut::deref_mut).map(foo)

or

.map(|items| items.as_mut())

Or to use a lambda

.map(|mut items| foo(&mut items))

The current error doesn’t help to understand what the issue is and it’s very confusing because it may look like a lifetime error (because of the for<'r>…).

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

Activity

  1. added
    A-diagnosticsArea: Messages for errors, warnings, and lints
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Dec 5, 2022
  2. added
    D-confusingDiagnostics: Confusing error or lint that should be reworked.
    D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.
    D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.
    on Dec 5, 2022
  3. ch-iv commented on Dec 6, 2022

    @ch-iv
    Contributor

    @rustbot claim

  4. robinmoussu commented on Dec 6, 2022

    @robinmoussu
    Author

    Trying to force the deref using from is equally as confusing:

        let x = x
            .iter_mut()
            .map(<&mut [u8]>::from) // <-- this line
            .map(foo);
    error[[E0631]](https://doc.rust-lang.org/stable/error-index.html#E0631): type mismatch in function arguments
      --> src/main.rs:18:14
       |
    18 |         .map(<&mut [u8]>::from)
       |          --- ^^^^^^^^^^^^^^^^^
       |          |   |
       |          |   expected due to this
       |          |   found signature defined here
       |          required by a bound introduced by this call
       |
       = note: expected function signature `fn(&mut Vec<u8>) -> _`
                  found function signature `fn(&mut [u8]) -> _`
    note: required by a bound in `map`
  5. ch-iv commented on Dec 9, 2022

    @ch-iv
    Contributor

    As I understand, the issue is that x.iter_mut() returns an IterMut and when iterating over it, the elements are references. In order to fix the error, the elements must be dereferenced first, for example, by calling .map(std::ops::DerefMut::deref_mut). The error and notes don't give any indication of that. Is my understanding correct?

  6. ch-iv commented on Dec 20, 2022

    @ch-iv
    Contributor

    I couldn't find confirmation, so I am releasing.
    @rustbot release-assignment

  7. robinmoussu commented on Dec 20, 2022

    @robinmoussu
    Author

    As I understand, the issue is that x.iter_mut() returns an IterMut and when iterating over it, the elements are references. In order to fix the error, the elements must be dereferenced first, for example, by calling .map(std::ops::DerefMut::deref_mut). The error and notes don't give any indication of that. Is my understanding correct?

    @ch-iv Your understanding is right. Sorry, I did not saw the notification, which explain why I didn’t responded earlier.

  8. ch-iv commented on Dec 21, 2022

    @ch-iv
    Contributor

    @rustbot claim

  9. estebank commented on Jan 7, 2023

    @estebank
    Contributor

    @ch-iv you can take a look at #105674 for inspiration on how to walk the method chain looking for the previous types, but in this case you need to look at the expected/found arguments, detect there's a single one and then check if the found implements Deref or DerefMut into the expected type, and then suggest the map(appropriate::method).

  10. ch-iv commented on Jan 7, 2023

    @ch-iv
    Contributor

    @estebank Ok, thank you. I was unsure about how to proceed, but I hope this will help.

  11. estebank commented on Oct 4, 2024

    @estebank
    Contributor

    Current output:

    error[E0631]: type mismatch in function arguments
       --> src/main.rs:14:14
        |
    1   | fn foo(items: &mut [u8]) -> u8 {
        | ------------------------------ found signature defined here
    ...
    14  |         .map(foo); // <-- this line
        |          --- ^^^ expected due to this
        |          |
        |          required by a bound introduced by this call
        |
        = note: expected function signature `fn(&mut Vec<u8>) -> _`
                   found function signature `fn(&mut [u8]) -> _`
    note: required by a bound in `map`
       --> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:765:12
        |
    762 |     fn map<B, F>(self, f: F) -> Map<Self, F>
        |        --- required by a bound in this associated function
    ...
    765 |         F: FnMut(Self::Item) -> B,
        |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
    help: consider wrapping the function in a closure
        |
    14  |         .map(|arg0: &mut Vec<u8>| foo(/* &mut [u8] */)); // <-- this line
        |              ++++++++++++++++++++    +++++++++++++++++
    

    The suggestion isn't perfect, but it provides a path to get to working code:

    error[E0596]: cannot borrow `arg0` as mutable, as it is not declared as mutable
      --> src/main.rs:14:39
       |
    14 |         .map(|arg0: &mut Vec<u8>| foo(&mut arg0)); // <-- this line
       |                                       ^^^^^^^^^ cannot borrow as mutable
       |
    note: the binding is already a mutable borrow
      --> src/main.rs:14:21
       |
    14 |         .map(|arg0: &mut Vec<u8>| foo(&mut arg0)); // <-- this line
       |                     ^^^^^^^^^^^^
    help: try removing `&mut` here
       |
    14 -         .map(|arg0: &mut Vec<u8>| foo(&mut arg0)); // <-- this line
    14 +         .map(|arg0: &mut Vec<u8>| foo(arg0)); // <-- this line
       |
    

    After passing arg0 directly, the code compiles.

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 lintsD-confusingDiagnostics: Confusing error or lint that should be reworked.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.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

    No branches or pull requests

    Issue actions