Skip to content

Commit d77ce17

Browse files
committed
replace recursion with metaprogramming, enabling stronger inference
In particular, this enables more calls to be constant folded.
1 parent ea704c1 commit d77ce17

File tree

1 file changed

+38
-38
lines changed

1 file changed

+38
-38
lines changed

base/promotion.jl

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -347,45 +347,45 @@ function _promote_type_binary_detect_loop(T::Type, S::Type, A::Type, B::Type)
347347
onesided(T::Type, S::Type, A::Type, B::Type) = _types_are_equal(T, A) && _types_are_equal(S, B)
348348
onesided(T, S, A, B) || onesided(T, S, B, A)
349349
end
350-
function _promote_type_binary(T::Type, S::Type, recursion_depth_limit::Tuple{Vararg{Nothing}})
351-
# Try promote_rule in both orders.
352-
ts = promote_rule(T, S)
353-
st = promote_rule(S, T)
354-
# If no promote_rule is defined, both directions give Bottom. In that
355-
# case use typejoin on the original types instead.
356-
st_is_bottom = _type_is_bottom(st)
357-
ts_is_bottom = _type_is_bottom(ts)
358-
if st_is_bottom && ts_is_bottom
359-
return typejoin(T, S)
360-
end
361-
if ts_is_bottom
362-
return st
363-
end
364-
if st_is_bottom || _types_are_equal(st, ts)
365-
return ts
366-
end
367-
if _promote_type_binary_detect_loop(T, S, ts, st)
368-
# This is not strictly necessary, as we already limit the recursion depth, but
369-
# makes for nicer UX.
370-
_promote_type_binary_err_detected_infinite_recursion()
371-
end
372-
if recursion_depth_limit === ()
373-
_promote_type_binary_err_giving_up()
350+
macro _promote_type_binary_step()
351+
e = quote
352+
# Try promote_rule in both orders.
353+
ts = promote_rule(T, S)
354+
st = promote_rule(S, T)
355+
# If no promote_rule is defined, both directions give Bottom. In that
356+
# case use typejoin on the original types instead.
357+
st_is_bottom = _type_is_bottom(st)
358+
ts_is_bottom = _type_is_bottom(ts)
359+
if st_is_bottom && ts_is_bottom
360+
return typejoin(T, S)
361+
end
362+
if ts_is_bottom
363+
return st
364+
end
365+
if st_is_bottom || _types_are_equal(st, ts)
366+
return ts
367+
end
368+
if _promote_type_binary_detect_loop(T, S, ts, st)
369+
# This is not strictly necessary, as we already limit the recursion depth, but
370+
# makes for nicer UX.
371+
_promote_type_binary_err_detected_infinite_recursion()
372+
end
373+
T = ts
374+
S = st
374375
end
375-
l = tail(recursion_depth_limit)
376-
_promote_type_binary(ts, st, l)
376+
esc(e)
377377
end
378-
379-
"""
380-
_promote_type_binary_recursion_depth_limit::Tuple{Vararg{Nothing}}
381-
382-
Recursion depth limit for `_promote_type_binary`, to prevent stack overflow.
383-
"""
384-
const _promote_type_binary_recursion_depth_limit = let
385-
n2 = (nothing, nothing)
386-
n4 = (n2..., n2...)
387-
n8 = (n4..., n4...)
388-
n8
378+
function _promote_type_binary(T::Type, S::Type)
379+
@_promote_type_binary_step
380+
@_promote_type_binary_step
381+
@_promote_type_binary_step
382+
@_promote_type_binary_step
383+
@_promote_type_binary_step
384+
@_promote_type_binary_step
385+
@_promote_type_binary_step
386+
@_promote_type_binary_step
387+
388+
_promote_type_binary_err_giving_up()
389389
end
390390

391391
function promote_type(::Type{T}, ::Type{S}) where {T,S}
@@ -395,7 +395,7 @@ function promote_type(::Type{T}, ::Type{S}) where {T,S}
395395
if _type_is_bottom(S) || _types_are_equal(S, T)
396396
return T
397397
end
398-
_promote_type_binary(T, S, _promote_type_binary_recursion_depth_limit)
398+
_promote_type_binary(T, S)
399399
end
400400

401401
"""

0 commit comments

Comments
 (0)