@@ -302,19 +302,44 @@ promote_type(T) = T
302
302
promote_type (T, S, U) = (@inline ; promote_type (promote_type (T, S), U))
303
303
promote_type (T, S, U, V... ) = (@inline ; afoldl (promote_type, promote_type (T, S, U), V... ))
304
304
305
- promote_type (:: Type{Bottom} , :: Type{Bottom} ) = Bottom
306
- promote_type (:: Type{T} , :: Type{T} ) where {T} = T
307
- promote_type (:: Type{T} , :: Type{Bottom} ) where {T} = T
308
- promote_type (:: Type{Bottom} , :: Type{T} ) where {T} = T
309
-
310
305
function promote_type (:: Type{T} , :: Type{S} ) where {T,S}
311
- @inline
312
- # Try promote_rule in both orders. Typically only one is defined,
313
- # and there is a fallback returning Bottom below, so the common case is
314
- # promote_type(T, S) =>
315
- # promote_result(T, S, result, Bottom) =>
316
- # typejoin(result, Bottom) => result
317
- promote_result (T, S, promote_rule (T,S), promote_rule (S,T))
306
+ @_terminates_locally_meta
307
+ normalized_type (:: Type{Typ} ) where {Typ} = Typ
308
+ types_are_identical (:: Type{A} , :: Type{B} ) where {A,B} = A === B
309
+ is_bottom (:: Type{Typ} ) where {Typ} = Typ <: Bottom
310
+ left = T
311
+ right = S
312
+ for _ ∈ 1 : 1000
313
+ if types_are_identical (left, right) || is_bottom (left) || is_bottom (right)
314
+ break
315
+ end
316
+ # Try `promote_rule` in both orders.
317
+ a = normalized_type (promote_rule (left, right))
318
+ b = normalized_type (promote_rule (right, left))
319
+ loop_is_detected_1 = types_are_identical (left, a) && types_are_identical (right, b)
320
+ loop_is_detected_2 = types_are_identical (left, b) && types_are_identical (right, a)
321
+ if loop_is_detected_1 || loop_is_detected_2
322
+ let s = LazyString (" `promote_type(" , T, " , " , S, " )` failed, there are conflicting `promote_rule` definitions for types " , a, " , " , b)
323
+ throw (ArgumentError (s))
324
+ end
325
+ end
326
+ if is_bottom (a) && is_bottom (b)
327
+ # If no `promote_rule` is defined, both directions give `Bottom`. In that
328
+ # case use `typejoin` on the original types.
329
+ return typejoin (left, right)
330
+ end
331
+ left = a
332
+ right = b
333
+ end
334
+ if (left === right) || is_bottom (left)
335
+ right
336
+ elseif is_bottom (right)
337
+ left
338
+ else
339
+ let s = LazyString (" `promote_type(" , T, " , " , S, " )` failed, ended up with (" , left, " , " , right, " ), check for faulty `promote_rule` methods" )
340
+ throw (ArgumentError (s))
341
+ end
342
+ end
318
343
end
319
344
320
345
"""
@@ -334,11 +359,6 @@ promote_rule(::Type{Bottom}, ::Type{Bottom}, slurp...) = Bottom # not strictly n
334
359
promote_rule (:: Type{Bottom} , :: Type{T} , slurp... ) where {T} = T
335
360
promote_rule (:: Type{T} , :: Type{Bottom} , slurp... ) where {T} = T
336
361
337
- promote_result (:: Type ,:: Type ,:: Type{T} ,:: Type{S} ) where {T,S} = (@inline ; promote_type (T,S))
338
- # If no promote_rule is defined, both directions give Bottom. In that
339
- # case use typejoin on the original types instead.
340
- promote_result (:: Type{T} ,:: Type{S} ,:: Type{Bottom} ,:: Type{Bottom} ) where {T,S} = (@inline ; typejoin (T, S))
341
-
342
362
"""
343
363
promote(xs...)
344
364
0 commit comments