diff --git a/base/iterators.jl b/base/iterators.jl index 11e94d3384de8..9f6f8ae40c5dc 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -387,6 +387,16 @@ function _zip_min_length(is) end end _zip_min_length(is::Tuple{}) = nothing +function _zip_lengths_finite_equal(is) + i = is[1] + b, n = _zip_lengths_finite_equal(tail(is)) + if IteratorSize(i) isa Union{IsInfinite, SizeUnknown} + return (false, nothing) + else + return (b && (n === nothing || n == length(i)), length(i)) + end +end +_zip_lengths_finite_equal(is::Tuple{}) = (true, nothing) size(z::Zip) = _promote_tuple_shape(Base.map(size, z.is)...) axes(z::Zip) = _promote_tuple_shape(Base.map(axes, z.is)...) _promote_tuple_shape((a,)::Tuple{OneTo}, (b,)::Tuple{OneTo}) = (intersect(a, b),) @@ -468,8 +478,13 @@ zip_iteratoreltype() = HasEltype() zip_iteratoreltype(a) = a zip_iteratoreltype(a, tail...) = and_iteratoreltype(a, zip_iteratoreltype(tail...)) -reverse(z::Zip) = Zip(Base.map(reverse, z.is)) # n.b. we assume all iterators are the same length last(z::Zip) = getindex.(z.is, minimum(Base.map(lastindex, z.is))) +function reverse(z::Zip) + if !first(_zip_lengths_finite_equal(z.is)) + throw(ArgumentError("Zipped iterators of unknown, infinite, or unequal lengths must be collected before reversing")) + end + Zip(Base.map(reverse, z.is)) +end # filter diff --git a/test/iterators.jl b/test/iterators.jl index 59588bdac9684..5f74f47a749fc 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -11,6 +11,10 @@ using Dates: Date, Day # issue #4718 @test collect(Iterators.filter(x->x[1], zip([true, false, true, false],"abcd"))) == [(true,'a'),(true,'c')] +# issue #45085 +@test_throws ArgumentError Iterators.reverse(zip("abc", "abcd")) +@test_throws ArgumentError Iterators.reverse(zip("abc", Iterators.cycle("ab"))) + let z = zip(1:2) @test size(z) == (2,) @test collect(z) == [(1,), (2,)]