@@ -307,19 +307,52 @@ promote_type(T) = T
307
307
promote_type (T, S, U) = (@inline ; promote_type (promote_type (T, S), U))
308
308
promote_type (T, S, U, V... ) = (@inline ; afoldl (promote_type, promote_type (T, S, U), V... ))
309
309
310
- promote_type (:: Type{Bottom} , :: Type{Bottom} ) = Bottom
311
- promote_type (:: Type{T} , :: Type{T} ) where {T} = T
312
- promote_type (:: Type{T} , :: Type{Bottom} ) where {T} = T
313
- promote_type (:: Type{Bottom} , :: Type{T} ) where {T} = T
314
-
315
310
function promote_type (:: Type{T} , :: Type{S} ) where {T,S}
316
- @inline
317
- # Try promote_rule in both orders. Typically only one is defined,
318
- # and there is a fallback returning Bottom below, so the common case is
319
- # promote_type(T, S) =>
320
- # promote_result(T, S, result, Bottom) =>
321
- # typejoin(result, Bottom) => result
322
- promote_result (T, S, promote_rule (T,S), promote_rule (S,T))
311
+ @_terminates_locally_meta
312
+ normalized_type (:: Type{Typ} ) where {Typ} = Typ
313
+ types_are_equal (:: Type , :: Type ) = false
314
+ types_are_equal (:: Type{Typ} , :: Type{Typ} ) where {Typ} = true
315
+ is_bottom (:: Type ) = false
316
+ is_bottom (:: Type{Bottom} ) = true
317
+ function throw_conflicting_promote_rules ((@nospecialize i1:: Type ), (@nospecialize i2:: Type ), (@nospecialize left:: Type ), (@nospecialize right:: Type ))
318
+ @noinline
319
+ s = LazyString (" `promote_type(" , i1, " , " , i2, " )` failed, there are conflicting `promote_rule` definitions for types " , left, " , " , right)
320
+ throw (ArgumentError (s))
321
+ end
322
+ function throw_gave_up ((@nospecialize i1:: Type ), (@nospecialize i2:: Type ), (@nospecialize left:: Type ), (@nospecialize right:: Type ))
323
+ @noinline
324
+ s = LazyString (" `promote_type(" , i1, " , " , i2, " )` failed, ended up with (" , left, " , " , right, " ), check for faulty `promote_rule` methods" )
325
+ throw (ArgumentError (s))
326
+ end
327
+ left = T
328
+ right = S
329
+ for _ ∈ 1 : 1000 # guarantee local termination
330
+ if types_are_equal (left, right) || is_bottom (left) || is_bottom (right)
331
+ break
332
+ end
333
+ # Try `promote_rule` in both orders.
334
+ a = normalized_type (promote_rule (left, right))
335
+ b = normalized_type (promote_rule (right, left))
336
+ loop_is_detected_1 = types_are_equal (left, a) && types_are_equal (right, b)
337
+ loop_is_detected_2 = types_are_equal (left, b) && types_are_equal (right, a)
338
+ if loop_is_detected_1 || loop_is_detected_2
339
+ throw_conflicting_promote_rules (T, S, left, right)
340
+ end
341
+ if is_bottom (a) && is_bottom (b)
342
+ # If no `promote_rule` is defined, both directions give `Bottom`. In that
343
+ # case use `typejoin` on the original types.
344
+ return typejoin (left, right)
345
+ end
346
+ left = a
347
+ right = b
348
+ end
349
+ if types_are_equal (left, right) || is_bottom (left)
350
+ right
351
+ elseif is_bottom (right)
352
+ left
353
+ else
354
+ throw_gave_up (T, S, left, right)
355
+ end
323
356
end
324
357
325
358
"""
@@ -339,11 +372,6 @@ promote_rule(::Type{Bottom}, ::Type{Bottom}, slurp...) = Bottom # not strictly n
339
372
promote_rule (:: Type{Bottom} , :: Type{T} , slurp... ) where {T} = T
340
373
promote_rule (:: Type{T} , :: Type{Bottom} , slurp... ) where {T} = T
341
374
342
- promote_result (:: Type ,:: Type ,:: Type{T} ,:: Type{S} ) where {T,S} = (@inline ; promote_type (T,S))
343
- # If no promote_rule is defined, both directions give Bottom. In that
344
- # case use typejoin on the original types instead.
345
- promote_result (:: Type{T} ,:: Type{S} ,:: Type{Bottom} ,:: Type{Bottom} ) where {T,S} = (@inline ; typejoin (T, S))
346
-
347
375
"""
348
376
promote(xs...)
349
377
0 commit comments