diff --git a/base/array.jl b/base/array.jl index 9e8da6c384ba0..f126c9984e520 100644 --- a/base/array.jl +++ b/base/array.jl @@ -656,6 +656,14 @@ function collect_to_with_first!(dest, v1, itr, st) return grow_to!(dest, itr, st) end +function setindex_widen_up_to(dest::AbstractArray{T}, el, i) where T + @_inline_meta + new = similar(dest, promote_typejoin(T, typeof(el))) + copyto!(new, firstindex(new), dest, firstindex(dest), i-1) + @inbounds new[i] = el + return new +end + function collect_to!(dest::AbstractArray{T}, itr, offs, st) where T # collect to dest array, checking the type of each result. if a result does not # match, widen the result type and re-dispatch. @@ -668,10 +676,7 @@ function collect_to!(dest::AbstractArray{T}, itr, offs, st) where T @inbounds dest[i] = el::T i += 1 else - R = promote_typejoin(T, typeof(el)) - new = similar(dest, R) - copyto!(new,1, dest,1, i-1) - @inbounds new[i] = el + new = setindex_widen_up_to(dest, el, i) return collect_to!(new, itr, i+1, st) end end @@ -686,6 +691,19 @@ function grow_to!(dest, itr) grow_to!(dest2, itr, y[2]) end +function push_widen(dest, el) + @_inline_meta + new = sizehint!(empty(dest, promote_typejoin(eltype(dest), typeof(el))), length(dest)) + if new isa AbstractSet + # TODO: merge back these two branches when copy! is re-enabled for sets/vectors + union!(new, dest) + else + append!(new, dest) + end + push!(new, el) + return new +end + function grow_to!(dest, itr, st) T = eltype(dest) y = iterate(itr, st) @@ -695,14 +713,7 @@ function grow_to!(dest, itr, st) if S === T || S <: T push!(dest, el::T) else - new = sizehint!(empty(dest, promote_typejoin(T, S)), length(dest)) - if new isa AbstractSet - # TODO: merge back these two branches when copy! is re-enabled for sets/vectors - union!(new, dest) - else - append!(new, dest) - end - push!(new, el) + new = push_widen(dest, el) return grow_to!(new, itr, st) end y = iterate(itr, st)