summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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