@@ -2018,12 +2018,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2018
2018
val tp2a = dropIfSuper(tp2, tp1)
2019
2019
if tp2a ne tp2 then glb(tp1, tp2a)
2020
2020
else tp2 match // normalize to disjunctive normal form if possible.
2021
- case OrType (tp21, tp22) =>
2022
- tp1 & tp21 | tp1 & tp22
2021
+ case tp2 @ OrType (tp21, tp22) =>
2022
+ lub( tp1 & tp21, tp1 & tp22, isSoft = tp2.isSoft)
2023
2023
case _ =>
2024
2024
tp1 match
2025
- case OrType (tp11, tp12) =>
2026
- tp11 & tp2 | tp12 & tp2
2025
+ case tp1 @ OrType (tp11, tp12) =>
2026
+ lub( tp11 & tp2, tp12 & tp2, isSoft = tp1.isSoft)
2027
2027
case tp1 : ConstantType =>
2028
2028
tp2 match
2029
2029
case tp2 : ConstantType =>
@@ -2045,9 +2045,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2045
2045
2046
2046
/** The least upper bound of two types
2047
2047
* @param canConstrain If true, new constraints might be added to simplify the lub.
2048
+ * @param isSoft If the lub is a union, this determines whether it's a soft union.
2048
2049
* @note We do not admit singleton types in or-types as lubs.
2049
2050
*/
2050
- def lub (tp1 : Type , tp2 : Type , canConstrain : Boolean = false ): Type = /* >|>*/ trace(s " lub( ${tp1.show}, ${tp2.show}, canConstrain= $canConstrain) " , subtyping, show = true ) /* <|<*/ {
2051
+ 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 ) /* <|<*/ {
2051
2052
if (tp1 eq tp2) tp1
2052
2053
else if (! tp1.exists) tp1
2053
2054
else if (! tp2.exists) tp2
@@ -2073,8 +2074,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2073
2074
def widen (tp : Type ) = if (widenInUnions) tp.widen else tp.widenIfUnstable
2074
2075
val tp1w = widen(tp1)
2075
2076
val tp2w = widen(tp2)
2076
- if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w, canConstrain)
2077
- else orType(tp1w, tp2w) // no need to check subtypes again
2077
+ if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w, canConstrain = canConstrain, isSoft = isSoft )
2078
+ else orType(tp1w, tp2w, isSoft = isSoft ) // no need to check subtypes again
2078
2079
}
2079
2080
mergedLub(tp1.stripLazyRef, tp2.stripLazyRef)
2080
2081
}
@@ -2183,11 +2184,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2183
2184
case tp2 @ OrType (tp21, tp22) =>
2184
2185
val higher1 = mergeIfSuper(tp1, tp21, canConstrain)
2185
2186
if (higher1 eq tp21) tp2
2186
- else if (higher1.exists) higher1 | tp22
2187
+ else if (higher1.exists) lub( higher1, tp22, isSoft = tp2.isSoft)
2187
2188
else {
2188
2189
val higher2 = mergeIfSuper(tp1, tp22, canConstrain)
2189
2190
if (higher2 eq tp22) tp2
2190
- else if (higher2.exists) tp21 | higher2
2191
+ else if (higher2.exists) lub( tp21, higher2, isSoft = tp2.isSoft)
2191
2192
else NoType
2192
2193
}
2193
2194
case _ =>
@@ -2235,17 +2236,18 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2235
2236
* ExprType, LambdaType). Also, when forming an `|`,
2236
2237
* instantiated TypeVars are dereferenced and annotations are stripped.
2237
2238
*
2239
+ * @param isSoft If the result is a union, this determines whether it's a soft union.
2238
2240
* @param isErased Apply erasure semantics. If erased is true, instead of creating
2239
2241
* an OrType, the lub will be computed using TypeCreator#erasedLub.
2240
2242
*/
2241
- final def orType (tp1 : Type , tp2 : Type , isErased : Boolean = ctx.erasedTypes): Type = {
2242
- val t1 = distributeOr(tp1, tp2)
2243
+ final def orType (tp1 : Type , tp2 : Type , isSoft : Boolean = true , isErased : Boolean = ctx.erasedTypes): Type = {
2244
+ val t1 = distributeOr(tp1, tp2, isSoft )
2243
2245
if (t1.exists) t1
2244
2246
else {
2245
- val t2 = distributeOr(tp2, tp1)
2247
+ val t2 = distributeOr(tp2, tp1, isSoft )
2246
2248
if (t2.exists) t2
2247
2249
else if (isErased) erasedLub(tp1, tp2)
2248
- else liftIfHK(tp1, tp2, OrType (_, _, soft = true ), _ | _, _ & _)
2250
+ else liftIfHK(tp1, tp2, OrType (_, _, soft = isSoft ), _ | _, _ & _)
2249
2251
}
2250
2252
}
2251
2253
@@ -2333,18 +2335,18 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2333
2335
*
2334
2336
* The rhs is a proper supertype of the lhs.
2335
2337
*/
2336
- private def distributeOr (tp1 : Type , tp2 : Type ): Type = tp1 match {
2338
+ private def distributeOr (tp1 : Type , tp2 : Type , isSoft : Boolean = true ): Type = tp1 match {
2337
2339
case ExprType (rt1) =>
2338
2340
tp2 match {
2339
2341
case ExprType (rt2) =>
2340
- ExprType (rt1 | rt2)
2342
+ ExprType (lub( rt1, rt2, isSoft = isSoft) )
2341
2343
case _ =>
2342
2344
NoType
2343
2345
}
2344
2346
case tp1 : TypeVar if tp1.isInstantiated =>
2345
- tp1.underlying | tp2
2347
+ lub( tp1.underlying, tp2, isSoft = isSoft)
2346
2348
case tp1 : AnnotatedType if ! tp1.isRefining =>
2347
- tp1.underlying | tp2
2349
+ lub( tp1.underlying, tp2, isSoft = isSoft)
2348
2350
case _ =>
2349
2351
NoType
2350
2352
}
@@ -2699,8 +2701,8 @@ object TypeComparer {
2699
2701
def matchingMethodParams (tp1 : MethodType , tp2 : MethodType )(using Context ): Boolean =
2700
2702
comparing(_.matchingMethodParams(tp1, tp2))
2701
2703
2702
- def lub (tp1 : Type , tp2 : Type , canConstrain : Boolean = false )(using Context ): Type =
2703
- comparing(_.lub(tp1, tp2, canConstrain))
2704
+ def lub (tp1 : Type , tp2 : Type , canConstrain : Boolean = false , isSoft : Boolean = true )(using Context ): Type =
2705
+ comparing(_.lub(tp1, tp2, canConstrain = canConstrain, isSoft = isSoft ))
2704
2706
2705
2707
/** The least upper bound of a list of types */
2706
2708
final def lub (tps : List [Type ])(using Context ): Type =
@@ -2716,8 +2718,8 @@ object TypeComparer {
2716
2718
def glb (tps : List [Type ])(using Context ): Type =
2717
2719
tps.foldLeft(defn.AnyType : Type )(glb)
2718
2720
2719
- def orType (using Context )(tp1 : Type , tp2 : Type , isErased : Boolean = ctx.erasedTypes): Type =
2720
- comparing(_.orType(tp1, tp2, isErased))
2721
+ def orType (using Context )(tp1 : Type , tp2 : Type , isSoft : Boolean = true , isErased : Boolean = ctx.erasedTypes): Type =
2722
+ comparing(_.orType(tp1, tp2, isSoft = isSoft, isErased = isErased))
2721
2723
2722
2724
def andType (using Context )(tp1 : Type , tp2 : Type , isErased : Boolean = ctx.erasedTypes): Type =
2723
2725
comparing(_.andType(tp1, tp2, isErased))
@@ -2946,9 +2948,9 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
2946
2948
super .hasMatchingMember(name, tp1, tp2)
2947
2949
}
2948
2950
2949
- override def lub (tp1 : Type , tp2 : Type , canConstrain : Boolean = false ): Type =
2950
- traceIndented(s " lub( ${show(tp1)}, ${show(tp2)}, canConstrain= $canConstrain) " ) {
2951
- super .lub(tp1, tp2, canConstrain)
2951
+ override def lub (tp1 : Type , tp2 : Type , canConstrain : Boolean , isSoft : Boolean ): Type =
2952
+ traceIndented(s " lub( ${show(tp1)}, ${show(tp2)}, canConstrain= $canConstrain, isSoft= $isSoft ) " ) {
2953
+ super .lub(tp1, tp2, canConstrain, isSoft )
2952
2954
}
2953
2955
2954
2956
override def glb (tp1 : Type , tp2 : Type ): Type =
0 commit comments