Skip to content
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

explicit_iter_loop: x.iter_mut() vs &mut *x #11074

Closed
dtolnay opened this issue Jul 3, 2023 · 8 comments · Fixed by #11418
Closed

explicit_iter_loop: x.iter_mut() vs &mut *x #11074

dtolnay opened this issue Jul 3, 2023 · 8 comments · Fixed by #11418
Labels
C-bug Category: Clippy is not doing the correct thing I-false-positive Issue: The lint was triggered on code it shouldn't have

Comments

@dtolnay
Copy link
Member

dtolnay commented Jul 3, 2023

Summary

I have a hard time being confident that Clippy's suggestion in the following case constitutes an improvement to the code:

-     for xi in x.iter_mut() {
+     for xi in &mut *x {

Could we revisit whether it is worth suggesting a change in this case?

In cases where the suggestion is for xi in x {, I am fully supportive of the lint. Obviously for xi in x is a clear improvement over for xi in x.iter_mut() (modulo the restriction from #8585 being turned on).

I am also generally supportive of for xi in &mut x.

But the case of for xi in &mut *x starts to be over the line for me in symbol soup.

Lint Name

explicit_iter_loop

Reproducer

#![warn(clippy::pedantic)]

pub fn imul(x: &mut Vec<u64>, y: u64) {
    // Multiply iteratively over all elements, adding the carry each time.
    let mut carry = 0;
    for xi in x.iter_mut() {
        carry = scalar::imul(xi, y, carry);
    }

    // Overflow of value, add to end.
    if carry != 0 {
        x.push(carry);
    }
}

mod scalar {
    pub fn imul(_x: &mut u64, _y: u64, _carry: u64) -> u64 {
        todo!()
    }
}
$ cargo clippy

warning: it is more concise to loop over references to containers instead of using explicit iteration methods
 --> src/main.rs:6:15
  |
6 |     for xi in x.iter_mut() {
  |               ^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *x`

This is a case where neither for xi in x { nor for xi in &mut x { compiles.

error[E0382]: borrow of moved value: `x`
   --> src/main.rs:12:9
    |
3   | pub fn imul(x: &mut Vec<u64>, y: u64) {
    |             - move occurs because `x` has type `&mut Vec<u64>`, which does not implement the `Copy` trait
...
6   |     for xi in x {
    |               - `x` moved due to this implicit call to `.into_iter()`
...
12  |         x.push(carry);
    |         ^^^^^^^^^^^^^ value borrowed here after move
    |
note: `into_iter` takes ownership of the receiver `self`, which moves `x`
error[E0277]: `Vec<u64>` is not an iterator
 --> src/main.rs:6:15
  |
6 |     for xi in &mut x {
  |               ^^^^^^ `Vec<u64>` is not an iterator; try calling `.into_iter()` or `.iter()`
  |
  = help: the trait `Iterator` is not implemented for `Vec<u64>`
  = note: required for `&mut Vec<u64>` to implement `Iterator`
  = note: 1 redundant requirement hidden
  = note: required for `&mut &mut Vec<u64>` to implement `Iterator`
  = note: required for `&mut &mut Vec<u64>` to implement `IntoIterator`
help: consider removing the leading `&`-reference
  |
6 -     for xi in &mut x {
6 +     for xi in x {
  |

Version

rustc 1.72.0-nightly (839e9a6e1 2023-07-02)
binary: rustc
commit-hash: 839e9a6e1210934fd24b15548b811a97c77138fc
commit-date: 2023-07-02
host: x86_64-unknown-linux-gnu
release: 1.72.0-nightly
LLVM version: 16.0.5

Additional Labels

No response

@dtolnay dtolnay added C-bug Category: Clippy is not doing the correct thing I-false-positive Issue: The lint was triggered on code it shouldn't have labels Jul 3, 2023
@tertsdiepraam
Copy link

tertsdiepraam commented Aug 25, 2023

Another variant of this problem is with an immutable borrow where clippy suggests this:

- for xi in x.iter() {}
+ for xi in &*x {}

For us, in uutils (see uutils/coreutils#5204), this has popped up since Rust 1.72. We think the suggested code is less readable and harder to understand (especially for beginners). I think a good compromise would be to only suggest these changes if no * need to be inserted.

github-merge-queue bot pushed a commit to bevyengine/bevy that referenced this issue Aug 25, 2023
# Objective

[Rust 1.72.0](https://blog.rust-lang.org/2023/08/24/Rust-1.72.0.html) is
now stable.

# Notes

- `let-else` formatting has arrived!
- I chose to allow `explicit_iter_loop` due to
rust-lang/rust-clippy#11074.
  
We didn't hit any of the false positives that prevent compilation, but
fixing this did produce a lot of the "symbol soup" mentioned, e.g. `for
image in &mut *image_events {`.
  
  Happy to undo this if there's consensus the other way.

---------

Co-authored-by: François <mockersf@gmail.com>
@Benjscho
Copy link
Contributor

Benjscho commented Aug 25, 2023

Another compromise would be to split this into two lints explicit_iter_loop_deref and explicit_iter_loop_std, where the deref lint contains Deref *, Reborrow &*, and ReborrowMut &mut * syntax. explicit_iter_loop_std can then be pedantic, while explicit_iter_loop_deref can move back to the style group.

Benjscho added a commit to Benjscho/rust-clippy that referenced this issue Aug 25, 2023
Referencing this raised issue: rust-lang#11074

The lint adds too much visual noise when deref lints are enforced. This commit
splits the explicit_iter_loop into two versions, the first, `std`, where
non-deref types are linted, and the second `deref` where deref types are
linted.
@Benjscho
Copy link
Contributor

Created a PR (#11406) that would split these and resolve this issue if that's the desired behaviour.

@tertsdiepraam
Copy link

Though I like the idea, one problem with splitting it is that it would require that everyone's allow attributes would need to be changed. I think it's worth exploring how many people actually want the version with *. My guess is that it isn't many people, but I might be wrong.

@Benjscho
Copy link
Contributor

Benjscho commented Aug 25, 2023

That's true, and one option for that is to then change explicit_iter_loop_std back to explicit_iter_loop. This has the drawback that the behaviour of explicit_iter_loop has then changed. I think needing to readjust the allow attributes makes most sense

@Benjscho
Copy link
Contributor

I misunderstood the pedantic/style designation before. Updated my PR so both lints are active as pedantic, but can be separately allowed/disallowed. This would leave users having to update their allow attributes, but gives better granularity in the linting.

@Centri3
Copy link
Member

Centri3 commented Aug 25, 2023

You could add explicit_iter_loop -> explicit_iter_loop_std in renamed_lints.

@Benjscho
Copy link
Contributor

Awesome thanks, will do that!

Philippe-Cholet added a commit to Philippe-Cholet/rusty-aoc that referenced this issue Aug 26, 2023
- I won't document panics.
- `clippy::tuple-array-conversions` seems to have false positives.
- `clippy::tuple-array-conversions` seems to have false positives and is not very nice yet.
- `clippy::explicit-iter-loop` is currently only partly nice. See rust-lang/rust-clippy#11074
Trashtalk217 pushed a commit to Trashtalk217/bevy that referenced this issue Aug 28, 2023
[Rust 1.72.0](https://blog.rust-lang.org/2023/08/24/Rust-1.72.0.html) is
now stable.

- `let-else` formatting has arrived!
- I chose to allow `explicit_iter_loop` due to
rust-lang/rust-clippy#11074.

We didn't hit any of the false positives that prevent compilation, but
fixing this did produce a lot of the "symbol soup" mentioned, e.g. `for
image in &mut *image_events {`.

  Happy to undo this if there's consensus the other way.

---------

Co-authored-by: François <mockersf@gmail.com>
bors added a commit that referenced this issue Aug 30, 2023
Add config flag for reborrows in explicit_iter_loop

This PR adds a config flag for enforcing explicit into iter lint for reborrowed values. The config flag, `enforce_iter_loop_reborrow`, can be added to clippy.toml files to enable the linting behaviour. By default the reborrow lint is disabled.

fixes: #11074

changelog: [`explicit_iter_loop`]: add config flag `enforce_iter_loop_reborrow` to disable reborrow linting by default
@bors bors closed this as completed in c50d86f Aug 31, 2023
Subserial pushed a commit to Subserial/bevy_winit_hook that referenced this issue Jan 24, 2024
# Objective

[Rust 1.72.0](https://blog.rust-lang.org/2023/08/24/Rust-1.72.0.html) is
now stable.

# Notes

- `let-else` formatting has arrived!
- I chose to allow `explicit_iter_loop` due to
rust-lang/rust-clippy#11074.
  
We didn't hit any of the false positives that prevent compilation, but
fixing this did produce a lot of the "symbol soup" mentioned, e.g. `for
image in &mut *image_events {`.
  
  Happy to undo this if there's consensus the other way.

---------

Co-authored-by: François <mockersf@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Clippy is not doing the correct thing I-false-positive Issue: The lint was triggered on code it shouldn't have
Projects
None yet
4 participants