@@ -2363,7 +2363,16 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2363
2363
else if tp1.isAny && ! tp2.isLambdaSub || tp1.isAnyKind || isBottom(tp2) then tp1
2364
2364
else if tp2.isAny && ! tp1.isLambdaSub || tp2.isAnyKind || isBottom(tp1) then tp2
2365
2365
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.
2367
2376
tp1.atoms match
2368
2377
case Atoms .Range (lo1, hi1) if ! widenInUnions =>
2369
2378
tp2.atoms match
@@ -2373,18 +2382,22 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2373
2382
if (hi1 & hi2).isEmpty then return orType(tp1, tp2, isSoft = isSoft)
2374
2383
case none =>
2375
2384
case none =>
2376
- val t1 = mergeIfSuper(tp1, tp2, canConstrain)
2377
- if (t1.exists) return t1
2378
2385
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
2383
2394
val tp1w = widen(tp1)
2384
2395
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
+
2388
2401
mergedLub(dropExpr(tp1.stripLazyRef), dropExpr(tp2.stripLazyRef))
2389
2402
}
2390
2403
@@ -2448,21 +2461,34 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2448
2461
Nil
2449
2462
}
2450
2463
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)
2455
2472
2456
2473
/** If some (&-operand of) `tp` is a supertype of `sub` replace it with `NoType`.
2457
2474
*/
2458
2475
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
2461
2478
case tp @ AndType (tp1, tp2) =>
2462
- recombineAnd (tp, dropIfSuper(tp1, sub), dropIfSuper(tp2, sub))
2479
+ recombine (tp, dropIfSuper(tp1, sub), dropIfSuper(tp2, sub))
2463
2480
case _ =>
2464
2481
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
2466
2492
2467
2493
/** Merge `t1` into `tp2` if t1 is a subtype of some &-summand of tp2.
2468
2494
*/
0 commit comments