diff --git a/base/array.jl b/base/array.jl index bd5cda891903a..d88aac162d9f1 100644 --- a/base/array.jl +++ b/base/array.jl @@ -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 diff --git a/base/range.jl b/base/range.jl index 1f3e104655f95..381efd9ea5f2f 100644 --- a/base/range.jl +++ b/base/range.jl @@ -763,18 +763,24 @@ 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)) @@ -782,46 +788,53 @@ 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.) diff --git a/test/arrayops.jl b/test/arrayops.jl index 66715a1bd3308..ceee283cf2fe3 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -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 diff --git a/test/ranges.jl b/test/ranges.jl index 47c33807e7dcf..fa54567a6e563 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -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)