aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeComparer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-10-31 12:14:50 +0100
committerMartin Odersky <odersky@gmail.com>2013-10-31 12:14:50 +0100
commitdbaf6f42da9e5eb950d1a21b1912d417536330f7 (patch)
treeaf013713f4a9cd2f1493c4f24fa1aa4f4cde1973 /src/dotty/tools/dotc/core/TypeComparer.scala
parent8c6b062a4b2c6323287441e37cef01acd9a4d7ac (diff)
downloaddotty-dbaf6f42da9e5eb950d1a21b1912d417536330f7.tar.gz
dotty-dbaf6f42da9e5eb950d1a21b1912d417536330f7.tar.bz2
dotty-dbaf6f42da9e5eb950d1a21b1912d417536330f7.zip
Fixes to subtyping tests for constrained parameters.
1. When testing A <:< B where A and B are both in the current constraint set, we used to do a A <:< L first, where L is the lower bound of B. But that gives the wrong upper bound to A, it should be B instead of L!. This comment corrects that. 2. Again when testing A <:< B we need to record B as an upper bound of A, but also record A as a lower bound of B. That way, either instantiation of A and B will propagate correctly. If we dod not do that and just recorded B as upper bound of A, we could then minimize B to Nothing, so A would be forced to Nothing as well. This is clearly wrong. We should have minimized B to A instead.
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeComparer.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala54
1 files changed, 38 insertions, 16 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index c66e3a111..5c261a03d 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -68,12 +68,9 @@ class TypeComparer(initctx: Context) extends DotClass {
def addConstraint(param: PolyParam, bound: Type, fromBelow: Boolean): Boolean =
!frozenConstraint && {
bound match {
- case bound: TypeVar =>
- if (bound.isInstantiated)
- addConstraint1(param, bound.instanceOpt, fromBelow)
- else
- addConstraint1(param, bound, fromBelow) &&
- addConstraint1(bound.origin, param, !fromBelow)
+ case bound: PolyParam if constraint(bound).exists =>
+ addConstraint1(param, bound, fromBelow) &&
+ addConstraint1(bound, param, !fromBelow)
case _ =>
addConstraint1(param, bound, fromBelow)
}
@@ -107,9 +104,10 @@ class TypeComparer(initctx: Context) extends DotClass {
}
def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
+ val saved = frozenConstraint
frozenConstraint = true
try isSubType(tp1, tp2)
- finally frozenConstraint = false
+ finally frozenConstraint = saved
}
def isSubType(tp1: Type, tp2: Type): Boolean =
@@ -134,6 +132,17 @@ class TypeComparer(initctx: Context) extends DotClass {
result
} catch {
case ex: Throwable =>
+ if (ex.isInstanceOf[AssertionError]) { // !!!DEBUG
+ println(disambiguated(implicit ctx => s"assertion failure for ${tp1.show} <:< ${tp2.show}"))
+ def explainPoly(tp: Type) = tp match {
+ case tp: PolyParam => println(s"polyparam ${tp.show} found in ${tp.binder.show}")
+ case tp: TypeRef => println(s"typeref ${tp.show} found in ${tp.symbol.owner.show}")
+ case tp: TypeVar => println(s"typevar ${tp.show}, origin = ${tp.origin}")
+ case _ => println(s"${tp.show} is a ${tp.getClass}")
+ }
+ explainPoly(tp1)
+ explainPoly(tp2)
+ }
recCount -= 1
constraint = cs
throw ex
@@ -189,16 +198,18 @@ class TypeComparer(initctx: Context) extends DotClass {
secondTry(tp1, tp2)
case tp2: PolyParam =>
tp2 == tp1 || {
- //println(constraint.show)
- constraint(tp2) match {
- case TypeBounds(lo, _) => isSubType(tp1, lo) || addConstraint(tp2, tp1.widen, fromBelow = true)
- case _ => secondTry(tp1, tp2)
+ isSubTypeWhenFrozen(tp1, bounds(tp2).lo) || {
+ println(s"adding ${tp1.show} <:< ${tp2.show} to ${constraint.show}") // !!!DEBUG
+ constraint(tp2) match {
+ case TypeBounds(lo, _) => addConstraint(tp2, tp1.widen, fromBelow = true)
+ case _ => secondTry(tp1, tp2)
+ }
}
}
case tp2: BoundType =>
tp2 == tp1 || secondTry(tp1, tp2)
case tp2: TypeVar =>
- isSubType(tp1, tp2.underlying)
+ (tp1 eq tp2) || isSubType(tp1, tp2.underlying)
case tp2: ProtoType =>
tp2.isMatchedBy(tp1)
case tp2: WildcardType =>
@@ -226,15 +237,19 @@ class TypeComparer(initctx: Context) extends DotClass {
thirdTry(tp1, tp2)
case tp1: PolyParam =>
(tp1 == tp2) || {
- constraint(tp1) match {
- case TypeBounds(_, hi) => isSubType(hi, tp2) || addConstraint(tp1, tp2, fromBelow = false)
- case _ => thirdTry(tp1, tp2)
+ isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || {
+ println(s"adding ${tp1.show} <:< ${tp2.show} to ${constraint.show}")
+ assert(frozenConstraint || !(tp2 isRef defn.NothingClass)) // !!!DEBUG
+ constraint(tp1) match {
+ case TypeBounds(_, hi) => addConstraint(tp1, tp2, fromBelow = false)
+ case _ => thirdTry(tp1, tp2)
+ }
}
}
case tp1: BoundType =>
tp1 == tp2 || secondTry(tp1, tp2)
case tp1: TypeVar =>
- isSubType(tp1.underlying, tp2)
+ (tp1 eq tp2) || isSubType(tp1.underlying, tp2)
case tp1: WildcardType =>
tp1.optBounds match {
case TypeBounds(lo, _) => isSubType(lo, tp2)
@@ -361,6 +376,13 @@ class TypeComparer(initctx: Context) extends DotClass {
case _ =>
false
}
+
+ /** The current bounds of type parameter `param` */
+ def bounds(param: PolyParam): TypeBounds = constraint(param) match {
+ case bounds: TypeBounds => bounds
+ case _ => param.binder.paramBounds(param.paramNum)
+ }
+
/* not needed
def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[TypeSymbol]): Boolean = tparams match {
case tparam :: tparams1 =>