@@ -657,11 +657,24 @@ trait ConstraintHandling {
657
657
* as those could leak the annotation to users (see run/inferred-repeated-result).
658
658
*/
659
659
def widenInferred (inst : Type , bound : Type , widenUnions : Boolean )(using Context ): Type =
660
+ def typeSize (tp : Type ): Int = tp match
661
+ case tp : AndOrType => typeSize(tp.tp1) + typeSize(tp.tp2)
662
+ case _ => 1
663
+
660
664
def widenOr (tp : Type ) =
661
665
if widenUnions then
662
- val tpw = tp.widenUnion
663
- if (tpw ne tp) && ! isTransparent(tpw, traitOnly = false ) && (tpw <:< bound) then tpw else tp
664
- else tp.hardenUnions
666
+ val tpw = tp.widenUnion
667
+ if tpw ne tp then
668
+ if tpw.isTransparent() then
669
+ // Now also widen singletons of soft unions. Before these were skipped
670
+ // since we widenUnion on soft unions is independent of whether singletons
671
+ // are widened or not. This avoids an expensive subtype check in widenSingle,
672
+ // see 19907_*.scala for test cases.
673
+ tp.widenSingletons()
674
+ else if tpw <:< bound then tpw
675
+ else tp
676
+ else tp
677
+ else tp.hardenUnions
665
678
666
679
def widenSingle (tp : Type ) =
667
680
val tpw = tp.widenSingletons
@@ -674,8 +687,16 @@ trait ConstraintHandling {
674
687
val wideInst =
675
688
if isSingleton(bound) then inst
676
689
else
677
- val widenedFromSingle = widenSingle(inst)
678
- val widenedFromUnion = widenOr(widenedFromSingle)
690
+ val widenedFromUnion =
691
+ if widenUnions && typeSize(inst) > 64 then
692
+ // If the inferred type `inst` is too large, the subtype check for `bound` in `widenSingle`
693
+ // can be expensive due to comparisons between large union types, so we avoid it by
694
+ // `widenUnion` directly here.
695
+ // See issue #19907.
696
+ widenOr(inst)
697
+ else
698
+ val widenedFromSingle = widenSingle(inst)
699
+ if widenUnions then widenOr(widenedFromSingle) else widenedFromSingle.hardenUnions
679
700
val widened = dropTransparentTraits(widenedFromUnion, bound)
680
701
widenIrreducible(widened)
681
702
0 commit comments