@@ -418,7 +418,15 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
418418 case _ =>
419419 false
420420 }
421- joinOK || recur(tp11, tp2) && recur(tp12, tp2)
421+ def widenOK =
422+ (tp2.widenSingletons eq tp2) &&
423+ (tp1.widenSingletons ne tp1) &&
424+ recur(tp1.widenSingletons, tp2)
425+
426+ if (tp2.atoms.nonEmpty && canCompare(tp2.atoms))
427+ tp1.atoms.nonEmpty && tp1.atoms.subsetOf(tp2.atoms)
428+ else
429+ widenOK || joinOK || recur(tp11, tp2) && recur(tp12, tp2)
422430 case tp1 : MatchType =>
423431 val reduced = tp1.reduced
424432 if (reduced.exists) recur(reduced, tp2) else thirdTry
@@ -573,10 +581,28 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
573581 }
574582 compareTypeLambda
575583 case OrType (tp21, tp22) =>
576- val tp1a = tp1.widenDealiasKeepRefiningAnnots
584+ if (tp2.atoms.nonEmpty && canCompare(tp2.atoms))
585+ return tp1.atoms.nonEmpty && tp1.atoms.subsetOf(tp2.atoms) ||
586+ tp1.isRef(NothingClass )
587+
588+ // The next clause handles a situation like the one encountered in i2745.scala.
589+ // We have:
590+ //
591+ // x: A | B, x.type <:< A | X where X is a type variable
592+ //
593+ // We should instantiate X to B instead of x.type or A | B. To do this, we widen
594+ // the LHS to A | B and recur *without indicating that this is a lowApprox*. The
595+ // latter point is important since otherwise we would not get to instantiate X.
596+ // If that succeeds, fine. If not we continue and hit the `either` below.
597+ // That second path is important to handle comparisons with unions of singletons,
598+ // as in `1 <:< 1 | 2`.
599+ val tp1w = tp1.widen
600+ if ((tp1w ne tp1) && recur(tp1w, tp2))
601+ return true
602+
603+ val tp1a = tp1.dealiasKeepRefiningAnnots
577604 if (tp1a ne tp1)
578- // Follow the alias; this might avoid truncating the search space in the either below
579- // Note that it's safe to widen here because singleton types cannot be part of `|`.
605+ // Follow the alias; this might lead to an OrType on the left which needs to be split
580606 return recur(tp1a, tp2)
581607
582608 // Rewrite T1 <: (T211 & T212) | T22 to T1 <: (T211 | T22) and T1 <: (T212 | T22)
@@ -1038,6 +1064,23 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
10381064 else None
10391065 }
10401066
1067+ /** Check whether we can compare the given set of atoms with another to determine
1068+ * a subtype test between OrTypes. There is one situation where this is not
1069+ * the case, which has to do with SkolemTypes. TreeChecker sometimes expects two
1070+ * types to be equal that have different skolems. To account for this, we identify
1071+ * two different skolems in all phases `p`, where `p.isTyper` is false.
1072+ * But in that case comparing two sets of atoms that contain skolems
1073+ * for equality would give the wrong result, so we should not use the sets
1074+ * for comparisons.
1075+ */
1076+ def canCompare (atoms : Set [Type ]): Boolean =
1077+ ctx.phase.isTyper || {
1078+ val hasSkolems = new ExistsAccumulator (_.isInstanceOf [SkolemType ]) {
1079+ override def stopAtStatic = true
1080+ }
1081+ ! atoms.exists(hasSkolems(false , _))
1082+ }
1083+
10411084 /** Subtype test for corresponding arguments in `args1`, `args2` according to
10421085 * variances in type parameters `tparams2`.
10431086 *
@@ -1499,30 +1542,38 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
14991542 /** The greatest lower bound of a list types */
15001543 final def glb (tps : List [Type ]): Type = ((AnyType : Type ) /: tps)(glb)
15011544
1545+ def widenInUnions (implicit ctx : Context ): Boolean = ctx.scala2Mode || ctx.erasedTypes
1546+
15021547 /** The least upper bound of two types
15031548 * @param canConstrain If true, new constraints might be added to simplify the lub.
15041549 * @note We do not admit singleton types in or-types as lubs.
15051550 */
15061551 def lub (tp1 : Type , tp2 : Type , canConstrain : Boolean = false ): Type = /* >|>*/ trace(s " lub( ${tp1.show}, ${tp2.show}, canConstrain= $canConstrain) " , subtyping, show = true ) /* <|<*/ {
1507- if (tp1 eq tp2) tp1
1508- else if (! tp1.exists) tp1
1509- else if (! tp2.exists) tp2
1510- else if ((tp1 isRef AnyClass ) || (tp1 isRef AnyKindClass ) || (tp2 isRef NothingClass )) tp1
1511- else if ((tp2 isRef AnyClass ) || (tp2 isRef AnyKindClass ) || (tp1 isRef NothingClass )) tp2
1512- else {
1513- val t1 = mergeIfSuper(tp1, tp2, canConstrain)
1514- if (t1.exists) t1
1515- else {
1516- val t2 = mergeIfSuper(tp2, tp1, canConstrain)
1517- if (t2.exists) t2
1518- else {
1519- val tp1w = tp1.widen
1520- val tp2w = tp2.widen
1521- if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w)
1522- else orType(tp1w, tp2w) // no need to check subtypes again
1523- }
1552+ if (tp1 eq tp2) return tp1
1553+ if (! tp1.exists) return tp1
1554+ if (! tp2.exists) return tp2
1555+ if ((tp1 isRef AnyClass ) || (tp1 isRef AnyKindClass ) || (tp2 isRef NothingClass )) return tp1
1556+ if ((tp2 isRef AnyClass ) || (tp2 isRef AnyKindClass ) || (tp1 isRef NothingClass )) return tp2
1557+ val atoms1 = tp1.atoms
1558+ if (atoms1.nonEmpty && ! widenInUnions) {
1559+ val atoms2 = tp2.atoms
1560+ if (atoms2.nonEmpty) {
1561+ if (atoms1.subsetOf(atoms2)) return tp2
1562+ if (atoms2.subsetOf(atoms1)) return tp1
1563+ if ((atoms1 & atoms2).isEmpty) return orType(tp1, tp2)
15241564 }
15251565 }
1566+ val t1 = mergeIfSuper(tp1, tp2, canConstrain)
1567+ if (t1.exists) return t1
1568+
1569+ val t2 = mergeIfSuper(tp2, tp1, canConstrain)
1570+ if (t2.exists) return t2
1571+
1572+ def widen (tp : Type ) = if (widenInUnions) tp.widen else tp.widenIfUnstable
1573+ val tp1w = widen(tp1)
1574+ val tp2w = widen(tp2)
1575+ if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w)
1576+ else orType(tp1w, tp2w) // no need to check subtypes again
15261577 }
15271578
15281579 /** The least upper bound of a list of types */
@@ -2213,6 +2264,11 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
22132264 super .isSubType(tp1, tp2, approx)
22142265 }
22152266
2267+ override def recur (tp1 : Type , tp2 : Type ): Boolean =
2268+ traceIndented(s " ${show(tp1)} <:< ${show(tp2)} recur ${if (frozenConstraint) " frozen" else " " }" ) {
2269+ super .recur(tp1, tp2)
2270+ }
2271+
22162272 override def hasMatchingMember (name : Name , tp1 : Type , tp2 : RefinedType ): Boolean =
22172273 traceIndented(s " hasMatchingMember( ${show(tp1)} . $name, ${show(tp2.refinedInfo)}), member = ${show(tp1.member(name).info)}" ) {
22182274 super .hasMatchingMember(name, tp1, tp2)
0 commit comments