Skip to content
10 changes: 7 additions & 3 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2196,8 +2196,11 @@ function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
# into the destination
nd = N
Ndim = 0
for a ∈ as
for i ∈ eachindex(as)
a = as[i]
if a isa AbstractArray
length(a) > 0 ||
throw(ArgumentError("element $i has no elements"))
cat_size(a, N) == length(a) ||
throw(ArgumentError("all dimensions of elements other than $N must be of length 1"))
nd = max(nd, cat_ndims(a))
Expand Down Expand Up @@ -2299,8 +2302,9 @@ function _typed_hvncat(::Type{T}, shape::Tuple{Vararg{Tuple, N}}, row_first::Boo
shapepos = ones(Int, nd)

for i ∈ eachindex(as)
length(as[i]) > 0 || throw(ArgumentError("argument $i has no elements"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why this is a special case, i.e. why isn't it covered by the other check that the number of elements matches?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example [zeros(1,2,0);;;7 8] doesn't need to be an error.

Copy link
Contributor Author

@BioTurboNick BioTurboNick Jun 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The former check is the length of as; this is the length of each element. Though I should probably be using cat_length here in case any of them are strings.

But you're right. This is a crude check. The dimension calculating algorithm right now just can't handle arrays with a zero dimension. e.g. [zeros(1, 0);;;7 8] creates an underfilled array. Seems better to make them error for now until I can address that.

wasstartblock = false
for d ∈ 1:N
for d ∈ 1:nd
ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
dsize = cat_size(as[i], ad)
blockcounts[d] += 1
Expand All @@ -2313,7 +2317,7 @@ function _typed_hvncat(::Type{T}, shape::Tuple{Vararg{Tuple, N}}, row_first::Boo

wasstartblock = blockcounts[d] == 1 # remember for next dimension

isendblock = blockcounts[d] == shape[d][shapepos[d]]
isendblock = blockcounts[d] == shape[min(end, d)][shapepos[d]]
if isendblock
if outdims[d] == 0
outdims[d] = currentdims[d]
Expand Down
31 changes: 30 additions & 1 deletion test/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1389,7 +1389,36 @@ end
@test [v v;;; fill(v, 1, 2)] == fill(v, 1, 2, 2)
end

@test_throws BoundsError hvncat(((1, 2), (3,)), false, zeros(Int, 0, 0, 0), 7, 8)
# ensure that a shape with greater dimensionality than the concatenation expression is supported #41047
x = [1 2 ; 3 4 ;;;; 5 6 ; 7 8]
y = [x x]
@test [x x ;;; y] == [y ;;; x x]

# zero-length arrays as arguments aren't supported #41047
@test_throws ArgumentError hvncat(((1, 2), (3,)), false, zeros(Int, 0, 0, 0), 7, 8)
@test_throws ArgumentError hvncat(((1, 2), (3,)), false, zeros(Int, 0), 7, 8)

#41047 - ensure zero-length arrays do not cause a segfault
for v in (fill(1, 0), fill(1, 0, 0), fill(1, 0, 0, 0), fill(1, 0, 0, 0))
@test_throws ArgumentError [v ;; 1]
@test_throws ArgumentError [v ;;; 1]
@test_throws ArgumentError [v ;;;; 1]
@test_throws ArgumentError [1 ;; v]
@test_throws ArgumentError [1 ;;; v]
@test_throws ArgumentError [1 ;;;; v]
@test_throws ArgumentError [v ;; 1; 2]
@test_throws ArgumentError [v ;;; 1 2]
@test_throws ArgumentError [v ;;; 1;; 2]
@test_throws ArgumentError [v ;;;; 1;; 2]
@test_throws ArgumentError [1; 2 ;; v]
@test_throws ArgumentError [1 2 ;;; v]
@test_throws ArgumentError [1;; 2 ;;; v]
@test_throws ArgumentError [1;; 2 ;;;; v]
@test_throws ArgumentError [v; v;; 1; 2]
@test_throws ArgumentError [v v;;; 1 2]
@test_throws ArgumentError [v;; v;;; 1;; 2]
@test_throws ArgumentError [v;; v ;;;; 1;; 2]
end
end

@testset "keepat!" begin
Expand Down