rust-clippy icon indicating copy to clipboard operation
rust-clippy copied to clipboard

False positive in `needless_collect` with borrowing error

Open feds01 opened this issue 2 years ago • 0 comments

Summary

Inlining an iterator to a later call site whilst the iterator is accessed causes a compile error and potentially different program behaviour.

Lint Name

needless_collect

Reproducer

I tried this code:

fn main() {
    let prefix = 1;

    let mut children = [1, 2, 3, 4].into_iter();

    let prefix: Vec<_> = children.by_ref().take(prefix).collect();
    let suffix: Vec<_> = children.collect();

    let dummy = 0;

    let items = prefix
        .into_iter()
        .chain(std::iter::once(dummy))
        .chain(suffix);

    println!("{:?}", items.collect::<Vec<_>>())
}

I saw this happen:

warning: avoid using `collect()` when not needed
  --> src/main.rs:6:57
   |
6  |       let prefix: Vec<_> = children.by_ref().take(prefix).collect();
   |                                                           ^^^^^^^
...
11 |       let items = prefix
   |  _________________-
12 | |         .into_iter()
   | |____________________- the iterator could be used here instead
   |
   = note: `#[warn(clippy::needless_collect)]` on by default
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
help: use the original Iterator instead of collecting it and then producing a new one
   |
6  ~     
7  |     let suffix: Vec<_> = children.collect();
 ...
10 | 
11 ~     let items = children.by_ref().take(prefix)
   |

I expected to see this happen:

No warning, applying the lint causes a compile error and further fixing the error causes the program's logic to change:

the fixed code would be:

fn main() {
    let prefix = 1;

    let mut children = [1, 2, 3, 4].into_iter();

    let suffix: Vec<_> = children.by_ref().collect();

    let dummy = 0;

    let items = children.by_ref().take(prefix)
        .chain(std::iter::once(dummy))
        .chain(suffix);

    println!("{:?}", items.collect::<Vec<_>>())
}

and prints:

[0, 1, 2, 3, 4]

but the original program would print:

[1, 0, 2, 3, 4]

Version

rustc 1.64.0-nightly (f8588549c 2022-07-18)
binary: rustc
commit-hash: f8588549c3c3d45c32b404210cada01e2a45def3
commit-date: 2022-07-18
host: x86_64-apple-darwin
release: 1.64.0-nightly
LLVM version: 14.0.6

Additional Labels

@rustbot label +I-suggestion-causes-error

feds01 avatar Aug 05 '22 20:08 feds01