@@ -327,26 +327,81 @@ promote_type(::Type{T}, ::Type{T}) where {T} = T
327
327
promote_type (:: Type{T} , :: Type{Bottom} ) where {T} = T
328
328
promote_type (:: Type{Bottom} , :: Type{T} ) where {T} = T
329
329
330
- const _promote_type_binary_recursion_depth_limit_exception = let
331
- s = " `promote_type`: recursion depth limit reached, giving up; check for faulty/conflicting/missing `promote_rule` methods"
332
- ArgumentError (s)
330
+ """
331
+ TypePromotionError <: Exception
332
+
333
+ Exception type thrown by [`promote_type`](@ref) when giving up for either of two reasons:
334
+
335
+ * Because bugs in the [`promote_rule`](@ref) logic which would have caused infinite recursion were detected.
336
+
337
+ * Because a threshold on the recursion depth was reached.
338
+
339
+ Check for bugs in the [`promote_rule`](@ref) logic if this exception gets thrown.
340
+ """
341
+ struct TypePromotionError <: Exception
342
+ T_initial:: Type
343
+ S_initial:: Type
344
+ T:: Type
345
+ S:: Type
346
+ ts:: Type
347
+ st:: Type
348
+ threshold_reached:: Bool
333
349
end
334
- const _promote_type_binary_detected_infinite_recursion_exception = let
335
- s = " `promote_type`: detected unbounded recursion caused by faulty `promote_rule` logic"
336
- ArgumentError (s)
350
+
351
+ function showerror (io:: IO , e:: TypePromotionError )
352
+ print (io, " TypePromotionError: `promote_type(T, S)` failed: " )
353
+
354
+ desc = if e. threshold_reached
355
+ " giving up because the recursion depth limit was reached: check for faulty/conflicting/missing `promote_rule` methods\n "
356
+ else
357
+ " detected unbounded recursion caused by faulty `promote_rule` logic\n "
358
+ end
359
+
360
+ print (io, desc)
361
+
362
+ print (io, " initial `T`: " )
363
+ show (io, e. T_initial)
364
+ print (io, ' \n ' )
365
+
366
+ print (io, " initial `S`: " )
367
+ show (io, e. S_initial)
368
+ print (io, ' \n ' )
369
+
370
+ print (io, " next-to-last `T`: " )
371
+ show (io, e. T)
372
+ print (io, ' \n ' )
373
+
374
+ print (io, " next-to-last `S`: " )
375
+ show (io, e. S)
376
+ print (io, ' \n ' )
377
+
378
+ print (io, " last `T`: " )
379
+ show (io, e. ts)
380
+ print (io, ' \n ' )
381
+
382
+ print (io, " last `S`: " )
383
+ show (io, e. st)
384
+ print (io, ' \n ' )
385
+
386
+ nothing
337
387
end
338
- function _promote_type_binary_err_giving_up ()
388
+
389
+ function _promote_type_binary_err_giving_up (@nospecialize (T_initial:: Type ), @nospecialize (S_initial:: Type ), @nospecialize (T:: Type ), @nospecialize (S:: Type ), @nospecialize (ts:: Type ), @nospecialize (st:: Type ))
339
390
@noinline
340
- throw (_promote_type_binary_recursion_depth_limit_exception)
391
+ @_nospecializeinfer_meta
392
+ throw (TypePromotionError (T_initial, S_initial, T, S, ts, st, true ))
341
393
end
342
- function _promote_type_binary_err_detected_infinite_recursion ()
394
+ function _promote_type_binary_err_detected_infinite_recursion (@nospecialize (T_initial :: Type ), @nospecialize (S_initial :: Type ), @nospecialize (T :: Type ), @nospecialize (S :: Type ), @nospecialize (ts :: Type ), @nospecialize (st :: Type ) )
343
395
@noinline
344
- throw (_promote_type_binary_detected_infinite_recursion_exception)
396
+ @_nospecializeinfer_meta
397
+ throw (TypePromotionError (T_initial, S_initial, T, S, ts, st, false ))
345
398
end
399
+
346
400
function _promote_type_binary_detect_loop (T:: Type , S:: Type , A:: Type , B:: Type )
347
401
onesided (T:: Type , S:: Type , A:: Type , B:: Type ) = _types_are_equal (T, A) && _types_are_equal (S, B)
348
402
onesided (T, S, A, B) || onesided (T, S, B, A)
349
403
end
404
+
350
405
macro _promote_type_binary_step ()
351
406
e = quote
352
407
# Try promote_rule in both orders.
@@ -368,14 +423,18 @@ macro _promote_type_binary_step()
368
423
if _promote_type_binary_detect_loop (T, S, ts, st)
369
424
# This is not strictly necessary, as we already limit the recursion depth, but
370
425
# makes for nicer UX.
371
- _promote_type_binary_err_detected_infinite_recursion ()
426
+ _promote_type_binary_err_detected_infinite_recursion (T_initial, S_initial, T, S, ts, st )
372
427
end
373
428
T = ts
374
429
S = st
375
430
end
376
431
esc (e)
377
432
end
433
+
378
434
function _promote_type_binary (T:: Type , S:: Type )
435
+ T_initial = T
436
+ S_initial = S
437
+
379
438
@_promote_type_binary_step
380
439
@_promote_type_binary_step
381
440
@_promote_type_binary_step
@@ -385,7 +444,7 @@ function _promote_type_binary(T::Type, S::Type)
385
444
@_promote_type_binary_step
386
445
@_promote_type_binary_step
387
446
388
- _promote_type_binary_err_giving_up ()
447
+ _promote_type_binary_err_giving_up (T_initial, S_initial, T, S, ts, st )
389
448
end
390
449
391
450
function promote_type (:: Type{T} , :: Type{S} ) where {T,S}
0 commit comments