@@ -42,6 +42,8 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
42
42
43
43
private var needsGc = false
44
44
45
+ private var canCompareAtoms : Boolean = true // used for internal consistency checking
46
+
45
47
/** Is a subtype check in progress? In that case we may not
46
48
* permanently instantiate type variables, because the corresponding
47
49
* constraint might still be retracted and the instantiation should
@@ -418,6 +420,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
418
420
if (tp11.stripTypeVar eq tp12.stripTypeVar) recur(tp11, tp2)
419
421
else thirdTry
420
422
case tp1 @ OrType (tp11, tp12) =>
423
+ compareAtoms(tp1, tp2) match
424
+ case Some (b) => return b
425
+ case None =>
421
426
422
427
def joinOK = tp2.dealiasKeepRefiningAnnots match {
423
428
case tp2 : AppliedType if ! tp2.tycon.typeSymbol.isClass =>
@@ -440,21 +445,14 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
440
445
(tp1.widenSingletons ne tp1) &&
441
446
recur(tp1.widenSingletons, tp2)
442
447
443
- tp2.atoms() match
444
- case Some (ts2) if canCompare(ts2) =>
445
- tp1.atoms(widenOK = true ) match
446
- case Some (ts1) => ts1.subsetOf(ts2)
447
- case none => false
448
- case _ =>
449
- widenOK
450
- || joinOK
451
- || recur(tp11, tp2) && recur(tp12, tp2)
452
- || containsAnd(tp1) && recur(tp1.join, tp2)
453
- // An & on the left side loses information. Compensate by also trying the join.
454
- // This is less ad-hoc than it looks since we produce joins in type inference,
455
- // and then need to check that they are indeed supertypes of the original types
456
- // under -Ycheck. Test case is i7965.scala.
457
-
448
+ widenOK
449
+ || joinOK
450
+ || recur(tp11, tp2) && recur(tp12, tp2)
451
+ || containsAnd(tp1) && recur(tp1.join, tp2)
452
+ // An & on the left side loses information. Compensate by also trying the join.
453
+ // This is less ad-hoc than it looks since we produce joins in type inference,
454
+ // and then need to check that they are indeed supertypes of the original types
455
+ // under -Ycheck. Test case is i7965.scala.
458
456
case tp1 : MatchType =>
459
457
val reduced = tp1.reduced
460
458
if (reduced.exists) recur(reduced, tp2) else thirdTry
@@ -615,13 +613,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
615
613
}
616
614
compareTypeLambda
617
615
case OrType (tp21, tp22) =>
618
- tp2.atoms() match
619
- case Some (ts2) if canCompare(ts2) =>
620
- val atomsFit = tp1.atoms(widenOK = true ) match
621
- case Some (ts1) => ts1.subsetOf(ts2)
622
- case none => false
623
- return atomsFit || isSubType(tp1, NothingType )
624
- case none =>
616
+ compareAtoms(tp1, tp2) match
617
+ case Some (b) => return b
618
+ case _ =>
625
619
626
620
// The next clause handles a situation like the one encountered in i2745.scala.
627
621
// We have:
@@ -1187,13 +1181,37 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
1187
1181
* for equality would give the wrong result, so we should not use the sets
1188
1182
* for comparisons.
1189
1183
*/
1190
- def canCompare ( atoms : Set [ Type ] ): Boolean =
1191
- ctx.phase.isTyper || {
1184
+ def compareAtoms ( tp1 : Type , tp2 : Type ): Option [ Boolean ] =
1185
+ def canCompare ( ts : Set [ Type ]) = ctx.phase.isTyper || {
1192
1186
val hasSkolems = new ExistsAccumulator (_.isInstanceOf [SkolemType ]) {
1193
1187
override def stopAtStatic = true
1194
1188
}
1195
- ! atoms .exists(hasSkolems(false , _))
1189
+ ! ts .exists(hasSkolems(false , _))
1196
1190
}
1191
+ def verified (result : Boolean ): Boolean =
1192
+ if Config .checkAtomsComparisons && false then
1193
+ try
1194
+ canCompareAtoms = false
1195
+ val regular = recur(tp1, tp2)
1196
+ assert(result == regular,
1197
+ i """ Atoms inconsistency for $tp1 <:< $tp2
1198
+ |atoms predicted $result
1199
+ |atoms1 = ${tp1.atoms}
1200
+ |atoms2 = ${tp2.atoms}""" )
1201
+ finally canCompareAtoms = true
1202
+ result
1203
+
1204
+ def falseUnlessBottom = Some (verified(recur(tp1, NothingType )))
1205
+
1206
+ tp2.atoms match
1207
+ case Atoms .Range (lo2, hi2) if canCompareAtoms && canCompare(hi2) =>
1208
+ tp1.atoms match
1209
+ case Atoms .Range (lo1, hi1) =>
1210
+ if hi1.subsetOf(lo2) then Some (verified(true ))
1211
+ else if ! lo1.subsetOf(hi2) then falseUnlessBottom
1212
+ else None
1213
+ case _ => falseUnlessBottom
1214
+ case _ => None
1197
1215
1198
1216
/** Subtype test for corresponding arguments in `args1`, `args2` according to
1199
1217
* variances in type parameters `tparams2`.
@@ -1789,13 +1807,13 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
1789
1807
else if tp2.isAny && ! tp1.isLambdaSub || tp2.isAnyKind || tp1.isRef(NothingClass ) then tp2
1790
1808
else
1791
1809
def mergedLub (tp1 : Type , tp2 : Type ): Type = {
1792
- tp1.atoms(widenOK = true ) match
1793
- case Some (ts1 ) if ! widenInUnions =>
1794
- tp2.atoms(widenOK = true ) match
1795
- case Some (ts2 ) =>
1796
- if ts1 .subsetOf(ts2 ) then return tp2
1797
- if ts2 .subsetOf(ts1 ) then return tp1
1798
- if (ts1 & ts2 ).isEmpty then return orType(tp1, tp2)
1810
+ tp1.atoms match
1811
+ case Atoms . Range (lo1, hi1 ) if ! widenInUnions =>
1812
+ tp2.atoms match
1813
+ case Atoms . Range (lo2, hi2 ) =>
1814
+ if hi1 .subsetOf(lo2 ) then return tp2
1815
+ if hi2 .subsetOf(lo1 ) then return tp1
1816
+ if (hi1 & hi2 ).isEmpty then return orType(tp1, tp2)
1799
1817
case none =>
1800
1818
case none =>
1801
1819
val t1 = mergeIfSuper(tp1, tp2, canConstrain)
0 commit comments