@@ -2363,7 +2363,16 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
23632363 else if tp1.isAny && ! tp2.isLambdaSub || tp1.isAnyKind || isBottom(tp2) then tp1
23642364 else if tp2.isAny && ! tp1.isLambdaSub || tp2.isAnyKind || isBottom(tp1) then tp2
23652365 else
2366- def mergedLub (tp1 : Type , tp2 : Type ): Type = {
2366+ def mergedLub (tp1 : Type , tp2 : Type ): Type =
2367+ // First, if tp1 and tp2 are the same singleton type, return one of them.
2368+ if tp1.isSingleton && isSubType(tp1, tp2, whenFrozen = ! canConstrain) then
2369+ return tp2
2370+ if tp2.isSingleton && isSubType(tp2, tp1, whenFrozen = ! canConstrain) then
2371+ return tp1
2372+
2373+ // Second, handle special cases when tp1 and tp2 are disjunctions of
2374+ // singleton types. This saves time otherwise spent in
2375+ // costly subtype comparisons performed in dropIfSub below.
23672376 tp1.atoms match
23682377 case Atoms .Range (lo1, hi1) if ! widenInUnions =>
23692378 tp2.atoms match
@@ -2373,18 +2382,22 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
23732382 if (hi1 & hi2).isEmpty then return orType(tp1, tp2, isSoft = isSoft)
23742383 case none =>
23752384 case none =>
2376- val t1 = mergeIfSuper(tp1, tp2, canConstrain)
2377- if (t1.exists) return t1
23782385
2379- val t2 = mergeIfSuper(tp2, tp1, canConstrain)
2380- if (t2.exists) return t2
2381-
2382- def widen (tp : Type ) = if (widenInUnions) tp.widen else tp.widenIfUnstable
2386+ // Third, try to simplify after widening as follows:
2387+ // 1. Drop all or-factors in tp2 that are subtypes of an or-factor
2388+ // in tp1, yielding tp2Final.
2389+ // 2. Drop all or-factors in tp1 that are subtypes of an or-factor
2390+ // in tp2Final, yielding tp1Final.
2391+ // 3. Combine the two final types in an OrType
2392+ def widen (tp : Type ) =
2393+ if widenInUnions then tp.widen else tp.widenIfUnstable
23832394 val tp1w = widen(tp1)
23842395 val tp2w = widen(tp2)
2385- if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w, canConstrain = canConstrain, isSoft = isSoft)
2386- else orType(tp1w, tp2w, isSoft = isSoft) // no need to check subtypes again
2387- }
2396+ val tp2Final = dropIfSub(tp2w, tp1w, canConstrain)
2397+ val tp1Final = dropIfSub(tp1w, tp2Final, canConstrain)
2398+ recombine(tp1Final, tp2Final, orType(_, _, isSoft = isSoft))
2399+ end mergedLub
2400+
23882401 mergedLub(dropExpr(tp1.stripLazyRef), dropExpr(tp2.stripLazyRef))
23892402 }
23902403
@@ -2448,21 +2461,34 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24482461 Nil
24492462 }
24502463
2451- private def recombineAnd (tp : AndType , tp1 : Type , tp2 : Type ) =
2452- if (! tp1.exists) tp2
2453- else if (! tp2.exists) tp1
2454- else tp.derivedAndType(tp1, tp2)
2464+ private def recombine (tp1 : Type , tp2 : Type , rebuild : (Type , Type ) => Type ): Type =
2465+ if ! tp1.exists then tp2
2466+ else if ! tp2.exists then tp1
2467+ else rebuild(tp1, tp2)
2468+
2469+
2470+ private def recombine (tp : AndOrType , tp1 : Type , tp2 : Type ): Type =
2471+ recombine(tp1, tp2, tp.derivedAndOrType)
24552472
24562473 /** If some (&-operand of) `tp` is a supertype of `sub` replace it with `NoType`.
24572474 */
24582475 private def dropIfSuper (tp : Type , sub : Type ): Type =
2459- if ( isSubTypeWhenFrozen(sub, tp)) NoType
2460- else tp match {
2476+ if isSubTypeWhenFrozen(sub, tp) then NoType
2477+ else tp match
24612478 case tp @ AndType (tp1, tp2) =>
2462- recombineAnd (tp, dropIfSuper(tp1, sub), dropIfSuper(tp2, sub))
2479+ recombine (tp, dropIfSuper(tp1, sub), dropIfSuper(tp2, sub))
24632480 case _ =>
24642481 tp
2465- }
2482+
2483+ private def dropIfSub (tp : Type , sup : Type , canConstrain : Boolean ): Type =
2484+ def isSub (sup : Type ): Boolean = sup.stripTypeVar match
2485+ case OrType (sup1, sup2) => isSub(sup1) || isSub(sup2)
2486+ case _ => isSubType(tp, sup, whenFrozen = ! canConstrain)
2487+ tp.stripTypeVar match
2488+ case tp @ OrType (tp1, tp2) =>
2489+ recombine(tp, dropIfSub(tp1, sup, canConstrain), dropIfSub(tp2, sup, canConstrain))
2490+ case _ =>
2491+ if isSub(sup) then NoType else tp
24662492
24672493 /** Merge `t1` into `tp2` if t1 is a subtype of some &-summand of tp2.
24682494 */
0 commit comments