@@ -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
@@ -289,7 +289,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
289
289
def compareTypeParamRef =
290
290
ctx.mode.is(Mode .TypevarsMissContext ) ||
291
291
isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || {
292
- if (canConstrain(tp1) && ( approx & HiApprox ) == 0 )
292
+ if (canConstrain(tp1) && ! approx.high )
293
293
addConstraint(tp1, tp2, fromBelow = false ) && flagNothingBound
294
294
else thirdTry
295
295
}
@@ -355,8 +355,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
355
355
GADTusage (tp2.symbol)
356
356
}
357
357
val tryLowerFirst = frozenConstraint || ! isCappable(tp1)
358
- if (tryLowerFirst) isSubType(tp1, lo2, approx | HiApprox ) || compareGADT || fourthTry
359
- else compareGADT || fourthTry || isSubType(tp1, lo2, approx | HiApprox )
358
+ if (tryLowerFirst) isSubType(tp1, lo2, approx.addHigh ) || compareGADT || fourthTry
359
+ else compareGADT || fourthTry || isSubType(tp1, lo2, approx.addHigh )
360
360
361
361
case _ =>
362
362
val cls2 = tp2.symbol
@@ -370,7 +370,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
370
370
// If `cls2` is parameterized, we are seeing a raw type, so we need to compare only the symbol
371
371
return base.typeSymbol == cls2
372
372
if (base ne tp1)
373
- return isSubType(base, tp2, if (tp1.isRef(cls2)) approx else approx | LoApprox )
373
+ return isSubType(base, tp2, if (tp1.isRef(cls2)) approx else approx.addLow )
374
374
}
375
375
if (cls2 == defn.SingletonClass && tp1.isStable) return true
376
376
}
@@ -397,7 +397,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
397
397
if (frozenConstraint) isSubType(tp1, bounds(tp2).lo)
398
398
else isSubTypeWhenFrozen(tp1, tp2)
399
399
alwaysTrue || {
400
- if (canConstrain(tp2) && ( approx & LoApprox ) == 0 )
400
+ if (canConstrain(tp2) && ! approx.low )
401
401
addConstraint(tp2, tp1.widenExpr, fromBelow = true )
402
402
else fourthTry
403
403
}
@@ -564,7 +564,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
564
564
narrowGADTBounds(tp1, tp2, approx, isUpper = true )) &&
565
565
GADTusage (tp1.symbol)
566
566
}
567
- isSubType(hi1, tp2, approx | LoApprox ) || compareGADT
567
+ isSubType(hi1, tp2, approx.addLow ) || compareGADT
568
568
case _ =>
569
569
def isNullable (tp : Type ): Boolean = tp.widenDealias match {
570
570
case tp : TypeRef => tp.symbol.isNullableClass
@@ -743,7 +743,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
743
743
* @param tyconLo The type constructor's lower approximation.
744
744
*/
745
745
def fallback (tyconLo : Type ) =
746
- either(fourthTry, isSubType(tp1, tyconLo.applyIfParameterized(args2), approx | HiApprox ))
746
+ either(fourthTry, isSubType(tp1, tyconLo.applyIfParameterized(args2), approx.addHigh ))
747
747
748
748
/** Let `tycon2bounds` be the bounds of the RHS type constructor `tycon2`.
749
749
* Let `app2 = tp2` where the type constructor of `tp2` is replaced by
@@ -757,7 +757,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
757
757
def compareLower (tycon2bounds : TypeBounds , tyconIsTypeRef : Boolean ): Boolean =
758
758
if (tycon2bounds.lo eq tycon2bounds.hi)
759
759
if (tyconIsTypeRef) recur(tp1, tp2.superType)
760
- else isSubType(tp1, tycon2bounds.lo.applyIfParameterized(args2), approx | HiApprox )
760
+ else isSubType(tp1, tycon2bounds.lo.applyIfParameterized(args2), approx.addHigh )
761
761
else
762
762
fallback(tycon2bounds.lo)
763
763
@@ -774,7 +774,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
774
774
case info2 : ClassInfo =>
775
775
val base = tp1.baseType(info2.cls)
776
776
if (base.exists && base.ne(tp1))
777
- isSubType(base, tp2, if (tp1.isRef(info2.cls)) approx else approx | LoApprox )
777
+ isSubType(base, tp2, if (tp1.isRef(info2.cls)) approx else approx.addLow )
778
778
else fourthTry
779
779
case _ =>
780
780
fourthTry
@@ -801,7 +801,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
801
801
false
802
802
}
803
803
canConstrain(param1) && canInstantiate ||
804
- isSubType(bounds(param1).hi.applyIfParameterized(args1), tp2, approx | LoApprox )
804
+ isSubType(bounds(param1).hi.applyIfParameterized(args1), tp2, approx.addLow )
805
805
case tycon1 : TypeRef if tycon1.symbol.isClass =>
806
806
false
807
807
case tycon1 : TypeProxy =>
@@ -817,7 +817,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
817
817
if (isCovered(tp1) && isCovered(tp2)) {
818
818
// println(s"useless subtype: $tp1 <:< $tp2")
819
819
false
820
- } else isSubType(tp1, tp2, approx | LoApprox )
820
+ } else isSubType(tp1, tp2, approx.addLow )
821
821
822
822
def recur (tp1 : Type , tp2 : Type ) = isSubType(tp1, tp2, approx)
823
823
@@ -1099,8 +1099,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
1099
1099
* Test that the resulting bounds are still satisfiable.
1100
1100
*/
1101
1101
private def narrowGADTBounds (tr : NamedType , bound : Type , approx : ApproxState , isUpper : Boolean ): Boolean = {
1102
- val boundIsPrecise = (approx & ( if (isUpper) HiApprox else LoApprox )) == 0
1103
- ctx.mode.is(Mode .GADTflexible ) && ! frozenConstraint && boundIsPrecise && {
1102
+ val boundImprecise = if (isUpper) approx.high else approx.low
1103
+ ctx.mode.is(Mode .GADTflexible ) && ! frozenConstraint && ! boundImprecise && {
1104
1104
val tparam = tr.symbol
1105
1105
gadts.println(i " narrow gadt bound of $tparam: ${tparam.info} from ${if (isUpper) " above" else " below" } to $bound ${bound.toString} ${bound.isRef(tparam)}" )
1106
1106
if (bound.isRef(tparam)) false
@@ -1621,10 +1621,22 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
1621
1621
1622
1622
object TypeComparer {
1623
1623
1624
- type ApproxState = Int
1625
- val Precise = 0
1626
- val LoApprox = 1
1627
- val HiApprox = 2
1624
+ private val LoApprox = 1
1625
+ private val HiApprox = 2
1626
+
1627
+ class ApproxState (private val bits : Int ) extends AnyVal {
1628
+ override def toString = {
1629
+ val lo = if ((bits & LoApprox ) != 0 ) " LoApprox" else " "
1630
+ val hi = if ((bits & HiApprox ) != 0 ) " HiApprox" else " "
1631
+ lo ++ hi
1632
+ }
1633
+ def addLow = new ApproxState (bits | LoApprox )
1634
+ def addHigh = new ApproxState (bits | HiApprox )
1635
+ def low = (bits & LoApprox ) != 0
1636
+ def high = (bits & HiApprox ) != 0
1637
+ }
1638
+
1639
+ val NoApprox = new ApproxState (0 )
1628
1640
1629
1641
/** Show trace of comparison operations when performing `op` as result string */
1630
1642
def explained [T ](op : Context => T )(implicit ctx : Context ): String = {
0 commit comments