Repository navigation
Confusing compilation error when forgetting to deref_mut in a chain of iterators #105337
Description
Activity
- addedA-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
on Dec 5, 2022 - addedD-confusingDiagnostics: Confusing error or lint that should be reworked.Diagnostics: Confusing error or lint that should be reworked.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.Diagnostics: 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.Diagnostics: An error or lint that doesn't give enough information about the problem at hand.
on Dec 5, 2022 @rustbot claim
Trying to force the deref using
fromis 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`
As I understand, the issue is that
x.iter_mut()returns anIterMutand 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?I couldn't find confirmation, so I am releasing.
@rustbot release-assignmentAs I understand, the issue is that
x.iter_mut()returns anIterMutand 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.
@rustbot claim
Reacted by Esteban Kuber@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
DereforDerefMutinto the expected type, and then suggest themap(appropriate::method).@estebank Ok, thank you. I was unsure about how to proceed, but I hope this will help.
Reacted by Esteban KuberCurrent 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
arg0directly, the code compiles.
This doesn’t compile:
The solution is either to call first deref
or
Or to use a lambda
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