From d8a08e7f8808736eab0db6fb93cd2197226f5c0a Mon Sep 17 00:00:00 2001 From: Nicolau Leal Werneck Date: Tue, 12 Jul 2022 23:53:07 +0200 Subject: [PATCH 1/2] dealing with empty reshapes --- base/reshapedarray.jl | 18 +++++++++++++++++- test/abstractarray.jl | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index 4037aff246a81..ec6607003c294 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -125,7 +125,13 @@ reshape(parent::AbstractArray, dims::Tuple{Vararg{Union{Int,Colon}}}) = reshape( pre = _before_colon(dims...) post = _after_colon(dims...) _any_colon(post...) && throw1(dims) - sz, remainder = divrem(length(A), prod(pre)*prod(post)) + sz, remainder = if _all_zero(size(A)...) && (_any_zero(pre...) || _any_zero(post...)) + (0, 0) + elseif _any_zero(size(A)...) && (_any_zero(pre...) || _any_zero(post...)) + divrem(prod(_remove_zeros(size(A)...)), prod(_remove_zeros(pre...))*prod(_remove_zeros(post...))) + else + divrem(length(A), prod(pre)*prod(post)) + end remainder == 0 || throw2(A, dims) (pre..., Int(sz), post...) end @@ -136,6 +142,16 @@ end @inline _before_colon(dim::Colon, tail...) = () @inline _after_colon(dim::Any, tail...) = _after_colon(tail...) @inline _after_colon(dim::Colon, tail...) = tail +@inline _any_zero() = false +@inline _any_zero(head::Any, tail...) = iszero(head) || _any_zero(tail...) +@inline _all_zero() = false +@inline _all_zero(head::Any, tail...) = iszero(head) && _any_zero(tail...) +@inline _remove_zeros(dim::Any, tail...) = if iszero(dim) + _remove_zeros(tail...) +else + (dim, _remove_zeros(tail...)...) +end +@inline _remove_zeros() = () reshape(parent::AbstractArray{T,N}, ndims::Val{N}) where {T,N} = parent function reshape(parent::AbstractArray, ndims::Val{N}) where N diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 88156e499616c..761effc888f43 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -1649,3 +1649,17 @@ end @test (@inferred A[i,i,i]) === A[1] @test (@inferred to_indices([], (1, CIdx(1, 1), 1, CIdx(1, 1), 1, CIdx(1, 1), 1))) == ntuple(Returns(1), 10) end + +@testset "reshape inference for empty arrays preserves size of non-empty dimensions (issue #45589)" begin + @test size(reshape(zeros(0,2), :)) == (0,) + @test size(reshape(zeros(0,2), 0,:)) == (0,2) + @test size(reshape(zeros(0,0,0), 0,:,0)) == (0,0,0) + @test size(reshape(zeros(0,0,0), 0,:,1)) == (0,0,1) + @test size(reshape(zeros(0,0,0), 0,:,1111)) == (0,0,1111) + @test size(reshape(zeros(0,2,3), 0,:)) == (0,6) + @test size(reshape(zeros(0,2,3), 0,:,2)) == (0,3,2) + @test size(reshape(zeros(0,2,3), 3,:,2)) == (3,0,2) + @test size(reshape(zeros(0,2,3), 0,:,6)) == (0,1,6) + @test size(reshape(zeros(0,2,3), 1,:,6)) == (1,0,6) + @test size(reshape(zeros(0,2,3), 1,:,3)) == (1,0,3) +end From d30ce47791df6a0188c8918bca7c06bdfcaeeccc Mon Sep 17 00:00:00 2001 From: Nicolau Leal Werneck Date: Wed, 13 Jul 2022 09:48:36 +0200 Subject: [PATCH 2/2] empty input should completely disable the shape test --- base/reshapedarray.jl | 2 +- test/abstractarray.jl | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index ec6607003c294..6636583e7679c 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -132,7 +132,7 @@ reshape(parent::AbstractArray, dims::Tuple{Vararg{Union{Int,Colon}}}) = reshape( else divrem(length(A), prod(pre)*prod(post)) end - remainder == 0 || throw2(A, dims) + length(A) == 0 || remainder == 0 || throw2(A, dims) (pre..., Int(sz), post...) end @inline _any_colon() = false diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 761effc888f43..95f3385636170 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -1650,16 +1650,27 @@ end @test (@inferred to_indices([], (1, CIdx(1, 1), 1, CIdx(1, 1), 1, CIdx(1, 1), 1))) == ntuple(Returns(1), 10) end -@testset "reshape inference for empty arrays preserves size of non-empty dimensions (issue #45589)" begin +@testset "reshape inference for empty arrays does not fail, and attempts to preserve size of non-empty dimensions (issue #45589)" begin @test size(reshape(zeros(0,2), :)) == (0,) @test size(reshape(zeros(0,2), 0,:)) == (0,2) + @test size(reshape(zeros(0,2), 1,:)) == (1,0) + @test size(reshape(zeros(0,2), 2,:)) == (2,0) + @test size(reshape(zeros(0,2), 3,:)) == (3,0) @test size(reshape(zeros(0,0,0), 0,:,0)) == (0,0,0) @test size(reshape(zeros(0,0,0), 0,:,1)) == (0,0,1) @test size(reshape(zeros(0,0,0), 0,:,1111)) == (0,0,1111) @test size(reshape(zeros(0,2,3), 0,:)) == (0,6) + @test size(reshape(zeros(0,2,3), 5,:)) == (5,0) + @test size(reshape(zeros(0,2,3), 6,:)) == (6,0) + @test size(reshape(zeros(0,2,3), 7,:)) == (7,0) @test size(reshape(zeros(0,2,3), 0,:,2)) == (0,3,2) - @test size(reshape(zeros(0,2,3), 3,:,2)) == (3,0,2) + @test size(reshape(zeros(0,2,3), 0,:,3)) == (0,2,3) + @test size(reshape(zeros(0,2,3), 0,:,5)) == (0,1,5) @test size(reshape(zeros(0,2,3), 0,:,6)) == (0,1,6) - @test size(reshape(zeros(0,2,3), 1,:,6)) == (1,0,6) + @test size(reshape(zeros(0,2,3), 0,:,7)) == (0,0,7) @test size(reshape(zeros(0,2,3), 1,:,3)) == (1,0,3) + @test size(reshape(zeros(0,2,3), 1,:,5)) == (1,0,5) + @test size(reshape(zeros(0,2,3), 1,:,6)) == (1,0,6) + @test size(reshape(zeros(0,2,3), 1,:,7)) == (1,0,7) + @test size(reshape(zeros(0,2,3), 3,:,2)) == (3,0,2) end