@@ -418,7 +418,15 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
418
418
case _ =>
419
419
false
420
420
}
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)
422
430
case tp1 : MatchType =>
423
431
val reduced = tp1.reduced
424
432
if (reduced.exists) recur(reduced, tp2) else thirdTry
@@ -573,10 +581,28 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
573
581
}
574
582
compareTypeLambda
575
583
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
577
604
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
580
606
return recur(tp1a, tp2)
581
607
582
608
// Rewrite T1 <: (T211 & T212) | T22 to T1 <: (T211 | T22) and T1 <: (T212 | T22)
@@ -1038,6 +1064,23 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
1038
1064
else None
1039
1065
}
1040
1066
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
+
1041
1084
/** Subtype test for corresponding arguments in `args1`, `args2` according to
1042
1085
* variances in type parameters `tparams2`.
1043
1086
*
@@ -1499,30 +1542,38 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
1499
1542
/** The greatest lower bound of a list types */
1500
1543
final def glb (tps : List [Type ]): Type = ((AnyType : Type ) /: tps)(glb)
1501
1544
1545
+ def widenInUnions (implicit ctx : Context ): Boolean = ctx.scala2Mode || ctx.erasedTypes
1546
+
1502
1547
/** The least upper bound of two types
1503
1548
* @param canConstrain If true, new constraints might be added to simplify the lub.
1504
1549
* @note We do not admit singleton types in or-types as lubs.
1505
1550
*/
1506
1551
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)
1524
1564
}
1525
1565
}
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
1526
1577
}
1527
1578
1528
1579
/** The least upper bound of a list of types */
@@ -2213,6 +2264,11 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
2213
2264
super .isSubType(tp1, tp2, approx)
2214
2265
}
2215
2266
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
+
2216
2272
override def hasMatchingMember (name : Name , tp1 : Type , tp2 : RefinedType ): Boolean =
2217
2273
traceIndented(s " hasMatchingMember( ${show(tp1)} . $name, ${show(tp2.refinedInfo)}), member = ${show(tp1.member(name).info)}" ) {
2218
2274
super .hasMatchingMember(name, tp1, tp2)
0 commit comments