summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala27
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala4
2 files changed, 19 insertions, 12 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 8f72bdcde6..f4f0d1e4a7 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -114,7 +114,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
}
private[Types] def record(tv: TypeVar) = {log = (tv, tv.constr.cloneInternal) :: log}
- private[Types] def clear {log = List()}
+ private[Types] def clear() { log = List() } // TODO: what's the point of this method? -- we roll back the log (using undoTo) in the combinators below anyway, see comments at clear() calls below
// `block` should not affect constraints on typevars
def undo[T](block: => T): T = {
@@ -2309,23 +2309,28 @@ A type's typeSymbol should never be inspected directly.
// only one of them is in the set of tvars that need to be solved, but
// they share the same TypeConstraint instance
-
+ // <region name="constraint mutators + undoLog">
+ // invariant: before mutating constr, save old state in undoLog (undoLog is used to reset constraints to avoid piling up unrelated ones)
def setInst(tp: Type) {
// assert(!(tp containsTp this), this)
+ undoLog record this
constr.inst = tp
}
def addLoBound(tp: Type, numBound: Boolean = false) {
assert(tp != this) // implies there is a cycle somewhere (?)
//println("addLoBound: "+(safeToString, debugString(tp))) //DEBUG
+ undoLog record this
constr.addLoBound(tp, numBound)
}
def addHiBound(tp: Type, numBound: Boolean = false) {
// assert(tp != this)
//println("addHiBound: "+(safeToString, debugString(tp))) //DEBUG
+ undoLog record this
constr.addHiBound(tp, numBound)
}
+ // </region>
// ignore subtyping&equality checks while true -- see findMember
private[TypeVar] var suspended = false
@@ -2342,8 +2347,6 @@ A type's typeSymbol should never be inspected directly.
def registerBound(tp: Type, isLowerBound: Boolean, numBound: Boolean = false): Boolean = { //println("regBound: "+(safeToString, debugString(tp), isLowerBound)) //@MDEBUG
if(isLowerBound) assert(tp != this)
- undoLog record this
-
def checkSubtype(tp1: Type, tp2: Type) =
if (numBound)
if (isLowerBound) tp1 weak_<:< tp2
@@ -2391,8 +2394,6 @@ A type's typeSymbol should never be inspected directly.
if (suspended) tp =:= origin
else if (constr.instValid) checkIsSameType(tp)
else isRelatable(tp) && {
- undoLog record this
-
val newInst = wildcardToTypeVarMap(tp)
if (constr.isWithinBounds(newInst)) {
setInst(tp)
@@ -2444,7 +2445,7 @@ A type's typeSymbol should never be inspected directly.
origin+
(if(typeArgs.isEmpty) "" else (typeArgs map (_.safeToString)).mkString("[ ", ", ", " ]")) // +"#"+tid //DEBUG
if (constr.inst eq null) "<null " + origin + ">"
- else if (settings.debug.value) varString+"(@"+constr.## +")"+constr.toString
+ // else if (settings.debug.value) varString+"(@"+constr.## +")"+constr.toString
else if (constr.inst eq NoType) varString
else constr.inst.toString
}
@@ -4027,7 +4028,9 @@ A type's typeSymbol should never be inspected directly.
}
} finally {
subsametypeRecursions -= 1
- if (subsametypeRecursions == 0) undoLog.clear
+ // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
+ // it doesn't help to keep separate recursion counts for the three methods that now share it
+ // if (subsametypeRecursions == 0) undoLog.clear()
}
def isDifferentType(tp1: Type, tp2: Type): Boolean = try {
@@ -4037,7 +4040,9 @@ A type's typeSymbol should never be inspected directly.
}
} finally {
subsametypeRecursions -= 1
- if (subsametypeRecursions == 0) undoLog.clear
+ // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
+ // it doesn't help to keep separate recursion counts for the three methods that now share it
+ // if (subsametypeRecursions == 0) undoLog.clear()
}
def isDifferentTypeConstructor(tp1: Type, tp2: Type): Boolean = tp1 match {
@@ -4366,7 +4371,9 @@ A type's typeSymbol should never be inspected directly.
}
} finally {
subsametypeRecursions -= 1
- if (subsametypeRecursions == 0) undoLog clear
+ // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
+ // it doesn't help to keep separate recursion counts for the three methods that now share it
+ // if (subsametypeRecursions == 0) undoLog.clear()
}
/** Does this type have a prefix that begins with a type variable,
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index c494185133..e4ae8f680d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -168,11 +168,11 @@ trait Typers { self: Analyzer =>
import context0.unit
val infer = new Inferencer(context0) {
- override def isCoercible(tp: Type, pt: Type): Boolean =
+ override def isCoercible(tp: Type, pt: Type): Boolean = undoLog undo { // #3281
tp.isError || pt.isError ||
context0.implicitsEnabled && // this condition prevents chains of views
inferView(EmptyTree, tp, pt, false) != EmptyTree
- }
+ }}
/** Find implicit arguments and pass them to given tree.
*/