| Line | Exclusive | Inclusive | Code |
|---|---|---|---|
| 1 | # This file is a part of Julia. License is MIT: https://julialang.org/license | ||
| 2 | |||
| 3 | ## type join (closest common ancestor, or least upper bound) ## | ||
| 4 | |||
| 5 | """ | ||
| 6 | typejoin(T, S) | ||
| 7 | |||
| 8 | |||
| 9 | Return the closest common ancestor of `T` and `S`, i.e. the narrowest type from which | ||
| 10 | they both inherit. | ||
| 11 | """ | ||
| 12 | typejoin() = (@_pure_meta; Bottom) | ||
| 13 | typejoin(@nospecialize(t)) = (@_pure_meta; t) | ||
| 14 | typejoin(@nospecialize(t), ts...) = (@_pure_meta; typejoin(t, typejoin(ts...))) | ||
| 15 | function typejoin(@nospecialize(a), @nospecialize(b)) | ||
| 16 | @_pure_meta | ||
| 17 | if isa(a, TypeVar) | ||
| 18 | return typejoin(a.ub, b) | ||
| 19 | elseif isa(b, TypeVar) | ||
| 20 | return typejoin(a, b.ub) | ||
| 21 | elseif a <: b | ||
| 22 | return b | ||
| 23 | elseif b <: a | ||
| 24 | return a | ||
| 25 | elseif isa(a, UnionAll) | ||
| 26 | return UnionAll(a.var, typejoin(a.body, b)) | ||
| 27 | elseif isa(b, UnionAll) | ||
| 28 | return UnionAll(b.var, typejoin(a, b.body)) | ||
| 29 | elseif isa(a, Union) | ||
| 30 | return typejoin(typejoin(a.a, a.b), b) | ||
| 31 | elseif isa(b, Union) | ||
| 32 | return typejoin(a, typejoin(b.a, b.b)) | ||
| 33 | elseif a <: Tuple | ||
| 34 | if !(b <: Tuple) | ||
| 35 | return Any | ||
| 36 | end | ||
| 37 | ap, bp = a.parameters, b.parameters | ||
| 38 | lar = length(ap)::Int | ||
| 39 | lbr = length(bp)::Int | ||
| 40 | if lar == 0 | ||
| 41 | return Tuple{Vararg{tailjoin(bp, 1)}} | ||
| 42 | end | ||
| 43 | if lbr == 0 | ||
| 44 | return Tuple{Vararg{tailjoin(ap, 1)}} | ||
| 45 | end | ||
| 46 | laf, afixed = full_va_len(ap) | ||
| 47 | lbf, bfixed = full_va_len(bp) | ||
| 48 | if laf < lbf | ||
| 49 | if isvarargtype(ap[lar]) && !afixed | ||
| 50 | c = Vector{Any}(undef, laf) | ||
| 51 | c[laf] = Vararg{typejoin(unwrapva(ap[lar]), tailjoin(bp, laf))} | ||
| 52 | n = laf-1 | ||
| 53 | else | ||
| 54 | c = Vector{Any}(undef, laf+1) | ||
| 55 | c[laf+1] = Vararg{tailjoin(bp, laf+1)} | ||
| 56 | n = laf | ||
| 57 | end | ||
| 58 | elseif lbf < laf | ||
| 59 | if isvarargtype(bp[lbr]) && !bfixed | ||
| 60 | c = Vector{Any}(undef, lbf) | ||
| 61 | c[lbf] = Vararg{typejoin(unwrapva(bp[lbr]), tailjoin(ap, lbf))} | ||
| 62 | n = lbf-1 | ||
| 63 | else | ||
| 64 | c = Vector{Any}(undef, lbf+1) | ||
| 65 | c[lbf+1] = Vararg{tailjoin(ap, lbf+1)} | ||
| 66 | n = lbf | ||
| 67 | end | ||
| 68 | else | ||
| 69 | c = Vector{Any}(undef, laf) | ||
| 70 | n = laf | ||
| 71 | end | ||
| 72 | for i = 1:n | ||
| 73 | ai = ap[min(i,lar)]; bi = bp[min(i,lbr)] | ||
| 74 | ci = typejoin(unwrapva(ai), unwrapva(bi)) | ||
| 75 | c[i] = i == length(c) && (isvarargtype(ai) || isvarargtype(bi)) ? Vararg{ci} : ci | ||
| 76 | end | ||
| 77 | return Tuple{c...} | ||
| 78 | elseif b <: Tuple | ||
| 79 | return Any | ||
| 80 | end | ||
| 81 | while b !== Any | ||
| 82 | if a <: b.name.wrapper | ||
| 83 | while a.name !== b.name | ||
| 84 | a = supertype(a) | ||
| 85 | end | ||
| 86 | if a.name === Type.body.name | ||
| 87 | ap = a.parameters[1] | ||
| 88 | bp = b.parameters[1] | ||
| 89 | if ((isa(ap,TypeVar) && ap.lb === Bottom && ap.ub === Any) || | ||
| 90 | (isa(bp,TypeVar) && bp.lb === Bottom && bp.ub === Any)) | ||
| 91 | # handle special Type{T} supertype | ||
| 92 | return Type | ||
| 93 | end | ||
| 94 | end | ||
| 95 | aprimary = a.name.wrapper | ||
| 96 | # join on parameters | ||
| 97 | n = length(a.parameters) | ||
| 98 | if n == 0 | ||
| 99 | return aprimary | ||
| 100 | end | ||
| 101 | vars = [] | ||
| 102 | for i = 1:n | ||
| 103 | ai, bi = a.parameters[i], b.parameters[i] | ||
| 104 | if ai === bi || (isa(ai,Type) && isa(bi,Type) && ai <: bi && bi <: ai) | ||
| 105 | aprimary = aprimary{ai} | ||
| 106 | else | ||
| 107 | # pushfirst!(vars, aprimary.var) | ||
| 108 | _growbeg!(vars, 1) | ||
| 109 | arrayset(false, vars, aprimary.var, 1) | ||
| 110 | aprimary = aprimary.body | ||
| 111 | end | ||
| 112 | end | ||
| 113 | for v in vars | ||
| 114 | aprimary = UnionAll(v, aprimary) | ||
| 115 | end | ||
| 116 | return aprimary | ||
| 117 | end | ||
| 118 | b = supertype(b) | ||
| 119 | end | ||
| 120 | return Any | ||
| 121 | end | ||
| 122 | |||
| 123 | """ | ||
| 124 | promote_typejoin(T, S) | ||
| 125 | |||
| 126 | Compute a type that contains both `T` and `S`, which could be | ||
| 127 | either a parent of both types, or a `Union` if appropriate. | ||
| 128 | Falls back to [`typejoin`](@ref). | ||
| 129 | """ | ||
| 130 | promote_typejoin(@nospecialize(a), @nospecialize(b)) = _promote_typejoin(a, b)::Type | ||
| 131 | _promote_typejoin(@nospecialize(a), @nospecialize(b)) = typejoin(a, b) | ||
| 132 | _promote_typejoin(::Type{Nothing}, ::Type{T}) where {T} = | ||
| 133 | isconcretetype(T) || T === Union{} ? Union{T, Nothing} : Any | ||
| 134 | _promote_typejoin(::Type{T}, ::Type{Nothing}) where {T} = | ||
| 135 | isconcretetype(T) || T === Union{} ? Union{T, Nothing} : Any | ||
| 136 | _promote_typejoin(::Type{Missing}, ::Type{T}) where {T} = | ||
| 137 | isconcretetype(T) || T === Union{} ? Union{T, Missing} : Any | ||
| 138 | _promote_typejoin(::Type{T}, ::Type{Missing}) where {T} = | ||
| 139 | isconcretetype(T) || T === Union{} ? Union{T, Missing} : Any | ||
| 140 | _promote_typejoin(::Type{Nothing}, ::Type{Missing}) = Union{Nothing, Missing} | ||
| 141 | _promote_typejoin(::Type{Missing}, ::Type{Nothing}) = Union{Nothing, Missing} | ||
| 142 | _promote_typejoin(::Type{Nothing}, ::Type{Nothing}) = Nothing | ||
| 143 | _promote_typejoin(::Type{Missing}, ::Type{Missing}) = Missing | ||
| 144 | |||
| 145 | # Returns length, isfixed | ||
| 146 | function full_va_len(p) | ||
| 147 | isempty(p) && return 0, true | ||
| 148 | last = p[end] | ||
| 149 | if isvarargtype(last) | ||
| 150 | N = unwrap_unionall(last).parameters[2] | ||
| 151 | if isa(N, Integer) | ||
| 152 | return (length(p) + N - 1)::Int, true | ||
| 153 | end | ||
| 154 | return length(p)::Int, false | ||
| 155 | end | ||
| 156 | return length(p)::Int, true | ||
| 157 | end | ||
| 158 | |||
| 159 | # reduce typejoin over A[i:end] | ||
| 160 | function tailjoin(A, i) | ||
| 161 | if i > length(A) | ||
| 162 | return unwrapva(A[end]) | ||
| 163 | end | ||
| 164 | t = Bottom | ||
| 165 | for j = i:length(A) | ||
| 166 | t = typejoin(t, unwrapva(A[j])) | ||
| 167 | end | ||
| 168 | return t | ||
| 169 | end | ||
| 170 | |||
| 171 | ## promotion mechanism ## | ||
| 172 | |||
| 173 | """ | ||
| 174 | promote_type(type1, type2) | ||
| 175 | |||
| 176 | Promotion refers to converting values of mixed types to a single common type. | ||
| 177 | `promote_type` represents the default promotion behavior in Julia when | ||
| 178 | operators (usually mathematical) are given arguments of differing types. | ||
| 179 | `promote_type` generally tries to return a type which can at least approximate | ||
| 180 | most values of either input type without excessively widening. Some loss is | ||
| 181 | tolerated; for example, `promote_type(Int64, Float64)` returns | ||
| 182 | [`Float64`](@ref) even though strictly, not all [`Int64`](@ref) values can be | ||
| 183 | represented exactly as `Float64` values. | ||
| 184 | |||
| 185 | ```jldoctest | ||
| 186 | julia> promote_type(Int64, Float64) | ||
| 187 | Float64 | ||
| 188 | |||
| 189 | julia> promote_type(Int32, Int64) | ||
| 190 | Int64 | ||
| 191 | |||
| 192 | julia> promote_type(Float32, BigInt) | ||
| 193 | BigFloat | ||
| 194 | |||
| 195 | julia> promote_type(Int16, Float16) | ||
| 196 | Float16 | ||
| 197 | |||
| 198 | julia> promote_type(Int64, Float16) | ||
| 199 | Float16 | ||
| 200 | |||
| 201 | julia> promote_type(Int8, UInt16) | ||
| 202 | UInt16 | ||
| 203 | ``` | ||
| 204 | """ | ||
| 205 | function promote_type end | ||
| 206 | |||
| 207 | promote_type() = Bottom | ||
| 208 | promote_type(T) = T | ||
| 209 | promote_type(T, S, U, V...) = (@_inline_meta; promote_type(T, promote_type(S, U, V...))) | ||
| 210 | |||
| 211 | promote_type(::Type{Bottom}, ::Type{Bottom}) = Bottom | ||
| 212 | promote_type(::Type{T}, ::Type{T}) where {T} = T | ||
| 213 | promote_type(::Type{T}, ::Type{Bottom}) where {T} = T | ||
| 214 | promote_type(::Type{Bottom}, ::Type{T}) where {T} = T | ||
| 215 | |||
| 216 | function promote_type(::Type{T}, ::Type{S}) where {T,S} | ||
| 217 | @_inline_meta | ||
| 218 | # Try promote_rule in both orders. Typically only one is defined, | ||
| 219 | # and there is a fallback returning Bottom below, so the common case is | ||
| 220 | # promote_type(T, S) => | ||
| 221 | # promote_result(T, S, result, Bottom) => | ||
| 222 | # typejoin(result, Bottom) => result | ||
| 223 | promote_result(T, S, promote_rule(T,S), promote_rule(S,T)) | ||
| 224 | end | ||
| 225 | |||
| 226 | """ | ||
| 227 | promote_rule(type1, type2) | ||
| 228 | |||
| 229 | Specifies what type should be used by [`promote`](@ref) when given values of types `type1` and | ||
| 230 | `type2`. This function should not be called directly, but should have definitions added to | ||
| 231 | it for new types as appropriate. | ||
| 232 | """ | ||
| 233 | function promote_rule end | ||
| 234 | |||
| 235 | promote_rule(::Type{<:Any}, ::Type{<:Any}) = Bottom | ||
| 236 | |||
| 237 | promote_result(::Type{<:Any},::Type{<:Any},::Type{T},::Type{S}) where {T,S} = (@_inline_meta; promote_type(T,S)) | ||
| 238 | # If no promote_rule is defined, both directions give Bottom. In that | ||
| 239 | # case use typejoin on the original types instead. | ||
| 240 | promote_result(::Type{T},::Type{S},::Type{Bottom},::Type{Bottom}) where {T,S} = (@_inline_meta; typejoin(T, S)) | ||
| 241 | |||
| 242 | """ | ||
| 243 | promote(xs...) | ||
| 244 | |||
| 245 | Convert all arguments to a common type, and return them all (as a tuple). | ||
| 246 | If no arguments can be converted, an error is raised. | ||
| 247 | |||
| 248 | # Examples | ||
| 249 | ```jldoctest | ||
| 250 | julia> promote(Int8(1), Float16(4.5), Float32(4.1)) | ||
| 251 | (1.0f0, 4.5f0, 4.1f0) | ||
| 252 | ``` | ||
| 253 | """ | ||
| 254 | function promote end | ||
| 255 | |||
| 256 | function _promote(x::T, y::S) where {T,S} | ||
| 257 | @_inline_meta | ||
| 258 | R = promote_type(T, S) | ||
| 259 | return (convert(R, x), convert(R, y)) | ||
| 260 | end | ||
| 261 | promote_typeof(x) = typeof(x) | ||
| 262 | promote_typeof(x, xs...) = (@_inline_meta; promote_type(typeof(x), promote_typeof(xs...))) | ||
| 263 | function _promote(x, y, z) | ||
| 264 | @_inline_meta | ||
| 265 | R = promote_typeof(x, y, z) | ||
| 266 | return (convert(R, x), convert(R, y), convert(R, z)) | ||
| 267 | end | ||
| 268 | function _promote(x, y, zs...) | ||
| 269 | @_inline_meta | ||
| 270 | R = promote_typeof(x, y, zs...) | ||
| 271 | return (convert(R, x), convert(R, y), convert(Tuple{Vararg{R}}, zs)...) | ||
| 272 | end | ||
| 273 | # TODO: promote(x::T, ys::T...) where {T} here to catch all circularities? | ||
| 274 | |||
| 275 | ## promotions in arithmetic, etc. ## | ||
| 276 | |||
| 277 | promote() = () | ||
| 278 | promote(x) = (x,) | ||
| 279 | |||
| 280 | function promote(x, y) | ||
| 281 | @_inline_meta | ||
| 282 | px, py = _promote(x, y) | ||
| 283 | not_sametype((x,y), (px,py)) | ||
| 284 | px, py | ||
| 285 | end | ||
| 286 | function promote(x, y, z) | ||
| 287 | @_inline_meta | ||
| 288 | px, py, pz = _promote(x, y, z) | ||
| 289 | not_sametype((x,y,z), (px,py,pz)) | ||
| 290 | px, py, pz | ||
| 291 | end | ||
| 292 | function promote(x, y, z, a...) | ||
| 293 | p = _promote(x, y, z, a...) | ||
| 294 | not_sametype((x, y, z, a...), p) | ||
| 295 | p | ||
| 296 | end | ||
| 297 | |||
| 298 | promote(x::T, y::T, zs::T...) where {T} = (x, y, zs...) | ||
| 299 | |||
| 300 | not_sametype(x::T, y::T) where {T} = sametype_error(x) | ||
| 301 | |||
| 302 | not_sametype(x, y) = nothing | ||
| 303 | |||
| 304 | function sametype_error(input) | ||
| 305 | @_noinline_meta | ||
| 306 | error("promotion of types ", | ||
| 307 | join(map(x->string(typeof(x)), input), ", ", " and "), | ||
| 308 | " failed to change any arguments") | ||
| 309 | end | ||
| 310 | |||
| 311 | +(x::Number, y::Number) = +(promote(x,y)...) | ||
| 312 | *(x::Number, y::Number) = *(promote(x,y)...) | ||
| 313 | -(x::Number, y::Number) = -(promote(x,y)...) | ||
| 314 | /(x::Number, y::Number) = /(promote(x,y)...) | ||
| 315 | |||
| 316 | """ | ||
| 317 | ^(x, y) | ||
| 318 | |||
| 319 | Exponentiation operator. If `x` is a matrix, computes matrix exponentiation. | ||
| 320 | |||
| 321 | If `y` is an `Int` literal (e.g. `2` in `x^2` or `-3` in `x^-3`), the Julia code | ||
| 322 | `x^y` is transformed by the compiler to `Base.literal_pow(^, x, Val(y))`, to | ||
| 323 | enable compile-time specialization on the value of the exponent. | ||
| 324 | (As a default fallback we have `Base.literal_pow(^, x, Val(y)) = ^(x,y)`, | ||
| 325 | where usually `^ == Base.^` unless `^` has been defined in the calling | ||
| 326 | namespace.) | ||
| 327 | |||
| 328 | ```jldoctest | ||
| 329 | julia> 3^5 | ||
| 330 | 243 | ||
| 331 | |||
| 332 | julia> A = [1 2; 3 4] | ||
| 333 | 2×2 Array{Int64,2}: | ||
| 334 | 1 2 | ||
| 335 | 3 4 | ||
| 336 | |||
| 337 | julia> A^3 | ||
| 338 | 2×2 Array{Int64,2}: | ||
| 339 | 37 54 | ||
| 340 | 81 118 | ||
| 341 | ``` | ||
| 342 | """ | ||
| 343 | ^(x::Number, y::Number) = ^(promote(x,y)...) | ||
| 344 | |||
| 345 | fma(x::Number, y::Number, z::Number) = fma(promote(x,y,z)...) | ||
| 346 | muladd(x::Number, y::Number, z::Number) = muladd(promote(x,y,z)...) | ||
| 347 | |||
| 348 | ==(x::Number, y::Number) = (==)(promote(x,y)...) | ||
| 349 | <( x::Real, y::Real) = (< )(promote(x,y)...) | ||
| 350 | <=(x::Real, y::Real) = (<=)(promote(x,y)...) | ||
| 351 | |||
| 352 | rem(x::Real, y::Real) = rem(promote(x,y)...) | ||
| 353 | mod(x::Real, y::Real) = mod(promote(x,y)...) | ||
| 354 | |||
| 355 | mod1(x::Real, y::Real) = mod1(promote(x,y)...) | ||
| 356 | fld1(x::Real, y::Real) = fld1(promote(x,y)...) | ||
| 357 | |||
| 358 | max(x::Real, y::Real) = max(promote(x,y)...) | ||
| 359 | min(x::Real, y::Real) = min(promote(x,y)...) | ||
| 360 | minmax(x::Real, y::Real) = minmax(promote(x, y)...) | ||
| 361 | |||
| 362 | if isdefined(Core, :Compiler) | ||
| 363 | const _return_type = Core.Compiler.return_type | ||
| 364 | else | ||
| 365 | _return_type(@nospecialize(f), @nospecialize(t)) = Any | ||
| 366 | end | ||
| 367 | |||
| 368 | """ | ||
| 369 | promote_op(f, argtypes...) | ||
| 370 | |||
| 371 | Guess what an appropriate container eltype would be for storing results of | ||
| 372 | `f(::argtypes...)`. The guess is in part based on type inference, so can change any time. | ||
| 373 | |||
| 374 | !!! warning | ||
| 375 | Due to its fragility, use of `promote_op` should be avoided. It is preferable to base | ||
| 376 | the container eltype on the type of the actual elements. Only in the absence of any | ||
| 377 | elements (for an empty result container), it may be unavoidable to call `promote_op`. | ||
| 378 | """ | ||
| 379 | promote_op(f, S::Type...) = _return_type(f, Tuple{S...}) | ||
| 380 | |||
| 381 | ## catch-alls to prevent infinite recursion when definitions are missing ## | ||
| 382 | |||
| 383 | no_op_err(name, T) = error(name," not defined for ",T) | ||
| 384 | (+)(x::T, y::T) where {T<:Number} = no_op_err("+", T) | ||
| 385 | (*)(x::T, y::T) where {T<:Number} = no_op_err("*", T) | ||
| 386 | (-)(x::T, y::T) where {T<:Number} = no_op_err("-", T) | ||
| 387 | (/)(x::T, y::T) where {T<:Number} = no_op_err("/", T) | ||
| 388 | (^)(x::T, y::T) where {T<:Number} = no_op_err("^", T) | ||
| 389 | |||
| 390 | fma(x::T, y::T, z::T) where {T<:Number} = no_op_err("fma", T) | ||
| 391 | fma(x::Integer, y::Integer, z::Integer) = x*y+z | ||
| 392 | muladd(x::T, y::T, z::T) where {T<:Number} = x*y+z | ||
| 393 | |||
| 394 | (&)(x::T, y::T) where {T<:Integer} = no_op_err("&", T) | ||
| 395 | (|)(x::T, y::T) where {T<:Integer} = no_op_err("|", T) | ||
| 396 | xor(x::T, y::T) where {T<:Integer} = no_op_err("xor", T) | ||
| 397 | |||
| 398 | 53 (6 %) | 53 (6 %) |
53 (6 %)
samples spent in ==
(==)(x::T, y::T) where {T<:Number} = x === y
4 (8 %) (ex.), 4 (8 %) (incl.) when called from iszero line 40 9 (17 %) (ex.), 9 (17 %) (incl.) when called from < line 334 40 (75 %) (ex.), 40 (75 %) (incl.) when called from _eq line 288 |
| 399 | (< )(x::T, y::T) where {T<:Real} = no_op_err("<" , T) | ||
| 400 | (<=)(x::T, y::T) where {T<:Real} = no_op_err("<=", T) | ||
| 401 | |||
| 402 | rem(x::T, y::T) where {T<:Real} = no_op_err("rem", T) | ||
| 403 | mod(x::T, y::T) where {T<:Real} = no_op_err("mod", T) | ||
| 404 | |||
| 405 | min(x::Real) = x | ||
| 406 | max(x::Real) = x | ||
| 407 | minmax(x::Real) = (x, x) | ||
| 408 | |||
| 409 | max(x::T, y::T) where {T<:Real} = ifelse(y < x, x, y) | ||
| 410 | min(x::T, y::T) where {T<:Real} = ifelse(y < x, y, x) | ||
| 411 | minmax(x::T, y::T) where {T<:Real} = y < x ? (y, x) : (x, y) | ||
| 412 | |||
| 413 | flipsign(x::T, y::T) where {T<:Signed} = no_op_err("flipsign", T) |