Skip to content

Commit

Permalink
change array and range promotion rule not to convert both containers (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson authored and ararslan committed Jul 24, 2017
1 parent fdc33b2 commit 04d76f3
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 20 deletions.
2 changes: 1 addition & 1 deletion base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ convert(::Type{Array{T,n}}, x::Array{T,n}) where {T,n} = x
convert(::Type{Array{T}}, x::AbstractArray{S,n}) where {T,n,S} = convert(Array{T,n}, x)
convert(::Type{Array{T,n}}, x::AbstractArray{S,n}) where {T,n,S} = copy!(Array{T,n}(size(x)), x)

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

## copying iterators to containers

Expand Down
51 changes: 32 additions & 19 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -763,65 +763,78 @@ end

/(x::Number, r::Range) = [ x/y for y=r ]

promote_rule(::Type{UnitRange{T1}},::Type{UnitRange{T2}}) where {T1,T2} =
UnitRange{promote_type(T1,T2)}
# 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{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) = typejoin(a, b)

promote_rule(a::Type{UnitRange{T1}}, b::Type{UnitRange{T2}}) where {T1,T2} =
el_same(promote_type(T1,T2), a, b)
convert(::Type{UnitRange{T}}, r::UnitRange{T}) where {T<:Real} = r
convert(::Type{UnitRange{T}}, r::UnitRange) where {T<:Real} = UnitRange{T}(r.start, r.stop)

promote_rule(::Type{OneTo{T1}},::Type{OneTo{T2}}) where {T1,T2} =
OneTo{promote_type(T1,T2)}
promote_rule(a::Type{OneTo{T1}}, b::Type{OneTo{T2}}) where {T1,T2} =
el_same(promote_type(T1,T2), a, b)
convert(::Type{OneTo{T}}, r::OneTo{T}) where {T<:Real} = r
convert(::Type{OneTo{T}}, r::OneTo) where {T<:Real} = OneTo{T}(r.stop)

promote_rule(::Type{UnitRange{T1}}, ::Type{UR}) where {T1,UR<:AbstractUnitRange} =
UnitRange{promote_type(T1,eltype(UR))}
promote_rule(a::Type{UnitRange{T1}}, ::Type{UR}) where {T1,UR<:AbstractUnitRange} =
promote_rule(a, UnitRange{eltype(UR)})
convert(::Type{UnitRange{T}}, r::AbstractUnitRange) where {T<:Real} = UnitRange{T}(first(r), last(r))
convert(::Type{UnitRange}, r::AbstractUnitRange) = UnitRange(first(r), last(r))

convert(::Type{AbstractUnitRange{T}}, r::AbstractUnitRange{T}) where {T} = r
convert(::Type{AbstractUnitRange{T}}, r::UnitRange) where {T} = convert(UnitRange{T}, r)
convert(::Type{AbstractUnitRange{T}}, r::OneTo) where {T} = convert(OneTo{T}, r)

promote_rule(::Type{StepRange{T1a,T1b}},::Type{StepRange{T2a,T2b}}) where {T1a,T1b,T2a,T2b} =
StepRange{promote_type(T1a,T2a),promote_type(T1b,T2b)}
promote_rule(::Type{StepRange{T1a,T1b}}, ::Type{StepRange{T2a,T2b}}) where {T1a,T1b,T2a,T2b} =
el_same(promote_type(T1a,T2a),
# el_same only operates on array element type, so just promote second type parameter
StepRange{T1a, promote_type(T1b,T2b)},
StepRange{T2a, promote_type(T1b,T2b)})
convert(::Type{StepRange{T1,T2}}, r::StepRange{T1,T2}) where {T1,T2} = r

promote_rule(::Type{StepRange{T1a,T1b}},::Type{UR}) where {T1a,T1b,UR<:AbstractUnitRange} =
StepRange{promote_type(T1a,eltype(UR)),promote_type(T1b,eltype(UR))}
promote_rule(a::Type{StepRange{T1a,T1b}}, ::Type{UR}) where {T1a,T1b,UR<:AbstractUnitRange} =
promote_rule(a, StepRange{eltype(UR), eltype(UR)})
convert(::Type{StepRange{T1,T2}}, r::Range) where {T1,T2} =
StepRange{T1,T2}(convert(T1, first(r)), convert(T2, step(r)), convert(T1, last(r)))
convert(::Type{StepRange}, r::AbstractUnitRange{T}) where {T} =
StepRange{T,T}(first(r), step(r), last(r))
convert(::Type{StepRange{T1,T2} where T1}, r::Range) where {T2} =
convert(StepRange{eltype(r),T2}, r)

promote_rule(::Type{StepRangeLen{T1,R1,S1}},::Type{StepRangeLen{T2,R2,S2}}) where {T1,T2,R1,R2,S1,S2} =
StepRangeLen{promote_type(T1,T2), promote_type(R1,R2), promote_type(S1,S2)}
el_same(promote_type(T1,T2),
StepRangeLen{T1,promote_type(R1,R2),promote_type(S1,S2)},
StepRangeLen{T2,promote_type(R1,R2),promote_type(S1,S2)})
convert(::Type{StepRangeLen{T,R,S}}, r::StepRangeLen{T,R,S}) where {T,R,S} = r
convert(::Type{StepRangeLen{T,R,S}}, r::StepRangeLen) where {T,R,S} =
StepRangeLen{T,R,S}(convert(R, r.ref), convert(S, r.step), length(r), r.offset)
convert(::Type{StepRangeLen{T}}, r::StepRangeLen) where {T} =
StepRangeLen(convert(T, r.ref), convert(T, r.step), length(r), r.offset)

promote_rule(::Type{StepRangeLen{T,R,S}}, ::Type{OR}) where {T,R,S,OR<:Range} =
StepRangeLen{promote_type(T,eltype(OR)),promote_type(R,eltype(OR)),promote_type(S,eltype(OR))}
promote_rule(a::Type{StepRangeLen{T,R,S}}, ::Type{OR}) where {T,R,S,OR<:Range} =
promote_rule(a, StepRangeLen{eltype(OR), eltype(OR), eltype(OR)})
convert(::Type{StepRangeLen{T,R,S}}, r::Range) where {T,R,S} =
StepRangeLen{T,R,S}(R(first(r)), S(step(r)), length(r))
convert(::Type{StepRangeLen{T}}, r::Range) where {T} =
StepRangeLen(T(first(r)), T(step(r)), length(r))
convert(::Type{StepRangeLen}, r::Range) = convert(StepRangeLen{eltype(r)}, r)

promote_rule(::Type{LinSpace{T1}},::Type{LinSpace{T2}}) where {T1,T2} =
LinSpace{promote_type(T1,T2)}
promote_rule(a::Type{LinSpace{T1}}, b::Type{LinSpace{T2}}) where {T1,T2} =
el_same(promote_type(T1,T2), a, b)
convert(::Type{LinSpace{T}}, r::LinSpace{T}) where {T} = r
convert(::Type{LinSpace{T}}, r::Range) where {T} =
LinSpace{T}(first(r), last(r), length(r))
convert(::Type{LinSpace}, r::Range{T}) where {T} =
convert(LinSpace{T}, r)

promote_rule(::Type{LinSpace{T}}, ::Type{OR}) where {T,OR<:OrdinalRange} =
LinSpace{promote_type(T,eltype(OR))}
promote_rule(a::Type{LinSpace{T}}, ::Type{OR}) where {T,OR<:OrdinalRange} =
promote_rule(a, LinSpace{eltype(OR)})

promote_rule(::Type{LinSpace{L}}, ::Type{StepRangeLen{T,R,S}}) where {L,T,R,S} =
StepRangeLen{promote_type(L,T),promote_type(L,R),promote_type(L,S)}
promote_rule(::Type{LinSpace{L}}, b::Type{StepRangeLen{T,R,S}}) where {L,T,R,S} =
promote_rule(StepRangeLen{L,L,L}, b)

# +/- of ranges is defined in operators.jl (to be able to use @eval etc.)

Expand Down
7 changes: 7 additions & 0 deletions test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2177,3 +2177,10 @@ let TT = Union{UInt8, Int8}
@test a[1] == b[1] == 0x0
@test a == b
end

let a = Vector{Int}[[1]],
b = Vector{Float64}[[2.0]],
c = Vector{Char}[['a']]
@test eltype([a;b]) == Vector{Float64}
@test eltype([a;c]) == Vector
end
3 changes: 3 additions & 0 deletions test/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,9 @@ end
@test convert(LinSpace, 0.0:0.1:0.3) === LinSpace{Float64}(0.0, 0.3, 4)
@test convert(LinSpace, 0:3) === LinSpace{Int}(0, 3, 4)

@test promote('a':'z', 1:2) === ('a':'z', 1:1:2)
@test eltype(['a':'z', 1:2]) == (StepRange{T,Int} where T)

@test start(LinSpace(0,3,4)) == 1
@test 2*LinSpace(0,3,4) == LinSpace(0,6,4)
@test LinSpace(0,3,4)*2 == LinSpace(0,6,4)
Expand Down

0 comments on commit 04d76f3

Please sign in to comment.