aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeComparer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-01-01 22:24:21 +0100
committerMartin Odersky <odersky@gmail.com>2015-01-01 22:24:21 +0100
commit9c1d4868ee8003e6ce11b95b97ddabe347ba00cb (patch)
treea171f8214b441950ef341a0649a1eb0d4cffb2d5 /src/dotty/tools/dotc/core/TypeComparer.scala
parentbd405e5ae89093c83f7914bd515d82dcdec22f32 (diff)
downloaddotty-9c1d4868ee8003e6ce11b95b97ddabe347ba00cb.tar.gz
dotty-9c1d4868ee8003e6ce11b95b97ddabe347ba00cb.tar.bz2
dotty-9c1d4868ee8003e6ce11b95b97ddabe347ba00cb.zip
isSubType reorg
Capture original types in enclosing scope instead of passing them explicitly.
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeComparer.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala211
1 files changed, 112 insertions, 99 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 93cf60f3b..3a4a2305d 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -308,11 +308,6 @@ class TypeComparer(initctx: Context) extends DotClass {
}
}
- private def narrowRefined(tp: Type): Type = tp match {
- case tp: RefinedType => RefinedThis(tp, 0) // !!! TODO check that we can drop narrowRefined entirely
- case _ => tp
- }
-
/** If the prefix of a named type is `this` (i.e. an instance of type
* `ThisType` or `RefinedThis`), and there is a refinement type R that
* "refines" (transitively contains as its parent) a class reference
@@ -357,21 +352,75 @@ class TypeComparer(initctx: Context) extends DotClass {
(tp2 eq AnyType) && tp1.isValueType) return true
isSubType(tp1, tp2)
}
-
- protected def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = isSubTypeWhenFrozen(tp1, tp2, tp1)
- protected def isSubTypeWhenFrozen(tp1: Type, tp2: Type, pre: Type): Boolean = {
+
+ protected def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
val saved = frozenConstraint
frozenConstraint = true
- try isSubType(tp1, tp2, pre)
+ try isSubType(tp1, tp2)
finally frozenConstraint = saved
}
private def traceInfo(tp1: Type, tp2: Type) =
s"${tp1.show} <:< ${tp2.show}" +
(if (ctx.settings.verbose.value) s" ${tp1.getClass} ${tp2.getClass}${if (frozenConstraint) " frozen" else ""}" else "")
-
- def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, tp1)
- def isSubType(tp1: Type, tp2: Type, pre: Type): Boolean = /*>|>*/ ctx.traceIndented(s"isSubType ${traceInfo(tp1, tp2)}", subtyping) /*<|<*/ {
+
+ def isSubType(orig1: Type, orig2: Type): Boolean = {
+
+ def ctdSubType(tp1: Type, tp2: Type): Boolean = /*>|>*/ ctx.traceIndented(s"isSubType ${traceInfo(orig1, tp2)}, orig1 = ${orig1.show}, class2 = ${tp2.getClass}", subtyping) /*<|<*/ {
+ if (tp2 eq NoType) false
+ else if (tp1 eq tp2) true
+ else {
+ val saved = constraint
+ val savedSuccessCount = successCount
+ try {
+ recCount = recCount + 1
+ val result =
+ if (recCount < LogPendingSubTypesThreshold) firstTry(tp1, tp2)
+ else monitoredIsSubType(tp1, tp2)
+ recCount = recCount - 1
+ if (!result) constraint = saved
+ else if (recCount == 0 && needsGc) state.gc()
+
+ def recordStatistics = {
+ // Stats.record(s"isSubType ${tp1.show} <:< ${tp2.show}")
+ totalCount += 1
+ if (result) successCount += 1 else successCount = savedSuccessCount
+ if (recCount == 0) {
+ Stats.record("successful subType", successCount)
+ Stats.record("total subType", totalCount)
+ successCount = 0
+ totalCount = 0
+ }
+ }
+ if (Stats.monitored) recordStatistics
+
+ result
+ } catch {
+ case NonFatal(ex) =>
+ def showState = {
+ println(disambiguated(implicit ctx => s"assertion failure for ${tp1.show} <:< ${tp2.show}, frozen = $frozenConstraint"))
+ def explainPoly(tp: Type) = tp match {
+ case tp: PolyParam => println(s"polyparam ${tp.show} found in ${tp.binder.show}")
+ case tp: TypeRef if tp.symbol.exists => 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)
+ }
+ if (ex.isInstanceOf[AssertionError]) showState
+ recCount -= 1
+ constraint = saved
+ successCount = savedSuccessCount
+ throw ex
+ }
+ }
+ }
+
+ def narrowRefined(tp: Type): Type = tp match {
+ case tp: RefinedType => RefinedThis(tp, 0) // !!! TODO check that we can drop narrowRefined entirely
+ case _ => tp
+ }
def firstTry(tp1: Type, tp2: Type): Boolean = {
tp2 match {
@@ -419,9 +468,9 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: PolyParam =>
def comparePolyParam =
tp2 == tp1 || {
- if (solvedConstraint && (constraint contains tp2)) isSubType(tp1, bounds(tp2).lo, pre)
+ if (solvedConstraint && (constraint contains tp2)) ctdSubType(tp1, bounds(tp2).lo)
else
- isSubTypeWhenFrozen(tp1, bounds(tp2).lo) || {
+ ctdSubTypeWhenFrozen(tp1, bounds(tp2).lo) || {
if (isConstrained(tp2)) addConstraint(tp2, tp1.widenExpr, fromBelow = true)
else (ctx.mode is Mode.TypevarsMissContext) || secondTry(tp1, tp2)
}
@@ -430,17 +479,17 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: BoundType =>
tp2 == tp1 || secondTry(tp1, tp2)
case tp2: TypeVar =>
- isSubType(tp1, tp2.underlying, pre)
+ ctdSubType(tp1, tp2.underlying)
case tp2: WildcardType =>
def compareWild = tp2.optBounds match {
- case TypeBounds(_, hi) => isSubType(tp1, hi, pre)
+ case TypeBounds(_, hi) => ctdSubType(tp1, hi)
case NoType => true
}
compareWild
case tp2: LazyRef =>
- isSubType(tp1, tp2.ref, pre)
+ ctdSubType(tp1, tp2.ref)
case tp2: AnnotatedType =>
- isSubType(tp1, tp2.tpe, pre) // todo: refine?
+ ctdSubType(tp1, tp2.tpe) // todo: refine?
case tp2: ThisType =>
tp1 match {
case tp1: ThisType =>
@@ -454,13 +503,13 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: SuperType =>
tp1 match {
case tp1: SuperType =>
- isSubType(tp1.thistpe, tp2.thistpe, pre) &&
+ ctdSubType(tp1.thistpe, tp2.thistpe) &&
isSameType(tp1.supertpe, tp2.supertpe)
case _ =>
secondTry(tp1, tp2)
}
case AndType(tp21, tp22) =>
- isSubType(tp1, tp21, pre) && isSubType(tp1, tp22, pre)
+ ctdSubType(tp1, tp21) && ctdSubType(tp1, tp22)
case ErrorType =>
true
case _ =>
@@ -477,13 +526,13 @@ class TypeComparer(initctx: Context) extends DotClass {
secondTryNamed(tp1, tp2)
}
case OrType(tp11, tp12) =>
- isSubType(tp11, tp2, pre) && isSubType(tp12, tp2, pre)
+ ctdSubType(tp11, tp2) && ctdSubType(tp12, tp2)
case tp1: PolyParam =>
def comparePolyParam =
tp1 == tp2 || {
- if (solvedConstraint && (constraint contains tp1)) isSubType(bounds(tp1).lo, tp2, pre)
+ if (solvedConstraint && (constraint contains tp1)) ctdSubType(bounds(tp1).lo, tp2)
else
- isSubTypeWhenFrozen(bounds(tp1).hi, tp2, pre) || {
+ ctdSubTypeWhenFrozen(bounds(tp1).hi, tp2) || {
if (isConstrained(tp1))
addConstraint(tp1, tp2, fromBelow = false) && {
if ((!frozenConstraint) &&
@@ -507,17 +556,17 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp1: BoundType =>
tp1 == tp2 || thirdTry(tp1, tp2)
case tp1: TypeVar =>
- (tp1 eq tp2) || isSubType(tp1.underlying, tp2, pre)
+ (tp1 eq tp2) || ctdSubType(tp1.underlying, tp2)
case tp1: WildcardType =>
def compareWild = tp1.optBounds match {
- case TypeBounds(lo, _) => isSubType(lo, tp2, pre)
+ case TypeBounds(lo, _) => ctdSubType(lo, tp2)
case _ => true
}
compareWild
case tp1: LazyRef =>
- isSubType(tp1.ref, tp2, pre)
+ ctdSubType(tp1.ref, tp2)
case tp1: AnnotatedType =>
- isSubType(tp1.tpe, tp2, pre)
+ ctdSubType(tp1.tpe, tp2)
case ErrorType =>
true
case _ =>
@@ -527,7 +576,7 @@ class TypeComparer(initctx: Context) extends DotClass {
def secondTryNamed(tp1: NamedType, tp2: Type): Boolean = {
def tryRebase2nd = {
val tp1rebased = rebase(tp1)
- if (tp1rebased ne tp1) isSubType(tp1rebased, tp2)
+ if (tp1rebased ne tp1) ctdSubType(tp1rebased, tp2)
else thirdTry(tp1, tp2)
}
tp1.info match {
@@ -550,11 +599,11 @@ class TypeComparer(initctx: Context) extends DotClass {
case TypeBounds(lo1, hi1) =>
val gbounds1 = ctx.gadt.bounds(tp1.symbol)
if (gbounds1 != null)
- isSubTypeWhenFrozen(gbounds1.hi, tp2, pre) ||
+ ctdSubTypeWhenFrozen(gbounds1.hi, tp2) ||
(ctx.mode is Mode.GADTflexible) &&
narrowGADTBounds(tp1, TypeBounds(gbounds1.lo, gbounds1.hi & tp2)) ||
tryRebase2nd
- else if (lo1 eq hi1) isSubType(hi1, tp2, pre)
+ else if (lo1 eq hi1) ctdSubType(hi1, tp2)
else tryRebase2nd
case _ =>
tryRebase2nd
@@ -565,26 +614,26 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: NamedType =>
def tryRebase3rd = {
val tp2rebased = rebase(tp2)
- if (tp2rebased ne tp2) isSubType(tp1, tp2rebased)
+ if (tp2rebased ne tp2) ctdSubType(tp1, tp2rebased)
else fourthTry(tp1, tp2)
}
def compareNamed: Boolean = tp2.info match {
case TypeBounds(lo2, hi2) =>
val gbounds2 = ctx.gadt.bounds(tp2.symbol)
if (gbounds2 != null)
- isSubTypeWhenFrozen(tp1, gbounds2.lo, pre) ||
+ ctdSubTypeWhenFrozen(tp1, gbounds2.lo) ||
(ctx.mode is Mode.GADTflexible) &&
narrowGADTBounds(tp2, TypeBounds(gbounds2.lo | tp1, gbounds2.hi)) ||
fourthTry(tp1, tp2)
else
- ((frozenConstraint || !isCappable(tp1)) && isSubType(tp1, lo2, pre)
+ ((frozenConstraint || !isCappable(tp1)) && ctdSubType(tp1, lo2)
|| tryRebase3rd)
case _ =>
val cls2 = tp2.symbol
if (cls2.isClass) {
val base = tp1.baseTypeRef(cls2)
- if (base.exists && (base ne tp1)) return isSubType(base, tp2, pre)
+ if (base.exists && (base ne tp1)) return ctdSubType(base, tp2)
if (cls2 == defn.SingletonClass && tp1.isStable) return true
}
tryRebase3rd
@@ -599,6 +648,11 @@ class TypeComparer(initctx: Context) extends DotClass {
def compareRefinedSlow: Boolean = {
def hasMatchingMember(name: Name): Boolean = /*>|>*/ ctx.traceIndented(s"hasMatchingMember($name) ${tp1.member(name).info.show}", subtyping) /*<|<*/ {
val tp1r = rebaseQual(tp1, name)
+ //val old = memberMatches(narrowRefined(tp1r) member name)
+ //val now = memberMatches(orig1.ensureSingleton member name)
+ //if (old != now)
+ // assert(false, i"discrepancy: $tp1 <:< $tp2, narrowRefined = ${narrowRefined(tp1r)} -> $old, ensureSingle = ${orig1.ensureSingleton}: $orig1 -> $now")
+
(memberMatches(narrowRefined(tp1r) member name)
||
{ // special case for situations like:
@@ -614,14 +668,14 @@ class TypeComparer(initctx: Context) extends DotClass {
val saved = pendingRefinedBases
try {
addPendingName(name2, tp2, tp2)
- isSubType(tp1, parent2, pre)
+ ctdSubType(tp1, parent2)
} finally pendingRefinedBases = saved
}
(matchesParent && (
name2 == nme.WILDCARD
|| hasMatchingMember(name2)
|| fourthTry(tp1, tp2))
- || needsEtaLift(tp1, tp2) && tp1.testLifted(tp2.typeParams, isSubType(_, tp2, pre)))
+ || needsEtaLift(tp1, tp2) && tp1.testLifted(tp2.typeParams, ctdSubType(_, tp2)))
}
def compareRefined: Boolean = tp1.widen match {
case tp1 @ RefinedType(parent1, name1) if name1 == name2 && name1.isTypeName =>
@@ -631,7 +685,7 @@ class TypeComparer(initctx: Context) extends DotClass {
val saved = pendingRefinedBases
try {
addPendingName(name1, tp1, tp2)
- isSubType(parent1, parent2, pre)
+ ctdSubType(parent1, parent2)
} finally pendingRefinedBases = saved
}
case _ =>
@@ -673,18 +727,18 @@ class TypeComparer(initctx: Context) extends DotClass {
// as members of the same type. And it seems most logical to take
// ()T <:< => T, since everything one can do with a => T one can
// also do with a ()T by automatic () insertion.
- case tp1 @ MethodType(Nil, _) => isSubType(tp1.resultType, restpe2, pre)
- case _ => isSubType(tp1.widenExpr, restpe2, pre)
+ case tp1 @ MethodType(Nil, _) => ctdSubType(tp1.resultType, restpe2)
+ case _ => ctdSubType(tp1.widenExpr, restpe2)
}
compareExpr
case tp2 @ TypeBounds(lo2, hi2) =>
def compareTypeBounds = tp1 match {
case tp1 @ TypeBounds(lo1, hi1) =>
(tp2.variance > 0 && tp1.variance >= 0 || isSubType(lo2, lo1)) &&
- (tp2.variance < 0 && tp1.variance <= 0 || isSubType(hi1, hi2, pre))
+ (tp2.variance < 0 && tp1.variance <= 0 || ctdSubType(hi1, hi2))
case tp1: ClassInfo =>
val tt = tp1.typeRef
- isSubType(lo2, tt) && isSubType(tt, hi2, pre)
+ ctdSubType(lo2, tt) && isSubType(tt, hi2)
case _ =>
false
}
@@ -711,7 +765,7 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp1: TypeRef =>
tp1.info match {
case TypeBounds(lo1, hi1) =>
- isSubType(hi1, tp2, pre)
+ ctdSubType(hi1, tp2)
case _ =>
def isNullable(tp: Type): Boolean = tp.dealias match {
case tp: TypeRef => tp.symbol.isNullableClass
@@ -730,9 +784,9 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: TermRef =>
tp2.info match {
case tp2i: TermRef =>
- isSubType(tp1, tp2i, pre)
+ ctdSubType(tp1, tp2i)
case ExprType(tp2i: TermRef) if (ctx.phase.id > ctx.gettersPhase.id) =>
- isSubType(tp1, tp2i, pre)
+ ctdSubType(tp1, tp2i)
case _ =>
false
}
@@ -747,7 +801,7 @@ class TypeComparer(initctx: Context) extends DotClass {
isNewSubType(tp1.parent, tp2)
}
finally pendingRefinedBases = saved
- } || needsEtaLift(tp2, tp1) && tp2.testLifted(tp1.typeParams, isSubType(tp1, _, pre))
+ } || needsEtaLift(tp2, tp1) && tp2.testLifted(tp1.typeParams, ctdSubType(tp1, _))
case AndType(tp11, tp12) =>
eitherIsSubType(tp11, tp2, tp12, tp2)
case JavaArrayType(elem1) =>
@@ -786,13 +840,13 @@ class TypeComparer(initctx: Context) extends DotClass {
*/
def eitherIsSubType(tp11: Type, tp21: Type, tp12: Type, tp22: Type) = {
val preConstraint = constraint
- isSubType(tp11, tp21, pre) && {
+ ctdSubType(tp11, tp21) && {
val leftConstraint = constraint
constraint = preConstraint
- if (isSubType(tp12, tp22, pre) && !subsumes(leftConstraint, constraint, preConstraint))
+ if (ctdSubType(tp12, tp22) && !subsumes(leftConstraint, constraint, preConstraint))
constraint = leftConstraint
true
- } || isSubType(tp12, tp22, pre)
+ } || ctdSubType(tp12, tp22)
}
/** Like tp1 <:< tp2, but returns false immediately if we know that
@@ -802,7 +856,14 @@ class TypeComparer(initctx: Context) extends DotClass {
if (isCovered(tp1) && isCovered(tp2)) {
//println(s"useless subtype: $tp1 <:< $tp2")
false
- } else isSubType(tp1, tp2, pre)
+ } else ctdSubType(tp1, tp2)
+
+ def ctdSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
+ val saved = frozenConstraint
+ frozenConstraint = true
+ try ctdSubType(tp1, tp2)
+ finally frozenConstraint = saved
+ }
def monitoredIsSubType(tp1: Type, tp2: Type) = {
if (pendingSubTypes == null) {
@@ -823,56 +884,8 @@ class TypeComparer(initctx: Context) extends DotClass {
}
}
}
-
- // begin isSubType
- if (tp2 eq NoType) false
- else if (tp1 eq tp2) true
- else {
- val saved = constraint
- val savedSuccessCount = successCount
- try {
- recCount = recCount + 1
- val result =
- if (recCount < LogPendingSubTypesThreshold) firstTry(tp1, tp2)
- else monitoredIsSubType(tp1, tp2)
- recCount = recCount - 1
- if (!result) constraint = saved
- else if (recCount == 0 && needsGc) state.gc()
-
- def recordStatistics = {
- // Stats.record(s"isSubType ${tp1.show} <:< ${tp2.show}")
- totalCount += 1
- if (result) successCount += 1 else successCount = savedSuccessCount
- if (recCount == 0) {
- Stats.record("successful subType", successCount)
- Stats.record("total subType", totalCount)
- successCount = 0
- totalCount = 0
- }
- }
- if (Stats.monitored) recordStatistics
-
- result
- } catch {
- case NonFatal(ex) =>
- def showState = {
- println(disambiguated(implicit ctx => s"assertion failure for ${tp1.show} <:< ${tp2.show}, frozen = $frozenConstraint"))
- def explainPoly(tp: Type) = tp match {
- case tp: PolyParam => println(s"polyparam ${tp.show} found in ${tp.binder.show}")
- case tp: TypeRef if tp.symbol.exists => 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)
- }
- if (ex.isInstanceOf[AssertionError]) showState
- recCount -= 1
- constraint = saved
- successCount = savedSuccessCount
- throw ex
- }
- }
+
+ ctdSubType(orig1, orig2)
}
/** A type has been covered previously in subtype checking if it