@@ -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  =  /*  >|> * /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  =  /*  >|> * /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