@@ -42,6 +42,8 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
4242
4343 private var needsGc = false
4444
45+ private var canCompareAtoms : Boolean = true // used for internal consistency checking
46+
4547 /** Is a subtype check in progress? In that case we may not
4648 * permanently instantiate type variables, because the corresponding
4749 * constraint might still be retracted and the instantiation should
@@ -418,6 +420,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
418420 if (tp11.stripTypeVar eq tp12.stripTypeVar) recur(tp11, tp2)
419421 else thirdTry
420422 case tp1 @ OrType (tp11, tp12) =>
423+ compareAtoms(tp1, tp2) match
424+ case Some (b) => return b
425+ case None =>
421426
422427 def joinOK = tp2.dealiasKeepRefiningAnnots match {
423428 case tp2 : AppliedType if ! tp2.tycon.typeSymbol.isClass =>
@@ -440,21 +445,14 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
440445 (tp1.widenSingletons ne tp1) &&
441446 recur(tp1.widenSingletons, tp2)
442447
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.
458456 case tp1 : MatchType =>
459457 val reduced = tp1.reduced
460458 if (reduced.exists) recur(reduced, tp2) else thirdTry
@@ -615,13 +613,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
615613 }
616614 compareTypeLambda
617615 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 _ =>
625619
626620 // The next clause handles a situation like the one encountered in i2745.scala.
627621 // We have:
@@ -1187,13 +1181,37 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
11871181 * for equality would give the wrong result, so we should not use the sets
11881182 * for comparisons.
11891183 */
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 || {
11921186 val hasSkolems = new ExistsAccumulator (_.isInstanceOf [SkolemType ]) {
11931187 override def stopAtStatic = true
11941188 }
1195- ! atoms .exists(hasSkolems(false , _))
1189+ ! ts .exists(hasSkolems(false , _))
11961190 }
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
11971215
11981216 /** Subtype test for corresponding arguments in `args1`, `args2` according to
11991217 * variances in type parameters `tparams2`.
@@ -1793,13 +1811,13 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
17931811 else if tp2.isAny && ! tp1.isLambdaSub || tp2.isAnyKind || tp1.isRef(NothingClass ) then tp2
17941812 else
17951813 def mergedLub (tp1 : Type , tp2 : Type ): Type = {
1796- tp1.atoms(widenOK = true ) match
1797- case Some (ts1 ) if ! widenInUnions =>
1798- tp2.atoms(widenOK = true ) match
1799- case Some (ts2 ) =>
1800- if ts1 .subsetOf(ts2 ) then return tp2
1801- if ts2 .subsetOf(ts1 ) then return tp1
1802- if (ts1 & ts2 ).isEmpty then return orType(tp1, tp2)
1814+ tp1.atoms match
1815+ case Atoms . Range (lo1, hi1 ) if ! widenInUnions =>
1816+ tp2.atoms match
1817+ case Atoms . Range (lo2, hi2 ) =>
1818+ if hi1 .subsetOf(lo2 ) then return tp2
1819+ if hi2 .subsetOf(lo1 ) then return tp1
1820+ if (hi1 & hi2 ).isEmpty then return orType(tp1, tp2)
18031821 case none =>
18041822 case none =>
18051823 val t1 = mergeIfSuper(tp1, tp2, canConstrain)
0 commit comments