julia> promote_type(Float64, Rational{Int})
Float64
julia> promote_type(Float64, Complex{Rational{Int}})
ComplexF64 (alias for Complex{Float64})
julia> promote_type(Float64, ComplexF64)
ComplexF64 (alias for Complex{Float64})

what I’d expect from promote_type(Float64, Union{Complex{Rational{Int}},Rational{Int}}) is either ComplexF64 (by expanding the union) or Union{ComplexF64,Float64} (by distribution rule). However, Julia gives Number which means it’s trying to find a shared supertype. Why doesn’t Julia implement the two rules that I expect?

NOT RECOMMENDED BECAUSE THIS USES INTERNALS but here it is anyway:

julia> Base.promote_union(Union{Float64, Union{Complex{Rational{Int}}, Rational{Int}}})
ComplexF64 (alias for Complex{Float64})

Note that I had to wrap everything in an additional Union to make this work. I’ll recommend you take a peek at the implementation. All it does is recurse on any unions and promote_type when it reaches a pair of non-unions, so you could roll your own version if you wanted to.

A problem is that the a and b fields of a Union object are again not public API. It seems like there should be some supported way of doing this, though. I made an issue/feature request on Julia’s Github: