Skip to content

into_iter_without_iter warns when code blocks are in particular order #12964

@ijijn

Description

@ijijn

Summary

A bit of a weird one this time... 😅

Clippy is behaving differently in essentially equivalent code, warning or not warning with into_iter_without_iter depending on where the iter impl is located relative to other impl blocks for the affected type: specifically, whether it resides in the first available block or not. Blocks for other types don't seem to affect this, happily, but even an empty impl block makes a difference, as shown below. This only started happening recently, perhaps a week or two ago.

Lint Name

into_iter_without_iter

Reproducer

I tried this code (main.rs):

#![warn(clippy::pedantic)]

pub struct MyIter<'a, T: 'a> {
    iter: std::slice::Iter<'a, T>,
}

impl<'a, T> Iterator for MyIter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

pub struct MyContainer<T> {
    inner: Vec<T>,
}

// after commenting out this empty block, or moving it below the `iter` impl, the lint doesn't trigger
// Clippy only seems to look at the first relevant block in this instance, even when such a block is constrained,
// e.g. `where T: Default`
impl<T> MyContainer<T> {}

impl<T> MyContainer<T> {
    #[must_use]
    pub fn iter(&self) -> MyIter<'_, T> {
        <&Self as IntoIterator>::into_iter(self)
    }
}

// `clippy::into_iter_without_iter` warns about this
impl<'a, T> IntoIterator for &'a MyContainer<T> {
    type Item = &'a T;

    type IntoIter = MyIter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        Self::IntoIter {
            iter: self.inner.as_slice().iter(),
        }
    }
}

pub fn main() {
    let mut container = MyContainer { inner: Vec::new() };
    container.inner.push(42);
    for item in &container {
        dbg!(item);
    }
}

I saw this happen:

warning: `IntoIterator` implemented for a reference type without an `iter` method
  --> src/main.rs:32:1
   |
32 | / impl<'a, T> IntoIterator for &'a MyContainer<T> {
33 | |     type Item = &'a T;
34 | |
35 | |     type IntoIter = MyIter<'a, T>;
...  |
41 | |     }
42 | | }
   | |_^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter
note: the lint level is defined here
  --> src/main.rs:1:9
   |
1  | #![warn(clippy::pedantic)]
   |         ^^^^^^^^^^^^^^^^
   = note: `#[warn(clippy::into_iter_without_iter)]` implied by `#[warn(clippy::pedantic)]`
help: consider implementing `iter`
   |
32 +
33 + impl MyContainer<T> {
34 +     fn iter(&self) -> MyIter<'a, T> {
35 +         <&Self as IntoIterator>::into_iter(self)
36 +     }
37 + }
   |

I expected to see this happen:

No warnings, as when the code is modified as mentioned above in the comments.

Version

rustc 1.81.0-nightly (8fcd4dd08 2024-06-18)
binary: rustc
commit-hash: 8fcd4dd08e2ba3e922d917d819ba0be066bdb005
commit-date: 2024-06-18
host: x86_64-pc-windows-msvc
release: 1.81.0-nightly
LLVM version: 18.1.7

Additional Labels

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: Clippy is not doing the correct thingI-false-positiveIssue: The lint was triggered on code it shouldn't have

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions