rust-lang / rust-clippy

A bunch of lints to catch common mistakes and improve your Rust code. Book: https://doc.rust-lang.org/clippy/
https://rust-lang.github.io/rust-clippy/
Other
11.21k stars 1.5k forks source link

`iter_on_empty_collections` emitted when `iter::empty()` cannot work #11680

Open tgross35 opened 10 months ago

tgross35 commented 10 months ago

Summary

The suggestion for iter_on_empty_collections causes an incompatible match arm error in some cases.

Lint Name

iter_on_empty_collections

Reproducer

I am having a hard time finding a minimal reproduction, this seems to work OK in most other cases I try. Probably clippy just having trouble seeing through the mess of iterators. This is a snip from the full example:

use itertools::Either;

impl Source {
    /// Iterate through all morph info available
    pub fn morphs(&self) -> impl Iterator<Item = &MorphInfo> {
        match self {
            Source::Affix(rule) => {
                let iter = rule
                    .patterns()
                    .iter()
                    .flat_map(|pat| pat.morph_info().iter());
                Either::Left(iter)
            }
            // v is `&Box<[Arc<MorphInfo>]>`
            Source::Dict(v) => Either::Right(v.as_ref().iter()),
            Source::Personal(v) => Either::Right(v.morph.iter()),
            // problem arm
            Source::Raw => Either::Right([].iter()),
        }
        .map(AsRef::as_ref)
    }
}

I saw this happen:

warning: `iter` call on an empty collection
  --> zspell/src/dict/types.rs:77:42
   |
77 |             Source::Raw => Either::Right([].iter()),
   |                                          ^^^^^^^^^ help: try: `std::iter::empty()`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections
note: the lint level is defined here
  --> zspell/src/lib.rs:87:9
   |
87 | #![warn(clippy::nursery)]
   |         ^^^^^^^^^^^^^^^
   = note: `#[warn(clippy::iter_on_empty_collections)]` implied by `#[warn(clippy::nursery)]`

Following the lint gives

error[E0308]: `match` arms have incompatible types
  --> zspell/src/dict/types.rs:77:28
   |
67 | /         match self {
68 | |             Source::Affix(rule) => {
69 | |                 let iter = rule
70 | |                     .patterns()
71 | |                     .iter()
72 | |                     .flat_map(|pat| pat.morph_info().iter());
   | |                               ----- the expected closure
73 | |                 Either::Left(iter)
   | |                 ------------------ this is found to be of type `itertools::Either<std::iter::FlatMap<std::slice::Iter<'_, dict::rule::AfxRulePattern>, std::slice::Iter<'_, std::sync::Arc<morph::MorphInfo>>, [closure@zspell/src/dict/types.rs:72:31: 72:36]>, std::slice::Iter<'_, std::sync::Arc<morph::MorphInfo>>>`
74 | |             }
75 | |             Source::Dict(v) => Either::Right(v.as_ref().iter()),
   | |                                -------------------------------- this is found to be of type `itertools::Either<std::iter::FlatMap<std::slice::Iter<'_, dict::rule::AfxRulePattern>, std::slice::Iter<'_, std::sync::Arc<morph::MorphInfo>>, [closure@zspell/src/dict/types.rs:72:31: 72:36]>, std::slice::Iter<'_, std::sync::Arc<morph::MorphInfo>>>`
76 | |             Source::Personal(v) => Either::Right(v.morph.iter()),
   | |                                    ----------------------------- this is found to be of type `itertools::Either<std::iter::FlatMap<std::slice::Iter<'_, dict::rule::AfxRulePattern>, std::slice::Iter<'_, std::sync::Arc<morph::MorphInfo>>, [closure@zspell/src/dict/types.rs:72:31: 72:36]>, std::slice::Iter<'_, std::sync::Arc<morph::MorphInfo>>>`
77 | |             Source::Raw => Either::Right(std::iter::empty()),
   | |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Either<FlatMap<Iter<'_, ...>, ..., ...>, ...>`, found `Either<_, Empty<_>>`
78 | |         }
   | |_________- `match` arms have incompatible types
   |
   = note: expected enum `itertools::Either<std::iter::FlatMap<std::slice::Iter<'_, dict::rule::AfxRulePattern>, std::slice::Iter<'_, std::sync::Arc<morph::MorphInfo>>, [closure@zspell/src/dict/types.rs:72:31: 72:36]>, std::slice::Iter<'_, std::sync::Arc<morph::MorphInfo>>>`
              found enum `itertools::Either<_, std::iter::Empty<_>>`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `zspell` (lib) due to previous error

I expected to see this happen: no error

Version

rustc 1.74.0-nightly (b4e54c6e3 2023-09-11)
binary: rustc
commit-hash: b4e54c6e39984840a04dcd02d14ec8c3574d30e5
commit-date: 2023-09-11
host: x86_64-unknown-linux-gnu
release: 1.74.0-nightly
LLVM version: 17.0.0

Additional Labels

@rustbot label +I-suggestion-causes-error

J-ZhengLi commented 3 months ago

@rustbot claim