Skip to content

Random access impl of Take::for_each/Take::fold suppresses side effects of next call on empty iterator #161350

Description

@maxdexh

I tried this code:

use std::fmt::Debug;

fn main() {
    eprintln!("does_print:");
    consume(does_print());
    eprintln!("does_not_print:");
    consume(does_not_print());
}

fn does_not_print() -> impl Iterator<Item: Debug> {
    [1, 2, 3].iter()
}
fn does_print() -> impl Iterator<Item: Debug> {
    [1, 2, 3].iter().filter(|_| true) // use any noop adapter without `TrustedRandomAccessNoCoerce` here
}

fn consume(iter: impl Iterator<Item: Debug>) {
    // the skip covers all the elements, meaning `take` is called on an empty iterator
    iter.map(|it| dbg!(it)).skip(3).take(100).for_each(|_| {});
}

I expected to see this happen:

Either both iterations print, or neither does, since the only difference is that one iterator is being adapted with filter(true), which is a noop.

Instead, this happened:

does_print:
[src/main.rs:11:19] it = 1
[src/main.rs:11:19] it = 2
[src/main.rs:11:19] it = 3
does_not_print:

@rustbot label A-iterators T-libs

Metadata

Metadata

Assignees

Labels

A-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsA-iteratorsArea: IteratorsC-bugCategory: This is a bug.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions