summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-09-27 19:51:27 +0000
committerPaul Phillips <paulp@improving.org>2010-09-27 19:51:27 +0000
commita56c33b6a470939a1396015972f09e19dc493245 (patch)
tree4c38946754440c8860180ccda2b1bb83eb938a3a
parentb40f4ba3221f1091f4821423f18c157907e9a3c7 (diff)
downloadscala-a56c33b6a470939a1396015972f09e19dc493245.tar.gz
scala-a56c33b6a470939a1396015972f09e19dc493245.tar.bz2
scala-a56c33b6a470939a1396015972f09e19dc493245.zip
Bringing the tree and icode checkers back to life.
build/pack/bin/scalac -d /tmp -Ycheck-debug -Ycheck:all \ src/compiler/scala/tools/nsc/Global.scala That blows up in constructors as most files do, so also try it with -Ycheck:icode to see the pretty icode output (for a little while anyway, after which it will again blow up.) Our work has only just begun! See test/checker-tests/fail*.scala for 11 examples of places where the checker cries foul. Many of them are telling us about real issues and we should listen, but I will need help to figure out which are legitimate and which should be eliminated by altering the checkers. This patch also hacks on some territory the checkers drew me into, especially TypeKinds, where I figured anything which had been commented out since 2005 was fair game. (Optional) review by dragos. (The one place I know I could use a look is in Checkers.scala, because I had to relax some checks and add at least one newer opcode.)
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala5
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Checkers.scala452
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala43
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/ICodes.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala16
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala83
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala438
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala12
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala4
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala16
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala28
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala67
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala92
-rw-r--r--src/compiler/scala/tools/nsc/util/Set.scala4
-rw-r--r--test/checker-tests/fail1.scala17
-rw-r--r--test/checker-tests/fail10.scala23
-rw-r--r--test/checker-tests/fail11.scala71
-rw-r--r--test/checker-tests/fail2.scala50
-rw-r--r--test/checker-tests/fail3.scala54
-rw-r--r--test/checker-tests/fail4.scala136
-rw-r--r--test/checker-tests/fail5.scala197
-rw-r--r--test/checker-tests/fail6.scala61
-rw-r--r--test/checker-tests/fail7.scala70
-rw-r--r--test/checker-tests/fail8.scala145
-rw-r--r--test/checker-tests/fail9.scala145
33 files changed, 1630 insertions, 665 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 75dd7aea63..6d9bc2976a 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -755,12 +755,11 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
if (settings.check contains globalPhase.prev.name) {
if (globalPhase.prev.checkable) {
phase = globalPhase
+ inform("[Now checking: " + phase.prev.name + "]")
if (globalPhase.id >= icodePhase.id) icodeChecker.checkICodes
else checker.checkTrees
}
- else if (!settings.check.doAllPhases) {
- warning("It is not possible to check the result of the "+globalPhase.name+" phase")
- }
+ else inform("[Not checkable: " + globalPhase.prev.name + "]")
}
if (settings.Ystatistics.value) statistics.print(phase)
advancePhase
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 3ce61cf65e..32c0d936b2 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -405,13 +405,9 @@ trait BasicBlocks {
out.println()
}
- def fullString: String = {
- val buf = new StringBuilder()
- buf.append("Block ").append(label.toString())
- buf.append("\nSuccessors: ").append(successors)
- buf.append("\nPredecessors: ").append(predecessors)
- buf.toString()
- }
+ private def succString = if (successors.isEmpty) "[S: N/A]" else successors.distinct.mkString("[S: ", ", ", "]")
+ private def predString = if (predecessors.isEmpty) "[P: N/A]" else predecessors.distinct.mkString("[P: ", ", ", "]")
+ def fullString: String = List("Block", label, succString, predString) mkString " "
override def toString(): String = "" + label
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala
index 2b4d66fc49..8f402876bb 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala
@@ -3,7 +3,6 @@
* @author Martin Odersky
*/
-
package scala.tools.nsc
package backend
package icode
@@ -66,9 +65,15 @@ abstract class Checkers {
val emptyStack = new TypeStack()
val STRING = REFERENCE(definitions.StringClass)
- val SCALA_ALL = REFERENCE(definitions.NothingClass)
- val SCALA_ALL_REF = REFERENCE(definitions.NullClass)
- val THROWABLE = REFERENCE(definitions.ThrowableClass)
+ val SCALA_NOTHING = REFERENCE(definitions.NothingClass)
+ val SCALA_NULL = REFERENCE(definitions.NullClass)
+
+ /** A wrapper to route log messages to debug output also.
+ */
+ def logChecker(msg: String) = {
+ log(msg)
+ checkerDebug(msg)
+ }
def checkICodes: Unit = {
if (settings.verbose.value)
@@ -76,33 +81,30 @@ abstract class Checkers {
classes.values foreach check
}
+ /** Only called when m1 < m2, so already known that (m1 ne m2).
+ */
+ private def isConfict(m1: IMember, m2: IMember, canOverload: Boolean) = (
+ (m1.symbol.name == m2.symbol.name) &&
+ (!canOverload || (m1.symbol.tpe =:= m2.symbol.tpe))
+ )
+
def check(cls: IClass) {
- log("Checking class " + cls)
+ logChecker("\n** Checking class " + cls)
clasz = cls
- for (f1 <- cls.fields; f2 <- cls.fields if f1 ne f2)
- if (f1.symbol.name == f2.symbol.name)
- Checkers.this.global.error("Repetitive field name: " +
- f1.symbol.fullName);
-
- for (m1 <- cls.methods; m2 <- cls.methods if m1 ne m2)
- if (m1.symbol.name == m2.symbol.name &&
- m1.symbol.tpe =:= m2.symbol.tpe)
- Checkers.this.global.error("Repetitive method: " +
- m1.symbol.fullName);
- clasz.methods.foreach(check)
- }
+ for (f1 <- cls.fields ; f2 <- cls.fields ; if f1 < f2)
+ if (isConfict(f1, f2, false))
+ Checkers.this.global.error("Repetitive field name: " + f1.symbol.fullName)
- /** Apply the give function to each pair of the cartesian product of
- * l1 x l2.
- */
- def pairwise[a](l1: List[a], l2: List[a])(f: (a, a) => Unit) =
- l1 foreach { x =>
- l2 foreach { y => f(x, y) }
- }
+ for (m1 <- cls.methods ; m2 <- cls.methods ; if m1 < m2)
+ if (isConfict(m1, m2, true))
+ Checkers.this.global.error("Repetitive method: " + m1.symbol.fullName)
+
+ clasz.methods foreach check
+ }
def check(m: IMethod) {
- log("Checking method " + m)
+ logChecker("\n** Checking method " + m)
method = m
if (!m.isDeferred)
check(m.code)
@@ -116,7 +118,8 @@ abstract class Checkers {
if (!(worklist contains bl))
worklist += bl
- in.clear; out.clear;
+ in.clear;
+ out.clear;
code = c;
worklist += c.startBlock
for (bl <- c.blocks) {
@@ -124,15 +127,17 @@ abstract class Checkers {
out += (bl -> emptyStack)
}
- while (worklist.length > 0) {
- val block = worklist(0); worklist.trimStart(1);
+ while (worklist.nonEmpty) {
+ val block = worklist(0);
+ worklist.trimStart(1);
val output = check(block, in(block));
- if (output != out(block) ||
- (out(block) eq emptyStack)) {
- log("Output changed for block: " + block.fullString);
- out(block) = output;
- append(block.successors);
- block.successors foreach meet;
+ if (output != out(block) || (out(block) eq emptyStack)) {
+ if (block.successors.nonEmpty || block.successors.nonEmpty)
+ logChecker("Output changed for " + block.fullString)
+
+ out(block) = output
+ append(block.successors)
+ block.successors foreach meet
}
}
}
@@ -149,9 +154,19 @@ abstract class Checkers {
if (s1 eq emptyStack) s2
else if (s2 eq emptyStack) s1
else {
- if (s1.length != s2.length)
+ if (s1.isEmpty && s2.isEmpty) {
+ // PP: I do not know the significance of this condition, but it arises a lot
+ // so I'm taking the intuitive position that any two empty stacks are as good
+ // as another, rather than throwing an exception as it did.
+ // If the reference eq test is achieving something please document.
+ return emptyStack
+ }
+ else if (s1.length != s2.length)
throw new CheckerException("Incompatible stacks: " + s1 + " and " + s2 + " in " + method + " at entry to block: " + bl);
- new TypeStack((s1.types, s2.types).zipped map lub)
+
+ val types = (s1.types, s2.types).zipped map lub
+ checkerDebug("Checker created new stack: (%s, %s) => %s".format(s1.types, s2.types, types))
+ new TypeStack(types)
}
}
@@ -170,29 +185,67 @@ abstract class Checkers {
* produced type stack.
*/
def check(b: BasicBlock, initial: TypeStack): TypeStack = {
- log("** Checking block:\n" + b.fullString + " with initial stack:\n" + initial)
+ logChecker({
+ val prefix = "** Checking " + b.fullString
+
+ if (initial.isEmpty) prefix
+ else prefix + " with initial stack " + initial.types.mkString("[", ", ", "]")
+ })
+
var stack = new TypeStack(initial)
+ def checkStack(len: Int) {
+ if (stack.length < len)
+ ICodeChecker.this.error("Expected at least " + len + " elements on the stack", stack)
+ }
+
+ def sizeString(push: Boolean) = {
+ val arrow = if (push) "-> " else "<- "
+ val sp = " " * stack.length
+
+ sp + stack.length + arrow
+ }
+ def _popStack: TypeKind = {
+ if (stack.isEmpty) {
+ error("Popped empty stack in " + b.fullString + ", throwing a Unit")
+ return UNIT
+ }
+
+ val res = stack.pop
+ checkerDebug(sizeString(false) + res)
+ res
+ }
+ def popStack = { checkStack(1) ; _popStack }
+ def popStack2 = { checkStack(2) ; (_popStack, _popStack) }
+ def popStack3 = { checkStack(3) ; (_popStack, _popStack, _popStack) }
+ def clearStack() = 1 to stack.length foreach (_ => popStack)
+
+ def pushStack(xs: TypeKind*): Unit = {
+ xs foreach { x =>
+ if (x == UNIT)
+ logChecker("Ignoring pushed UNIT")
+ else {
+ stack push x
+ checkerDebug(sizeString(true) + x)
+ }
+ }
+ }
this.typeStack = stack
this.basicBlock = b
def typeError(k1: TypeKind, k2: TypeKind) {
- error(" expected: " + k1 + " but " + k2 + " found")
+ error("\n expected: " + k1 + "\n found: " + k2)
}
- for (instr <- b) {
+ def subtypeTest(k1: TypeKind, k2: TypeKind): Unit =
+ if (k1 <:< k2) ()
+ else typeError(k2, k1)
- def checkStack(len: Int) {
- if (stack.length < len)
- ICodeChecker.this.error("Expected at least " + len + " elements on the stack", stack);
- else
- ()
- }
+ for (instr <- b) {
- def checkLocal(local: Local) {
- method.lookupLocal(local.sym.name) match {
- case None => error(" " + local + " is not defined in method " + method);
- case _ => ()
+ def checkLocal(local: Local): Unit = {
+ (method lookupLocal local.sym.name) getOrElse {
+ error(" " + local + " is not defined in method " + method)
}
}
@@ -208,17 +261,17 @@ abstract class Checkers {
/** Checks that tpe is a subtype of one of the allowed types */
def checkType(tpe: TypeKind, allowed: TypeKind*) {
- if (isOneOf(tpe, allowed: _*))
- ()
- else
- error(tpe.toString() + " is not one of: " + allowed.toList.mkString("{", ", ", "}"));
+ if (isOneOf(tpe, allowed: _*)) ()
+ else error(tpe + " is not one of: " + allowed.mkString("{", ", ", "}"))
}
+ def checkNumeric(tpe: TypeKind) =
+ checkType(tpe, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)
/** Checks that the 2 topmost elements on stack are of the
* kind TypeKind.
*/
def checkBinop(kind: TypeKind) {
- val (a, b) = stack.pop2
+ val (a, b) = popStack2
checkType(a, kind)
checkType(b, kind)
}
@@ -227,7 +280,7 @@ abstract class Checkers {
def checkMethodArgs(method: Symbol) {
val params = method.info.paramTypes
checkStack(params.length)
- params.reverse.foreach( (tpe) => checkType(stack.pop, toTypeKind(tpe)))
+ params.reverse foreach (tpe => checkType(popStack, toTypeKind(tpe)))
}
/** Checks that the object passed as receiver has a method
@@ -241,11 +294,11 @@ abstract class Checkers {
case REFERENCE(sym) =>
checkBool(sym.info.member(method.name) != NoSymbol,
"Method " + method + " does not exist in " + sym.fullName);
- if (method hasFlag Flags.PRIVATE)
+ if (method.isPrivate)
checkBool(method.owner == clasz.symbol,
"Cannot call private method of " + method.owner.fullName
+ " from " + clasz.symbol.fullName);
- else if (method hasFlag Flags.PROTECTED)
+ else if (method.isProtected)
checkBool(clasz.symbol isSubClass method.owner,
"Cannot call protected method of " + method.owner.fullName
+ " from " + clasz.symbol.fullName);
@@ -259,7 +312,7 @@ abstract class Checkers {
}
def checkBool(cond: Boolean, msg: String) =
- if (cond) () else error(msg)
+ if (!cond) error(msg)
this.instruction = instr
@@ -270,18 +323,16 @@ abstract class Checkers {
}
instr match {
case THIS(clasz) =>
- stack push toTypeKind(clasz.tpe)
+ pushStack(toTypeKind(clasz.tpe))
case CONSTANT(const) =>
- stack push toTypeKind(const.tpe)
+ pushStack(toTypeKind(const.tpe))
case LOAD_ARRAY_ITEM(kind) =>
- checkStack(2)
- (stack.pop2: @unchecked) match {
+ popStack2 match {
case (INT, ARRAY(elem)) =>
- if (!(elem <:< kind))
- typeError(kind, elem);
- stack.push(elem);
+ subtypeTest(elem, kind)
+ pushStack(elem)
case (a, b) =>
error(" expected and INT and a array reference, but " +
a + ", " + b + " found");
@@ -289,33 +340,32 @@ abstract class Checkers {
case LOAD_LOCAL(local) =>
checkLocal(local)
- stack.push(local.kind)
+ pushStack(local.kind)
case LOAD_FIELD(field, isStatic) =>
- if (isStatic) {
- // the symbol's owner should contain it's field, but
- // this is already checked by the type checker, no need
- // to redo that here
- } else {
- checkStack(1)
- val obj = stack.pop
- checkField(obj, field)
- }
- stack.push(toTypeKind(field.tpe))
+ // the symbol's owner should contain it's field, but
+ // this is already checked by the type checker, no need
+ // to redo that here
+ if (isStatic) ()
+ else checkField(popStack, field)
+
+ pushStack(toTypeKind(field.tpe))
case LOAD_MODULE(module) =>
checkBool((module.isModule || module.isModuleClass),
"Expected module: " + module + " flags: " + Flags.flagsToString(module.flags));
- stack.push(toTypeKind(module.tpe));
+ pushStack(toTypeKind(module.tpe));
+
+ case STORE_THIS(kind) =>
+ val actualType = popStack
+ if (actualType.isReferenceType) subtypeTest(actualType, kind)
+ else error("Expected this reference but found: " + actualType)
case STORE_ARRAY_ITEM(kind) =>
- checkStack(3);
- (stack.pop3: @unchecked) match {
+ popStack3 match {
case (k, INT, ARRAY(elem)) =>
- if (!(k <:< kind))
- typeError(kind, k);
- if (!(k <:< elem))
- typeError(elem, k);
+ subtypeTest(k, kind)
+ subtypeTest(k, elem)
case (a, b, c) =>
error(" expected and array reference, and int and " + kind +
" but " + a + ", " + b + ", " + c + " found");
@@ -323,166 +373,145 @@ abstract class Checkers {
case STORE_LOCAL(local) =>
checkLocal(local)
- checkStack(1)
-
- val actualType = stack.pop;
- if (!(actualType <:< local.kind) &&
- //actualType != CASE_CLASS &&
- local.kind != SCALA_ALL_REF)
- typeError(local.kind, actualType);
-
- case STORE_FIELD(field, isStatic) =>
- if (isStatic) {
- checkStack(1);
- val fieldType = toTypeKind(field.tpe);
- val actualType = stack.pop;
- if (!(actualType <:< fieldType))
- // && actualType != CASE_CLASS)
- typeError(fieldType, actualType);
- } else {
- checkStack(2);
- stack.pop2 match {
- case (value, obj) =>
- checkField(obj, field);
- val fieldType = toTypeKind(field.tpe);
- if (fieldType != SCALA_ALL_REF && !(value <:< fieldType))
- //&& value != CASE_CLASS)
- typeError(fieldType, value);
- }
- }
+ val actualType = popStack
+ // PP: ThrowableReference is temporary to deal with exceptions
+ // not yet appearing typed.
+ if (actualType == ThrowableReference || local.kind == SCALA_NULL) ()
+ else subtypeTest(actualType, local.kind)
+
+ case STORE_FIELD(field, true) => // static
+ val fieldType = toTypeKind(field.tpe)
+ val actualType = popStack
+ subtypeTest(actualType, fieldType)
+
+ case STORE_FIELD(field, false) => // not static
+ val (value, obj) = popStack2
+ checkField(obj, field)
+ val fieldType = toTypeKind(field.tpe)
+ if (fieldType == SCALA_NULL) ()
+ else subtypeTest(value, fieldType)
case CALL_PRIMITIVE(primitive) =>
- checkStack(instr.consumed);
+ checkStack(instr.consumed)
primitive match {
case Negation(kind) =>
- checkType(kind, BOOL, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE);
- checkType(stack.pop, kind);
- stack push kind;
+ checkType(kind, BOOL, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)
+ checkType(popStack, kind)
+ pushStack(kind)
case Test(op, kind, zero) =>
- if (zero) {
- val actualType = stack.pop;
- checkType(actualType, kind);
- } else
- checkBinop(kind);
- stack push BOOL
+ if (zero) checkType(popStack, kind)
+ else checkBinop(kind)
+
+ pushStack(BOOL)
case Comparison(op, kind) =>
- checkType(kind, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)
+ checkNumeric(kind)
checkBinop(kind)
- stack push INT
+ pushStack(INT)
case Arithmetic(op, kind) =>
- checkType(kind, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)
+ checkNumeric(kind)
if (op == NOT)
- checkType(stack.pop, kind)
+ checkType(popStack, kind)
else
checkBinop(kind)
- stack push kind
+ pushStack(kind)
case Logical(op, kind) =>
- checkType(kind, BOOL, BYTE, CHAR, SHORT, INT, LONG)
+ checkType(kind, BOOL, BYTE, CHAR, SHORT, INT, LONG)
checkBinop(kind)
- stack push kind
+ pushStack(kind)
case Shift(op, kind) =>
checkType(kind, BYTE, CHAR, SHORT, INT, LONG)
- val (a, b) = stack.pop2
+ val (a, b) = popStack2
checkType(a, INT)
checkType(b, kind)
- stack push kind
+ pushStack(kind)
case Conversion(src, dst) =>
- checkType(src, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)
- checkType(dst, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)
- checkType(stack.pop, src)
- stack push dst
+ checkNumeric(src)
+ checkNumeric(dst)
+ checkType(popStack, src)
+ pushStack(dst)
case ArrayLength(kind) =>
- val arr = stack.pop
- arr match {
- case ARRAY(elem) =>
- checkType(elem, kind);
- case _ =>
- error(" array reference expected, but " + arr + " found");
+ popStack match {
+ case ARRAY(elem) => checkType(elem, kind)
+ case arr => error(" array reference expected, but " + arr + " found")
}
- stack push INT
+ pushStack(INT)
case StartConcat =>
- stack.push(ConcatClass)
+ pushStack(ConcatClass)
case EndConcat =>
- checkType(stack.pop, ConcatClass)
- stack.push(STRING)
+ checkType(popStack, ConcatClass)
+ pushStack(STRING)
case StringConcat(el) =>
- checkType(stack.pop, el)
- checkType(stack.pop, ConcatClass)
- stack push ConcatClass
+ checkType(popStack, el)
+ checkType(popStack, ConcatClass)
+ pushStack(ConcatClass)
}
case CALL_METHOD(method, style) =>
+ def paramCount = method.info.paramTypes.length
+ def pushReturnType = pushStack(toTypeKind(method.info.resultType))
+
style match {
case Dynamic | InvokeDynamic =>
- checkStack(1 + method.info.paramTypes.length)
+ checkStack(1 + paramCount)
checkMethodArgs(method)
- checkMethod(stack.pop, method)
- stack.push(toTypeKind(method.info.resultType))
+ checkMethod(popStack, method)
+ pushReturnType
case Static(onInstance) =>
if (onInstance) {
- checkStack(1 + method.info.paramTypes.length)
- checkBool(method.hasFlag(Flags.PRIVATE) || method.isConstructor,
+ checkStack(1 + paramCount)
+ checkBool(method.isPrivate || method.isConstructor,
"Static call to non-private method.")
checkMethodArgs(method)
- checkMethod(stack.pop, method)
+ checkMethod(popStack, method)
if (!method.isConstructor)
- stack.push(toTypeKind(method.info.resultType));
- } else {
- checkStack(method.info.paramTypes.length);
+ pushReturnType
+ }
+ else {
+ checkStack(paramCount);
checkMethodArgs(method);
- stack.push(toTypeKind(method.info.resultType));
+ pushReturnType
}
case SuperCall(mix) =>
- checkStack(1 + method.info.paramTypes.length)
+ checkStack(1 + paramCount)
checkMethodArgs(method)
- checkMethod(stack.pop, method)
- stack.push(toTypeKind(method.info.resultType))
+ checkMethod(popStack, method)
+ pushReturnType
}
case NEW(kind) =>
- kind match {
- case REFERENCE(cls) =>
- stack.push(kind)
- //bq: had to change from _ to null, because otherwise would be unreachable code
- case null =>
- error("NEW call to non-reference type: " + kind)
- }
+ pushStack(kind)
case CREATE_ARRAY(elem, dims) =>
checkStack(dims)
stack.pop(dims) foreach (checkType(_, INT))
- stack.push(ARRAY(elem))
+ pushStack(ARRAY(elem))
case IS_INSTANCE(tpe) =>
- val ref = stack.pop
- checkBool(ref.isReferenceType || ref.isArrayType,
- "IS_INSTANCE on primitive type: " + ref)
- checkBool(tpe.isReferenceType || tpe.isArrayType,
- "IS_INSTANCE to primitive type: " + tpe)
- stack.push(BOOL);
+ val ref = popStack
+ checkBool(!ref.isValueType, "IS_INSTANCE on primitive type: " + ref)
+ checkBool(!tpe.isValueType, "IS_INSTANCE on primitive type: " + tpe)
+ pushStack(BOOL)
case CHECK_CAST(tpe) =>
- val ref = stack.pop
- checkBool(ref.isReferenceType || ref.isArrayType,
- "CHECK_CAST on primitive type: " + ref)
- checkBool(tpe.isReferenceType || tpe.isArrayType,
- "CHECK_CAST to primitive type: " + tpe)
- stack.push(tpe);
+ val ref = popStack
+ checkBool(!ref.isValueType, "CHECK_CAST to primitive type: " + ref)
+ checkBool(!tpe.isValueType, "CHECK_CAST to primitive type: " + tpe)
+ pushStack(tpe)
case SWITCH(tags, labels) =>
- checkType(stack.pop, INT)
+ checkType(popStack, INT)
checkBool(tags.length == labels.length - 1,
"The number of tags and labels does not coincide.")
checkBool(labels forall (b => code.blocks contains b),
@@ -504,60 +533,46 @@ abstract class Checkers {
"Jump to non-existant block " + success)
checkBool(code.blocks contains failure,
"Jump to non-existant block " + failure)
- checkType(stack.pop, kind)
+ checkType(popStack, kind)
+ case RETURN(UNIT) => ()
case RETURN(kind) =>
- kind match {
- case UNIT => ()
-
- case REFERENCE(_) | ARRAY(_) =>
- checkStack(1)
- val top = stack.pop
- checkBool(top.isReferenceType || top.isArrayType,
- "" + kind + " is a reference type, but " + top + " is not");
- case _ =>
- checkStack(1)
- val top = stack.pop
- checkType(top, kind)
- }
+ val top = popStack
+ if (kind.isValueType) checkType(top, kind)
+ else checkBool(!top.isValueType, "" + kind + " is a reference type, but " + top + " is not");
case THROW() =>
- val thrown = stack.pop
+ val thrown = popStack
checkBool(thrown.toType <:< definitions.ThrowableClass.tpe,
"Element on top of stack should implement 'Throwable': " + thrown);
- stack.push(SCALA_ALL)
+ pushStack(SCALA_NOTHING)
case DROP(kind) =>
- checkType(stack.pop, kind)
+ checkType(popStack, kind)
case DUP(kind) =>
- val top = stack.pop
+ val top = popStack
checkType(top, kind)
- stack.push(top)
- stack.push(top)
+ pushStack(top)
+ pushStack(top)
case MONITOR_ENTER() =>
- checkStack(1)
- checkBool(stack.pop.isReferenceType,
- "MONITOR_ENTER on non-reference type")
+ checkBool(popStack.isReferenceType, "MONITOR_ENTER on non-reference type")
case MONITOR_EXIT() =>
- checkStack(1)
- checkBool(stack.pop.isReferenceType,
- "MONITOR_EXIT on non-reference type")
+ checkBool(popStack.isReferenceType, "MONITOR_EXIT on non-reference type")
case BOX(kind) =>
- checkStack(1)
- checkType(stack.pop, kind)
- stack.push(icodes.AnyRefReference)
+ checkType(popStack, kind)
+ pushStack(icodes.ObjectReference)
case UNBOX(kind) =>
- checkStack(1)
- stack.pop
- stack.push(kind)
+ popStack
+ pushStack(kind)
case LOAD_EXCEPTION() =>
- stack.push(THROWABLE)
+ clearStack()
+ pushStack(ThrowableReference)
case SCOPE_ENTER(_) | SCOPE_EXIT(_) =>
()
@@ -572,15 +587,16 @@ abstract class Checkers {
//////////////// Error reporting /////////////////////////
def error(msg: String) {
- Console.println(method.toString() + " in block: " + basicBlock.label)
- printLastInstructions
+ Console.println("Error in " + method + ", block: " + basicBlock.label)
+ printLastInstructions(8)
Checkers.this.global.error("ICode checker: " + method + ": " + msg)
}
- /** Prints the last 4 instructions. */
- def printLastInstructions {
- val buf = basicBlock.reverse dropWhile (_ != instruction) take 4 reverse;
+ /** Prints the last n instructions. */
+ def printLastInstructions(n: Int) {
+ val buf = basicBlock.reverse dropWhile (_ != instruction) take n reverse;
+ Console.println("Last " + buf.size + " instructions: ")
buf foreach (Console println _)
Console.println("at: " + buf.head.pos)
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index ec8ffd1ddb..93eaa9123f 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -55,10 +55,9 @@ abstract class GenICode extends SubComponent {
// this depends on the backend! should be changed.
val ANY_REF_CLASS = REFERENCE(ObjectClass)
-
- val SCALA_ALL = REFERENCE(NothingClass)
- val SCALA_ALLREF = REFERENCE(NullClass)
- val THROWABLE = REFERENCE(ThrowableClass)
+ val SCALA_NOTHING = REFERENCE(NothingClass)
+ val SCALA_NULL = REFERENCE(NullClass)
+ val THROWABLE = REFERENCE(ThrowableClass)
override def run {
scalaPrimitives.init
@@ -222,7 +221,7 @@ abstract class GenICode extends SubComponent {
case rarg :: Nil =>
resKind = getMaxType(larg.tpe :: rarg.tpe :: Nil);
if (scalaPrimitives.isShiftOp(code) || scalaPrimitives.isBitwiseOp(code))
- assert(resKind.isIntType | resKind == BOOL,
+ assert(resKind.isIntegralType | resKind == BOOL,
resKind.toString() + " incompatible with arithmetic modulo operation: " + ctx1);
ctx1 = genLoad(larg, ctx1, resKind)
@@ -704,7 +703,7 @@ abstract class GenICode extends SubComponent {
val ctx1 = genLoad(expr, ctx, THROWABLE)
ctx1.bb.emit(THROW(), tree.pos)
ctx1.bb.enterIgnoreMode
- generatedType = SCALA_ALL
+ generatedType = SCALA_NOTHING
ctx1
case New(tpt) =>
@@ -1028,7 +1027,7 @@ abstract class GenICode extends SubComponent {
generatedType = DOUBLE
case (NullTag, _) =>
ctx.bb.emit(CONSTANT(value), tree.pos);
- generatedType = SCALA_ALLREF
+ generatedType = SCALA_NULL
case _ =>
ctx.bb.emit(CONSTANT(value), tree.pos);
generatedType = toTypeKind(tree.tpe)
@@ -1121,7 +1120,7 @@ abstract class GenICode extends SubComponent {
}
private def adapt(from: TypeKind, to: TypeKind, ctx: Context, pos: Position): Unit = {
- if (!(from <:< to) && !(from == SCALA_ALLREF && to == SCALA_ALL)) {
+ if (!(from <:< to) && !(from == SCALA_NULL && to == SCALA_NOTHING)) {
to match {
case UNIT =>
ctx.bb.emit(DROP(from), pos)
@@ -1134,13 +1133,18 @@ abstract class GenICode extends SubComponent {
assert(!from.isReferenceType && !to.isReferenceType, "type error: can't convert from " + from + " to " + to +" in unit "+this.unit)
ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to)), pos);
}
- } else if (from == SCALA_ALL) {
+ } else if (from == SCALA_NOTHING) {
ctx.bb.emit(THROW())
ctx.bb.enterIgnoreMode
- } else if (from == SCALA_ALLREF) {
+ } else if (from == SCALA_NULL) {
ctx.bb.emit(DROP(from))
ctx.bb.emit(CONSTANT(Constant(null)))
- } else (from, to) match {
+ }
+ else if (from == THROWABLE) {
+ log("Inserted check-cast on throwable to " + to + " at " + pos)
+ ctx.bb.emit(CHECK_CAST(to))
+ }
+ else (from, to) match {
case (BYTE, LONG) | (SHORT, LONG) | (CHAR, LONG) | (INT, LONG) => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, LONG)))
case _ => ()
}
@@ -1874,6 +1878,15 @@ abstract class GenICode extends SubComponent {
buf.toString()
}
+ /** PP: This instruction was only emitted when settings.Xdce.value = true,
+ * but I don't understand the condition. It seems like the exception handler
+ * stacks won't balance without it, so put it in under -Ycheck too.
+ */
+ def maybeLoadException(ctx: Context) = {
+ if (settings.Xdce.value || !settings.check.isDefault)
+ ctx.bb.emit(LOAD_EXCEPTION())
+ }
+
def this(other: Context) = {
this()
this.packg = other.packg
@@ -2089,7 +2102,7 @@ abstract class GenICode extends SubComponent {
this.addActiveHandler(exh) // .. and body aswell
val ctx = finalizerCtx.enterHandler(exh)
val exception = ctx.makeLocal(finalizer.pos, ThrowableClass.tpe, "exc")
- if (settings.Xdce.value) ctx.bb.emit(LOAD_EXCEPTION())
+ maybeLoadException(ctx)
ctx.bb.emit(STORE_LOCAL(exception));
val ctx1 = genLoad(finalizer, ctx, UNIT);
ctx1.bb.emit(LOAD_LOCAL(exception));
@@ -2103,7 +2116,7 @@ abstract class GenICode extends SubComponent {
val exhs = handlers.map { handler =>
val exh = this.newHandler(handler._1, handler._2)
var ctx1 = outerCtx.enterHandler(exh)
- if (settings.Xdce.value) ctx1.bb.emit(LOAD_EXCEPTION())
+ maybeLoadException(ctx1)
ctx1 = handler._3(ctx1)
// emit finalizer
val ctx2 = emitFinalizer(ctx1)
@@ -2157,7 +2170,7 @@ abstract class GenICode extends SubComponent {
val exh = outerCtx.newHandler(NoSymbol, UNIT)
this.addActiveHandler(exh)
val ctx = finalizerCtx.enterHandler(exh)
- if (settings.Xdce.value) ctx.bb.emit(LOAD_EXCEPTION())
+ maybeLoadException(ctx)
val ctx1 = genLoad(finalizer, ctx, UNIT)
// need jump for the ICode to be valid. MSIL backend will emit `Endfinally` instead.
ctx1.bb.closeWith(JUMP(afterCtx.bb))
@@ -2167,7 +2180,7 @@ abstract class GenICode extends SubComponent {
for (handler <- handlers) {
val exh = this.newHandler(handler._1, handler._2)
var ctx1 = outerCtx.enterHandler(exh)
- if (settings.Xdce.value) ctx1.bb.emit(LOAD_EXCEPTION())
+ maybeLoadException(ctx1)
ctx1 = handler._3(ctx1)
// msil backend will emit `Leave` to jump out of a handler
ctx1.bb.closeWith(JUMP(afterCtx.bb))
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
index 30aaebc3c2..f1be717d12 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
@@ -40,6 +40,10 @@ abstract class ICodes extends AnyRef
/** The ICode representation of classes */
var classes: HashMap[global.Symbol, IClass] = new HashMap()
+ /** Debugging flag */
+ var isCheckerDebug: Boolean = global.settings.checkDebug.value
+ def checkerDebug(msg: String) = if (isCheckerDebug) println(msg)
+
/** The ICode linearizer. */
val linearizer: Linearizer =
if (global.settings.Xlinearizer.value == "rpo")
@@ -87,7 +91,8 @@ abstract class ICodes extends AnyRef
val global: ICodes.this.global.type = ICodes.this.global
}
- lazy val AnyRefReference: TypeKind = REFERENCE(global.definitions.ObjectClass)
+ lazy val ObjectReference: TypeKind = REFERENCE(global.definitions.ObjectClass)
+ lazy val ThrowableReference: TypeKind = REFERENCE(global.definitions.ThrowableClass)
object icodeReader extends ICodeReader {
lazy val global: ICodes.this.global.type = ICodes.this.global
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
index 68360776b3..9d9e3c92e4 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
@@ -89,8 +89,18 @@ trait Members { self: ICodes =>
}
}
+ /** Common interface for IClass/IField/IMethod. */
+ trait IMember extends Ordered[IMember] {
+ def symbol: Symbol
+
+ def compare(other: IMember) =
+ if (symbol eq other.symbol) 0
+ else if (symbol isLess other.symbol) -1
+ else 1
+ }
+
/** Represent a class in ICode */
- class IClass(val symbol: Symbol) {
+ class IClass(val symbol: Symbol) extends IMember {
var fields: List[IField] = Nil
var methods: List[IMethod] = Nil
var cunit: CompilationUnit = _
@@ -122,7 +132,7 @@ trait Members { self: ICodes =>
}
/** Represent a field in ICode */
- class IField(val symbol: Symbol) { }
+ class IField(val symbol: Symbol) extends IMember { }
/**
* Represents a method in ICode. Local variables contain
@@ -134,7 +144,7 @@ trait Members { self: ICodes =>
* reversing them and putting them back, when the generation is
* finished (GenICode does that).
*/
- class IMethod(val symbol: Symbol) {
+ class IMethod(val symbol: Symbol) extends IMember {
var code: Code = null
var native = false
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
index 7f2dd7684a..6c3ec7fc19 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
@@ -112,7 +112,7 @@ trait Opcodes { self: ICodes =>
*/
case class THIS(clasz: Symbol) extends Instruction {
/** Returns a string representation of this constant */
- override def toString(): String = "THIS"
+ override def toString = "THIS(" + clasz.name + ")"
override def consumed = 0
override def produced = 1
@@ -125,9 +125,6 @@ trait Opcodes { self: ICodes =>
* ->: ...:constant
*/
case class CONSTANT(constant: Constant) extends Instruction {
- /** Returns a string representation of this constant */
- override def toString(): String = "CONSTANT ("+constant.toString()+")"
-
override def consumed = 0
override def produced = 1
@@ -140,9 +137,6 @@ trait Opcodes { self: ICodes =>
* ->: ...:element(a)
*/
case class LOAD_ARRAY_ITEM(kind: TypeKind) extends Instruction {
- /** Returns a string representation of this instruction */
- override def toString(): String = "LOAD_ARRAY_ITEM (" + kind + ")"
-
override def consumed = 2
override def produced = 1
@@ -155,9 +149,6 @@ trait Opcodes { self: ICodes =>
* ->: ...:value
*/
case class LOAD_LOCAL(local: Local) extends Instruction {
- /** Returns a string representation of this instruction */
- override def toString(): String = "LOAD_LOCAL "+local.toString() //+isArgument?" (argument)":"";
-
override def consumed = 0
override def produced = 1
@@ -182,11 +173,9 @@ trait Opcodes { self: ICodes =>
}
case class LOAD_MODULE(module: Symbol) extends Instruction {
- assert(module != NoSymbol,
- "Invalid module symbol");
+ assert(module != NoSymbol, "Invalid module symbol")
/** Returns a string representation of this instruction */
- override def toString(): String =
- "LOAD_MODULE " + module.toString()
+ override def toString(): String = "LOAD_MODULE " + module
override def consumed = 0
override def produced = 1
@@ -199,9 +188,6 @@ trait Opcodes { self: ICodes =>
* ->: ...
*/
case class STORE_ARRAY_ITEM(kind: TypeKind) extends Instruction {
- /** Returns a string representation of this instruction */
- override def toString(): String = "STORE_ARRAY_ITEM (" + kind + ")"
-
override def consumed = 3
override def produced = 0
@@ -213,9 +199,6 @@ trait Opcodes { self: ICodes =>
* ->: ...
*/
case class STORE_LOCAL(local: Local) extends Instruction {
- /** Returns a string representation of this instruction */
- override def toString(): String = "STORE_LOCAL "+local.toString(); //+isArgument?" (argument)":"";
-
override def consumed = 1
override def produced = 0
@@ -229,7 +212,7 @@ trait Opcodes { self: ICodes =>
case class STORE_FIELD(field: Symbol, isStatic: Boolean) extends Instruction {
/** Returns a string representation of this instruction */
override def toString(): String =
- "STORE_FIELD "+field.toString() + (if (isStatic) " (static)" else " (dynamic)");
+ "STORE_FIELD "+field + (if (isStatic) " (static)" else " (dynamic)");
override def consumed = if(isStatic) 1 else 2;
override def produced = 0;
@@ -246,7 +229,6 @@ trait Opcodes { self: ICodes =>
* ->: ...
*/
case class STORE_THIS(kind: TypeKind) extends Instruction {
- override def toString() = "STORE_THIS(" + kind + ")"
override def consumed = 1
override def produced = 0
override def consumedTypes = List(kind)
@@ -257,9 +239,6 @@ trait Opcodes { self: ICodes =>
* ->: ...:result
*/
case class CALL_PRIMITIVE(primitive: Primitive) extends Instruction {
- /** Returns a string representation of this instruction */
- override def toString(): String ="CALL_PRIMITIVE "+primitive.toString()
-
override def consumed = primitive match {
case Negation(_) => 1
case Test(_,_, true) => 1
@@ -322,7 +301,7 @@ trait Opcodes { self: ICodes =>
case class CALL_METHOD(method: Symbol, style: InvokeStyle) extends Instruction with ReferenceEquality {
/** Returns a string representation of this instruction */
override def toString(): String =
- "CALL_METHOD " + hostClass.fullName + method.fullName +" ("+style.toString()+")";
+ "CALL_METHOD " + method.fullName +" ("+style+")"
var hostClass: Symbol = method.owner
def setHostClass(cls: Symbol): this.type = { hostClass = cls; this }
@@ -342,7 +321,7 @@ trait Opcodes { self: ICodes =>
override def consumed = params.length + consumesInstance
override def consumedTypes = {
val args = params map toTypeKind
- if (consumesInstance > 0) AnyRefReference :: args
+ if (consumesInstance > 0) ObjectReference :: args
else args
}
@@ -371,7 +350,7 @@ trait Opcodes { self: ICodes =>
case class UNBOX(boxType: TypeKind) extends Instruction {
override def toString(): String = "UNBOX " + boxType
override def consumed = 1
- override def consumedTypes = AnyRefReference :: Nil
+ override def consumedTypes = ObjectReference :: Nil
override def produced = 1
}
@@ -397,7 +376,7 @@ trait Opcodes { self: ICodes =>
*/
case class CREATE_ARRAY(elem: TypeKind, dims: Int) extends Instruction {
/** Returns a string representation of this instruction */
- override def toString(): String ="CREATE_ARRAY "+elem.toString() + " x " + dims;
+ override def toString(): String ="CREATE_ARRAY "+elem + " x " + dims;
override def consumed = dims;
override def consumedTypes = List.fill(dims)(INT)
@@ -410,10 +389,10 @@ trait Opcodes { self: ICodes =>
*/
case class IS_INSTANCE(typ: TypeKind) extends Instruction {
/** Returns a string representation of this instruction */
- override def toString(): String ="IS_INSTANCE "+typ.toString()
+ override def toString(): String ="IS_INSTANCE "+typ
override def consumed = 1
- override def consumedTypes = AnyRefReference :: Nil
+ override def consumedTypes = ObjectReference :: Nil
override def produced = 1
}
@@ -423,11 +402,11 @@ trait Opcodes { self: ICodes =>
*/
case class CHECK_CAST(typ: TypeKind) extends Instruction {
/** Returns a string representation of this instruction */
- override def toString(): String ="CHECK_CAST "+typ.toString()
+ override def toString(): String ="CHECK_CAST "+typ
override def consumed = 1
override def produced = 1
- override val consumedTypes = List(AnyRefReference)
+ override val consumedTypes = List(ObjectReference)
override def producedTypes = List(typ)
}
@@ -473,7 +452,7 @@ trait Opcodes { self: ICodes =>
/** Returns a string representation of this instruction */
override def toString(): String = (
"CJUMP (" + kind + ")" +
- cond.toString()+" ? "+successBlock.label+" : "+failureBlock.label
+ cond + " ? "+successBlock.label+" : "+failureBlock.label
);
override def consumed = 2
@@ -492,7 +471,7 @@ trait Opcodes { self: ICodes =>
/** Returns a string representation of this instruction */
override def toString(): String = (
"CZJUMP (" + kind + ")" +
- cond.toString()+" ? "+successBlock.label+" : "+failureBlock.label
+ cond + " ? "+successBlock.label+" : "+failureBlock.label
);
override def consumed = 1
@@ -505,9 +484,6 @@ trait Opcodes { self: ICodes =>
* ->: ...
*/
case class RETURN(kind: TypeKind) extends Instruction {
- /** Returns a string representation of this instruction */
- override def toString(): String ="RETURN (" + kind + ")"
-
override def consumed = if (kind == UNIT) 0 else 1
override def produced = 0
}
@@ -530,7 +506,7 @@ trait Opcodes { self: ICodes =>
*/
case class DROP (typ: TypeKind) extends Instruction {
/** Returns a string representation of this instruction */
- override def toString(): String ="DROP "+typ.toString()
+ override def toString(): String ="DROP "+typ
override def consumed = 1
override def produced = 0
@@ -541,9 +517,6 @@ trait Opcodes { self: ICodes =>
* ->: ...:something:something
*/
case class DUP (typ: TypeKind) extends Instruction {
- /** Returns a string representation of this instruction */
- override def toString(): String ="DUP"
-
override def consumed = 1
override def produced = 2
}
@@ -553,7 +526,6 @@ trait Opcodes { self: ICodes =>
* ->: ...:
*/
case class MONITOR_ENTER() extends Instruction {
-
/** Returns a string representation of this instruction */
override def toString(): String ="MONITOR_ENTER"
@@ -566,7 +538,6 @@ trait Opcodes { self: ICodes =>
* ->: ...:
*/
case class MONITOR_EXIT() extends Instruction {
-
/** Returns a string representation of this instruction */
override def toString(): String ="MONITOR_EXIT";
@@ -603,7 +574,7 @@ trait Opcodes { self: ICodes =>
override def toString(): String = "LOAD_EXCEPTION"
override def consumed = error("LOAD_EXCEPTION does clean the whole stack, no idea how many things it consumes!")
override def produced = 1
- override def producedTypes = AnyRefReference :: Nil
+ override def producedTypes = ThrowableReference :: Nil
}
/** This class represents a method invocation style. */
@@ -627,18 +598,18 @@ trait Opcodes { self: ICodes =>
/** Is this an instance method call? */
def hasInstance: Boolean = this match {
- case Dynamic => true
+ case Dynamic => true
case Static(onInstance) => onInstance
- case SuperCall(_) => true
- case _ => false
+ case SuperCall(_) => true
+ case _ => false
}
/** Returns a string representation of this style. */
override def toString(): String = this match {
- case Dynamic => "dynamic"
- case InvokeDynamic => "invoke-dynamic"
- case Static(false) => "static-class"
- case Static(true) => "static-instance"
+ case Dynamic => "dynamic"
+ case InvokeDynamic => "invoke-dynamic"
+ case Static(false) => "static-class"
+ case Static(true) => "static-instance"
case SuperCall(mix) => "super(" + mix + ")"
}
}
@@ -663,7 +634,7 @@ trait Opcodes { self: ICodes =>
case class CIL_LOAD_LOCAL_ADDRESS(local: Local) extends Instruction {
/** Returns a string representation of this instruction */
- override def toString(): String = "CIL_LOAD_LOCAL_ADDRESS "+local.toString() //+isArgument?" (argument)":"";
+ override def toString(): String = "CIL_LOAD_LOCAL_ADDRESS "+local //+isArgument?" (argument)":"";
override def consumed = 0
override def produced = 1
@@ -674,7 +645,7 @@ trait Opcodes { self: ICodes =>
case class CIL_LOAD_FIELD_ADDRESS(field: Symbol, isStatic: Boolean) extends Instruction {
/** Returns a string representation of this instruction */
override def toString(): String =
- "CIL_LOAD_FIELD_ADDRESS " + (if (isStatic) field.fullName else field.toString());
+ "CIL_LOAD_FIELD_ADDRESS " + (if (isStatic) field.fullName else field.toString)
override def consumed = if (isStatic) 0 else 1
override def produced = 1
@@ -697,7 +668,7 @@ trait Opcodes { self: ICodes =>
case class CIL_UNBOX(valueType: TypeKind) extends Instruction {
override def toString(): String = "CIL_UNBOX " + valueType
override def consumed = 1
- override def consumedTypes = AnyRefReference :: Nil // actually consumes a 'boxed valueType'
+ override def consumedTypes = ObjectReference :: Nil // actually consumes a 'boxed valueType'
override def produced = 1
override def producedTypes = List(msil_mgdptr(valueType))
}
@@ -705,7 +676,7 @@ trait Opcodes { self: ICodes =>
case class CIL_INITOBJ(valueType: TypeKind) extends Instruction {
override def toString(): String = "CIL_INITOBJ " + valueType
override def consumed = 1
- override def consumedTypes = AnyRefReference :: Nil // actually consumes a managed pointer
+ override def consumedTypes = ObjectReference :: Nil // actually consumes a managed pointer
override def produced = 0
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
index 62042ce3ce..b18c0da2a9 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -3,7 +3,6 @@
* @author Martin Odersky
*/
-
package scala.tools.nsc
package backend
package icode
@@ -24,16 +23,15 @@ package icode
*/
-import scala.collection.mutable.{ Map, HashMap }
-
trait TypeKinds { self: ICodes =>
import global._
import definitions.{ ArrayClass, AnyRefClass, ObjectClass, NullClass, NothingClass }
+ import icodes.checkerDebug
/** A map from scala primitive Types to ICode TypeKinds */
- lazy val primitiveTypeMap: collection.Map[Symbol, TypeKind] = {
+ lazy val primitiveTypeMap: Map[Symbol, TypeKind] = {
import definitions._
- collection.Map(
+ Map(
UnitClass -> UNIT,
BooleanClass -> BOOL,
CharClass -> CHAR,
@@ -46,62 +44,68 @@ trait TypeKinds { self: ICodes =>
)
}
/** Reverse map for toType */
- private lazy val reversePrimitiveMap: collection.Map[TypeKind, Symbol] =
- collection.Map(primitiveTypeMap.toList map (_.swap) : _*)
+ private lazy val reversePrimitiveMap: Map[TypeKind, Symbol] =
+ primitiveTypeMap map (_.swap) toMap
/** This class represents a type kind. Type kinds
* represent the types that the VM know (or the ICode
* view of what VMs know).
*/
sealed abstract class TypeKind {
+ def maxType(other: TypeKind): TypeKind
- def toType: Type = (reversePrimitiveMap get this) match {
- case Some(sym) => sym.tpe
- case None => this match {
- case REFERENCE(cls) => cls.tpe // typeRef(cls.typeConstructor.prefix, cls, Nil)
- // case VALUE(cls) => typeRef(cls.typeConstructor.prefix, cls, Nil)
+ def toType: Type = (reversePrimitiveMap get this) map (_.tpe) getOrElse {
+ this match {
+ case REFERENCE(cls) => cls.tpe
case ARRAY(elem) => typeRef(ArrayClass.typeConstructor.prefix, ArrayClass, List(elem.toType))
case _ => abort("Unknown type kind.")
}
}
+ def toTypeAt(ph: Phase): Type = atPhase(ph)(toType)
- def isReferenceType: Boolean = false
- def isArrayType: Boolean = false
- def isValueType: Boolean = !isReferenceType && !isArrayType
+ def isReferenceType = false
+ def isArrayType = false
+ def isValueType = false
+ final def isRefOrArrayType = isReferenceType || isArrayType
+ final def isNothingType = this == REFERENCE(NothingClass)
-
- def isIntType: Boolean = this match {
+ def isIntegralType: Boolean = this match {
case BYTE | SHORT | INT | LONG | CHAR => true
- case _ => false
+ case _ => false
}
-
def isRealType: Boolean = this match {
case FLOAT | DOUBLE => true
- case _ => false
+ case _ => false
}
-
- def isNumericType: Boolean = isIntType | isRealType
-
- def maxType(other: TypeKind): TypeKind
+ def isNumericType: Boolean = isIntegralType | isRealType
/** Simple subtyping check */
def <:<(other: TypeKind): Boolean = (this eq other) || (this match {
- case BOOL | BYTE | SHORT | CHAR =>
- other match {
- case INT | LONG => true
- case _ => false
- }
- case _ => this eq other
+ case BOOL | BYTE | SHORT | CHAR => other == INT || other == LONG
+ case _ => this eq other
})
/** Is this type a category 2 type in JVM terms? */
def isWideType: Boolean = this match {
- case DOUBLE | LONG => true
- case _ => false
+ case DOUBLE | LONG => true
+ case _ => false
}
/** The number of dimensions for array types. */
def dimensions: Int = 0
+
+ protected def uncomparable(thisKind: String, other: TypeKind): Nothing =
+ abort("Uncomparable type kinds: " + thisKind + " with " + other)
+
+ protected def uncomparable(other: TypeKind): Nothing =
+ uncomparable(this.toString, other)
+ }
+
+ sealed abstract class ValueTypeKind extends TypeKind {
+ override def isValueType = true
+ override def toString = {
+ this.getClass.getName stripSuffix "$" dropWhile (_ != '$') drop 1
+ }
}
var lubs0 = 0
@@ -113,14 +117,34 @@ trait TypeKinds { self: ICodes =>
* The lub is based on the lub of scala types.
*/
def lub(a: TypeKind, b: TypeKind): TypeKind = {
- def lub0(t1: Type, t2: Type): Type = {
- //lubs0 += 1
- global.lub(t1 :: t2 :: Nil)
+ def lub0(tk1: TypeKind, tk2: TypeKind): Type = {
+ /** Returning existing implementation unless flag given. See #3872. */
+ if (!isCheckerDebug)
+ return global.lub(List(tk1.toType, tk2.toType))
+
+ /** PP: Obviously looking for " with " is a bit short of the ideal robustness,
+ * but that's why it's only used under -Ycheck-debug. Correct fix is likely
+ * to change compound types to lead with the class type.
+ */
+ atPhase(currentRun.typerPhase) {
+ val t1 = tk1.toType
+ val t2 = tk2.toType
+ val calculated = global.lub(List(t1, t2))
+ checkerDebug("at Phase %s, lub0(%s, %s) == %s".format(global.globalPhase, t1, t2, calculated))
+ calculated match {
+ case x: CompoundType =>
+ val tps = x.baseTypeSeq.toList filterNot (_.toString contains " with ")
+ val id = global.erasure.erasure.intersectionDominator(tps)
+ checkerDebug("intersectionDominator(%s) == %s".format(tps.mkString(", "), id))
+ id
+ case x => x
+ }
+ }
}
if (a == b) a
- else if (a == REFERENCE(NothingClass)) b
- else if (b == REFERENCE(NothingClass)) a
+ else if (a.isNothingType) b
+ else if (b.isNothingType) a
else (a, b) match {
case (BOXED(a1), BOXED(b1)) => if (a1 == b1) a else REFERENCE(AnyRefClass)
case (BOXED(_), REFERENCE(_)) | (REFERENCE(_), BOXED(_)) => REFERENCE(AnyRefClass)
@@ -130,123 +154,96 @@ trait TypeKinds { self: ICodes =>
case (CHAR, INT) | (INT, CHAR) => INT
case (BOOL, INT) | (INT, BOOL) => INT
case _ =>
- if ((a.isReferenceType || a.isArrayType) &&
- (b.isReferenceType || b.isArrayType))
- toTypeKind(lub0(a.toType, b.toType))
+ if (a.isRefOrArrayType && b.isRefOrArrayType)
+ toTypeKind(lub0(a, b))
else
throw new CheckerException("Incompatible types: " + a + " with " + b)
}
}
/** The unit value */
- case object UNIT extends TypeKind {
- def maxType(other: TypeKind): TypeKind = other match {
- case UNIT => UNIT
- case REFERENCE(NothingClass) => UNIT
- case _ => abort("Uncomparable type kinds: UNIT with " + other)
+ case object UNIT extends ValueTypeKind {
+ def maxType(other: TypeKind) = other match {
+ case UNIT | REFERENCE(NothingClass) => UNIT
+ case _ => uncomparable(other)
}
}
/** A boolean value */
- case object BOOL extends TypeKind {
- override def maxType(other: TypeKind): TypeKind = other match {
- case BOOL => BOOL
- case REFERENCE(NothingClass) => BOOL
- case _ => abort("Uncomparable type kinds: BOOL with " + other)
+ case object BOOL extends ValueTypeKind {
+ def maxType(other: TypeKind) = other match {
+ case BOOL | REFERENCE(NothingClass) => BOOL
+ case _ => uncomparable(other)
}
}
- /** A 1-byte signed integer */
- case object BYTE extends TypeKind {
- override def maxType(other: TypeKind): TypeKind =
- other match {
- case CHAR => INT
- case BYTE | SHORT | INT | LONG | FLOAT | DOUBLE => other
- case REFERENCE(NothingClass) => BYTE
- case _ => abort("Uncomparable type kinds: BYTE with " + other)
- }
- }
-
/** Note that the max of Char/Byte and Char/Short is Int, because
* neither strictly encloses the other due to unsignedness.
* See ticket #2087 for a consequence.
*/
+ /** A 1-byte signed integer */
+ case object BYTE extends ValueTypeKind {
+ def maxType(other: TypeKind) = {
+ if (other == BYTE || other.isNothingType) BYTE
+ else if (other == CHAR) INT
+ else if (other.isNumericType) other
+ else uncomparable(other)
+ }
+ }
+
/** A 2-byte signed integer */
- case object SHORT extends TypeKind {
- override def maxType(other: TypeKind): TypeKind =
- other match {
- case CHAR => INT
- case BYTE | SHORT => SHORT
- case REFERENCE(NothingClass) => SHORT
- case INT | LONG | FLOAT | DOUBLE => other
- case _ => abort("Uncomparable type kinds: SHORT with " + other)
- }
+ case object SHORT extends ValueTypeKind {
+ override def maxType(other: TypeKind) = other match {
+ case BYTE | SHORT | REFERENCE(NothingClass) => SHORT
+ case CHAR => INT
+ case INT | LONG | FLOAT | DOUBLE => other
+ case _ => uncomparable(other)
+ }
}
/** A 2-byte UNSIGNED integer */
- case object CHAR extends TypeKind {
- override def maxType(other: TypeKind): TypeKind =
- other match {
- case CHAR => CHAR
- case BYTE | SHORT => INT
- case REFERENCE(NothingClass) => CHAR
- case INT | LONG | FLOAT | DOUBLE => other
- case _ => abort("Uncomparable type kinds: CHAR with " + other)
- }
+ case object CHAR extends ValueTypeKind {
+ override def maxType(other: TypeKind) = other match {
+ case CHAR | REFERENCE(NothingClass) => CHAR
+ case BYTE | SHORT => INT
+ case INT | LONG | FLOAT | DOUBLE => other
+ case _ => uncomparable(other)
+ }
}
-
/** A 4-byte signed integer */
- case object INT extends TypeKind {
- override def maxType(other: TypeKind): TypeKind =
- other match {
- case BYTE | SHORT | CHAR | INT => INT
- case REFERENCE(NothingClass) => INT
- case LONG | FLOAT | DOUBLE => other
- case _ => abort("Uncomparable type kinds: INT with " + other)
- }
+ case object INT extends ValueTypeKind {
+ override def maxType(other: TypeKind) = other match {
+ case BYTE | SHORT | CHAR | INT | REFERENCE(NothingClass) => INT
+ case LONG | FLOAT | DOUBLE => other
+ case _ => uncomparable(other)
+ }
}
/** An 8-byte signed integer */
- case object LONG extends TypeKind {
+ case object LONG extends ValueTypeKind {
override def maxType(other: TypeKind): TypeKind =
- other match {
- case BYTE | SHORT | CHAR | INT | LONG => LONG
- case REFERENCE(NothingClass) => LONG
- case FLOAT | DOUBLE => DOUBLE
- case _ => abort("Uncomparable type kinds: LONG with " + other)
- }
+ if (other.isIntegralType || other.isNothingType) LONG
+ else if (other.isRealType) DOUBLE
+ else uncomparable(other)
}
/** A 4-byte floating point number */
- case object FLOAT extends TypeKind {
- override def maxType(other: TypeKind): TypeKind = other match {
- case BYTE | SHORT | CHAR | INT | LONG | FLOAT => FLOAT
- case REFERENCE(NothingClass) => FLOAT
- case DOUBLE => DOUBLE
- case _ => abort("Uncomparable type kinds: FLOAT with " + other)
- }
+ case object FLOAT extends ValueTypeKind {
+ override def maxType(other: TypeKind): TypeKind =
+ if (other == DOUBLE) DOUBLE
+ else if (other.isNumericType || other.isNothingType) FLOAT
+ else uncomparable(other)
}
/** An 8-byte floating point number */
- case object DOUBLE extends TypeKind {
+ case object DOUBLE extends ValueTypeKind {
override def maxType(other: TypeKind): TypeKind =
- if (other.isNumericType)
- DOUBLE
- else if (other == REFERENCE(NothingClass)) DOUBLE
- else abort("Uncomparable type kinds: DOUBLE with " + other)
+ if (other.isNumericType || other.isNothingType) DOUBLE
+ else uncomparable(other)
}
- /** A string reference */
- // case object STRING extends TypeKind {
- // override def maxType(other: TypeKind): TypeKind = other match {
- // case STRING => STRING;
- // case _ =>
- // abort("Uncomparable type kinds: STRING with " + other);
- // }
- // }
-
/** A class type. */
final case class REFERENCE(cls: Symbol) extends TypeKind {
assert(cls ne null,
@@ -256,70 +253,40 @@ trait TypeKinds { self: ICodes =>
assert(cls != NoSymbol,
"REFERENCE to NoSymbol not allowed!")
- override def toString(): String =
- "REFERENCE(" + cls.fullName + ")"
-
/**
* Approximate `lub'. The common type of two references is
* always AnyRef. For 'real' least upper bound wrt to subclassing
* use method 'lub'.
*/
- override def maxType(other: TypeKind): TypeKind =
- other match {
- case REFERENCE(_) | ARRAY(_) =>
- REFERENCE(AnyRefClass)
- case _ =>
- abort("Uncomparable type kinds: REFERENCE with " + other)
- }
+ override def maxType(other: TypeKind) = other match {
+ case REFERENCE(_) | ARRAY(_) => REFERENCE(AnyRefClass)
+ case _ => uncomparable("REFERENCE", other)
+ }
/** Checks subtyping relationship. */
- override def <:<(other: TypeKind): Boolean =
- if (cls == NothingClass)
- true
- else other match {
- case REFERENCE(cls2) =>
- cls.tpe <:< cls2.tpe
- case ARRAY(_) =>
- cls == NullClass
- case _ => false
- }
-
- override def isReferenceType: Boolean = true;
+ override def <:<(other: TypeKind) = isNothingType || (other match {
+ case REFERENCE(cls2) => cls.tpe <:< cls2.tpe
+ case ARRAY(_) => cls == NullClass
+ case _ => false
+ })
+ override def isReferenceType = true
}
-// final case class VALUE(cls: Symbol) extends TypeKind {
-// override def equals(other: Any): Boolean = other match {
-// case VALUE(cls2) => cls == cls2;
-// case _ => false;
-// }
-
-// def maxType(other: TypeKind): TypeKind =
-// abort(toString() + " maxType " + other.toString());
-
-// override def toString(): String =
-// "VALUE(" + cls.fullName + ")";
-// }
-
def ArrayN(elem: TypeKind, dims: Int): ARRAY = {
assert(dims > 0)
- if (dims == 1)
- ARRAY(elem)
- else
- ARRAY(ArrayN(elem, dims - 1))
+ if (dims == 1) ARRAY(elem)
+ else ARRAY(ArrayN(elem, dims - 1))
}
final case class ARRAY(val elem: TypeKind) extends TypeKind {
- override def toString(): String =
- "ARRAY[" + elem + "]"
-
+ override def toString = "ARRAY[" + elem + "]"
override def isArrayType = true
-
- override def dimensions: Int = 1 + elem.dimensions
+ override def dimensions = 1 + elem.dimensions
/** The ultimate element type of this array. */
def elementKind: TypeKind = elem match {
- case a @ ARRAY(e1) => a.elementKind
- case k => k
+ case a @ ARRAY(_) => a.elementKind
+ case k => k
}
/**
@@ -327,58 +294,39 @@ trait TypeKinds { self: ICodes =>
* always AnyRef. For 'real' least upper bound wrt to subclassing
* use method 'lub'.
*/
- override def maxType(other: TypeKind): TypeKind =
- other match {
- case REFERENCE(_) =>
- REFERENCE(AnyRefClass)
- case ARRAY(elem2) =>
- if (elem == elem2) ARRAY(elem)
- else REFERENCE(AnyRefClass)
- case _ =>
- abort("Uncomparable type kinds: ARRAY with " + other)
- }
+ override def maxType(other: TypeKind) = other match {
+ case ARRAY(elem2) if elem == elem2 => ARRAY(elem)
+ case ARRAY(_) | REFERENCE(_) => REFERENCE(AnyRefClass)
+ case _ => uncomparable("ARRAY", other)
+ }
/** Array subtyping is covariant, as in Java. Necessary for checking
* code that interacts with Java. */
- override def <:<(other: TypeKind): Boolean =
- other match {
- case ARRAY(elem2) =>
- elem <:< elem2
- case REFERENCE(AnyRefClass | ObjectClass) =>
- true // TODO: platform dependent!
- case _ => false
- }
+ override def <:<(other: TypeKind) = other match {
+ case ARRAY(elem2) => elem <:< elem2
+ case REFERENCE(AnyRefClass | ObjectClass) => true // TODO: platform dependent!
+ case _ => false
+ }
}
/** A boxed value. */
case class BOXED(kind: TypeKind) extends TypeKind {
- override def toString(): String =
- "BOXED(" + kind + ")"
-
/**
* Approximate `lub'. The common type of two references is
* always AnyRef. For 'real' least upper bound wrt to subclassing
* use method 'lub'.
*/
- override def maxType(other: TypeKind): TypeKind =
- other match {
- case REFERENCE(_) | ARRAY(_) | BOXED(_) =>
- REFERENCE(AnyRefClass)
- case _ =>
- abort("Uncomparable type kinds: ARRAY with " + other)
- }
+ override def maxType(other: TypeKind) = other match {
+ case REFERENCE(_) | ARRAY(_) | BOXED(_) => REFERENCE(AnyRefClass)
+ case _ => uncomparable("BOXED", other)
+ }
/** Checks subtyping relationship. */
- override def <:<(other: TypeKind): Boolean =
- other match {
- case REFERENCE(AnyRefClass | ObjectClass) =>
- true // TODO: platform dependent!
-
- case BOXED(other) =>
- kind == other
-
- case _ => false
- }
+ override def <:<(other: TypeKind) = other match {
+ case BOXED(other) => kind == other
+ case REFERENCE(AnyRefClass | ObjectClass) => true // TODO: platform dependent!
+ case _ => false
+ }
}
/**
@@ -386,87 +334,61 @@ trait TypeKinds { self: ICodes =>
* way. For JVM it would have been a REFERENCE to 'StringBuffer'.
*/
case object ConcatClass extends TypeKind {
- override def toString() = "ConcatClass"
+ override def toString = "ConcatClass"
/**
* Approximate `lub'. The common type of two references is
* always AnyRef. For 'real' least upper bound wrt to subclassing
* use method 'lub'.
*/
- override def maxType(other: TypeKind): TypeKind =
- other match {
- case REFERENCE(_) =>
- REFERENCE(AnyRefClass)
- case _ =>
- abort("Uncomparable type kinds: ConcatClass with " + other)
- }
+ override def maxType(other: TypeKind) = other match {
+ case REFERENCE(_) => REFERENCE(AnyRefClass)
+ case _ => uncomparable(other)
+ }
/** Checks subtyping relationship. */
- override def <:<(other: TypeKind): Boolean = (this eq other)
-
- override def isReferenceType: Boolean = false
+ override def <:<(other: TypeKind) = this eq other
}
////////////////// Conversions //////////////////////////////
-
/** Return the TypeKind of the given type
*
* Call to .normalize fixes #3003 (follow type aliases). Otherwise,
- * arrayOrClassType below would return AnyRefReference.
+ * arrayOrClassType below would return ObjectReference.
*/
def toTypeKind(t: Type): TypeKind = t.normalize match {
- case ThisType(sym) =>
- if (sym == ArrayClass)
- AnyRefReference
- else
- REFERENCE(sym)
-
- case SingleType(pre, sym) =>
- primitiveTypeMap.getOrElse(sym, REFERENCE(sym))
-
- case ConstantType(value) =>
- toTypeKind(t.underlying)
-
- case TypeRef(_, sym, args) =>
- primitiveTypeMap.getOrElse(sym, arrayOrClassType(sym, args))
-
- case ClassInfoType(_, _, sym) =>
- primitiveTypeMap get sym match {
- case Some(k) => k
- case None =>
- if (sym == ArrayClass)
- abort("ClassInfoType to ArrayClass!")
- else
- REFERENCE(sym)
- }
-
- case ExistentialType(tparams, t) =>
- toTypeKind(t)
-
- case AnnotatedType(_, t, _) =>
- toTypeKind(t)
-
- //case WildcardType => // bq: useful hack when wildcard types come here
- // REFERENCE(definitions.ObjectClass)
-
- case _ =>
- abort("Unknown type: " + t + ", " + t.normalize + "[" + t.getClass + ", " + t.normalize.getClass + "]" +
- " TypeRef? " + t.isInstanceOf[TypeRef] + ", " + t.normalize.isInstanceOf[TypeRef])
+ case ThisType(ArrayClass) => ObjectReference
+ case ThisType(sym) => REFERENCE(sym)
+ case SingleType(_, sym) => primitiveOrRefType(sym)
+ case ConstantType(_) => toTypeKind(t.underlying)
+ case TypeRef(_, sym, args) => primitiveOrClassType(sym, args)
+ case ClassInfoType(_, _, ArrayClass) => abort("ClassInfoType to ArrayClass!")
+ case ClassInfoType(_, _, sym) => primitiveOrRefType(sym)
+ case ExistentialType(_, t) => toTypeKind(t)
+ case AnnotatedType(_, t, _) => toTypeKind(t)
+ // bq: useful hack when wildcard types come here
+ // case WildcardType => REFERENCE(ObjectClass)
+ case norm => abort(
+ "Unknown type: %s, %s [%s, %s] TypeRef? %s".format(
+ t, norm, t.getClass, norm.getClass, t.isInstanceOf[TypeRef]
+ )
+ )
}
/** Return the type kind of a class, possibly an array type.
*/
- private def arrayOrClassType(sym: Symbol, targs: List[Type]): TypeKind = {
- if (sym == ArrayClass)
- ARRAY(toTypeKind(targs.head))
- else if (sym.isClass)
- REFERENCE(sym)
- else {
+ private def arrayOrClassType(sym: Symbol, targs: List[Type]) = sym match {
+ case ArrayClass => ARRAY(toTypeKind(targs.head))
+ case _ if sym.isClass => REFERENCE(sym)
+ case _ =>
assert(sym.isType, sym) // it must be compiling Array[a]
- AnyRefReference
- }
+ ObjectReference
}
+ private def primitiveOrRefType(sym: Symbol) =
+ primitiveTypeMap.getOrElse(sym, REFERENCE(sym))
+ private def primitiveOrClassType(sym: Symbol, targs: List[Type]) =
+ primitiveTypeMap.getOrElse(sym, arrayOrClassType(sym, targs))
def msil_mgdptr(tk: TypeKind): TypeKind = (tk: @unchecked) match {
case REFERENCE(cls) => REFERENCE(loaders.clrTypes.mdgptrcls4clssym(cls))
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala
index 4c52d36d33..74abec78bc 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala
@@ -23,15 +23,21 @@ trait TypeStacks {
type Rep = List[TypeKind]
class TypeStack(var types: Rep) {
+ if (types.nonEmpty)
+ checkerDebug("TypeStack init: " + types.mkString(", "))
+
def this() = this(Nil)
def this(that: TypeStack) = this(that.types)
def length: Int = types.length
+ def isEmpty = length == 0
+ def nonEmpty = length != 0
/** Push a type on the type stack. UNITs are ignored. */
- def push(t: TypeKind) =
+ def push(t: TypeKind) = {
if (t != UNIT)
types = t :: types
+ }
def head: TypeKind = types.head
@@ -72,7 +78,9 @@ trait TypeStacks {
(types corresponds other.types)((t1, t2) => t1 <:< t2 || t2 <:< t1)
/* This method returns a String representation of the stack */
- override def toString() = types.mkString("\n", "\n", "\n")
+ override def toString() =
+ if (types.isEmpty) "TypeStack()"
+ else types.mkString("TypeStack(" + types.size + " elems) {\n ", "\n ", "\n}")
override def hashCode() = types.hashCode()
override def equals(other: Any): Boolean = other match {
diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
index bc7c88fcb8..ba7e00901a 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
@@ -173,14 +173,14 @@ abstract class ClosureElimination extends SubComponent {
val value = info.getBinding(loc1)
value match {
case Boxed(LocalVar(loc2)) =>
- bb.replaceInstruction(i, DROP(icodes.AnyRefReference) :: valueToInstruction(info.getBinding(loc2)) :: Nil)
+ bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(info.getBinding(loc2)) :: Nil)
log("replaced " + i + " with " + info.getBinding(loc2))
case _ =>
()
}
case Boxed(LocalVar(loc1)) :: _ =>
val loc2 = info.getAlias(loc1)
- bb.replaceInstruction(i, DROP(icodes.AnyRefReference) :: valueToInstruction(Deref(LocalVar(loc2))) :: Nil)
+ bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(Deref(LocalVar(loc2))) :: Nil)
log("replaced " + i + " with " + LocalVar(loc2))
case _ =>
()
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index b175cb24ee..abf7f3e0de 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -106,6 +106,7 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options")
val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after")
val check = PhasesSetting ("-Ycheck", "Check the tree at the end of")
+ val checkDebug = BooleanSetting ("-Ycheck-debug", "Lots of extra output for -Ycheck")
val Xcloselim = BooleanSetting ("-Yclosure-elim", "Perform closure elimination")
val Ycompacttrees = BooleanSetting ("-Ycompact-trees", "Use compact tree printer when displaying trees")
val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL")
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index a95c8ada8f..1f9f1c9701 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -79,13 +79,17 @@ abstract class SymbolLoaders {
override def load(root: Symbol) { complete(root) }
+ private def markAbsent(sym: Symbol): Unit = {
+ val tpe: Type = if (ok) NoType else ErrorType
+
+ if (sym != NoSymbol)
+ sym setInfo tpe
+ }
private def initRoot(root: Symbol) {
- if (root.rawInfo == this) {
- def markAbsent(sym: Symbol) =
- if (sym != NoSymbol) sym.setInfo(if (ok) NoType else ErrorType);
- markAbsent(root)
- markAbsent(root.moduleClass)
- } else if (root.isClass && !root.isModuleClass) root.rawInfo.load(root)
+ if (root.rawInfo == this)
+ List(root, root.moduleClass) foreach markAbsent
+ else if (root.isClass && !root.isModuleClass)
+ root.rawInfo.load(root)
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index c1afe0c3d8..4c20a901ef 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -247,9 +247,13 @@ abstract class Constructors extends Transform with ast.TreeDSL {
tree match {
case DefDef(_, _, _, _, _, body)
if (tree.symbol.isOuterAccessor && tree.symbol.owner == clazz && clazz.isFinal) =>
+ log("outerAccessors += " + tree.symbol.fullName)
outerAccessors ::= (tree.symbol, body)
case Select(_, _) =>
- if (!mustbeKept(tree.symbol)) accessedSyms addEntry tree.symbol
+ if (!mustbeKept(tree.symbol)) {
+ log("accessedSyms += " + tree.symbol.fullName)
+ accessedSyms addEntry tree.symbol
+ }
super.traverse(tree)
case _ =>
super.traverse(tree)
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 72868774e5..61f5c6e5d0 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -50,12 +50,13 @@ abstract class ExplicitOuter extends InfoTransform
clazz.owner.isClass &&
clazz.owner == parent.typeSymbol.owner &&
parent.prefix =:= clazz.owner.thisType
+
isInner(clazz) && !clazz.isTrait &&
- (clazz.info.parents.isEmpty || !hasSameOuter(clazz.info.parents.head))
+ !(clazz.info.parents.headOption exists hasSameOuter)
}
private def outerField(clazz: Symbol): Symbol = {
- val result = clazz.info.member(nme getterToLocal nme.OUTER)
+ val result = clazz.info.member(nme.OUTER_LOCAL)
assert(result != NoSymbol, "no outer field in "+clazz+clazz.info.decls+" at "+phase)
result
@@ -113,7 +114,7 @@ abstract class ExplicitOuter extends InfoTransform
if (sym.owner.isTrait && ((sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isModule)) { // 5
sym.makeNotPrivate(sym.owner)
}
- if (sym.owner.isTrait && (sym hasFlag PROTECTED)) sym setFlag notPROTECTED // 6
+ if (sym.owner.isTrait && sym.isProtected) sym setFlag notPROTECTED // 6
if (sym.isClassConstructor && isInner(sym.owner)) { // 1
val p = sym.newValueParameter(sym.pos, "arg" + nme.OUTER)
.setInfo(sym.owner.outerClass.thisType)
@@ -300,6 +301,8 @@ abstract class ExplicitOuter extends InfoTransform
* </p>
*/
class ExplicitOuterTransformer(unit: CompilationUnit) extends OuterPathTransformer(unit) {
+ transformer =>
+
/** The definition tree of the outer accessor of current class
*/
def outerFieldDef: Tree = VAL(outerField(currentClass)) === EmptyTree
@@ -328,13 +331,14 @@ abstract class ExplicitOuter extends InfoTransform
val path =
if (mixinClass.owner.isTerm) THIS(mixinClass.owner.enclClass)
else gen.mkAttributedQualifier(currentClass.thisType baseType mixinClass prefix)
- // Need to cast for nested outer refs in presence of self-types. See ticket #3274.
- val rhs = gen.mkAsInstanceOf(ExplicitOuterTransformer.this.transform(path),
- outerAcc.info.resultType)
- // @S: atPos not good enough because of nested atPos in DefDef method, which gives position from wrong class!
- rhs setPos currentClass.pos
- typedPos(currentClass.pos) { (DEF(outerAcc) === rhs) setPos currentClass.pos }
+ localTyper typed {
+ DEF(outerAcc) === {
+ // Need to cast for nested outer refs in presence of self-types. See ticket #3274.
+ // @S: atPos not good enough because of nested atPos in DefDef method, which gives position from wrong class!
+ transformer.transform(path) AS_ANY outerAcc.info.resultType setPos currentClass.pos
+ }
+ } setPos currentClass.pos
}
/** If FLAG is set on symbol, sets notFLAG (this exists in anticipation of generalizing). */
@@ -422,7 +426,7 @@ abstract class ExplicitOuter extends InfoTransform
case Template(parents, self, decls) =>
val newDefs = new ListBuffer[Tree]
atOwner(tree, currentOwner) {
- if (!(currentClass hasFlag INTERFACE) || (currentClass hasFlag lateINTERFACE)) {
+ if (!currentClass.isInterface || (currentClass hasFlag lateINTERFACE)) {
if (isInner(currentClass)) {
if (hasOuterField(currentClass))
newDefs += outerFieldDef // (1a)
@@ -464,12 +468,12 @@ abstract class ExplicitOuter extends InfoTransform
if (currentClass != sym.owner/* && currentClass != sym.moduleClass*/) // (3)
sym.makeNotPrivate(sym.owner)
val qsym = qual.tpe.widen.typeSymbol
- if ((sym hasFlag PROTECTED) && //(4)
+ if (sym.isProtected && //(4)
(qsym.isTrait || !(qual.isInstanceOf[Super] || (qsym isSubClass currentClass))))
sym setFlag notPROTECTED
super.transform(tree)
- case Apply(sel @ Select(qual, name), args) if (name == nme.CONSTRUCTOR && isInner(sel.symbol.owner)) =>
+ case Apply(sel @ Select(qual, nme.CONSTRUCTOR), args) if isInner(sel.symbol.owner) =>
val outerVal = atPos(tree.pos)(qual match {
// it's a call between constructors of same class
case _: This =>
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 7791cc0b02..ecf68fa922 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -14,20 +14,16 @@ import scala.collection.mutable.{HashMap, LinkedHashMap, ListBuffer}
abstract class LambdaLift extends InfoTransform {
import global._
import definitions._
- import typer.{typed, typedOperator}
/** the following two members override abstract members in Transform */
val phaseName: String = "lambdalift"
private val lifted = new TypeMap {
def apply(tp: Type): Type = tp match {
- case TypeRef(pre, sym, args) =>
- if (pre == NoPrefix && sym.isClass && !sym.isPackageClass) {
- assert(args.isEmpty);
- typeRef(apply(sym.owner.enclClass.thisType), sym, args)
- } else mapOver(tp)
+ case TypeRef(NoPrefix, sym, Nil) if sym.isClass && !sym.isPackageClass =>
+ typeRef(apply(sym.owner.enclClass.thisType), sym, Nil)
case ClassInfoType(parents, decls, clazz) =>
- val parents1 = parents mapConserve (this)
+ val parents1 = parents mapConserve this
if (parents1 eq parents) tp
else ClassInfoType(parents1, decls, clazz)
case _ =>
@@ -62,15 +58,16 @@ abstract class LambdaLift extends InfoTransform {
private type SymSet = TreeSet[Symbol]
- private def newSymSet = new TreeSet[Symbol]((x, y) => x.isLess(y))
+ private def newSymSet = new TreeSet[Symbol](_ isLess _)
- private def symSet(f: LinkedHashMap[Symbol, SymSet], sym: Symbol): SymSet = f.get(sym) match {
- case Some(ss) => ss
- case None => val ss = newSymSet; f(sym) = ss; ss
- }
+ private def symSet(f: LinkedHashMap[Symbol, SymSet], sym: Symbol): SymSet =
+ f.getOrElseUpdate(sym, newSymSet)
private def outer(sym: Symbol): Symbol =
- if (sym.isConstructor) sym.owner.owner else sym.owner;
+ if (sym.isConstructor) sym.owner.owner else sym.owner
+
+ private def isSameOwnerEnclosure(sym: Symbol) =
+ enclMethOrClass(sym.owner) == enclMethOrClass(currentOwner)
/** The method or class which logically encloses the current symbol.
* If the symbol is defined in the initialization part of a template
@@ -142,7 +139,7 @@ abstract class LambdaLift extends InfoTransform {
else if (owner.isPackageClass || !markFree(sym, enclMethOrClass(outer(owner)))) false
else {
val ss = symSet(free, owner)
- if (!(ss contains sym)) {
+ if (!ss(sym)) {
ss addEntry sym
renamable addEntry sym
atPhase(currentRun.picklerPhase) {
@@ -151,12 +148,12 @@ abstract class LambdaLift extends InfoTransform {
// def closure(x: Int) = { () => x }
// would have the signature
// closure: (x$1: Int)() => Int
- if (sym.hasFlag(PARAM) && sym.owner.info.paramss.exists(_.contains(sym)))
+ if (sym.isParameter && sym.owner.info.paramss.exists(_ contains sym))
sym.owner.setInfo(sym.owner.info.cloneInfo(sym.owner))
}
changedFreeVars = true
if (settings.debug.value) log("" + sym + " is free in " + owner);
- if ((sym.isVariable || (sym.isValue && sym.hasFlag(LAZY))) && !(sym hasFlag CAPTURED)) {
+ if ((sym.isVariable || (sym.isValue && sym.isLazy)) && !sym.hasFlag(CAPTURED)) {
sym setFlag CAPTURED
val symClass = sym.tpe.typeSymbol;
atPhase(phase.next) {
@@ -191,10 +188,8 @@ abstract class LambdaLift extends InfoTransform {
}
}
*/
- def freeVars(sym: Symbol): Iterator[Symbol] = free.get(sym) match {
- case Some(ss) => ss.iterator
- case None => Iterator.empty
- }
+ def freeVars(sym: Symbol): Iterator[Symbol] =
+ free get sym map (_.iterator) getOrElse Iterator.empty
/** The traverse function */
private val freeVarTraverser = new Traverser {
@@ -247,28 +242,29 @@ abstract class LambdaLift extends InfoTransform {
do {
changedFreeVars = false
- for (caller <- called.keysIterator;
- callee <- called(caller).iterator;
+ for (caller <- called.keys;
+ callee <- called(caller);
fv <- freeVars(callee))
markFree(fv, caller)
- } while (changedFreeVars);
+ } while (changedFreeVars)
- for (sym <- renamable.iterator) {
- val base =
+ for (sym <- renamable) {
+ val base = sym.name + "$" + (
if (sym.isAnonymousFunction && sym.owner.isMethod)
- sym.name.toString() + "$" + sym.owner.name.toString() + "$"
- else sym.name.toString() + "$"
+ sym.owner.name + "$"
+ else ""
+ )
val fresh = unit.fresh.newName(sym.pos, base)
sym.name = if (sym.name.isTypeName) fresh.toTypeName else fresh
if (settings.debug.value) log("renamed: " + sym.name)
}
atPhase(phase.next) {
- for (owner <- free.keysIterator) {
+ for (owner <- free.keys) {
if (settings.debug.value)
- log("free(" + owner + owner.locationString + ") = " + free(owner).iterator.toList);
+ log("free(" + owner + owner.locationString + ") = " + free(owner).toList)
proxies(owner) =
- for (fv <- free(owner).iterator.toList) yield {
+ for (fv <- free(owner).toList) yield {
val proxy = owner.newValue(owner.pos, fv.name)
.setFlag(if (owner.isClass) PARAMACCESSOR | PRIVATE | LOCAL else PARAM)
.setFlag(SYNTHETIC)
@@ -297,7 +293,7 @@ abstract class LambdaLift extends InfoTransform {
if (settings.debug.value)
log("proxy " + sym + " in " + sym.owner + " from " + currentOwner.ownerChain +
" " + enclMethOrClass(sym.owner));//debug
- if (enclMethOrClass(sym.owner) == enclMethOrClass(currentOwner)) sym
+ if (isSameOwnerEnclosure(sym)) sym
else searchIn(currentOwner)
}
@@ -411,7 +407,7 @@ abstract class LambdaLift extends InfoTransform {
val tpt1 = TypeTree(sym.tpe) setPos tpt.pos
val rhs1 =
atPos(rhs.pos) {
- typed {
+ typer typed {
Apply(Select(New(TypeTree(sym.tpe)), nme.CONSTRUCTOR), List(rhs))
}
}
@@ -434,14 +430,14 @@ abstract class LambdaLift extends InfoTransform {
if (sym != NoSymbol && sym.isTerm && !sym.isLabel)
if (sym.isMethod)
atPos(tree.pos)(memberRef(sym))
- else if (sym.isLocal && enclMethOrClass(sym.owner) != enclMethOrClass(currentOwner))
+ else if (sym.isLocal && !isSameOwnerEnclosure(sym))
atPos(tree.pos)(proxyRef(sym))
else tree
else tree;
if (sym.isCapturedVariable)
atPos(tree.pos) {
val tp = tree.tpe
- val elemTree = typed { Select(tree1 setType sym.tpe, nme.elem) }
+ val elemTree = typer typed Select(tree1 setType sym.tpe, nme.elem)
if (elemTree.tpe.typeSymbol != tp.typeSymbol) gen.mkAttributedCast(elemTree, tp) else elemTree
}
else tree1
@@ -462,8 +458,7 @@ abstract class LambdaLift extends InfoTransform {
stat, mods, name, tparams, treeCopy.Template(impl, parents, self, body ::: lifted))
liftedDefs -= stat.symbol
result
- case DefDef(mods, name, tp, vp, tpt, Block(Nil, expr))
- if !stat.symbol.isConstructor =>
+ case DefDef(mods, name, tp, vp, tpt, Block(Nil, expr)) if !stat.symbol.isConstructor =>
treeCopy.DefDef(stat, mods, name, tp, vp, tpt, expr)
case _ =>
stat
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index ad40e8568e..d22930c336 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -104,6 +104,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
"specialized overload " + sym + " in " + env
}
+
+ /** Just to mark uncheckable */
+ override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = new SpecializationPhase(prev)
+ class SpecializationPhase(prev: scala.tools.nsc.Phase) extends super.Phase(prev) {
+ override def checkable = false
+ }
+
protected def newTransformer(unit: CompilationUnit): Transformer =
new SpecializationTransformer(unit)
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index c4074d7efc..85db55472d 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -188,7 +188,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
* additional parameter sections of a case class are skipped.
*/
def uncurryTreeType(tp: Type): Type = tp match {
- case MethodType(params, MethodType(params1, restpe)) if (inPattern) =>
+ case MethodType(params, MethodType(params1, restpe)) if inPattern =>
uncurryTreeType(MethodType(params, restpe))
case _ =>
uncurry(tp)
@@ -204,14 +204,12 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
private val nonLocalReturnKeys = new HashMap[Symbol, Symbol]
/** Return non-local return key for given method */
- private def nonLocalReturnKey(meth: Symbol) = nonLocalReturnKeys.get(meth) match {
- case Some(k) => k
- case None =>
- val k = meth.newValue(meth.pos, unit.fresh.newName(meth.pos, "nonLocalReturnKey"))
- .setFlag(SYNTHETIC).setInfo(ObjectClass.tpe)
- nonLocalReturnKeys(meth) = k
- k
- }
+ private def nonLocalReturnKey(meth: Symbol) =
+ nonLocalReturnKeys.getOrElseUpdate(meth, {
+ meth.newValue(meth.pos, unit.fresh.newName(meth.pos, "nonLocalReturnKey"))
+ .setFlag (SYNTHETIC)
+ .setInfo (ObjectClass.tpe)
+ })
/** Generate a non-local return throw with given return expression from given method.
* I.e. for the method's non-local return key, generate:
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 80f833f03d..e039b00ee8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -48,6 +48,7 @@ trait Analyzer extends AnyRef
val runsRightAfter= Some("namer")
def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) {
+ override val checkable = false
import global._
val openPackageObjectsTraverser = new Traverser {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 7973313786..4906838e36 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -265,7 +265,7 @@ trait Contexts { self: Analyzer =>
}
private def unitError(pos: Position, msg: String) =
- unit.error(pos, if (checking) "**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg)
+ unit.error(pos, if (checking) "\n**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg)
def error(pos: Position, err: Throwable) =
if (reportGeneralErrors) unitError(pos, addDiagString(err.getMessage()))
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index f8466aed33..62f78eddfe 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -267,7 +267,21 @@ trait Infer {
Console.println(tree)
Console.println("" + pre + " " + sym.owner + " " + context.owner + " " + context.outer.enclClass.owner + " " + sym.owner.thisType + (pre =:= sym.owner.thisType))
}
- accessError("")
+ accessError(
+ if (settings.check.isDefault) "" else {
+ "\n because of an internal error (no accessible symbol):" +
+ "\nsym = " + sym +
+ "\nunderlying(sym) = " + underlying(sym) +
+ "\npre = " + pre +
+ "\nsite = " + site +
+ "\ntree = " + tree +
+ "\nsym.accessBoundary(sym.owner) = " + sym.accessBoundary(sym.owner) +
+ "\nsym.ownerChain = " + sym.ownerChain +
+ "\nsym.owner.thisType = " + sym.owner.thisType +
+ "\ncontext.owner = " + context.owner +
+ "\ncontext.outer.enclClass.owner = " + context.outer.enclClass.owner
+ }
+ )
} else {
if(sym1.isTerm)
sym1.cookJavaRawInfo() // xform java rawtypes into existentials
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index 2f271f237f..2bc3103854 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -20,9 +20,11 @@ abstract class TreeCheckers extends Analyzer {
try p.source.path + ":" + p.line
catch { case _: UnsupportedOperationException => p.toString }
- def errorFn(pos: Position, msg: Any) = println("[%s] %s: %s".format(phase, posstr(pos), msg))
+ def errorFn(msg: Any): Unit = println("[check: %s] %s".format(phase.prev, msg))
+ def errorFn(pos: Position, msg: Any): Unit = errorFn(posstr(pos) + ": " + msg)
+
def assertFn(cond: Boolean, msg: => Any) =
- if (!cond) errorFn(NoPosition, msg)
+ if (!cond) errorFn(msg)
def checkTrees {
if (settings.verbose.value)
@@ -38,6 +40,14 @@ abstract class TreeCheckers extends Analyzer {
global.printTypings = saved
result
}
+ def runWithUnit[T](unit: CompilationUnit)(body: => Unit): Unit = {
+ val unit0 = currentRun.currentUnit
+ currentRun.currentUnit = unit
+ body
+ currentRun.advanceUnit
+ assertFn(currentRun.currentUnit == unit, "currentUnit is " + currentRun.currentUnit + ", but unit is " + unit)
+ currentRun.currentUnit = unit0
+ }
def check(unit: CompilationUnit) {
informProgress("checking "+unit)
@@ -45,24 +55,22 @@ abstract class TreeCheckers extends Analyzer {
context.checking = true
tpeOfTree.clear
val checker = new TreeChecker(context)
-
- val unit0 = currentRun.currentUnit
- currentRun.currentUnit = unit
- checker.precheck.traverse(unit.body)
- // printingTypings(checker.typed(unit.body))
- checker.typed(unit.body)
- checker.postcheck.traverse(unit.body)
- currentRun.advanceUnit
- assertFn(currentRun.currentUnit == unit, "currentRun.currentUnit == unit")
- currentRun.currentUnit = unit0
+ runWithUnit(unit) {
+ checker.precheck.traverse(unit.body)
+ checker.typed(unit.body)
+ checker.postcheck.traverse(unit.body)
+ }
}
override def newTyper(context: Context): Typer = new TreeChecker(context)
class TreeChecker(context0: Context) extends Typer(context0) {
- private def treestr(t: Tree) = t + " [" + t.getClass() + "]"
- private def ownerstr(s: Symbol) = "" + s + s.locationString
+ private def classstr(x: AnyRef) = x.getClass.getName split '.' last;
+ private def typestr(x: Type) = " (tpe = " + x + ")"
+ private def treestr(t: Tree) = t + " [" + classstr(t) + "]" + typestr(t.tpe)
+ private def ownerstr(s: Symbol) = "'" + s + "'" + s.locationString
+ // XXX check for tree.original on TypeTrees.
private def treesDiffer(t1: Tree, t2: Tree) =
errorFn(t1.pos, "trees differ\n old: " + treestr(t1) + "\n new: " + treestr(t2))
private def typesDiffer(tree: Tree, tp1: Type, tp2: Type) =
@@ -72,6 +80,16 @@ abstract class TreeCheckers extends Analyzer {
errorFn(tree.pos, sym + " has wrong owner: " + ownerstr(sym.owner) + ", should be: " + ownerstr(shouldBe))
}
+ /** XXX Disabled reporting of position errors until there is less noise. */
+ private def noPos(t: Tree) =
+ () // errorFn("no pos: " + treestr(t))
+ private def noType(t: Tree) =
+ errorFn(t.pos, "no type: " + treestr(t))
+
+ private def checkSym(t: Tree) =
+ if (t.symbol == NoSymbol)
+ errorFn(t.pos, "no symbol: " + treestr(t))
+
override def typed(tree: Tree, mode: Int, pt: Type): Tree = returning(tree) {
case EmptyTree | TypeTree() => ()
case _ if tree.tpe != null =>
@@ -92,7 +110,7 @@ abstract class TreeCheckers extends Analyzer {
override def traverse(tree: Tree) {
val sym = tree.symbol
def accessed = sym.accessed
- def fail(msg: String) = errorFn(tree.pos, msg + tree.getClass + " / " + tree)
+ def fail(msg: String) = errorFn(tree.pos, msg + classstr(tree) + " / " + tree)
tree match {
case DefDef(_, _, _, _, _, _) =>
@@ -100,42 +118,48 @@ abstract class TreeCheckers extends Analyzer {
sym.tpe.resultType match {
case _: ConstantType => ()
case _ =>
- assertFn(accessed != NoSymbol, sym)
- assertFn(
- accessed.getter(sym.owner) == sym || accessed.setter(sym.owner) == sym,
- "accessed.getter(sym.owner) == sym || accessed.setter(sym.owner) == sym"
- )
+ checkSym(tree)
+ /** XXX: lots of syms show up here with accessed == NoSymbol. */
+ if (accessed != NoSymbol) {
+ val agetter = accessed.getter(sym.owner)
+ val asetter = accessed.setter(sym.owner)
+
+ assertFn(agetter == sym || asetter == sym,
+ sym + " is getter or setter, but accessed sym " + accessed + " shows " + agetter + " and " + asetter
+ )
+ }
}
}
case ValDef(_, _, _, _) =>
- if (sym.hasGetter) {
- assertFn(sym.getter(sym.owner) != NoSymbol, sym)
+ if (sym.hasGetter && !sym.isOuterField) {
+ assertFn(sym.getter(sym.owner) != NoSymbol, ownerstr(sym) + " has getter but cannot be found. " + sym.ownerChain)
}
- case Apply(_, args) =>
- assertFn(args forall (_ != EmptyTree), args)
+ case Apply(fn, args) =>
+ if (args exists (_ == EmptyTree))
+ errorFn(tree.pos, "Apply arguments to " + fn + " contains an empty tree: " + args)
+
case Select(qual, name) =>
- if (sym == NoSymbol)
- errorFn(tree.pos, "NoSymbol: " + tree)
+ checkSym(tree)
case This(_) =>
- if (sym == NoSymbol) errorFn(tree.pos, "NoSymbol: " + tree)
- else if (sym.isStatic && (sym hasFlag MODULE)) ()
+ checkSym(tree)
+ if (sym.isStatic && (sym hasFlag MODULE)) ()
else if (currentOwner.ownerChain takeWhile (_ != sym) exists (_ == NoSymbol))
return fail("tree symbol "+sym+" does not point to enclosing class; tree = ")
- /** Temporary while Import nodes are untyped. */
+ /** XXX: temporary while Import nodes are arriving untyped. */
case Import(_, _) =>
return
case _ =>
}
if (tree.pos == NoPosition && tree != EmptyTree)
- fail("tree without position: ")
+ noPos(tree)
else if (tree.tpe == null && phase.id > currentRun.typerPhase.id)
- fail("tree without type: ")
+ noType(tree)
else if (tree.isDef) {
- if (sym == NoSymbol)
- fail("DefTree with NoSymbol: ")
- else tree match {
+ checkSym(tree)
+
+ tree match {
case x: PackageDef =>
if (sym.ownerChain contains currentOwner) ()
else fail(sym + " owner chain does not contain currentOwner " + currentOwner)
diff --git a/src/compiler/scala/tools/nsc/util/Set.scala b/src/compiler/scala/tools/nsc/util/Set.scala
index c8ba3d27c9..a37a155907 100644
--- a/src/compiler/scala/tools/nsc/util/Set.scala
+++ b/src/compiler/scala/tools/nsc/util/Set.scala
@@ -16,6 +16,10 @@ abstract class Set[T <: AnyRef] {
def iterator: Iterator[T]
+ def foreach[U](f: T => U): Unit = iterator foreach f
+
+ def apply(x: T): Boolean = contains(x)
+
@deprecated("use `iterator' instead") def elements = iterator
def contains(x: T): Boolean =
diff --git a/test/checker-tests/fail1.scala b/test/checker-tests/fail1.scala
new file mode 100644
index 0000000000..b70a37d9cd
--- /dev/null
+++ b/test/checker-tests/fail1.scala
@@ -0,0 +1,17 @@
+case class DebugParam[T](param: T)
+
+// TypeStack init: REFERENCE(type AnyRef)
+// [Now checking: typer]
+// [check: typer] work/fail1.scala:1: trees differ
+// old: T [Trees$Ident] (tpe = T)
+// new: T [Trees$TypeTree] (tpe = T)
+// [check: typer] work/fail1.scala:1: trees differ
+// old: DebugParam[T] [Trees$AppliedTypeTree] (tpe = null)
+// new: DebugParam[T] [Trees$TypeTree] (tpe = DebugParam[T])
+// Exception in thread "main" java.lang.NullPointerException
+// at scala.tools.nsc.typechecker.Typers$Typer.typedTypeConstructor(Typers.scala:4337)
+// at scala.tools.nsc.typechecker.Typers$Typer.typedTypeConstructor(Typers.scala:4358)
+// at scala.tools.nsc.typechecker.Typers$Typer.typedNew$1(Typers.scala:3240)
+// at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:3994)
+// at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4223)
+// at scala.tools.nsc.typechecker.TreeCheckers$TreeChecker.scala$tools$nsc$typechecker$TreeCheckers$TreeChecker$$super$typed(TreeCheckers.scala:101)
diff --git a/test/checker-tests/fail10.scala b/test/checker-tests/fail10.scala
new file mode 100644
index 0000000000..6d4e6c27c9
--- /dev/null
+++ b/test/checker-tests/fail10.scala
@@ -0,0 +1,23 @@
+class ClassCounts extends scala.collection.mutable.HashMap[Class[_], Int] { }
+
+class A {
+ def f(xs: ClassCounts) {
+ // ok
+ xs(getClass) = xs(getClass) + 1
+ // not ok
+ xs(getClass) += 1
+ }
+}
+
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [Now checking: typer]
+// test/checker-tests/fail10.scala:8: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// type mismatch;
+// found : java.lang.Class[?0(in value ev$1)] where type ?0(in value ev$1)
+// required: java.lang.Class[?0(in method f)] where type ?0(in method f)
+// xs(getClass) += 1
+// ^
+// one error found
diff --git a/test/checker-tests/fail11.scala b/test/checker-tests/fail11.scala
new file mode 100644
index 0000000000..d5f619c674
--- /dev/null
+++ b/test/checker-tests/fail11.scala
@@ -0,0 +1,71 @@
+// Constructor rewriting does not preserve ordering.
+// Oddly the error is not issued without the thrown exception, even
+// though the same reordering takes place.
+class Foo(x: Int) {
+ def this(x1: Int, x2: Int) = {
+ this(x1 + x2)
+ throw new Exception
+ }
+}
+
+// Here it is at lambda lift:
+//
+// [[syntax trees at end of lambdalift]]// Scala source: fail11.scala
+// package <empty> {
+// class Foo extends java.lang.Object with ScalaObject {
+// <paramaccessor> private[this] val x: Int = _;
+// def this(x: Int): Foo = {
+// Foo.super.this();
+// ()
+// };
+// def this(x1: Int, x2: Int): Foo = {
+// Foo.this.this(x1.+(x2));
+// throw new java.lang.Exception();
+// ()
+// }
+// }
+// }
+
+//
+// % scalac -d /tmp -Xprint:constr -Ycheck-debug -Ycheck:all test/checker-tests/fail11.scala
+//
+// TypeStack init: REFERENCE(type AnyRef)
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [Now checking: typer]
+// [Now checking: superaccessors]
+// [Now checking: pickler]
+// [Now checking: refchecks]
+// [Now checking: selectiveanf]
+// [Now checking: liftcode]
+// [Now checking: selectivecps]
+// [Now checking: uncurry]
+// [Now checking: tailcalls]
+// [Not checkable: specialize]
+// [Not checkable: explicitouter]
+// [Now checking: erasure]
+// [Now checking: lazyvals]
+// [Now checking: lambdalift]
+// [[syntax trees at end of constructors]]// Scala source: fail11.scala
+// package <empty> {
+// class Foo extends java.lang.Object with ScalaObject {
+// def this(x1: Int, x2: Int): Foo = {
+// Foo.this.this(x1.+(x2));
+// throw new java.lang.Exception();
+// ()
+// };
+// def this(x: Int): Foo = {
+// Foo.super.this();
+// ()
+// }
+// }
+// }
+//
+// [Now checking: constructors]
+// test/checker-tests/fail11.scala:4: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// called constructor's definition must precede calling constructor's definition
+// this(x1 + x2)
+// ^
+// one error found
diff --git a/test/checker-tests/fail2.scala b/test/checker-tests/fail2.scala
new file mode 100644
index 0000000000..0f0d83aeb2
--- /dev/null
+++ b/test/checker-tests/fail2.scala
@@ -0,0 +1,50 @@
+// CC#9248 is conspicuously absent from the printed trees at every phase.
+class A {
+ def f[A, CC[X] <: Traversable[X]](): Unit = ()
+}
+
+// % work/check all -uniqid -Xprint:typer work/fail2.scala
+//
+// TypeStack init: REFERENCE(type AnyRef#2783)
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [[syntax trees at end of typer]]// Scala source: fail2.scala
+// package <empty>#3 {
+// class A#9239 extends java.lang.Object#2488 with ScalaObject#1481 {
+// def this#9243(): A#9239 = {
+// A#9239.super.this#5850();
+// ()
+// };
+// def f#9244[A#9245 >: Nothing#5846 <: Any#46, CC#9246[X#11055 >: Nothing#5846 <: Any#46] >: [X#11055]Nothing#5846 <: [X#11055]Traversable#3199[X#11055]](): Unit#3819 = ()
+// }
+// }
+//
+// [Now checking: typer]
+// [check: typer] work/fail2.scala:3: Expected owner type CC#9248, found type CC#9246: Trees$TypeDef / type X#11055>: Nothing#5846 <: Any#46
+// [Now checking: superaccessors]
+// [check: superaccessors] work/fail2.scala:3: Expected owner type CC#9248, found type CC#9246: Trees$TypeDef / type X#11055>: Nothing#5846 <: Any#46
+// [Now checking: pickler]
+// [check: pickler] work/fail2.scala:3: Expected owner type CC#9248, found type CC#9246: Trees$TypeDef / type X#11055>: Nothing#5846 <: Any#46
+// [Now checking: refchecks]
+// [check: refchecks] work/fail2.scala:3: Expected owner type CC#9248, found type CC#9246: Trees$TypeDef / type X#11055>: Nothing#5846 <: Any#46
+// [Now checking: selectiveanf]
+// [check: selectiveanf] work/fail2.scala:3: Expected owner type CC#9248, found type CC#9246: Trees$TypeDef / type X#11055>: Nothing#5846 <: Any#46
+// [Now checking: liftcode]
+// [check: liftcode] work/fail2.scala:3: Expected owner type CC#9248, found type CC#9246: Trees$TypeDef / type X#11055>: Nothing#5846 <: Any#46
+// [Now checking: selectivecps]
+// [check: selectivecps] work/fail2.scala:3: Expected owner type CC#9248, found type CC#9246: Trees$TypeDef / type X#11055>: Nothing#5846 <: Any#46
+// [Now checking: uncurry]
+// [check: uncurry] work/fail2.scala:3: Expected owner type CC#9248, found type CC#9246: Trees$TypeDef / type X#11055>: Nothing#5846 <: Any#46
+// [Now checking: tailcalls]
+// [check: tailcalls] work/fail2.scala:3: Expected owner type CC#9248, found type CC#9246: Trees$TypeDef / type X#11055>: Nothing#5846 <: Any#46
+// [Not checkable: specialize]
+// [Not checkable: explicitouter]
+// [Now checking: erasure]
+// [Now checking: lazyvals]
+// [Now checking: lambdalift]
+// [Now checking: constructors]
+// [Now checking: flatten]
+// [Now checking: mixin]
+// [Now checking: cleanup]
+// ... \ No newline at end of file
diff --git a/test/checker-tests/fail3.scala b/test/checker-tests/fail3.scala
new file mode 100644
index 0000000000..8eacc25473
--- /dev/null
+++ b/test/checker-tests/fail3.scala
@@ -0,0 +1,54 @@
+object Obby {
+ val Set = scala.collection.immutable.Set
+}
+
+// % work/check all -uniqid -Xprint:constructors work/fail3.scala
+// TypeStack init: REFERENCE(type AnyRef#2783)
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [Now checking: typer]
+// [Now checking: superaccessors]
+// [Now checking: pickler]
+// [Now checking: refchecks]
+// [Now checking: selectiveanf]
+// [Now checking: liftcode]
+// [Now checking: selectivecps]
+// [Now checking: uncurry]
+// [Now checking: tailcalls]
+// [Not checkable: specialize]
+// [Not checkable: explicitouter]
+// [Now checking: erasure]
+// [Now checking: lazyvals]
+// [Now checking: lambdalift]
+// [[syntax trees at end of constructors]]// Scala source: fail3.scala
+// package <empty>#3 {
+// final class Obby#9240 extends java.lang.Object#2488 with ScalaObject#1481 {
+// private[this] val Set#9246: object scala.collection.immutable.Set#9713 = _;
+// <stable> <accessor> def Set#9245(): object scala.collection.immutable.Set#9713 = Obby#9240.this.Set#9246;
+// def this#9244(): object Obby#9240 = {
+// Obby#9240.super.this#5850();
+// Obby#9240.this.Set#9246 = scala#23.collection#2221.immutable#8875.Set#9712;
+// ()
+// }
+// }
+// }
+//
+// [Now checking: constructors]
+// work/fail3.scala:2: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value Set#9246 in object Obby#9240 cannot be accessed in object Obby#9240
+// because of an internal error (no accessible symbol):
+// sym = value Set#9246
+// underlying(sym) = value Set#9246
+// pre = object Obby#9240
+// site = Obby#9240.this
+// tree = Obby#9240.this.Set#9246
+// sym.accessBoundary(sym.owner) = object Obby#9240
+// sym.ownerChain = List(value Set#9246, object Obby#9240, package <empty>#4, package <root>#2)
+// sym.owner.thisType = object Obby#9240
+// context.owner = package <empty>#4
+// context.outer.enclClass.owner = package <empty>#4
+// val Set = scala.collection.immutable.Set
+// ^
+// one error found
diff --git a/test/checker-tests/fail4.scala b/test/checker-tests/fail4.scala
new file mode 100644
index 0000000000..7bf44617f9
--- /dev/null
+++ b/test/checker-tests/fail4.scala
@@ -0,0 +1,136 @@
+// Incompatible stacks in icode: BoxedUnit vs. empty.
+class Classy {
+ def f(b: Boolean): Unit = synchronized {
+ if (b) ()
+ }
+}
+
+// % work/check all -Xprint:icode work/fail4.scala
+// TypeStack init: REFERENCE(type AnyRef)
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [Now checking: typer]
+// [Now checking: superaccessors]
+// [Now checking: pickler]
+// [Now checking: refchecks]
+// [Now checking: selectiveanf]
+// [Now checking: liftcode]
+// [Now checking: selectivecps]
+// [Now checking: uncurry]
+// [Now checking: tailcalls]
+// [Not checkable: specialize]
+// [Not checkable: explicitouter]
+// [Now checking: erasure]
+// [Now checking: lazyvals]
+// [Now checking: lambdalift]
+// [Now checking: constructors]
+// [Now checking: flatten]
+// [Now checking: mixin]
+// [Now checking: cleanup]
+// [[syntax trees at end of icode]]// Scala source: fail4.scala
+// package <empty> {
+// class Classy extends java.lang.Object with ScalaObject {
+// def f(b: Boolean): Unit = {
+// Classy.this.synchronized(if (b)
+// scala.runtime.BoxedUnit.UNIT
+// else
+// scala.runtime.BoxedUnit.UNIT);
+// ()
+// };
+// def this(): Classy = {
+// Classy.super.this();
+// ()
+// }
+// }
+// }
+//
+// [Now checking: icode]
+//
+// ** Checking class Classy
+//
+// ** Checking method Classy.f
+// ** Checking Block 1 [S: 4, 3] [P: N/A]
+// 1-> REFERENCE(class Classy)
+// 0<- REFERENCE(class Classy)
+// 1-> REFERENCE(class Classy)
+// 2-> REFERENCE(class Classy)
+// 1<- REFERENCE(class Classy)
+// 0<- REFERENCE(class Classy)
+// Output changed for Block 1 [S: 4, 3] [P: N/A]
+// ** Checking Block 4 [S: 3, 6, 5] [P: 1]
+// 1-> BOOL
+// 0<- BOOL
+// Output changed for Block 4 [S: 3, 6, 5] [P: 1]
+// ** Checking Block 3 [S: N/A] [P: 1, 4, 5, 6, 7]
+// 1-> REFERENCE(class Throwable)
+// 2-> REFERENCE(class Object)
+// 1<- REFERENCE(class Object)
+// 0<- REFERENCE(class Throwable)
+// 1-> REFERENCE(trait Nothing)
+// ** Checking Block 6 [S: 3, 7] [P: 4]
+// 1-> REFERENCE(class BoxedUnit)
+// Output changed for Block 6 [S: 3, 7] [P: 4]
+// ** Checking Block 5 [S: 3, 7] [P: 4]
+// 1-> REFERENCE(class BoxedUnit)
+// Output changed for Block 5 [S: 3, 7] [P: 4]
+// Checker created new stack: (List(REFERENCE(class BoxedUnit)), List(REFERENCE(class BoxedUnit))) => List(REFERENCE(class BoxedUnit))
+// TypeStack init: REFERENCE(class BoxedUnit)
+// Checker created new stack: (List(REFERENCE(class BoxedUnit)), List(REFERENCE(class BoxedUnit))) => List(REFERENCE(class BoxedUnit))
+// TypeStack init: REFERENCE(class BoxedUnit)
+// Checker created new stack: (List(REFERENCE(class BoxedUnit)), List(REFERENCE(class BoxedUnit))) => List(REFERENCE(class BoxedUnit))
+// TypeStack init: REFERENCE(class BoxedUnit)
+// ** Checking Block 3 [S: N/A] [P: 1, 4, 5, 6, 7] with initial stack [REFERENCE(class BoxedUnit)]
+// TypeStack init: REFERENCE(class BoxedUnit)
+// 0<- REFERENCE(class BoxedUnit)
+// 1-> REFERENCE(class Throwable)
+// 2-> REFERENCE(class Object)
+// 1<- REFERENCE(class Object)
+// 0<- REFERENCE(class Throwable)
+// 1-> REFERENCE(trait Nothing)
+// ** Checking Block 7 [S: 3, 2] [P: 5, 6] with initial stack [REFERENCE(class BoxedUnit)]
+// TypeStack init: REFERENCE(class BoxedUnit)
+// 0<- REFERENCE(class BoxedUnit)
+// 1-> REFERENCE(class Object)
+// 0<- REFERENCE(class Object)
+// Output changed for Block 7 [S: 3, 2] [P: 5, 6]
+// Checker created new stack: (List(REFERENCE(class BoxedUnit)), List(REFERENCE(class BoxedUnit))) => List(REFERENCE(class BoxedUnit))
+// TypeStack init: REFERENCE(class BoxedUnit)
+// Exception in thread "main" scala.tools.nsc.backend.icode.CheckerException: Incompatible stacks: TypeStack(1 elems) {
+// REFERENCE(class BoxedUnit)
+// } and TypeStack() in Classy.f at entry to block: 3
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.meet2$1(Checkers.scala:165)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$meet$2.apply(Checkers.scala:174)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$meet$2.apply(Checkers.scala:174)
+// at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized.scala:123)
+// at scala.collection.immutable.List.foldLeft(List.scala:45)
+// at scala.collection.LinearSeqOptimized$class.reduceLeft(LinearSeqOptimized.scala:137)
+// at scala.collection.immutable.List.reduceLeft(List.scala:45)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.meet(Checkers.scala:174)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$check$5.apply(Checkers.scala:140)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$check$5.apply(Checkers.scala:140)
+// at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
+// at scala.collection.immutable.List.foreach(List.scala:45)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.check(Checkers.scala:140)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.check(Checkers.scala:110)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$check$3.apply(Checkers.scala:103)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$check$3.apply(Checkers.scala:103)
+// at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
+// at scala.collection.immutable.List.foreach(List.scala:45)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.check(Checkers.scala:103)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$checkICodes$1.apply(Checkers.scala:81)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$checkICodes$1.apply(Checkers.scala:81)
+// at scala.collection.mutable.HashMap$$anon$2$$anonfun$foreach$3.apply(HashMap.scala:89)
+// at scala.collection.mutable.HashMap$$anon$2$$anonfun$foreach$3.apply(HashMap.scala:89)
+// at scala.collection.Iterator$class.foreach(Iterator.scala:631)
+// at scala.collection.mutable.HashTable$$anon$1.foreach(HashTable.scala:161)
+// at scala.collection.mutable.HashTable$class.foreachEntry(HashTable.scala:194)
+// at scala.collection.mutable.HashMap.foreachEntry(HashMap.scala:39)
+// at scala.collection.mutable.HashMap$$anon$2.foreach(HashMap.scala:89)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.checkICodes(Checkers.scala:81)
+// at scala.tools.nsc.Global$Run.compileSources(Global.scala:759)
+// at scala.tools.nsc.Global$Run.compile(Global.scala:823)
+// at scala.tools.nsc.Main$.process(Main.scala:106)
+// at scala.tools.nsc.Main$.main(Main.scala:120)
+// at scala.tools.nsc.Main.main(Main.scala)
+// [paulp@leaf trunk (check-all)]$
diff --git a/test/checker-tests/fail5.scala b/test/checker-tests/fail5.scala
new file mode 100644
index 0000000000..b821dc79f9
--- /dev/null
+++ b/test/checker-tests/fail5.scala
@@ -0,0 +1,197 @@
+// Incompatible stacks in icode: BooleanRef vs. empty.
+// This may be the same issue as fail4.scala, with the synchronized
+// block being introduced in the rewriting.
+class Crashy {
+ def go(x1: Int) = {
+ lazy val x2 = x1 < 0
+
+ x2
+ }
+}
+
+// % work/check all -Xprint:icode work/fail5.scala
+// TypeStack init: REFERENCE(type AnyRef)
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [Now checking: typer]
+// [Now checking: superaccessors]
+// [Now checking: pickler]
+// [Now checking: refchecks]
+// [Now checking: selectiveanf]
+// [Now checking: liftcode]
+// [Now checking: selectivecps]
+// [Now checking: uncurry]
+// [Now checking: tailcalls]
+// [Not checkable: specialize]
+// [Not checkable: explicitouter]
+// [Now checking: erasure]
+// [Now checking: lazyvals]
+// [Now checking: lambdalift]
+// [check: lambdalift] NoPosition: Apply arguments to new scala.runtime.BooleanRef contains an empty tree: List(<empty>)
+// [Now checking: constructors]
+// [check: constructors] NoPosition: Apply arguments to new scala.runtime.BooleanRef contains an empty tree: List(<empty>)
+// [Now checking: flatten]
+// [check: flatten] NoPosition: Apply arguments to new scala.runtime.BooleanRef contains an empty tree: List(<empty>)
+// [Now checking: mixin]
+// [check: mixin] NoPosition: Apply arguments to new scala.runtime.BooleanRef contains an empty tree: List(<empty>)
+// [Now checking: cleanup]
+// [[syntax trees at end of icode]]// Scala source: fail5.scala
+// package <empty> {
+// class Crashy extends java.lang.Object with ScalaObject {
+// def go(x1$1: Int): Boolean = {
+// @volatile var bitmap$0$1: scala.runtime.VolatileIntRef = new scala.runtime.VolatileIntRef(0);
+// lazy var x2$lzy$1: scala.runtime.BooleanRef = new scala.runtime.BooleanRef(<empty>);
+// Crashy.this.x2$1(x1$1, x2$lzy$1, bitmap$0$1)
+// };
+// final <stable> private[this] def x2$1(x1$1: Int, x2$lzy$1: scala.runtime.BooleanRef, bitmap$0$1: scala.runtime.VolatileIntRef): Boolean = {
+// if (bitmap$0$1.elem.&(1).==(0))
+// {
+// Crashy.this.synchronized({
+// if (bitmap$0$1.elem.&(1).==(0))
+// {
+// x2$lzy$1.elem = x1$1.<(0);
+// bitmap$0$1.elem = bitmap$0$1.elem.|(1);
+// ()
+// };
+// scala.runtime.BoxedUnit.UNIT
+// });
+// ()
+// };
+// x2$lzy$1.elem
+// };
+// def this(): Crashy = {
+// Crashy.super.this();
+// ()
+// }
+// }
+// }
+//
+// [Now checking: icode]
+//
+// ** Checking class Crashy
+//
+// ** Checking method Crashy.go
+// ** Checking Block 1 [S: N/A] [P: N/A]
+// 1-> REFERENCE(class VolatileIntRef)
+// 0<- REFERENCE(class VolatileIntRef)
+// 1-> REFERENCE(class VolatileIntRef)
+// 2-> REFERENCE(class VolatileIntRef)
+// 3-> INT
+// 2<- INT
+// 1<- REFERENCE(class VolatileIntRef)
+// 0<- REFERENCE(class VolatileIntRef)
+// 1-> REFERENCE(class BooleanRef)
+// 0<- REFERENCE(class BooleanRef)
+// 1-> REFERENCE(class BooleanRef)
+// 2-> REFERENCE(class BooleanRef)
+// 3-> BOOL
+// 2<- BOOL
+// 1<- REFERENCE(class BooleanRef)
+// 0<- REFERENCE(class BooleanRef)
+// 1-> REFERENCE(class Crashy)
+// 2-> INT
+// 3-> REFERENCE(class BooleanRef)
+// 4-> REFERENCE(class VolatileIntRef)
+// 3<- REFERENCE(class VolatileIntRef)
+// 2<- REFERENCE(class BooleanRef)
+// 1<- INT
+// 0<- REFERENCE(class Crashy)
+// 1-> BOOL
+// 0<- BOOL
+//
+// ** Checking method Crashy.x2$1
+// ** Checking Block 1 [S: 4, 2] [P: N/A]
+// 1-> REFERENCE(class VolatileIntRef)
+// 0<- REFERENCE(class VolatileIntRef)
+// 1-> INT
+// 2-> INT
+// 1<- INT
+// 0<- INT
+// 1-> INT
+// 2-> INT
+// 1<- INT
+// 0<- INT
+// Output changed for Block 1 [S: 4, 2] [P: N/A]
+// ** Checking Block 4 [S: N/A] [P: 1, 10]
+// 1-> REFERENCE(class BooleanRef)
+// 0<- REFERENCE(class BooleanRef)
+// 1-> BOOL
+// 0<- BOOL
+// ** Checking Block 2 [S: 7, 6] [P: 1]
+// 1-> REFERENCE(class Crashy)
+// 0<- REFERENCE(class Crashy)
+// 1-> REFERENCE(class Crashy)
+// 2-> REFERENCE(class Crashy)
+// 1<- REFERENCE(class Crashy)
+// 0<- REFERENCE(class Crashy)
+// Output changed for Block 2 [S: 7, 6] [P: 1]
+// ** Checking Block 7 [S: 6, 10, 8] [P: 2]
+// 1-> REFERENCE(class VolatileIntRef)
+// 0<- REFERENCE(class VolatileIntRef)
+// 1-> INT
+// 2-> INT
+// 1<- INT
+// 0<- INT
+// 1-> INT
+// 2-> INT
+// 1<- INT
+// 0<- INT
+// Output changed for Block 7 [S: 6, 10, 8] [P: 2]
+// ** Checking Block 6 [S: N/A] [P: 2, 7, 8, 10, 11, 12, 13]
+// 1-> REFERENCE(class Throwable)
+// 2-> REFERENCE(class Object)
+// 1<- REFERENCE(class Object)
+// 0<- REFERENCE(class Throwable)
+// 1-> REFERENCE(trait Nothing)
+// ** Checking Block 10 [S: 6, 4] [P: 7, 13]
+// 1-> REFERENCE(class BoxedUnit)
+// 0<- REFERENCE(class BoxedUnit)
+// 1-> REFERENCE(class Object)
+// 0<- REFERENCE(class Object)
+// Output changed for Block 10 [S: 6, 4] [P: 7, 13]
+// ** Checking Block 8 [S: 6, 12, 11] [P: 7]
+// 1-> REFERENCE(class BooleanRef)
+// 2-> INT
+// 3-> INT
+// 2<- INT
+// 1<- INT
+// Output changed for Block 8 [S: 6, 12, 11] [P: 7]
+// Exception in thread "main" scala.tools.nsc.backend.icode.CheckerException: Incompatible stacks: TypeStack(1 elems) {
+// REFERENCE(class BooleanRef)
+// } and TypeStack() in Crashy.x2$1 at entry to block: 6
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.meet2$1(Checkers.scala:165)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$meet$2.apply(Checkers.scala:174)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$meet$2.apply(Checkers.scala:174)
+// at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized.scala:123)
+// at scala.collection.immutable.List.foldLeft(List.scala:45)
+// at scala.collection.LinearSeqOptimized$class.reduceLeft(LinearSeqOptimized.scala:137)
+// at scala.collection.immutable.List.reduceLeft(List.scala:45)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.meet(Checkers.scala:174)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$check$5.apply(Checkers.scala:140)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$check$5.apply(Checkers.scala:140)
+// at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
+// at scala.collection.immutable.List.foreach(List.scala:45)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.check(Checkers.scala:140)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.check(Checkers.scala:110)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$check$3.apply(Checkers.scala:103)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$check$3.apply(Checkers.scala:103)
+// at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
+// at scala.collection.immutable.List.foreach(List.scala:45)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.check(Checkers.scala:103)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$checkICodes$1.apply(Checkers.scala:81)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker$$anonfun$checkICodes$1.apply(Checkers.scala:81)
+// at scala.collection.mutable.HashMap$$anon$2$$anonfun$foreach$3.apply(HashMap.scala:89)
+// at scala.collection.mutable.HashMap$$anon$2$$anonfun$foreach$3.apply(HashMap.scala:89)
+// at scala.collection.Iterator$class.foreach(Iterator.scala:631)
+// at scala.collection.mutable.HashTable$$anon$1.foreach(HashTable.scala:161)
+// at scala.collection.mutable.HashTable$class.foreachEntry(HashTable.scala:194)
+// at scala.collection.mutable.HashMap.foreachEntry(HashMap.scala:39)
+// at scala.collection.mutable.HashMap$$anon$2.foreach(HashMap.scala:89)
+// at scala.tools.nsc.backend.icode.Checkers$ICodeChecker.checkICodes(Checkers.scala:81)
+// at scala.tools.nsc.Global$Run.compileSources(Global.scala:759)
+// at scala.tools.nsc.Global$Run.compile(Global.scala:823)
+// at scala.tools.nsc.Main$.process(Main.scala:106)
+// at scala.tools.nsc.Main$.main(Main.scala:120)
+// at scala.tools.nsc.Main.main(Main.scala)
+// [paulp@leaf trunk (check-all)]$
diff --git a/test/checker-tests/fail6.scala b/test/checker-tests/fail6.scala
new file mode 100644
index 0000000000..c59be55c4e
--- /dev/null
+++ b/test/checker-tests/fail6.scala
@@ -0,0 +1,61 @@
+// BoxedUnit/Unit confusion involving while.
+//
+// Apply( // sym=method while$1, tpe=Unit, tpe.sym=class Unit, tpe.sym.owner=package scala
+// Ident("while$1"), // sym=method while$1, sym.owner=method f, sym.tpe=()Unit, tpe=()Unit, tpe.sym=<none>,
+class Erasure {
+ def f(b: Boolean) = {
+ if (b) "abc"
+ else while (b) ()
+ }
+}
+
+// % work/check all -Xprint:erasure work/fail6.scala
+// TypeStack init: REFERENCE(type AnyRef)
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [Now checking: typer]
+// [Now checking: superaccessors]
+// [Now checking: pickler]
+// [Now checking: refchecks]
+// [Now checking: selectiveanf]
+// [Now checking: liftcode]
+// [Now checking: selectivecps]
+// [Now checking: uncurry]
+// [Now checking: tailcalls]
+// [Not checkable: specialize]
+// [Not checkable: explicitouter]
+// [[syntax trees at end of erasure]]// Scala source: fail6.scala
+// package <empty> {
+// class Erasure extends java.lang.Object with ScalaObject {
+// def this(): Erasure = {
+// Erasure.super.this();
+// ()
+// };
+// def f(b: Boolean): java.lang.Object = if (b)
+// "abc"
+// else
+// while$1(){
+// if (b)
+// {
+// ();
+// while$1()
+// }
+// else
+// ();
+// scala.runtime.BoxedUnit.UNIT
+// }
+// }
+// }
+//
+// [Now checking: erasure]
+// work/fail6.scala:4: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// type mismatch;
+// found : scala.runtime.BoxedUnit
+// required: Unit
+// else while (b) ()
+// ^
+// one error found
+//
+//
diff --git a/test/checker-tests/fail7.scala b/test/checker-tests/fail7.scala
new file mode 100644
index 0000000000..1ffb745e0b
--- /dev/null
+++ b/test/checker-tests/fail7.scala
@@ -0,0 +1,70 @@
+case class Foo(x: Int)
+
+// 1) Checking typer specifically:
+//
+// [Now checking: typer]
+// work/fail7.scala:1: error: double definition:
+// method canEqual:(x$1: Any)Boolean and
+// method canEqual:(x$1: Any)Boolean at line 1
+// have same type
+// case class Foo(x: Int)
+// ^
+//
+// 2) Checking all, which somehow misses it until superaccessors:
+//
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [Now checking: typer]
+// [Now checking: superaccessors]
+// work/fail7.scala:1: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// method canEqual is defined twice
+// case class Foo(x: Int)
+// ^
+// one error found
+//
+// 3) Checking uncurry:
+//
+// [Now checking: uncurry]
+// work/fail7.scala:1: error: double definition:
+// method canEqual:(x$1: Any)Boolean and
+// method canEqual:(x$1: Any)Boolean at line 1
+// have same type
+// case class Foo(x: Int)
+// ^
+// exception when typing Foo.this.productArity()
+// Foo.this.productArity of type Int does not take parameters in file work/fail7.scala
+// scala.tools.nsc.symtab.Types$TypeError: Foo.this.productArity of type Int does not take parameters
+// at scala.tools.nsc.typechecker.Contexts$Context.error(Contexts.scala:277)
+// at scala.tools.nsc.typechecker.Infer$Inferencer.error(Infer.scala:205)
+// at scala.tools.nsc.typechecker.Infer$Inferencer.errorTree(Infer.scala:209)
+// at scala.tools.nsc.typechecker.Typers$Typer.doTypedApply(Typers.scala:2632)
+// at scala.tools.nsc.typechecker.Typers$Typer.typedApply$1(Typers.scala:3400)
+// at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:4069)
+// at scala.tools.nsc.transform.Erasure$Eraser.liftedTree1$1(Erasure.scala:663)
+// at scala.tools.nsc.transform.Erasure$Eraser.typed1(Erasure.scala:662)
+// at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4223)
+// at scala.tools.nsc.typechecker.Typers$Typer.transformedOrTyped(Typers.scala:4368)
+// at scala.tools.nsc.typechecker.Typers$Typer.typedDefDef(Typers.scala:1796)
+//
+// 4) Checking constructors:
+//
+// [Now checking: constructors]
+// work/fail7.scala:1: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value x in class Foo cannot be accessed in Foo
+// because of an internal error (no accessible symbol):
+// sym = value x
+// underlying(sym) = value x
+// pre = Foo
+// site = Foo.this
+// tree = Foo.this.x
+// sym.accessBoundary(sym.owner) = class Foo
+// sym.ownerChain = List(value x, class Foo, package <empty>, package <root>)
+// sym.owner.thisType = Foo
+// context.owner = package <empty>
+// context.outer.enclClass.owner = package <empty>
+// case class Foo(x: Int)
+// ^
+// one error found
diff --git a/test/checker-tests/fail8.scala b/test/checker-tests/fail8.scala
new file mode 100644
index 0000000000..d64e6e7bcc
--- /dev/null
+++ b/test/checker-tests/fail8.scala
@@ -0,0 +1,145 @@
+// reverse of fail9
+class Ding {
+ private val x1 = 1
+ private def x2 = 2
+ private lazy val x3 = 3
+ private[Ding] val x4 = 4
+ private[Ding] val x5 = 5
+ private[Ding] val x6 = 6
+}
+
+object Ding {
+ def y1 = new Ding x1
+ def y2 = new Ding x2
+ def y3 = new Ding x3
+ def y4 = new Ding x4
+ def y5 = new Ding x5
+ def y6 = new Ding x6
+}
+
+// % work/check all -Xprint:constru work/fail8.scala
+//
+// TypeStack init: REFERENCE(type AnyRef)
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [Now checking: typer]
+// [Now checking: superaccessors]
+// [Now checking: pickler]
+// [Now checking: refchecks]
+// [Now checking: selectiveanf]
+// [Now checking: liftcode]
+// [Now checking: selectivecps]
+// [Now checking: uncurry]
+// [Now checking: tailcalls]
+// [Not checkable: specialize]
+// [Not checkable: explicitouter]
+// [Now checking: erasure]
+// [Now checking: lazyvals]
+// [Now checking: lambdalift]
+// [[syntax trees at end of constructors]]// Scala source: fail8.scala
+// package <empty> {
+// class Ding extends java.lang.Object with ScalaObject {
+// private[this] val Ding$$x1: Int = _;
+// final <stable> <accessor> def Ding$$x1(): Int = Ding.this.Ding$$x1;
+// final def Ding$$x2(): Int = 2;
+// lazy private[this] var Ding$$x3: Int = _;
+// final <stable> <accessor> lazy def Ding$$x3(): Int = {
+// Ding.this.Ding$$x3 = 3;
+// Ding.this.Ding$$x3
+// };
+// private[this] val Ding$$x4: Int = _;
+// <stable> <accessor> private[Ding] def Ding$$x4(): Int = Ding.this.Ding$$x4;
+// private[this] val Ding$$x5: Int = _;
+// <stable> <accessor> private[Ding] def Ding$$x5(): Int = Ding.this.Ding$$x5;
+// private[this] val Ding$$x6: Int = _;
+// <stable> <accessor> private[Ding] def Ding$$x6(): Int = Ding.this.Ding$$x6;
+// def this(): Ding = {
+// Ding.super.this();
+// Ding.this.Ding$$x1 = 1;
+// Ding.this.Ding$$x4 = 4;
+// Ding.this.Ding$$x5 = 5;
+// Ding.this.Ding$$x6 = 6;
+// ()
+// }
+// };
+// final class Ding extends java.lang.Object with ScalaObject {
+// def y1(): Int = new Ding().Ding$$x1();
+// def y2(): Int = new Ding().Ding$$x2();
+// def y3(): Int = new Ding().Ding$$x3();
+// def y4(): Int = new Ding().Ding$$x4();
+// def y5(): Int = new Ding().Ding$$x5();
+// def y6(): Int = new Ding().Ding$$x6();
+// def this(): object Ding = {
+// Ding.super.this();
+// ()
+// }
+// }
+// }
+//
+// [Now checking: constructors]
+// work/fail8.scala:3: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value Ding$$x1 in class Ding cannot be accessed in Ding
+// because of an internal error (no accessible symbol):
+// sym = value Ding$$x1
+// underlying(sym) = value Ding$$x1
+// pre = Ding
+// site = Ding.this
+// tree = Ding.this.Ding$$x1
+// sym.accessBoundary(sym.owner) = class Ding
+// sym.ownerChain = List(value Ding$$x1, class Ding, package <empty>, package <root>)
+// sym.owner.thisType = Ding
+// context.owner = package <empty>
+// context.outer.enclClass.owner = package <empty>
+// private val x1 = 1
+// ^
+// work/fail8.scala:6: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value Ding$$x4 in class Ding cannot be accessed in Ding
+// because of an internal error (no accessible symbol):
+// sym = value Ding$$x4
+// underlying(sym) = value Ding$$x4
+// pre = Ding
+// site = Ding.this
+// tree = Ding.this.Ding$$x4
+// sym.accessBoundary(sym.owner) = class Ding
+// sym.ownerChain = List(value Ding$$x4, class Ding, package <empty>, package <root>)
+// sym.owner.thisType = Ding
+// context.owner = package <empty>
+// context.outer.enclClass.owner = package <empty>
+// private[Ding] val x4 = 4
+// ^
+// work/fail8.scala:7: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value Ding$$x5 in class Ding cannot be accessed in Ding
+// because of an internal error (no accessible symbol):
+// sym = value Ding$$x5
+// underlying(sym) = value Ding$$x5
+// pre = Ding
+// site = Ding.this
+// tree = Ding.this.Ding$$x5
+// sym.accessBoundary(sym.owner) = class Ding
+// sym.ownerChain = List(value Ding$$x5, class Ding, package <empty>, package <root>)
+// sym.owner.thisType = Ding
+// context.owner = package <empty>
+// context.outer.enclClass.owner = package <empty>
+// private[Ding] val x5 = 5
+// ^
+// work/fail8.scala:8: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value Ding$$x6 in class Ding cannot be accessed in Ding
+// because of an internal error (no accessible symbol):
+// sym = value Ding$$x6
+// underlying(sym) = value Ding$$x6
+// pre = Ding
+// site = Ding.this
+// tree = Ding.this.Ding$$x6
+// sym.accessBoundary(sym.owner) = class Ding
+// sym.ownerChain = List(value Ding$$x6, class Ding, package <empty>, package <root>)
+// sym.owner.thisType = Ding
+// context.owner = package <empty>
+// context.outer.enclClass.owner = package <empty>
+// private[Ding] val x6 = 6
+// ^
+// four errors found
diff --git a/test/checker-tests/fail9.scala b/test/checker-tests/fail9.scala
new file mode 100644
index 0000000000..54cf0fc01e
--- /dev/null
+++ b/test/checker-tests/fail9.scala
@@ -0,0 +1,145 @@
+// More from constructors
+class Dong {
+ def y1 = Dong.x1
+ def y2 = Dong.x2
+ def y3 = Dong.x3
+ def y4 = Dong.x4
+ def y5 = Dong.x5
+ def y6 = Dong.x6
+}
+
+object Dong {
+ private val x1 = 1
+ private def x2 = 2
+ private lazy val x3 = 3
+ private[Dong] val x4 = 4
+ private[Dong] val x5 = 5
+ private[Dong] val x6 = 6
+}
+
+// % work/check all -Xprint:constru work/fail9.scala
+//
+// TypeStack init: REFERENCE(type AnyRef)
+// [Not checkable: parser]
+// [Not checkable: namer]
+// [Not checkable: packageobjects]
+// [Now checking: typer]
+// [Now checking: superaccessors]
+// [Now checking: pickler]
+// [Now checking: refchecks]
+// [Now checking: selectiveanf]
+// [Now checking: liftcode]
+// [Now checking: selectivecps]
+// [Now checking: uncurry]
+// [Now checking: tailcalls]
+// [Not checkable: specialize]
+// [Not checkable: explicitouter]
+// [Now checking: erasure]
+// [Now checking: lazyvals]
+// [Now checking: lambdalift]
+// [[syntax trees at end of constructors]]// Scala source: fail9.scala
+// package <empty> {
+// class Dong extends java.lang.Object with ScalaObject {
+// def y1(): Int = Dong.Dong$$x1();
+// def y2(): Int = Dong.Dong$$x2();
+// def y3(): Int = Dong.Dong$$x3();
+// def y4(): Int = Dong.x4();
+// def y5(): Int = Dong.x5();
+// def y6(): Int = Dong.x6();
+// def this(): Dong = {
+// Dong.super.this();
+// ()
+// }
+// };
+// final class Dong extends java.lang.Object with ScalaObject {
+// private[this] val Dong$$x1: Int = _;
+// final <stable> <accessor> def Dong$$x1(): Int = Dong.this.Dong$$x1;
+// final def Dong$$x2(): Int = 2;
+// lazy private[this] var Dong$$x3: Int = _;
+// final <stable> <accessor> lazy def Dong$$x3(): Int = {
+// Dong.this.Dong$$x3 = 3;
+// Dong.this.Dong$$x3
+// };
+// private[this] val x4: Int = _;
+// <stable> <accessor> private[Dong] def x4(): Int = Dong.this.x4;
+// private[this] val x5: Int = _;
+// <stable> <accessor> private[Dong] def x5(): Int = Dong.this.x5;
+// private[this] val x6: Int = _;
+// <stable> <accessor> private[Dong] def x6(): Int = Dong.this.x6;
+// def this(): object Dong = {
+// Dong.super.this();
+// Dong.this.Dong$$x1 = 1;
+// Dong.this.x4 = 4;
+// Dong.this.x5 = 5;
+// Dong.this.x6 = 6;
+// ()
+// }
+// }
+// }
+//
+// [Now checking: constructors]
+// work/fail9.scala:12: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value Dong$$x1 in object Dong cannot be accessed in object Dong
+// because of an internal error (no accessible symbol):
+// sym = value Dong$$x1
+// underlying(sym) = value Dong$$x1
+// pre = object Dong
+// site = Dong.this
+// tree = Dong.this.Dong$$x1
+// sym.accessBoundary(sym.owner) = object Dong
+// sym.ownerChain = List(value Dong$$x1, object Dong, package <empty>, package <root>)
+// sym.owner.thisType = object Dong
+// context.owner = package <empty>
+// context.outer.enclClass.owner = package <empty>
+// private val x1 = 1
+// ^
+// work/fail9.scala:15: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value x4 in object Dong cannot be accessed in object Dong
+// because of an internal error (no accessible symbol):
+// sym = value x4
+// underlying(sym) = value x4
+// pre = object Dong
+// site = Dong.this
+// tree = Dong.this.x4
+// sym.accessBoundary(sym.owner) = object Dong
+// sym.ownerChain = List(value x4, object Dong, package <empty>, package <root>)
+// sym.owner.thisType = object Dong
+// context.owner = package <empty>
+// context.outer.enclClass.owner = package <empty>
+// private[Dong] val x4 = 4
+// ^
+// work/fail9.scala:16: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value x5 in object Dong cannot be accessed in object Dong
+// because of an internal error (no accessible symbol):
+// sym = value x5
+// underlying(sym) = value x5
+// pre = object Dong
+// site = Dong.this
+// tree = Dong.this.x5
+// sym.accessBoundary(sym.owner) = object Dong
+// sym.ownerChain = List(value x5, object Dong, package <empty>, package <root>)
+// sym.owner.thisType = object Dong
+// context.owner = package <empty>
+// context.outer.enclClass.owner = package <empty>
+// private[Dong] val x5 = 5
+// ^
+// work/fail9.scala:17: error:
+// **** ERROR DURING INTERNAL CHECKING ****
+// value x6 in object Dong cannot be accessed in object Dong
+// because of an internal error (no accessible symbol):
+// sym = value x6
+// underlying(sym) = value x6
+// pre = object Dong
+// site = Dong.this
+// tree = Dong.this.x6
+// sym.accessBoundary(sym.owner) = object Dong
+// sym.ownerChain = List(value x6, object Dong, package <empty>, package <root>)
+// sym.owner.thisType = object Dong
+// context.owner = package <empty>
+// context.outer.enclClass.owner = package <empty>
+// private[Dong] val x6 = 6
+// ^
+// four errors found