@@ -107,7 +107,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
107
107
assert(isSatisfiable, constraint.show)
108
108
}
109
109
110
- protected def isSubType (tp1 : Type , tp2 : Type ): Boolean = isSubType(tp1, tp2, Precise )
110
+ protected def isSubType (tp1 : Type , tp2 : Type ): Boolean = isSubType(tp1, tp2, NoApprox )
111
111
112
112
protected def isSubType (tp1 : Type , tp2 : Type , approx : ApproxState ): Boolean = trace(s " isSubType ${traceInfo(tp1, tp2)} $approx" , subtyping) {
113
113
@@ -273,7 +273,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
273
273
def compareTypeParamRef =
274
274
ctx.mode.is(Mode .TypevarsMissContext ) ||
275
275
isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || {
276
- if (canConstrain(tp1) && ( approx & HiApprox ) == 0 )
276
+ if (canConstrain(tp1) && ! approx.high )
277
277
addConstraint(tp1, tp2, fromBelow = false ) && flagNothingBound
278
278
else thirdTry
279
279
}
@@ -339,8 +339,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
339
339
GADTusage (tp2.symbol)
340
340
}
341
341
val tryLowerFirst = frozenConstraint || ! isCappable(tp1)
342
- if (tryLowerFirst) isSubType(tp1, lo2, approx | HiApprox ) || compareGADT || fourthTry
343
- else compareGADT || fourthTry || isSubType(tp1, lo2, approx | HiApprox )
342
+ if (tryLowerFirst) isSubType(tp1, lo2, approx.addHigh ) || compareGADT || fourthTry
343
+ else compareGADT || fourthTry || isSubType(tp1, lo2, approx.addHigh )
344
344
345
345
case _ =>
346
346
val cls2 = tp2.symbol
@@ -354,7 +354,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
354
354
// If `cls2` is parameterized, we are seeing a raw type, so we need to compare only the symbol
355
355
return base.typeSymbol == cls2
356
356
if (base ne tp1)
357
- return isSubType(base, tp2, if (tp1.isRef(cls2)) approx else approx | LoApprox )
357
+ return isSubType(base, tp2, if (tp1.isRef(cls2)) approx else approx.addLow )
358
358
}
359
359
if (cls2 == defn.SingletonClass && tp1.isStable) return true
360
360
}
@@ -381,7 +381,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
381
381
if (frozenConstraint) isSubType(tp1, bounds(tp2).lo)
382
382
else isSubTypeWhenFrozen(tp1, tp2)
383
383
alwaysTrue || {
384
- if (canConstrain(tp2) && ( approx & LoApprox ) == 0 )
384
+ if (canConstrain(tp2) && ! approx.low )
385
385
addConstraint(tp2, tp1.widenExpr, fromBelow = true )
386
386
else fourthTry
387
387
}
@@ -548,7 +548,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
548
548
narrowGADTBounds(tp1, tp2, approx, isUpper = true )) &&
549
549
GADTusage (tp1.symbol)
550
550
}
551
- isSubType(hi1, tp2, approx | LoApprox ) || compareGADT
551
+ isSubType(hi1, tp2, approx.addLow ) || compareGADT
552
552
case _ =>
553
553
def isNullable (tp : Type ): Boolean = tp.widenDealias match {
554
554
case tp : TypeRef => tp.symbol.isNullableClass
@@ -727,7 +727,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
727
727
* @param tyconLo The type constructor's lower approximation.
728
728
*/
729
729
def fallback (tyconLo : Type ) =
730
- either(fourthTry, isSubType(tp1, tyconLo.applyIfParameterized(args2), approx | HiApprox ))
730
+ either(fourthTry, isSubType(tp1, tyconLo.applyIfParameterized(args2), approx.addHigh ))
731
731
732
732
/** Let `tycon2bounds` be the bounds of the RHS type constructor `tycon2`.
733
733
* Let `app2 = tp2` where the type constructor of `tp2` is replaced by
@@ -741,7 +741,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
741
741
def compareLower (tycon2bounds : TypeBounds , tyconIsTypeRef : Boolean ): Boolean =
742
742
if (tycon2bounds.lo eq tycon2bounds.hi)
743
743
if (tyconIsTypeRef) recur(tp1, tp2.superType)
744
- else isSubType(tp1, tycon2bounds.lo.applyIfParameterized(args2), approx | HiApprox )
744
+ else isSubType(tp1, tycon2bounds.lo.applyIfParameterized(args2), approx.addHigh )
745
745
else
746
746
fallback(tycon2bounds.lo)
747
747
@@ -758,7 +758,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
758
758
case info2 : ClassInfo =>
759
759
val base = tp1.baseType(info2.cls)
760
760
if (base.exists && base.ne(tp1))
761
- isSubType(base, tp2, if (tp1.isRef(info2.cls)) approx else approx | LoApprox )
761
+ isSubType(base, tp2, if (tp1.isRef(info2.cls)) approx else approx.addLow )
762
762
else fourthTry
763
763
case _ =>
764
764
fourthTry
@@ -785,7 +785,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
785
785
false
786
786
}
787
787
canConstrain(param1) && canInstantiate ||
788
- isSubType(bounds(param1).hi.applyIfParameterized(args1), tp2, approx | LoApprox )
788
+ isSubType(bounds(param1).hi.applyIfParameterized(args1), tp2, approx.addLow )
789
789
case tycon1 : TypeRef if tycon1.symbol.isClass =>
790
790
false
791
791
case tycon1 : TypeProxy =>
@@ -801,7 +801,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
801
801
if (isCovered(tp1) && isCovered(tp2)) {
802
802
// println(s"useless subtype: $tp1 <:< $tp2")
803
803
false
804
- } else isSubType(tp1, tp2, approx | LoApprox )
804
+ } else isSubType(tp1, tp2, approx.addLow )
805
805
806
806
def recur (tp1 : Type , tp2 : Type ) = isSubType(tp1, tp2, approx)
807
807
@@ -1083,8 +1083,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
1083
1083
* Test that the resulting bounds are still satisfiable.
1084
1084
*/
1085
1085
private def narrowGADTBounds (tr : NamedType , bound : Type , approx : ApproxState , isUpper : Boolean ): Boolean = {
1086
- val boundIsPrecise = (approx & ( if (isUpper) HiApprox else LoApprox )) == 0
1087
- ctx.mode.is(Mode .GADTflexible ) && ! frozenConstraint && boundIsPrecise && {
1086
+ val boundImprecise = if (isUpper) approx.high else approx.low
1087
+ ctx.mode.is(Mode .GADTflexible ) && ! frozenConstraint && ! boundImprecise && {
1088
1088
val tparam = tr.symbol
1089
1089
gadts.println(i " narrow gadt bound of $tparam: ${tparam.info} from ${if (isUpper) " above" else " below" } to $bound ${bound.toString} ${bound.isRef(tparam)}" )
1090
1090
if (bound.isRef(tparam)) false
@@ -1605,10 +1605,22 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
1605
1605
1606
1606
object TypeComparer {
1607
1607
1608
- type ApproxState = Int
1609
- val Precise = 0
1610
- val LoApprox = 1
1611
- val HiApprox = 2
1608
+ private val LoApprox = 1
1609
+ private val HiApprox = 2
1610
+
1611
+ class ApproxState (private val bits : Int ) extends AnyVal {
1612
+ override def toString = {
1613
+ val lo = if ((bits & LoApprox ) != 0 ) " LoApprox" else " "
1614
+ val hi = if ((bits & HiApprox ) != 0 ) " HiApprox" else " "
1615
+ lo ++ hi
1616
+ }
1617
+ def addLow = new ApproxState (bits | LoApprox )
1618
+ def addHigh = new ApproxState (bits | HiApprox )
1619
+ def low = (bits & LoApprox ) != 0
1620
+ def high = (bits & HiApprox ) != 0
1621
+ }
1622
+
1623
+ val NoApprox = new ApproxState (0 )
1612
1624
1613
1625
/** Show trace of comparison operations when performing `op` as result string */
1614
1626
def explained [T ](op : Context => T )(implicit ctx : Context ): String = {
0 commit comments