## type join (closest common ancestor, or least upper bound) ## typejoin() = None typejoin(t::ANY) = t typejoin(t::ANY, ts...) = typejoin(t, typejoin(ts...)) function typejoin(a::ANY, b::ANY) if isa(a,TypeConstructor); a = a.body; end if isa(b,TypeConstructor); b = b.body; end if a <: b return b elseif b <: a return a end if isa(a,TypeVar) return typejoin(a.ub, b) end if isa(b,TypeVar) return typejoin(a, b.ub) end if isa(a,UnionType) || isa(b,UnionType) u = Union(a, b) if !isa(u,UnionType) return u end return reduce(typejoin, None, u.types) end if isa(a,Tuple) if !isa(b,Tuple) return Any end la = length(a)::Int; lb = length(b)::Int if la==0 || lb==0 return Tuple end if la < lb if isvarargtype(a[la]) c = cell(la) c[la] = Vararg{typejoin(a[la].parameters[1], tailjoin(b,la))} n = la-1 else c = cell(la+1) c[la+1] = Vararg{tailjoin(b,la+1)} n = la end elseif lb < la if isvarargtype(b[lb]) c = cell(lb) c[lb] = Vararg{typejoin(b[lb].parameters[1], tailjoin(a,lb))} n = lb-1 else c = cell(lb+1) c[lb+1] = Vararg{tailjoin(a,lb+1)} n = lb end else c = cell(la) n = la end for i=1:n ai = a[i]; bi = b[i] va = false if isvarargtype(ai); va=true; ai = ai.parameters[1]; end if isvarargtype(bi); va=true; bi = bi.parameters[1]; end t = typejoin(ai,bi) c[i] = va ? Vararg{t} : t end return tuple(c...) elseif isa(b,Tuple) return Any end while !is(b,Any) if a <: b return b end if a <: b.name.primary return b.name.primary end b = super(b) end return Any end # reduce typejoin over tup[i:end] function tailjoin(tup, i) t = None for j = i:length(tup) tj = tup[j] t = typejoin(t, isvarargtype(tj)?tj.parameters[1]:tj) end return t end ## promotion mechanism ## promote_type() = None promote_type(T) = T promote_type(T, S ) = typejoin(T, S) promote_type(T, S...) = promote_type(T, promote_type(S...)) promote_type(::Type{None}, ::Type{None}) = None promote_type{T}(::Type{T}, ::Type{T}) = T promote_type{T}(::Type{T}, ::Type{None}) = T promote_type{T}(::Type{None}, ::Type{T}) = T # Try promote_rule in both orders. Typically only one is defined, # and there is a fallback returning None below, so the common case is # promote_type(T, S) => # promote_result(T, S, result, None) => # typejoin(result, None) => result promote_type{T,S}(::Type{T}, ::Type{S}) = promote_result(T, S, promote_rule(T,S), promote_rule(S,T)) promote_rule(T, S) = None promote_result(t,s,T,S) = typejoin(T,S) # If no promote_rule is defined, both directions give None. In that # case use typejoin on the original types instead. promote_result{T,S}(::Type{T},::Type{S},::Type{None},::Type{None}) = typejoin(T, S) promote() = () promote(x) = (x,) function promote{T,S}(x::T, y::S) (convert(promote_type(T,S),x), convert(promote_type(T,S),y)) end function promote{T,S,U}(x::T, y::S, z::U) R = promote_type(promote_type(T,S), U) convert((R...), (x, y, z)) end function promote{T,S}(x::T, y::S, zs...) R = promote_type(T,S) for z in zs R = promote_type(R,typeof(z)) end convert((R...), tuple(x,y,zs...)) end # TODO: promote{T}(x::T, ys::T...) here to catch all circularities? ## promotions in arithmetic, etc. ## # Because of the promoting fallback definitions for Number, we need # a special case for undefined promote_rule on numeric types. # Otherwise, typejoin(T,S) is called (returning Number) so no conversion # happens, and +(promote(x,y)...) is called again, causing a stack # overflow. promote_result{T<:Number,S<:Number}(::Type{T},::Type{S},::Type{None},::Type{None}) = error("no promotion exists for ", T, " and ", S) +(x::Number, y::Number) = +(promote(x,y)...) *(x::Number, y::Number) = *(promote(x,y)...) -(x::Number, y::Number) = -(promote(x,y)...) /(x::Number, y::Number) = /(promote(x,y)...) ^(x::Number, y::Number) = ^(promote(x,y)...) (&)(x::Integer, y::Integer) = (&)(promote(x,y)...) (|)(x::Integer, y::Integer) = (|)(promote(x,y)...) ($)(x::Integer, y::Integer) = ($)(promote(x,y)...) ==(x::Number, y::Number) = (==)(promote(x,y)...) < (x::Real, y::Real) = (< )(promote(x,y)...) <=(x::Real, y::Real) = (<=)(promote(x,y)...) div(x::Real, y::Real) = div(promote(x,y)...) fld(x::Real, y::Real) = fld(promote(x,y)...) rem(x::Real, y::Real) = rem(promote(x,y)...) mod(x::Real, y::Real) = mod(promote(x,y)...) mod1(x::Real, y::Real) = mod1(promote(x,y)...) rem1(x::Real, y::Real) = rem1(promote(x,y)...) fld1(x::Real, y::Real) = fld1(promote(x,y)...) cmp(x::Real, y::Real) = cmp(promote(x,y)...) max(x::Real, y::Real) = max(promote(x,y)...) min(x::Real, y::Real) = min(promote(x,y)...) ## catch-alls to prevent infinite recursion when definitions are missing ## no_op_err(name, T) = error(name," not defined for ",T) +{T<:Number}(x::T, y::T) = no_op_err("+", T) *{T<:Number}(x::T, y::T) = no_op_err("*", T) -{T<:Number}(x::T, y::T) = no_op_err("-", T) /{T<:Number}(x::T, y::T) = no_op_err("/", T) ^{T<:Number}(x::T, y::T) = no_op_err("^", T) (&){T<:Integer}(x::T, y::T) = no_op_err("&", T) (|){T<:Integer}(x::T, y::T) = no_op_err("|", T) ($){T<:Integer}(x::T, y::T) = no_op_err("\$", T) =={T<:Number}(x::T, y::T) = x === y <{T<:Real}(x::T, y::T) = no_op_err("<", T) max{T<:Real}(x::T, y::T) = ifelse(y < x, x, y) min{T<:Real}(x::T, y::T) = ifelse(x < y, x, y)