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 |
|
|
Return the closest common ancestor of types `T` and `S`, i.e. the narrowest type from which
|
9 |
|
|
they both inherit. Recurses on additional varargs.
|
10 |
|
|
|
11 |
|
|
# Examples
|
12 |
|
|
```jldoctest
|
13 |
|
|
julia> typejoin(Int, Float64)
|
14 |
|
|
Real
|
15 |
|
|
|
16 |
|
|
julia> typejoin(Int, Float64, ComplexF32)
|
17 |
|
|
Number
|
18 |
|
|
```
|
19 |
|
|
"""
|
20 |
|
|
typejoin() = Bottom
|
21 |
|
|
typejoin(@nospecialize(t)) = t
|
22 |
|
|
typejoin(@nospecialize(t), ts...) = (@_foldable_meta; typejoin(t, typejoin(ts...)))
|
23 |
|
|
function typejoin(@nospecialize(a), @nospecialize(b))
|
24 |
|
|
@_foldable_meta
|
25 |
|
|
if isa(a, TypeVar)
|
26 |
|
|
return typejoin(a.ub, b)
|
27 |
|
|
elseif isa(b, TypeVar)
|
28 |
|
|
return typejoin(a, b.ub)
|
29 |
|
|
elseif a <: b
|
30 |
|
|
return b
|
31 |
|
|
elseif b <: a
|
32 |
|
|
return a
|
33 |
|
|
elseif isa(a, UnionAll)
|
34 |
|
|
return UnionAll(a.var, typejoin(a.body, b))
|
35 |
|
|
elseif isa(b, UnionAll)
|
36 |
|
|
return UnionAll(b.var, typejoin(a, b.body))
|
37 |
|
|
elseif isa(a, Union)
|
38 |
|
|
return typejoin(typejoin(a.a, a.b), b)
|
39 |
|
|
elseif isa(b, Union)
|
40 |
|
|
return typejoin(a, typejoin(b.a, b.b))
|
41 |
|
|
end
|
42 |
|
|
# a and b are DataTypes
|
43 |
|
|
# We have to hide Constant info from inference, see #44390
|
44 |
|
|
a, b = inferencebarrier(a)::DataType, inferencebarrier(b)::DataType
|
45 |
|
|
if a <: Tuple
|
46 |
|
|
if !(b <: Tuple)
|
47 |
|
|
return Any
|
48 |
|
|
end
|
49 |
|
|
ap, bp = a.parameters, b.parameters
|
50 |
|
|
lar = length(ap)
|
51 |
|
|
lbr = length(bp)
|
52 |
|
|
if lar == 0
|
53 |
|
|
return Tuple{Vararg{tailjoin(bp, 1)}}
|
54 |
|
|
end
|
55 |
|
|
if lbr == 0
|
56 |
|
|
return Tuple{Vararg{tailjoin(ap, 1)}}
|
57 |
|
|
end
|
58 |
|
|
laf, afixed = full_va_len(ap)
|
59 |
|
|
lbf, bfixed = full_va_len(bp)
|
60 |
|
|
if laf < lbf
|
61 |
|
|
if isvarargtype(ap[lar]) && !afixed
|
62 |
|
|
c = Vector{Any}(undef, laf)
|
63 |
|
|
c[laf] = Vararg{typejoin(unwrapva(ap[lar]), tailjoin(bp, laf))}
|
64 |
|
|
n = laf-1
|
65 |
|
|
else
|
66 |
|
|
c = Vector{Any}(undef, laf+1)
|
67 |
|
|
c[laf+1] = Vararg{tailjoin(bp, laf+1)}
|
68 |
|
|
n = laf
|
69 |
|
|
end
|
70 |
|
|
elseif lbf < laf
|
71 |
|
|
if isvarargtype(bp[lbr]) && !bfixed
|
72 |
|
|
c = Vector{Any}(undef, lbf)
|
73 |
|
|
c[lbf] = Vararg{typejoin(unwrapva(bp[lbr]), tailjoin(ap, lbf))}
|
74 |
|
|
n = lbf-1
|
75 |
|
|
else
|
76 |
|
|
c = Vector{Any}(undef, lbf+1)
|
77 |
|
|
c[lbf+1] = Vararg{tailjoin(ap, lbf+1)}
|
78 |
|
|
n = lbf
|
79 |
|
|
end
|
80 |
|
|
else
|
81 |
|
|
c = Vector{Any}(undef, laf)
|
82 |
|
|
n = laf
|
83 |
|
|
end
|
84 |
|
|
for i = 1:n
|
85 |
|
|
ai = ap[min(i,lar)]; bi = bp[min(i,lbr)]
|
86 |
|
|
ci = typejoin(unwrapva(ai), unwrapva(bi))
|
87 |
|
|
c[i] = i == length(c) && (isvarargtype(ai) || isvarargtype(bi)) ? Vararg{ci} : ci
|
88 |
|
|
end
|
89 |
|
|
return Tuple{c...}
|
90 |
|
|
elseif b <: Tuple
|
91 |
|
|
return Any
|
92 |
|
|
end
|
93 |
|
|
while b !== Any
|
94 |
|
|
if a <: b.name.wrapper
|
95 |
|
|
while a.name !== b.name
|
96 |
|
|
a = supertype(a)::DataType
|
97 |
|
|
end
|
98 |
|
|
if a.name === Type.body.name
|
99 |
|
|
ap = a.parameters[1]
|
100 |
|
|
bp = b.parameters[1]
|
101 |
|
|
if ((isa(ap,TypeVar) && ap.lb === Bottom && ap.ub === Any) ||
|
102 |
|
|
(isa(bp,TypeVar) && bp.lb === Bottom && bp.ub === Any))
|
103 |
|
|
# handle special Type{T} supertype
|
104 |
|
|
return Type
|
105 |
|
|
end
|
106 |
|
|
end
|
107 |
|
|
aprimary = a.name.wrapper
|
108 |
|
|
# join on parameters
|
109 |
|
|
n = length(a.parameters)
|
110 |
|
|
if n == 0
|
111 |
|
|
return aprimary
|
112 |
|
|
end
|
113 |
|
|
vars = []
|
114 |
|
|
for i = 1:n
|
115 |
|
|
ai, bi = a.parameters[i], b.parameters[i]
|
116 |
|
|
if ai === bi || (isa(ai,Type) && isa(bi,Type) && ai <: bi && bi <: ai)
|
117 |
|
|
aprimary = aprimary{ai}
|
118 |
|
|
else
|
119 |
|
|
aprimary = aprimary::UnionAll
|
120 |
|
|
# pushfirst!(vars, aprimary.var)
|
121 |
|
|
_growbeg!(vars, 1)
|
122 |
|
|
arrayset(false, vars, aprimary.var, 1)
|
123 |
|
|
aprimary = aprimary.body
|
124 |
|
|
end
|
125 |
|
|
end
|
126 |
|
|
for v in vars
|
127 |
|
|
aprimary = UnionAll(v, aprimary)
|
128 |
|
|
end
|
129 |
|
|
return aprimary
|
130 |
|
|
end
|
131 |
|
|
b = supertype(b)::DataType
|
132 |
|
|
end
|
133 |
|
|
return Any
|
134 |
|
|
end
|
135 |
|
|
|
136 |
|
|
# return an upper-bound on type `a` with type `b` removed
|
137 |
|
|
# such that `return <: a` && `Union{return, b} == Union{a, b}`
|
138 |
|
|
# WARNING: this is wrong for some objects for which subtyping is broken
|
139 |
|
|
# (Core.Compiler.isnotbrokensubtype), use only simple types for `b`
|
140 |
|
|
function typesplit(@nospecialize(a), @nospecialize(b))
|
141 |
|
|
@_foldable_meta
|
142 |
|
|
if a <: b
|
143 |
|
|
return Bottom
|
144 |
|
|
end
|
145 |
|
|
if isa(a, Union)
|
146 |
|
|
return Union{typesplit(a.a, b),
|
147 |
|
|
typesplit(a.b, b)}
|
148 |
|
|
end
|
149 |
|
|
return a
|
150 |
|
|
end
|
151 |
|
|
|
152 |
|
|
|
153 |
|
|
"""
|
154 |
|
|
promote_typejoin(T, S)
|
155 |
|
|
|
156 |
|
|
Compute a type that contains both `T` and `S`, which could be
|
157 |
|
|
either a parent of both types, or a `Union` if appropriate.
|
158 |
|
|
Falls back to [`typejoin`](@ref).
|
159 |
|
|
|
160 |
|
|
See instead [`promote`](@ref), [`promote_type`](@ref).
|
161 |
|
|
|
162 |
|
|
# Examples
|
163 |
|
|
```jldoctest
|
164 |
|
|
julia> Base.promote_typejoin(Int, Float64)
|
165 |
|
|
Real
|
166 |
|
|
|
167 |
|
|
julia> Base.promote_type(Int, Float64)
|
168 |
|
|
Float64
|
169 |
|
|
```
|
170 |
|
|
"""
|
171 |
|
|
function promote_typejoin(@nospecialize(a), @nospecialize(b))
|
172 |
|
|
c = typejoin(_promote_typesubtract(a), _promote_typesubtract(b))
|
173 |
|
|
return Union{a, b, c}::Type
|
174 |
|
|
end
|
175 |
|
|
_promote_typesubtract(@nospecialize(a)) =
|
176 |
|
|
a === Any ? a :
|
177 |
|
|
a >: Union{Nothing, Missing} ? typesplit(a, Union{Nothing, Missing}) :
|
178 |
|
|
a >: Nothing ? typesplit(a, Nothing) :
|
179 |
|
|
a >: Missing ? typesplit(a, Missing) :
|
180 |
|
|
a
|
181 |
|
|
|
182 |
|
|
function promote_typejoin_union(::Type{T}) where T
|
183 |
|
|
if T === Union{}
|
184 |
|
|
return Union{}
|
185 |
|
|
elseif T isa UnionAll
|
186 |
|
|
return Any # TODO: compute more precise bounds
|
187 |
|
|
elseif T isa Union
|
188 |
|
|
return promote_typejoin(promote_typejoin_union(T.a), promote_typejoin_union(T.b))
|
189 |
|
|
elseif T isa DataType
|
190 |
|
|
T <: Tuple && return typejoin_union_tuple(T)
|
191 |
|
|
return T
|
192 |
|
|
else
|
193 |
|
|
error("unreachable") # not a type??
|
194 |
|
|
end
|
195 |
|
|
end
|
196 |
|
|
|
197 |
|
|
function typejoin_union_tuple(T::DataType)
|
198 |
|
|
@_foldable_meta
|
199 |
|
|
u = Base.unwrap_unionall(T)
|
200 |
|
|
p = (u::DataType).parameters
|
201 |
|
|
lr = length(p)::Int
|
202 |
|
|
if lr == 0
|
203 |
|
|
return Tuple{}
|
204 |
|
|
end
|
205 |
|
|
c = Vector{Any}(undef, lr)
|
206 |
|
|
for i = 1:lr
|
207 |
|
|
pi = p[i]
|
208 |
|
|
U = Core.Compiler.unwrapva(pi)
|
209 |
|
|
if U === Union{}
|
210 |
|
|
ci = Union{}
|
211 |
|
|
elseif U isa Union
|
212 |
|
|
ci = typejoin(U.a, U.b)
|
213 |
|
|
elseif U isa UnionAll
|
214 |
|
|
return Any # TODO: compute more precise bounds
|
215 |
|
|
else
|
216 |
|
|
ci = promote_typejoin_union(U)
|
217 |
|
|
end
|
218 |
|
|
if i == lr && Core.Compiler.isvarargtype(pi)
|
219 |
|
|
c[i] = isdefined(pi, :N) ? Vararg{ci, pi.N} : Vararg{ci}
|
220 |
|
|
else
|
221 |
|
|
c[i] = ci
|
222 |
|
|
end
|
223 |
|
|
end
|
224 |
|
|
return Base.rewrap_unionall(Tuple{c...}, T)
|
225 |
|
|
end
|
226 |
|
|
|
227 |
|
|
# Returns length, isfixed
|
228 |
|
|
function full_va_len(p::Core.SimpleVector)
|
229 |
|
|
isempty(p) && return 0, true
|
230 |
|
|
last = p[end]
|
231 |
|
|
if isvarargtype(last)
|
232 |
|
|
if isdefined(last, :N)
|
233 |
|
|
N = last.N
|
234 |
|
|
isa(N, Int) && return length(p) + N - 1, true
|
235 |
|
|
end
|
236 |
|
|
return length(p), false
|
237 |
|
|
end
|
238 |
|
|
return length(p), true
|
239 |
|
|
end
|
240 |
|
|
|
241 |
|
|
# reduce typejoin over A[i:end]
|
242 |
|
|
function tailjoin(A, i)
|
243 |
|
|
if i > length(A)
|
244 |
|
|
return unwrapva(A[end])
|
245 |
|
|
end
|
246 |
|
|
t = Bottom
|
247 |
|
|
for j = i:length(A)
|
248 |
|
|
t = typejoin(t, unwrapva(A[j]))
|
249 |
|
|
end
|
250 |
|
|
return t
|
251 |
|
|
end
|
252 |
|
|
|
253 |
|
|
## promotion mechanism ##
|
254 |
|
|
|
255 |
|
|
"""
|
256 |
|
|
promote_type(type1, type2, ...)
|
257 |
|
|
|
258 |
|
|
Promotion refers to converting values of mixed types to a single common type.
|
259 |
|
|
`promote_type` represents the default promotion behavior in Julia when
|
260 |
|
|
operators (usually mathematical) are given arguments of differing types.
|
261 |
|
|
`promote_type` generally tries to return a type which can at least approximate
|
262 |
|
|
most values of either input type without excessively widening. Some loss is
|
263 |
|
|
tolerated; for example, `promote_type(Int64, Float64)` returns
|
264 |
|
|
[`Float64`](@ref) even though strictly, not all [`Int64`](@ref) values can be
|
265 |
|
|
represented exactly as `Float64` values.
|
266 |
|
|
|
267 |
|
|
See also: [`promote`](@ref), [`promote_typejoin`](@ref), [`promote_rule`](@ref).
|
268 |
|
|
|
269 |
|
|
# Examples
|
270 |
|
|
```jldoctest
|
271 |
|
|
julia> promote_type(Int64, Float64)
|
272 |
|
|
Float64
|
273 |
|
|
|
274 |
|
|
julia> promote_type(Int32, Int64)
|
275 |
|
|
Int64
|
276 |
|
|
|
277 |
|
|
julia> promote_type(Float32, BigInt)
|
278 |
|
|
BigFloat
|
279 |
|
|
|
280 |
|
|
julia> promote_type(Int16, Float16)
|
281 |
|
|
Float16
|
282 |
|
|
|
283 |
|
|
julia> promote_type(Int64, Float16)
|
284 |
|
|
Float16
|
285 |
|
|
|
286 |
|
|
julia> promote_type(Int8, UInt16)
|
287 |
|
|
UInt16
|
288 |
|
|
```
|
289 |
|
|
|
290 |
|
|
!!! warning "Don't overload this directly"
|
291 |
|
|
To overload promotion for your own types you should overload [`promote_rule`](@ref).
|
292 |
|
|
`promote_type` calls `promote_rule` internally to determine the type.
|
293 |
|
|
Overloading `promote_type` directly can cause ambiguity errors.
|
294 |
|
|
"""
|
295 |
|
|
function promote_type end
|
296 |
|
|
|
297 |
|
|
promote_type() = Bottom
|
298 |
|
|
promote_type(T) = T
|
299 |
|
|
promote_type(T, S, U, V...) = (@inline; promote_type(T, promote_type(S, U, V...)))
|
300 |
|
|
|
301 |
|
|
promote_type(::Type{Bottom}, ::Type{Bottom}) = Bottom
|
302 |
|
|
promote_type(::Type{T}, ::Type{T}) where {T} = T
|
303 |
|
|
promote_type(::Type{T}, ::Type{Bottom}) where {T} = T
|
304 |
|
|
promote_type(::Type{Bottom}, ::Type{T}) where {T} = T
|
305 |
|
|
|
306 |
|
|
function promote_type(::Type{T}, ::Type{S}) where {T,S}
|
307 |
|
|
@inline
|
308 |
|
|
# Try promote_rule in both orders. Typically only one is defined,
|
309 |
|
|
# and there is a fallback returning Bottom below, so the common case is
|
310 |
|
|
# promote_type(T, S) =>
|
311 |
|
|
# promote_result(T, S, result, Bottom) =>
|
312 |
|
|
# typejoin(result, Bottom) => result
|
313 |
|
|
promote_result(T, S, promote_rule(T,S), promote_rule(S,T))
|
314 |
|
|
end
|
315 |
|
|
|
316 |
|
|
"""
|
317 |
|
|
promote_rule(type1, type2)
|
318 |
|
|
|
319 |
|
|
Specifies what type should be used by [`promote`](@ref) when given values of types `type1` and
|
320 |
|
|
`type2`. This function should not be called directly, but should have definitions added to
|
321 |
|
|
it for new types as appropriate.
|
322 |
|
|
"""
|
323 |
|
|
function promote_rule end
|
324 |
|
|
|
325 |
|
|
promote_rule(::Type, ::Type) = Bottom
|
326 |
|
|
# Define some methods to avoid needing to enumerate unrelated possibilities when presented
|
327 |
|
|
# with Type{<:T}, and return a value in general accordance with the result given by promote_type
|
328 |
|
|
promote_rule(::Type{Bottom}, slurp...) = Bottom
|
329 |
|
|
promote_rule(::Type{Bottom}, ::Type{Bottom}, slurp...) = Bottom # not strictly necessary, since the next method would match unambiguously anyways
|
330 |
|
|
promote_rule(::Type{Bottom}, ::Type{T}, slurp...) where {T} = T
|
331 |
|
|
promote_rule(::Type{T}, ::Type{Bottom}, slurp...) where {T} = T
|
332 |
|
|
|
333 |
|
|
promote_result(::Type,::Type,::Type{T},::Type{S}) where {T,S} = (@inline; promote_type(T,S))
|
334 |
|
|
# If no promote_rule is defined, both directions give Bottom. In that
|
335 |
|
|
# case use typejoin on the original types instead.
|
336 |
|
|
promote_result(::Type{T},::Type{S},::Type{Bottom},::Type{Bottom}) where {T,S} = (@inline; typejoin(T, S))
|
337 |
|
|
|
338 |
|
|
"""
|
339 |
|
|
promote(xs...)
|
340 |
|
|
|
341 |
|
|
Convert all arguments to a common type, and return them all (as a tuple).
|
342 |
|
|
If no arguments can be converted, an error is raised.
|
343 |
|
|
|
344 |
|
|
See also: [`promote_type`](@ref), [`promote_rule`](@ref).
|
345 |
|
|
|
346 |
|
|
# Examples
|
347 |
|
|
```jldoctest
|
348 |
|
|
julia> promote(Int8(1), Float16(4.5), Float32(4.1))
|
349 |
|
|
(1.0f0, 4.5f0, 4.1f0)
|
350 |
|
|
|
351 |
|
|
julia> promote_type(Int8, Float16, Float32)
|
352 |
|
|
Float32
|
353 |
|
|
|
354 |
|
|
julia> reduce(Base.promote_typejoin, (Int8, Float16, Float32))
|
355 |
|
|
Real
|
356 |
|
|
|
357 |
|
|
julia> promote(1, "x")
|
358 |
|
|
ERROR: promotion of types Int64 and String failed to change any arguments
|
359 |
|
|
[...]
|
360 |
|
|
|
361 |
|
|
julia> promote_type(Int, String)
|
362 |
|
|
Any
|
363 |
|
|
```
|
364 |
|
|
"""
|
365 |
|
|
function promote end
|
366 |
|
|
|
367 |
|
|
function _promote(x::T, y::S) where {T,S}
|
368 |
|
|
@inline
|
369 |
|
|
R = promote_type(T, S)
|
370 |
|
|
return (convert(R, x), convert(R, y))
|
371 |
|
|
end
|
372 |
|
|
promote_typeof(x) = typeof(x)
|
373 |
|
|
promote_typeof(x, xs...) = (@inline; promote_type(typeof(x), promote_typeof(xs...)))
|
374 |
|
|
function _promote(x, y, z)
|
375 |
|
|
@inline
|
376 |
|
|
R = promote_typeof(x, y, z)
|
377 |
|
|
return (convert(R, x), convert(R, y), convert(R, z))
|
378 |
|
|
end
|
379 |
|
|
function _promote(x, y, zs...)
|
380 |
|
|
@inline
|
381 |
|
|
R = promote_typeof(x, y, zs...)
|
382 |
|
|
return (convert(R, x), convert(R, y), convert(Tuple{Vararg{R}}, zs)...)
|
383 |
|
|
end
|
384 |
|
|
# TODO: promote(x::T, ys::T...) where {T} here to catch all circularities?
|
385 |
|
|
|
386 |
|
|
## promotions in arithmetic, etc. ##
|
387 |
|
|
|
388 |
|
|
promote() = ()
|
389 |
|
|
promote(x) = (x,)
|
390 |
|
|
|
391 |
|
|
function promote(x, y)
|
392 |
|
|
@inline
|
393 |
|
|
px, py = _promote(x, y)
|
394 |
|
|
not_sametype((x,y), (px,py))
|
395 |
|
|
px, py
|
396 |
|
|
end
|
397 |
|
|
function promote(x, y, z)
|
398 |
|
|
@inline
|
399 |
|
|
px, py, pz = _promote(x, y, z)
|
400 |
|
|
not_sametype((x,y,z), (px,py,pz))
|
401 |
|
|
px, py, pz
|
402 |
|
|
end
|
403 |
|
|
function promote(x, y, z, a...)
|
404 |
|
|
p = _promote(x, y, z, a...)
|
405 |
|
|
not_sametype((x, y, z, a...), p)
|
406 |
|
|
p
|
407 |
|
|
end
|
408 |
|
|
|
409 |
|
|
promote(x::T, y::T, zs::T...) where {T} = (x, y, zs...)
|
410 |
|
|
|
411 |
|
|
not_sametype(x::T, y::T) where {T} = sametype_error(x)
|
412 |
|
|
|
413 |
|
|
not_sametype(x, y) = nothing
|
414 |
|
|
|
415 |
|
|
function sametype_error(input)
|
416 |
|
|
@noinline
|
417 |
|
|
error("promotion of types ",
|
418 |
|
|
join(map(x->string(typeof(x)), input), ", ", " and "),
|
419 |
|
|
" failed to change any arguments")
|
420 |
|
|
end
|
421 |
|
|
|
422 |
|
|
+(x::Number, y::Number) = +(promote(x,y)...)
|
423 |
|
|
*(x::Number, y::Number) = *(promote(x,y)...)
|
424 |
|
|
-(x::Number, y::Number) = -(promote(x,y)...)
|
425 |
|
|
/(x::Number, y::Number) = /(promote(x,y)...)
|
426 |
|
|
|
427 |
|
|
"""
|
428 |
|
|
^(x, y)
|
429 |
|
|
|
430 |
|
|
Exponentiation operator. If `x` is a matrix, computes matrix exponentiation.
|
431 |
|
|
|
432 |
|
|
If `y` is an `Int` literal (e.g. `2` in `x^2` or `-3` in `x^-3`), the Julia code
|
433 |
|
|
`x^y` is transformed by the compiler to `Base.literal_pow(^, x, Val(y))`, to
|
434 |
|
|
enable compile-time specialization on the value of the exponent.
|
435 |
|
|
(As a default fallback we have `Base.literal_pow(^, x, Val(y)) = ^(x,y)`,
|
436 |
|
|
where usually `^ == Base.^` unless `^` has been defined in the calling
|
437 |
|
|
namespace.) If `y` is a negative integer literal, then `Base.literal_pow`
|
438 |
|
|
transforms the operation to `inv(x)^-y` by default, where `-y` is positive.
|
439 |
|
|
|
440 |
|
|
# Examples
|
441 |
|
|
```jldoctest
|
442 |
|
|
julia> 3^5
|
443 |
|
|
243
|
444 |
|
|
|
445 |
|
|
julia> A = [1 2; 3 4]
|
446 |
|
|
2×2 Matrix{Int64}:
|
447 |
|
|
1 2
|
448 |
|
|
3 4
|
449 |
|
|
|
450 |
|
|
julia> A^3
|
451 |
|
|
2×2 Matrix{Int64}:
|
452 |
|
|
37 54
|
453 |
|
|
81 118
|
454 |
|
|
```
|
455 |
|
|
"""
|
456 |
|
|
^(x::Number, y::Number) = ^(promote(x,y)...)
|
457 |
|
|
|
458 |
|
|
fma(x::Number, y::Number, z::Number) = fma(promote(x,y,z)...)
|
459 |
|
|
muladd(x::Number, y::Number, z::Number) = muladd(promote(x,y,z)...)
|
460 |
|
|
|
461 |
|
|
==(x::Number, y::Number) = (==)(promote(x,y)...)
|
462 |
|
|
<( x::Real, y::Real) = (< )(promote(x,y)...)
|
463 |
|
|
<=(x::Real, y::Real) = (<=)(promote(x,y)...)
|
464 |
|
|
|
465 |
|
|
rem(x::Real, y::Real) = rem(promote(x,y)...)
|
466 |
|
|
mod(x::Real, y::Real) = mod(promote(x,y)...)
|
467 |
|
|
|
468 |
|
|
mod1(x::Real, y::Real) = mod1(promote(x,y)...)
|
469 |
|
|
fld1(x::Real, y::Real) = fld1(promote(x,y)...)
|
470 |
|
|
|
471 |
|
|
max(x::Real, y::Real) = max(promote(x,y)...)
|
472 |
|
|
min(x::Real, y::Real) = min(promote(x,y)...)
|
473 |
|
|
minmax(x::Real, y::Real) = minmax(promote(x, y)...)
|
474 |
|
|
|
475 |
|
|
if isdefined(Core, :Compiler)
|
476 |
|
|
const _return_type = Core.Compiler.return_type
|
477 |
|
|
else
|
478 |
|
|
_return_type(@nospecialize(f), @nospecialize(t)) = Any
|
479 |
|
|
end
|
480 |
|
|
|
481 |
|
|
function TupleOrBottom(tt...)
|
482 |
|
|
any(p -> p === Union{}, tt) && return Union{}
|
483 |
|
|
return Tuple{tt...}
|
484 |
|
|
end
|
485 |
|
|
|
486 |
|
|
"""
|
487 |
|
|
promote_op(f, argtypes...)
|
488 |
|
|
|
489 |
|
|
Guess what an appropriate container eltype would be for storing results of
|
490 |
|
|
`f(::argtypes...)`. The guess is in part based on type inference, so can change any time.
|
491 |
|
|
|
492 |
|
|
!!! warning
|
493 |
|
|
Due to its fragility, use of `promote_op` should be avoided. It is preferable to base
|
494 |
|
|
the container eltype on the type of the actual elements. Only in the absence of any
|
495 |
|
|
elements (for an empty result container), it may be unavoidable to call `promote_op`.
|
496 |
|
|
"""
|
497 |
|
|
function promote_op(f, S::Type...)
|
498 |
|
|
argT = TupleOrBottom(S...)
|
499 |
|
|
argT === Union{} && return Union{}
|
500 |
|
|
return _return_type(f, argT)
|
501 |
|
|
end
|
502 |
|
|
|
503 |
|
|
|
504 |
|
|
## catch-alls to prevent infinite recursion when definitions are missing ##
|
505 |
|
|
|
506 |
|
|
no_op_err(name, T) = error(name," not defined for ",T)
|
507 |
|
|
(+)(x::T, y::T) where {T<:Number} = no_op_err("+", T)
|
508 |
|
|
(*)(x::T, y::T) where {T<:Number} = no_op_err("*", T)
|
509 |
|
|
(-)(x::T, y::T) where {T<:Number} = no_op_err("-", T)
|
510 |
|
|
(/)(x::T, y::T) where {T<:Number} = no_op_err("/", T)
|
511 |
|
|
(^)(x::T, y::T) where {T<:Number} = no_op_err("^", T)
|
512 |
|
|
|
513 |
|
|
fma(x::T, y::T, z::T) where {T<:Number} = no_op_err("fma", T)
|
514 |
|
|
fma(x::Integer, y::Integer, z::Integer) = x*y+z
|
515 |
|
|
muladd(x::T, y::T, z::T) where {T<:Number} = x*y+z
|
516 |
|
|
|
517 |
|
|
(&)(x::T, y::T) where {T<:Integer} = no_op_err("&", T)
|
518 |
|
|
(|)(x::T, y::T) where {T<:Integer} = no_op_err("|", T)
|
519 |
|
|
xor(x::T, y::T) where {T<:Integer} = no_op_err("xor", T)
|
520 |
|
|
|
521 |
8 (3 %) |
8 (3 %) |
8 (3 %)
samples spent in ==
8 (100 %) (ex.),
8 (100 %) (incl.)
when called from iterate
line 901
(==)(x::T, y::T) where {T<:Number} = x === y
|
522 |
|
|
(< )(x::T, y::T) where {T<:Real} = no_op_err("<" , T)
|
523 |
|
|
(<=)(x::T, y::T) where {T<:Real} = (x == y) | (x < y)
|
524 |
|
|
|
525 |
|
|
rem(x::T, y::T) where {T<:Real} = no_op_err("rem", T)
|
526 |
|
|
mod(x::T, y::T) where {T<:Real} = no_op_err("mod", T)
|
527 |
|
|
|
528 |
|
|
min(x::Real) = x
|
529 |
|
|
max(x::Real) = x
|
530 |
|
|
minmax(x::Real) = (x, x)
|
531 |
|
|
|
532 |
|
|
max(x::T, y::T) where {T<:Real} = ifelse(y < x, x, y)
|
533 |
|
|
min(x::T, y::T) where {T<:Real} = ifelse(y < x, y, x)
|
534 |
|
|
minmax(x::T, y::T) where {T<:Real} = y < x ? (y, x) : (x, y)
|
535 |
|
|
|
536 |
|
|
flipsign(x::T, y::T) where {T<:Signed} = no_op_err("flipsign", T)
|