Skip to content

Commit

Permalink
implement promote for BitArray
Browse files Browse the repository at this point in the history
Defines a fallback promote_result for any AbstractArray, for the case
when specific promote_rules are not defined for the specific array type.

Fix #43551
Co-authored-by: Jakob Sachs <[email protected]>
  • Loading branch information
vtjnash committed Feb 13, 2022
1 parent befe38f commit 88d9741
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 12 deletions.
2 changes: 1 addition & 1 deletion base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
convert(::Type{T}, a::AbstractArray) where {T<:Array} = a isa T ? a : T(a)
convert(::Type{Union{}}, a::AbstractArray) = throw(MethodError(convert, (Union{}, a)))

promote_rule(a::Type{Array{T,n}}, b::Type{Array{S,n}}) where {T,n,S} = el_same(promote_type(T,S), a, b)
promote_rule(a::Type{<:Array{T,n}}, b::Type{<:Array{S,n}}) where {T,n,S} = el_same(promote_type(T, S), a, b)

## Constructors ##

Expand Down
4 changes: 2 additions & 2 deletions base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,9 @@ it for new types as appropriate.
"""
function promote_rule end

promote_rule(::Type{<:Any}, ::Type{<:Any}) = Bottom
promote_rule(::Type, ::Type) = Bottom

promote_result(::Type{<:Any},::Type{<:Any},::Type{T},::Type{S}) where {T,S} = (@inline; promote_type(T,S))
promote_result(::Type,::Type,::Type{T},::Type{S}) where {T,S} = (@inline; promote_type(T,S))
# If no promote_rule is defined, both directions give Bottom. In that
# case use typejoin on the original types instead.
promote_result(::Type{T},::Type{S},::Type{Bottom},::Type{Bottom}) where {T,S} = (@inline; typejoin(T, S))
Expand Down
8 changes: 6 additions & 2 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1263,13 +1263,17 @@ function -(r::LinRange)
LinRange{typeof(start)}(start, -r.stop, length(r))
end


# promote eltype if at least one container wouldn't change, otherwise join container types.
el_same(::Type{T}, a::Type{<:AbstractArray{T,n}}, b::Type{<:AbstractArray{T,n}}) where {T,n} = a
el_same(::Type{T}, a::Type{<:AbstractArray{T,n}}, b::Type{<:AbstractArray{T,n}}) where {T,n} = a # we assume a === b
el_same(::Type{T}, a::Type{<:AbstractArray{T,n}}, b::Type{<:AbstractArray{S,n}}) where {T,S,n} = a
el_same(::Type{T}, a::Type{<:AbstractArray{S,n}}, b::Type{<:AbstractArray{T,n}}) where {T,S,n} = b
el_same(::Type, a, b) = promote_typejoin(a, b)

promote_result(::Type{<:AbstractArray}, ::Type{<:AbstractArray}, ::Type{T}, ::Type{S}) where {T,S} = (@inline; promote_type(T,S))
promote_result(::Type{T}, ::Type{S}, ::Type{Bottom}, ::Type{Bottom}) where {T<:AbstractArray,S<:AbstractArray} = (@inline; promote_typejoin(T,S))
# If no promote_rule is defined, both directions give Bottom. In that case use typejoin on the eltypes instead and give Array as the container.
promote_result(::Type{<:AbstractArray{T,n}}, ::Type{<:AbstractArray{S,n}}, ::Type{Bottom}, ::Type{Bottom}) where {T,S,n} = (@inline; Array{promote_type(T,S),n})

promote_rule(a::Type{UnitRange{T1}}, b::Type{UnitRange{T2}}) where {T1,T2} =
el_same(promote_type(T1, T2), a, b)
UnitRange{T}(r::UnitRange{T}) where {T<:Real} = r
Expand Down
16 changes: 15 additions & 1 deletion test/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,20 @@ end

timesofar("conversions")

@testset "Promotions for size $sz" for (sz, T) in allsizes
@test isequal(promote(falses(sz...), zeros(sz...)),
(zeros(sz...), zeros(sz...)))
@test isequal(promote(trues(sz...), ones(sz...)),
(ones(sz...), ones(sz...)))
ae = falses(1, sz...)
ex = (@test_throws ErrorException promote(ae, ones(sz...))).value
@test startswith(ex.msg, "promotion of types Bit")
ex = (@test_throws ErrorException promote(ae, falses(sz...))).value
@test startswith(ex.msg, "promotion of types Bit")
end

timesofar("promotions")

@testset "utility functions" begin
b1 = bitrand(v1)
@test isequal(fill!(b1, true), trues(size(b1)))
Expand Down Expand Up @@ -1767,4 +1781,4 @@ end
@test all(bitarray[rangeout, rangein] .== true)
@test all(bitarray[rangein, rangeout] .== true)
end
end
end
15 changes: 9 additions & 6 deletions test/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -691,16 +691,19 @@ end
@test a == [1 1; 2 2; 3 3]
end

@testset "scalar .=" begin
A = [[1,2,3],4:5,6]
@testset "scalar .= and promotion" begin
A = [[1, 2, 3], 4:5, 6]
@test A isa Vector{Any}
A[1] .= 0
@test A[1] == [0,0,0]
@test A[1] == [0, 0, 0]
@test_throws Base.CanonicalIndexError A[2] .= 0
@test_throws MethodError A[3] .= 0
A = [[1,2,3],4:5]
A = [[1, 2, 3], 4:5]
@test A isa Vector{Vector{Int64}}
A[1] .= 0
@test A[1] == [0,0,0]
@test_throws Base.CanonicalIndexError A[2] .= 0
A[2] .= 0
@test A[1] == [0, 0, 0]
@test A[2] == [0, 0]
end

# Issue #22180
Expand Down

0 comments on commit 88d9741

Please sign in to comment.