@@ -2352,8 +2352,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
23522352 }
23532353
23542354 /** The greatest lower bound of two types */
2355- def glb (tp1 : Type , tp2 : Type ): Type = /* >|> * / trace(s " glb( ${tp1.show}, ${tp2.show}) " , subtyping, show = true ) /* <|< */ {
2356- if ( tp1 eq tp2) tp1
2355+ def glb (tp1 : Type , tp2 : Type ): Type = // trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true):
2356+ if tp1 eq tp2 then tp1
23572357 else if ! tp1.exists || (tp1 eq WildcardType ) then tp2
23582358 else if ! tp2.exists || (tp2 eq WildcardType ) then tp1
23592359 else if tp1.isAny && ! tp2.isLambdaSub || tp1.isAnyKind || isBottom(tp2) then tp2
@@ -2366,12 +2366,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
23662366 val tp2a = dropIfSuper(tp2, tp1)
23672367 if tp2a ne tp2 then glb(tp1, tp2a)
23682368 else tp2 match // normalize to disjunctive normal form if possible.
2369- case tp2 @ OrType (tp21, tp22 ) =>
2370- lub(tp1 & tp21 , tp1 & tp22 , isSoft = tp2.isSoft)
2369+ case tp2 @ OrType (tp2L, tp2R ) =>
2370+ lub(tp1 & tp2L , tp1 & tp2R , isSoft = tp2.isSoft)
23712371 case _ =>
23722372 tp1 match
2373- case tp1 @ OrType (tp11, tp12 ) =>
2374- lub(tp11 & tp2, tp12 & tp2, isSoft = tp1.isSoft)
2373+ case tp1 @ OrType (tp1L, tp1R ) =>
2374+ lub(tp1L & tp2, tp1R & tp2, isSoft = tp1.isSoft)
23752375 case tp1 : ConstantType =>
23762376 tp2 match
23772377 case tp2 : ConstantType =>
@@ -2386,8 +2386,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
23862386 NothingType
23872387 case _ => andType(tp1, tp2)
23882388 case _ => andType(tp1, tp2)
2389+ end mergedGlb
2390+
23892391 mergedGlb(dropExpr(tp1.stripLazyRef), dropExpr(tp2.stripLazyRef))
2390- }
2392+ end glb
23912393
23922394 def widenInUnions (using Context ): Boolean =
23932395 migrateTo3 || ctx.erasedTypes
@@ -2396,14 +2398,23 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
23962398 * @param canConstrain If true, new constraints might be added to simplify the lub.
23972399 * @param isSoft If the lub is a union, this determines whether it's a soft union.
23982400 */
2399- def lub (tp1 : Type , tp2 : Type , canConstrain : Boolean = false , isSoft : Boolean = true ): Type = /* >|> * / trace(s " lub( ${tp1.show}, ${tp2.show}, canConstrain= $canConstrain, isSoft= $isSoft) " , subtyping, show = true ) /* <|< */ {
2400- if ( tp1 eq tp2) tp1
2401+ def lub (tp1 : Type , tp2 : Type , canConstrain : Boolean = false , isSoft : Boolean = true ): Type = // trace(s"lub(${tp1.show}, ${tp2.show}, canConstrain=$canConstrain, isSoft=$isSoft)", subtyping, show = true):
2402+ if tp1 eq tp2 then tp1
24012403 else if ! tp1.exists || (tp2 eq WildcardType ) then tp1
24022404 else if ! tp2.exists || (tp1 eq WildcardType ) then tp2
24032405 else if tp1.isAny && ! tp2.isLambdaSub || tp1.isAnyKind || isBottom(tp2) then tp1
24042406 else if tp2.isAny && ! tp1.isLambdaSub || tp2.isAnyKind || isBottom(tp1) then tp2
24052407 else
2406- def mergedLub (tp1 : Type , tp2 : Type ): Type = {
2408+ def mergedLub (tp1 : Type , tp2 : Type ): Type =
2409+ // First, if tp1 and tp2 are the same singleton type, return one of them.
2410+ if tp1.isSingleton && isSubType(tp1, tp2, whenFrozen = ! canConstrain) then
2411+ return tp2
2412+ if tp2.isSingleton && isSubType(tp2, tp1, whenFrozen = ! canConstrain) then
2413+ return tp1
2414+
2415+ // Second, handle special cases when tp1 and tp2 are disjunctions of
2416+ // singleton types. This saves time otherwise spent in
2417+ // costly subtype comparisons performed in dropIfSub below.
24072418 tp1.atoms match
24082419 case Atoms .Range (lo1, hi1) if ! widenInUnions =>
24092420 tp2.atoms match
@@ -2413,20 +2424,24 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24132424 if (hi1 & hi2).isEmpty then return orType(tp1, tp2, isSoft = isSoft)
24142425 case none =>
24152426 case none =>
2416- val t1 = mergeIfSuper(tp1, tp2, canConstrain)
2417- if (t1.exists) return t1
24182427
2419- val t2 = mergeIfSuper(tp2, tp1, canConstrain)
2420- if (t2.exists) return t2
2421-
2422- def widen (tp : Type ) = if (widenInUnions) tp.widen else tp.widenIfUnstable
2428+ // Third, try to simplify after widening as follows:
2429+ // 1. Drop all or-factors in tp2 that are subtypes of an or-factor
2430+ // in tp1, yielding tp2Final.
2431+ // 2. Drop all or-factors in tp1 that are subtypes of an or-factor
2432+ // in tp2Final, yielding tp1Final.
2433+ // 3. Combine the two final types in an OrType
2434+ def widen (tp : Type ) =
2435+ if widenInUnions then tp.widen else tp.widenIfUnstable
24232436 val tp1w = widen(tp1)
24242437 val tp2w = widen(tp2)
2425- if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w, canConstrain = canConstrain, isSoft = isSoft)
2426- else orType(tp1w, tp2w, isSoft = isSoft) // no need to check subtypes again
2427- }
2438+ val tp2Final = dropIfSub(tp2w, tp1w, canConstrain)
2439+ val tp1Final = dropIfSub(tp1w, tp2Final, canConstrain)
2440+ recombine(tp1Final, tp2Final, orType(_, _, isSoft = isSoft))
2441+ end mergedLub
2442+
24282443 mergedLub(dropExpr(tp1.stripLazyRef), dropExpr(tp2.stripLazyRef))
2429- }
2444+ end lub
24302445
24312446 /** Try to produce joint arguments for a lub `A[T_1, ..., T_n] | A[T_1', ..., T_n']` using
24322447 * the following strategies:
@@ -2488,60 +2503,48 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24882503 Nil
24892504 }
24902505
2491- private def recombineAnd (tp : AndType , tp1 : Type , tp2 : Type ) =
2492- if (! tp1.exists) tp2
2493- else if (! tp2.exists) tp1
2494- else tp.derivedAndType(tp1, tp2)
2506+ private def recombine (tp1 : Type , tp2 : Type , rebuild : (Type , Type ) => Type ): Type =
2507+ if ! tp1.exists then tp2
2508+ else if ! tp2.exists then tp1
2509+ else rebuild(tp1, tp2)
2510+
2511+ private def recombine (tp1 : Type , tp2 : Type , tp : AndOrType ): Type =
2512+ recombine(tp1, tp2, tp.derivedAndOrType)
24952513
24962514 /** If some (&-operand of) `tp` is a supertype of `sub` replace it with `NoType`.
24972515 */
24982516 private def dropIfSuper (tp : Type , sub : Type ): Type =
2499- if (isSubTypeWhenFrozen(sub, tp)) NoType
2500- else tp match {
2517+
2518+ def isSuperOf (sub : Type ): Boolean = sub match
2519+ case AndType (sub1, sub2) => isSuperOf(sub1) || isSuperOf(sub2)
2520+ case sub : TypeVar if sub.isInstantiated => isSuperOf(sub.inst)
2521+ case _ => isSubTypeWhenFrozen(sub, tp)
2522+
2523+ tp match
25012524 case tp @ AndType (tp1, tp2) =>
2502- recombineAnd(tp, dropIfSuper(tp1, sub), dropIfSuper(tp2, sub))
2525+ recombine(dropIfSuper(tp1, sub), dropIfSuper(tp2, sub), tp)
2526+ case tp : TypeVar if tp.isInstantiated =>
2527+ dropIfSuper(tp.inst, sub)
25032528 case _ =>
2504- tp
2505- }
2529+ if isSuperOf(sub) then NoType else tp
2530+ end dropIfSuper
25062531
2507- /** Merge `t1` into `tp2` if t1 is a subtype of some &-summand of tp2.
2508- */
2509- private def mergeIfSub (tp1 : Type , tp2 : Type ): Type =
2510- if (isSubTypeWhenFrozen(tp1, tp2)) tp1
2511- else tp2 match {
2512- case tp2 @ AndType (tp21, tp22) =>
2513- val lower1 = mergeIfSub(tp1, tp21)
2514- if (lower1 eq tp21) tp2
2515- else if (lower1.exists) lower1 & tp22
2516- else {
2517- val lower2 = mergeIfSub(tp1, tp22)
2518- if (lower2 eq tp22) tp2
2519- else if (lower2.exists) tp21 & lower2
2520- else NoType
2521- }
2522- case _ =>
2523- NoType
2524- }
2532+ /** If some (|-operand of) `tp` is a subtype of `sup` replace it with `NoType`. */
2533+ private def dropIfSub (tp : Type , sup : Type , canConstrain : Boolean ): Type =
25252534
2526- /** Merge `tp1` into `tp2` if tp1 is a supertype of some |-summand of tp2.
2527- * @param canConstrain If true, new constraints might be added to make the merge possible.
2528- */
2529- private def mergeIfSuper (tp1 : Type , tp2 : Type , canConstrain : Boolean ): Type =
2530- if (isSubType(tp2, tp1, whenFrozen = ! canConstrain)) tp1
2531- else tp2 match {
2532- case tp2 @ OrType (tp21, tp22) =>
2533- val higher1 = mergeIfSuper(tp1, tp21, canConstrain)
2534- if (higher1 eq tp21) tp2
2535- else if (higher1.exists) lub(higher1, tp22, isSoft = tp2.isSoft)
2536- else {
2537- val higher2 = mergeIfSuper(tp1, tp22, canConstrain)
2538- if (higher2 eq tp22) tp2
2539- else if (higher2.exists) lub(tp21, higher2, isSoft = tp2.isSoft)
2540- else NoType
2541- }
2535+ def isSubOf (sup : Type ): Boolean = sup match
2536+ case OrType (sup1, sup2) => isSubOf(sup1) || isSubOf(sup2)
2537+ case sup : TypeVar if sup.isInstantiated => isSubOf(sup.inst)
2538+ case _ => isSubType(tp, sup, whenFrozen = ! canConstrain)
2539+
2540+ tp match
2541+ case tp @ OrType (tp1, tp2) =>
2542+ recombine(dropIfSub(tp1, sup, canConstrain), dropIfSub(tp2, sup, canConstrain), tp)
2543+ case tp : TypeVar if tp.isInstantiated =>
2544+ dropIfSub(tp.inst, sup, canConstrain)
25422545 case _ =>
2543- NoType
2544- }
2546+ if isSubOf(sup) then NoType else tp
2547+ end dropIfSub
25452548
25462549 /** There's a window of vulnerability between ElimByName and Erasure where some
25472550 * ExprTypes `=> T` that appear as parameters of function types are not yet converted
0 commit comments