Skip to content

Unable to call reverse on a Zip Iterator zipping a std::iter::Repeat #104729

Open
@IceTDrinker

Description

Hello, first off sorry if this is not the right issue type, but I could not choose one that seemed to better fit. I tried to search in existing issues with "zip repeat rev" and nothing came up in GitHub. I don't know if it qualifies as a bug, but at least the behavior feels highly unintuitive.

I tried this code:

fn main() {
    let vec_1 = vec![1; 10];
    
    let zipped_iter = vec_1.iter().zip( std::iter::repeat(0));
    
    println!("Forward");
    
    for (one, zero) in zipped_iter {
        println!("one: {one}, zero: {zero}");
    }
    
    let rev_vec_iter = vec_1.iter().rev();
    let rev_repeat_iter = std::iter::repeat(0).rev();
    
    // Manual reversed zip
    let rev_zipped_iter = rev_vec_iter.zip(rev_repeat_iter);
    
    println!("Backwards");
    
    for (one, zero) in rev_zipped_iter {
        println!("one: {one}, zero: {zero}");
    }
    
    println!("Now it gets tricky");
    
    // This is illegal with the current next_back implementation of Zip
    // Which requires ExactSizeIterator, which is not implemented by
    // std::iter::repeat, so won't compile
    
    let zipped_iter = vec_1.iter().zip( std::iter::repeat(0));
    
    // Cannot call rev here for automatic reversed zip constuction
    for (one, zero) in zipped_iter.rev() {
        println!("one: {one}, zero: {zero}");
    }
}

Rust playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=967385983c0fb72c27183385720fea8e

I expected to see this happen: the last iterator construction reversing the Zip iterator works the same as if I zipped two reverse iterator.

Instead, this happened: code does not compile because next_back implementation from Zip (ZipImpl::next_back) has ExactSizeIterator bounds for both iterator being zipped. std::iter::Repeat does not implement that trait. I'm not familiar with Zip internals or iterator internals but it seems it has to do with zip_impl_general_defaults which states:

        #[inline]
        default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
        where
            A: DoubleEndedIterator + ExactSizeIterator,
            B: DoubleEndedIterator + ExactSizeIterator,
        {
            // The function body below only uses `self.a/b.len()` and `self.a/b.next_back()`
            // and doesn’t call `next_back` too often, so this implementation is safe in
            // the `TrustedRandomAccessNoCoerce` specialization

Fails for all rustc versions in playground at the moment

image

Meta

rustc --version --verbose:

rustc --version --verbose
rustc 1.65.0 (897e37553 2022-11-02)
binary: rustc
commit-hash: 897e37553bba8b42751c67658967889d11ecd120
commit-date: 2022-11-02
host: x86_64-unknown-linux-gnu
release: 1.65.0
LLVM version: 15.0.0
Backtrace

Compiling playground v0.0.1 (/playground)
error[[E0277]](https://doc.rust-lang.org/stable/error-index.html#E0277): the trait bound `std::iter::Repeat<{integer}>: ExactSizeIterator` is not satisfied
  --> src/main.rs:33:24
   |
33 |     for (one, zero) in zipped_iter.rev() {
   |                        ^^^^^^^^^^^ --- required by a bound introduced by this call
   |                        |
   |                        the trait `ExactSizeIterator` is not implemented for `std::iter::Repeat<{integer}>`
   |
   = help: the following other types implement trait `ExactSizeIterator`:
             &mut I
             Args
             ArgsOs
             ArrayChunksMut<'_, T, N>
             ArrayWindows<'_, T, N>
             Box<I, A>
             Chunks<'_, T>
             ChunksExact<'_, T>
           and 108 others
   = note: required for `Zip<std::slice::Iter<'_, {integer}>, std::iter::Repeat<{integer}>>` to implement `DoubleEndedIterator`
note: required by a bound in `rev`

error[[E0277]](https://doc.rust-lang.org/stable/error-index.html#E0277): the trait bound `std::iter::Repeat<{integer}>: ExactSizeIterator` is not satisfied
  --> src/main.rs:33:24
   |
33 |     for (one, zero) in zipped_iter.rev() {
   |                        ^^^^^^^^^^^^^^^^^ the trait `ExactSizeIterator` is not implemented for `std::iter::Repeat<{integer}>`
   |
   = help: the following other types implement trait `ExactSizeIterator`:
             &mut I
             Args
             ArgsOs
             ArrayChunksMut<'_, T, N>
             ArrayWindows<'_, T, N>
             Box<I, A>
             Chunks<'_, T>
             ChunksExact<'_, T>
           and 108 others
   = note: required for `Zip<std::slice::Iter<'_, {integer}>, std::iter::Repeat<{integer}>>` to implement `DoubleEndedIterator`
   = note: required for `Rev<Zip<std::slice::Iter<'_, {integer}>, std::iter::Repeat<{integer}>>>` to implement `Iterator`
   = note: required for `Rev<Zip<std::slice::Iter<'_, {integer}>, std::iter::Repeat<{integer}>>>` to implement `IntoIterator`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to 2 previous errors

Metadata

Assignees

No one assigned

    Labels

    A-iteratorsArea: IteratorsC-enhancementCategory: An issue proposing an enhancement or a PR with one.T-libs-apiRelevant to the library API 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