diff options
108 files changed, 3324 insertions, 872 deletions
@@ -2010,9 +2010,28 @@ STABLE REFERENCE (STARR) <include name="forkjoin.jar"/> </fileset> </copy> + <!-- remove SHA1 files for no starr, so we don't loose artifacts. --> + <delete> + <fileset dir="${lib.dir}"> + <include name="fjbg.jar.desired.sha1"/> + <include name="msil.jar.desired.sha1"/> + <include name="forkjoin.jar.desired.sha1"/> + </fileset> + </delete> + </target> + + <target name="starr.removesha1" depends="starr.libs"> + <!-- remove SHA1 files for no starr, so we don't loose artifacts. --> + <delete> + <fileset dir="${lib.dir}"> + <include name="scala-compiler.jar.desired.sha1"/> + <include name="scala-library.jar.desired.sha1"/> + <include name="scala-library-src.jar.desired.sha1"/> + </fileset> + </delete> </target> - <target name="starr.done" depends="starr.libs"/> + <target name="starr.done" depends="starr.libs, starr.removesha1"/> <!-- =========================================================================== FORWARDED TARGETS FOR PACKAGING diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 62b0206c28..de490074b0 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -269,9 +269,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Create a new existential type skolem with this symbol its owner, * based on the given symbol and origin. */ - def newExistentialSkolem(basis: Symbol, origin: AnyRef): TypeSkolem = { - val skolem = newTypeSkolemSymbol(basis.name.toTypeName, origin, basis.pos, (basis.flags | EXISTENTIAL) & ~PARAM) - skolem setInfo (basis.info cloneInfo skolem) + def newExistentialSkolem(basis: Symbol, origin: AnyRef, name: TypeName = null, info: Type = null): TypeSkolem = { + val skolem = newTypeSkolemSymbol(if (name eq null) basis.name.toTypeName else name, origin, basis.pos, (basis.flags | EXISTENTIAL) & ~PARAM) + skolem setInfo (if (info eq null) basis.info cloneInfo skolem else info) } final def newExistential(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = @@ -853,8 +853,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => ) /** These should be moved somewhere like JavaPlatform. */ - def javaSimpleName: String = addModuleSuffix(nme.dropLocalSuffix(simpleName)).toString - def javaBinaryName: String = addModuleSuffix(fullNameInternal('/')).toString + def javaSimpleName: Name = addModuleSuffix(nme.dropLocalSuffix(simpleName)) + def javaBinaryName: Name = addModuleSuffix(fullNameInternal('/')) def javaClassName: String = addModuleSuffix(fullNameInternal('.')).toString /** The encoded full path name of this symbol, where outer names and inner names diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index ed1631fae5..b7b7ca5840 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -1118,7 +1118,14 @@ trait Types extends api.Types { self: SymbolTable => underlying.baseTypeSeq prepend this } override def isHigherKinded = false // singleton type classifies objects, thus must be kind * - override def safeToString: String = prefixString + "type" + override def safeToString: String = { + // Avoiding printing Predef.type and scala.package.type as "type", + // since in all other cases we omit those prefixes. + val pre = underlying.typeSymbol.skipPackageObject + if (pre.isOmittablePrefix) pre.fullName + ".type" + else prefixString + "type" + } + /* override def typeOfThis: Type = typeSymbol.typeOfThis override def bounds: TypeBounds = TypeBounds(this, this) @@ -4572,7 +4579,7 @@ trait Types extends api.Types { self: SymbolTable => var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true) if (rebind0 == NoSymbol) { if (sym.isAliasType) throw missingAliasException - if (settings.debug.value) println(pre+"."+sym+" does no longer exist, phase = "+phase) + debugwarn(pre+"."+sym+" does no longer exist, phase = "+phase) throw new MissingTypeControl // For build manager and presentation compiler purposes //assert(false, pre+"."+sym+" does no longer exist, phase = "+phase) } @@ -4628,7 +4635,7 @@ trait Types extends api.Types { self: SymbolTable => if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args)/* && sym.isExternal*/) { tp } else if (sym1 == NoSymbol) { - if (settings.debug.value) println("adapt fail: "+pre+" "+pre1+" "+sym) + debugwarn("adapt fail: "+pre+" "+pre1+" "+sym) tp } else { copyTypeRef(tp, pre1, sym1, args1) @@ -5839,7 +5846,7 @@ trait Types extends api.Types { self: SymbolTable => } } - val initialBTSes = ts map (_.baseTypeSeq.toList filter (_.typeSymbol.isPublic)) + val initialBTSes = ts map (_.baseTypeSeq.toList) if (printLubs) printLubMatrix(ts zip initialBTSes toMap, depth) diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 44dc2fe384..552479bc0b 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -773,7 +773,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb * where the value compares unequal to the previous phase's value. */ def afterEachPhase[T](op: => T): List[(Phase, T)] = { - phaseDescriptors.map(_.ownPhase).foldLeft(List[(Phase, T)]()) { (res, ph) => + phaseDescriptors.map(_.ownPhase).filterNot(_ eq NoPhase).foldLeft(List[(Phase, T)]()) { (res, ph) => val value = afterPhase(ph)(op) if (res.nonEmpty && res.head._2 == value) res else ((ph, value)) :: res diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 0e5f9ee80e..077f0f9c0e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -658,7 +658,8 @@ self => DocDef(doc, t) setPos { if (t.pos.isDefined) { val pos = doc.pos.withEnd(t.pos.endOrPoint) - if (t.pos.isOpaqueRange) pos else pos.makeTransparent + // always make the position transparent + pos.makeTransparent } else { t.pos } @@ -2967,9 +2968,9 @@ self => val annots = annotations(true) val pos = in.offset val mods = (localModifiers() | implicitMod) withAnnotations annots - val defs = joinComment( // for SI-5527 + val defs = if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) defOrDcl(pos, mods) - else List(tmplDef(pos, mods))) + else List(tmplDef(pos, mods)) in.token match { case RBRACE | CASE => defs :+ (Literal(Constant()) setPos o2p(in.offset)) diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index 2bcfb9d4a9..ec6c631bd1 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -350,6 +350,7 @@ trait Opcodes { self: ICodes => } case class BOX(boxType: TypeKind) extends Instruction { + assert(boxType.isValueType && (boxType ne UNIT)) // documentation override def toString(): String = "BOX " + boxType override def consumed = 1 override def consumedTypes = boxType :: Nil @@ -357,6 +358,7 @@ trait Opcodes { self: ICodes => } case class UNBOX(boxType: TypeKind) extends Instruction { + assert(boxType.isValueType && (boxType ne UNIT)) // documentation override def toString(): String = "UNBOX " + boxType override def consumed = 1 override def consumedTypes = ObjectReference :: Nil diff --git a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala index 37fff0e1e8..f99ac28e9d 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala @@ -120,47 +120,50 @@ trait Primitives { self: ICodes => /** This class represents a test operation. */ - class TestOp { + sealed abstract class TestOp { /** Returns the negation of this operation. */ - def negate(): TestOp = this match { - case EQ => NE - case NE => EQ - case LT => GE - case GE => LT - case LE => GT - case GT => LE - case _ => throw new RuntimeException("TestOp unknown case") - } + def negate(): TestOp /** Returns a string representation of this operation. */ - override def toString(): String = this match { - case EQ => "EQ" - case NE => "NE" - case LT => "LT" - case GE => "GE" - case LE => "LE" - case GT => "GT" - case _ => throw new RuntimeException("TestOp unknown case") - } + override def toString(): String } + /** An equality test */ - case object EQ extends TestOp + case object EQ extends TestOp { + def negate() = NE + override def toString() = "EQ" + } /** A non-equality test */ - case object NE extends TestOp + case object NE extends TestOp { + def negate() = EQ + override def toString() = "NE" + } /** A less-than test */ - case object LT extends TestOp + case object LT extends TestOp { + def negate() = GE + override def toString() = "LT" + } /** A greater-than-or-equal test */ - case object GE extends TestOp + case object GE extends TestOp { + def negate() = LT + override def toString() = "GE" + } /** A less-than-or-equal test */ - case object LE extends TestOp + case object LE extends TestOp { + def negate() = GT + override def toString() = "LE" + } /** A greater-than test */ - case object GT extends TestOp + case object GT extends TestOp { + def negate() = LE + override def toString() = "GT" + } /** This class represents an arithmetic operation. */ class ArithmeticOp { diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 5eef02f2cb..2ff0c1926c 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -74,22 +74,19 @@ trait TypeKinds { self: ICodes => case _ => false } - /** On the JVM, these types are like Ints for the - * purposes of calculating the lub. + /** On the JVM, + * BOOL, BYTE, CHAR, SHORT, and INT + * are like Ints for the purposes of calculating the lub. */ - def isIntSizedType: Boolean = this match { - case BOOL | CHAR | BYTE | SHORT | INT => true - case _ => false - } - def isIntegralType: Boolean = this match { - case BYTE | SHORT | INT | LONG | CHAR => true - case _ => false - } - def isRealType: Boolean = this match { - case FLOAT | DOUBLE => true - case _ => false - } - def isNumericType: Boolean = isIntegralType | isRealType + def isIntSizedType: Boolean = false + + /** On the JVM, similar to isIntSizedType except that BOOL isn't integral while LONG is. */ + def isIntegralType: Boolean = false + + /** On the JVM, FLOAT and DOUBLE. */ + def isRealType: Boolean = false + + final def isNumericType: Boolean = isIntegralType | isRealType /** Simple subtyping check */ def <:<(other: TypeKind): Boolean = (this eq other) || (this match { @@ -97,11 +94,8 @@ trait TypeKinds { self: ICodes => 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 - } + /** Is this type a category 2 type in JVM terms? (ie, is it LONG or DOUBLE?) */ + def isWideType: Boolean = false /** The number of dimensions for array types. */ def dimensions: Int = 0 @@ -182,6 +176,7 @@ trait TypeKinds { self: ICodes => /** A boolean value */ case object BOOL extends ValueTypeKind { + override def isIntSizedType = true def maxType(other: TypeKind) = other match { case BOOL | REFERENCE(NothingClass) => BOOL case _ => uncomparable(other) @@ -195,6 +190,8 @@ trait TypeKinds { self: ICodes => /** A 1-byte signed integer */ case object BYTE extends ValueTypeKind { + override def isIntSizedType = true + override def isIntegralType = true def maxType(other: TypeKind) = { if (other == BYTE || other.isNothingType) BYTE else if (other == CHAR) INT @@ -205,6 +202,8 @@ trait TypeKinds { self: ICodes => /** A 2-byte signed integer */ case object SHORT extends ValueTypeKind { + override def isIntSizedType = true + override def isIntegralType = true override def maxType(other: TypeKind) = other match { case BYTE | SHORT | REFERENCE(NothingClass) => SHORT case CHAR => INT @@ -215,6 +214,8 @@ trait TypeKinds { self: ICodes => /** A 2-byte UNSIGNED integer */ case object CHAR extends ValueTypeKind { + override def isIntSizedType = true + override def isIntegralType = true override def maxType(other: TypeKind) = other match { case CHAR | REFERENCE(NothingClass) => CHAR case BYTE | SHORT => INT @@ -225,6 +226,8 @@ trait TypeKinds { self: ICodes => /** A 4-byte signed integer */ case object INT extends ValueTypeKind { + override def isIntSizedType = true + override def isIntegralType = true override def maxType(other: TypeKind) = other match { case BYTE | SHORT | CHAR | INT | REFERENCE(NothingClass) => INT case LONG | FLOAT | DOUBLE => other @@ -234,6 +237,8 @@ trait TypeKinds { self: ICodes => /** An 8-byte signed integer */ case object LONG extends ValueTypeKind { + override def isIntegralType = true + override def isWideType = true override def maxType(other: TypeKind): TypeKind = if (other.isIntegralType || other.isNothingType) LONG else if (other.isRealType) DOUBLE @@ -242,6 +247,7 @@ trait TypeKinds { self: ICodes => /** A 4-byte floating point number */ case object FLOAT extends ValueTypeKind { + override def isRealType = true override def maxType(other: TypeKind): TypeKind = if (other == DOUBLE) DOUBLE else if (other.isNumericType || other.isNothingType) FLOAT @@ -250,6 +256,8 @@ trait TypeKinds { self: ICodes => /** An 8-byte floating point number */ case object DOUBLE extends ValueTypeKind { + override def isRealType = true + override def isWideType = true override def maxType(other: TypeKind): TypeKind = if (other.isNumericType || other.isNothingType) DOUBLE else uncomparable(other) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 387b7fb3d7..c609f126d3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -40,16 +40,16 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with private def outputDirectory(sym: Symbol): AbstractFile = settings.outputDirs outputDirFor beforeFlatten(sym.sourceFile) - private def getFile(base: AbstractFile, cls: JClass, suffix: String): AbstractFile = { + private def getFile(base: AbstractFile, clsName: String, suffix: String): AbstractFile = { var dir = base - val pathParts = cls.getName().split("[./]").toList + val pathParts = clsName.split("[./]").toList for (part <- pathParts.init) { dir = dir.subdirectoryNamed(part) } dir.fileNamed(pathParts.last + suffix) } - private def getFile(sym: Symbol, cls: JClass, suffix: String): AbstractFile = - getFile(outputDirectory(sym), cls, suffix) + private def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = + getFile(outputDirectory(sym), clsName, suffix) /** JVM code generation phase */ @@ -195,8 +195,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val StringBuilderClassName = javaName(definitions.StringBuilderClass) val BoxesRunTime = "scala.runtime.BoxesRunTime" - val StringBuilderType = new JObjectType(StringBuilderClassName) - val toStringType = new JMethodType(JAVA_LANG_STRING, JType.EMPTY_ARRAY) + val StringBuilderType = new JObjectType(StringBuilderClassName) // TODO use ASMType.getObjectType + val toStringType = new JMethodType(JAVA_LANG_STRING, JType.EMPTY_ARRAY) // TODO use ASMType.getMethodType val arrayCloneType = new JMethodType(JAVA_LANG_OBJECT, JType.EMPTY_ARRAY) val MethodTypeType = new JObjectType("java.dyn.MethodType") val JavaLangClassType = new JObjectType("java.lang.Class") @@ -215,10 +215,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with } // Additional interface parents based on annotations and other cues - def newParentForAttr(attr: Symbol): Option[Type] = attr match { - case SerializableAttr => Some(SerializableClass.tpe) - case CloneableAttr => Some(JavaCloneableClass.tpe) - case RemoteAttr => Some(RemoteInterfaceClass.tpe) + def newParentForAttr(attr: Symbol): Option[Symbol] = attr match { + case SerializableAttr => Some(SerializableClass) + case CloneableAttr => Some(JavaCloneableClass) + case RemoteAttr => Some(RemoteInterfaceClass) case _ => None } @@ -231,11 +231,47 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with vp } + private def helperBoxTo(kind: ValueTypeKind): Tuple2[String, JMethodType] = { + val boxedType = definitions.boxedClass(kind.toType.typeSymbol) + val mtype = new JMethodType(javaType(boxedType), Array(javaType(kind))) + + Pair("boxTo" + boxedType.decodedName, mtype) + } + + private val jBoxTo: Map[TypeKind, Tuple2[String, JMethodType]] = Map( + BOOL -> helperBoxTo(BOOL) , + BYTE -> helperBoxTo(BYTE) , + CHAR -> helperBoxTo(CHAR) , + SHORT -> helperBoxTo(SHORT) , + INT -> helperBoxTo(INT) , + LONG -> helperBoxTo(LONG) , + FLOAT -> helperBoxTo(FLOAT) , + DOUBLE -> helperBoxTo(DOUBLE) + ) + + private def helperUnboxTo(kind: ValueTypeKind): Tuple2[String, JMethodType] = { + val mtype = new JMethodType(javaType(kind), Array(JAVA_LANG_OBJECT)) + val mname = "unboxTo" + kind.toType.typeSymbol.decodedName + + Pair(mname, mtype) + } + + private val jUnboxTo: Map[TypeKind, Tuple2[String, JMethodType]] = Map( + BOOL -> helperUnboxTo(BOOL) , + BYTE -> helperUnboxTo(BYTE) , + CHAR -> helperUnboxTo(CHAR) , + SHORT -> helperUnboxTo(SHORT) , + INT -> helperUnboxTo(INT) , + LONG -> helperUnboxTo(LONG) , + FLOAT -> helperUnboxTo(FLOAT) , + DOUBLE -> helperUnboxTo(DOUBLE) + ) + var clasz: IClass = _ var method: IMethod = _ var jclass: JClass = _ var jmethod: JMethod = _ -// var jcode: JExtendedCode = _ + // var jcode: JExtendedCode = _ def isParcelableClass = isAndroidParcelableClass(clasz.symbol) def isRemoteClass = clasz.symbol hasAnnotation RemoteAttr @@ -263,7 +299,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with private def innerClassSymbolFor(s: Symbol): Symbol = if (s.isClass) s else if (s.isModule) s.moduleClass else NoSymbol - override def javaName(sym: Symbol): String = { + override def javaName(sym: Symbol): String = { // TODO Miguel says: check whether a single pass over `icodes.classes` can populate `innerClassBuffer` faster. /** * Checks if given symbol corresponds to inner class/object and add it to innerClassBuffer * @@ -274,10 +310,13 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with // TODO: some beforeFlatten { ... } which accounts for // being nested in parameterized classes (if we're going to selectively flatten.) val x = innerClassSymbolFor(s) - val isInner = x.isClass && !x.rawowner.isPackageClass - if (isInner) { - innerClassBuffer += x - collectInnerClass(x.rawowner) + if(x ne NoSymbol) { + assert(x.isClass, "not an inner-class symbol") + val isInner = !x.rawowner.isPackageClass + if (isInner) { + innerClassBuffer += x + collectInnerClass(x.rawowner) + } } } collectInnerClass(sym) @@ -339,38 +378,44 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with private var innerClassBuffer = mutable.LinkedHashSet[Symbol]() - /** Drop redundant interfaces (ones which are implemented by some - * other parent) from the immediate parents. This is important on - * android because there is otherwise an interface explosion. + /** Drop redundant interfaces (ones which are implemented by some other parent) from the immediate parents. + * This is important on Android because there is otherwise an interface explosion. */ - private def minimizeInterfaces(interfaces: List[Symbol]): List[Symbol] = ( - interfaces filterNot (int1 => - interfaces exists (int2 => - (int1 ne int2) && (int2 isSubClass int1) - ) - ) - ) + private def minimizeInterfaces(interfaces: List[Symbol]): List[Symbol] = { + var rest = interfaces + var leaves = List.empty[Symbol] + while(!rest.isEmpty) { + val candidate = rest.head + val nonLeaf = leaves exists { lsym => lsym isSubClass candidate } + if(!nonLeaf) { + leaves = candidate :: (leaves filterNot { lsym => candidate isSubClass lsym }) + } + rest = rest.tail + } + + leaves + } def genClass(c: IClass) { clasz = c innerClassBuffer.clear() val name = javaName(c.symbol) - val superClass :: superInterfaces = { - val parents0 = c.symbol.info.parents match { - case Nil => List(ObjectClass.tpe) - case ps => ps - } - parents0 ++ c.symbol.annotations.flatMap(ann => newParentForAttr(ann.symbol)) distinct - } - val ifaces = superInterfaces match { - case Nil => JClass.NO_INTERFACES - case _ => mkArray(minimizeInterfaces(superInterfaces map (_.typeSymbol)) map javaName) - } + + val ps = c.symbol.info.parents + + val superClass: Symbol = if(ps.isEmpty) ObjectClass else ps.head.typeSymbol; + + val superInterfaces0: List[Symbol] = if(ps.isEmpty) Nil else c.symbol.mixinClasses; + val superInterfaces = superInterfaces0 ++ c.symbol.annotations.flatMap(ann => newParentForAttr(ann.symbol)) distinct + + val ifaces = + if(superInterfaces.isEmpty) JClass.NO_INTERFACES + else mkArray(minimizeInterfaces(superInterfaces) map javaName) jclass = fjbgContext.JClass(javaFlags(c.symbol), name, - javaName(superClass.typeSymbol), + javaName(superClass), ifaces, c.cunit.source.toString) @@ -824,6 +869,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with def genField(f: IField) { debuglog("Adding field: " + f.symbol.fullName) + val jfield = jclass.addNewField( javaFlags(f.symbol) | javaFieldFlags(f.symbol), javaName(f.symbol), @@ -1126,8 +1172,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with linearization = linearizer.linearize(m) val labels = makeLabels(linearization) - /** local variables whose scope appears in this block. */ - val varsInBlock: mutable.Set[Local] = new mutable.HashSet var nextBlock: BasicBlock = linearization.head @@ -1137,302 +1181,298 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with case x :: y :: ys => nextBlock = y; genBlock(x); genBlocks(y :: ys) } - /** Generate exception handlers for the current method. */ - def genExceptionHandlers() { + /** Generate exception handlers for the current method. */ + def genExceptionHandlers() { - /** Return a list of pairs of intervals where the handler is active. - * The intervals in the list have to be inclusive in the beginning and - * exclusive in the end: [start, end). - */ - def ranges(e: ExceptionHandler): List[(Int, Int)] = { - var covered = e.covered - var ranges: List[(Int, Int)] = Nil - var start = -1 - var end = -1 - - linearization foreach { b => - if (! (covered contains b) ) { - if (start >= 0) { // we're inside a handler range - end = labels(b).getAnchor() - ranges ::= ((start, end)) - start = -1 + /** Return a list of pairs of intervals where the handler is active. + * The intervals in the list have to be inclusive in the beginning and + * exclusive in the end: [start, end). + */ + def ranges(e: ExceptionHandler): List[(Int, Int)] = { + var covered = e.covered + var ranges: List[(Int, Int)] = Nil + var start = -1 + var end = -1 + + linearization foreach { b => + if (! (covered contains b) ) { + if (start >= 0) { // we're inside a handler range + end = labels(b).getAnchor() + ranges ::= ((start, end)) + start = -1 + } + } else { + if (start < 0) // we're not inside a handler range + start = labels(b).getAnchor() + + end = endPC(b) + covered -= b } - } else { - if (start < 0) // we're not inside a handler range - start = labels(b).getAnchor() + } - end = endPC(b) - covered -= b + /* Add the last interval. Note that since the intervals are + * open-ended to the right, we have to give a number past the actual + * code! + */ + if (start >= 0) { + ranges ::= ((start, jcode.getPC())) } - } - /* Add the last interval. Note that since the intervals are - * open-ended to the right, we have to give a number past the actual - * code! - */ - if (start >= 0) { - ranges ::= ((start, jcode.getPC())) + if (!covered.isEmpty) + debuglog("Some covered blocks were not found in method: " + method + + " covered: " + covered + " not in " + linearization) + ranges } - if (!covered.isEmpty) - debuglog("Some covered blocks were not found in method: " + method + - " covered: " + covered + " not in " + linearization) - ranges + for (e <- this.method.exh ; p <- ranges(e).sortBy(_._1)) { + if (p._1 < p._2) { + debuglog("Adding exception handler " + e + "at block: " + e.startBlock + " for " + method + + " from: " + p._1 + " to: " + p._2 + " catching: " + e.cls); + val cls = if (e.cls == NoSymbol || e.cls == ThrowableClass) null + else javaName(e.cls) + jcode.addExceptionHandler(p._1, p._2, + labels(e.startBlock).getAnchor(), + cls) + } else + log("Empty exception range: " + p) + } } - for (e <- this.method.exh ; p <- ranges(e).sortBy(_._1)) { - if (p._1 < p._2) { - debuglog("Adding exception handler " + e + "at block: " + e.startBlock + " for " + method + - " from: " + p._1 + " to: " + p._2 + " catching: " + e.cls); - val cls = if (e.cls == NoSymbol || e.cls == ThrowableClass) null - else javaName(e.cls) - jcode.addExceptionHandler(p._1, p._2, - labels(e.startBlock).getAnchor(), - cls) - } else - log("Empty exception range: " + p) + def isAccessibleFrom(target: Symbol, site: Symbol): Boolean = { + target.isPublic || target.isProtected && { + (site.enclClass isSubClass target.enclClass) || + (site.enclosingPackage == target.privateWithin) + } } - } - def isAccessibleFrom(target: Symbol, site: Symbol): Boolean = { - target.isPublic || target.isProtected && { - (site.enclClass isSubClass target.enclClass) || - (site.enclosingPackage == target.privateWithin) - } - } + def genCallMethod(call: CALL_METHOD) { + val CALL_METHOD(method, style) = call + val siteSymbol = clasz.symbol + val hostSymbol = call.hostClass + val methodOwner = method.owner + // info calls so that types are up to date; erasure may add lateINTERFACE to traits + hostSymbol.info ; methodOwner.info + + def isInterfaceCall(sym: Symbol) = ( + sym.isInterface && methodOwner != ObjectClass + || sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass) + ) + // whether to reference the type of the receiver or + // the type of the method owner (if not an interface!) + val useMethodOwner = ( + style != Dynamic + || !isInterfaceCall(hostSymbol) && isAccessibleFrom(methodOwner, siteSymbol) + || hostSymbol.isBottomClass + ) + val receiver = if (useMethodOwner) methodOwner else hostSymbol + val jowner = javaName(receiver) + val jname = javaName(method) + val jtype = javaType(method).asInstanceOf[JMethodType] - def genCallMethod(call: CALL_METHOD) { - val CALL_METHOD(method, style) = call - val siteSymbol = clasz.symbol - val hostSymbol = call.hostClass - val methodOwner = method.owner - // info calls so that types are up to date; erasure may add lateINTERFACE to traits - hostSymbol.info ; methodOwner.info - - def isInterfaceCall(sym: Symbol) = ( - sym.isInterface && methodOwner != ObjectClass - || sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass) - ) - // whether to reference the type of the receiver or - // the type of the method owner (if not an interface!) - val useMethodOwner = ( - style != Dynamic - || !isInterfaceCall(hostSymbol) && isAccessibleFrom(methodOwner, siteSymbol) - || hostSymbol.isBottomClass - ) - val receiver = if (useMethodOwner) methodOwner else hostSymbol - val jowner = javaName(receiver) - val jname = javaName(method) - val jtype = javaType(method).asInstanceOf[JMethodType] - - def emit(invoke: String) { - debuglog("%s %s %s.%s:%s".format(invoke, receiver.accessString, jowner, jname, jtype)) - invoke match { - case "invokeinterface" => jcode.emitINVOKEINTERFACE(jowner, jname, jtype) - case "invokevirtual" => jcode.emitINVOKEVIRTUAL(jowner, jname, jtype) - case "invokespecial" => jcode.emitINVOKESPECIAL(jowner, jname, jtype) - case "invokestatic" => jcode.emitINVOKESTATIC(jowner, jname, jtype) + def debugMsg(invoke: String) { + debuglog("%s %s %s.%s:%s".format(invoke, receiver.accessString, jowner, jname, jtype)) } - } - def initModule() { - // we initialize the MODULE$ field immediately after the super ctor - if (isStaticModule(siteSymbol) && !isModuleInitialized && - jmethod.getName() == JMethod.INSTANCE_CONSTRUCTOR_NAME && - jname == JMethod.INSTANCE_CONSTRUCTOR_NAME) { - isModuleInitialized = true - jcode.emitALOAD_0() - jcode.emitPUTSTATIC(jclass.getName(), - nme.MODULE_INSTANCE_FIELD.toString, - jclass.getType()) + + def initModule() { + // we initialize the MODULE$ field immediately after the super ctor + if (isStaticModule(siteSymbol) && !isModuleInitialized && + jmethod.getName() == JMethod.INSTANCE_CONSTRUCTOR_NAME && + jname == JMethod.INSTANCE_CONSTRUCTOR_NAME) { + isModuleInitialized = true + jcode.emitALOAD_0() + jcode.emitPUTSTATIC(jclass.getName(), + nme.MODULE_INSTANCE_FIELD.toString, + jclass.getType()) + } } - } - style match { - case Static(true) => emit("invokespecial") - case Static(false) => emit("invokestatic") - case Dynamic if isInterfaceCall(receiver) => emit("invokeinterface") - case Dynamic => emit("invokevirtual") - case SuperCall(_) => emit("invokespecial") ; initModule() + style match { + case Static(true) => jcode.emitINVOKESPECIAL (jowner, jname, jtype) ; debugMsg("invokespecial") + case Static(false) => jcode.emitINVOKESTATIC (jowner, jname, jtype) ; debugMsg("invokestatic") + case Dynamic if isInterfaceCall(receiver) => jcode.emitINVOKEINTERFACE(jowner, jname, jtype) ; debugMsg("invokinterface") + case Dynamic => jcode.emitINVOKEVIRTUAL (jowner, jname, jtype) ; debugMsg("invokevirtual") + case SuperCall(_) => + jcode.emitINVOKESPECIAL(jowner, jname, jtype) + initModule() + debugMsg("invokespecial") + } } - } - def genBlock(b: BasicBlock) { - labels(b).anchorToNext() + def genBlock(b: BasicBlock) { + labels(b).anchorToNext() - debuglog("Generating code for block: " + b + " at pc: " + labels(b).getAnchor()) - var lastMappedPC = 0 - var lastLineNr = 0 - var crtPC = 0 - varsInBlock.clear() + debuglog("Generating code for block: " + b + " at pc: " + labels(b).getAnchor()) + var lastMappedPC = 0 + var lastLineNr = 0 + var crtPC = 0 - for (instr <- b) { + /** local variables whose scope appears in this block. */ + val varsInBlock: mutable.Set[Local] = new mutable.HashSet + val lastInstr = b.lastInstruction - instr match { - case THIS(clasz) => - jcode.emitALOAD_0() + for (instr <- b) { - case CONSTANT(const) => - genConstant(jcode, const) + instr match { + case THIS(clasz) => jcode.emitALOAD_0() - case LOAD_ARRAY_ITEM(kind) => - jcode.emitALOAD(javaType(kind)) + case CONSTANT(const) => genConstant(jcode, const) - case LOAD_LOCAL(local) => - jcode.emitLOAD(indexOf(local), javaType(local.kind)) + case LOAD_ARRAY_ITEM(kind) => + if(kind.isRefOrArrayType) { jcode.emitAALOAD() } + else { + (kind: @unchecked) match { + case UNIT => throw new IllegalArgumentException("invalid type for aload " + kind) + case BOOL | BYTE => jcode.emitBALOAD() + case SHORT => jcode.emitSALOAD() + case CHAR => jcode.emitCALOAD() + case INT => jcode.emitIALOAD() + case LONG => jcode.emitLALOAD() + case FLOAT => jcode.emitFALOAD() + case DOUBLE => jcode.emitDALOAD() + } + } - case lf @ LOAD_FIELD(field, isStatic) => - var owner = javaName(lf.hostClass) - debuglog("LOAD_FIELD with owner: " + owner + - " flags: " + Flags.flagsToString(field.owner.flags)) - if (isStatic) - jcode.emitGETSTATIC(owner, - javaName(field), - javaType(field)) - else - jcode.emitGETFIELD(owner, - javaName(field), - javaType(field)) - - case LOAD_MODULE(module) => -// assert(module.isModule, "Expected module: " + module) - debuglog("generating LOAD_MODULE for: " + module + " flags: " + - Flags.flagsToString(module.flags)); - if (clasz.symbol == module.moduleClass && jmethod.getName() != nme.readResolve.toString) - jcode.emitALOAD_0() - else - jcode.emitGETSTATIC(javaName(module) /* + "$" */ , - nme.MODULE_INSTANCE_FIELD.toString, - javaType(module)) - - case STORE_ARRAY_ITEM(kind) => - jcode emitASTORE javaType(kind) - - case STORE_LOCAL(local) => - jcode.emitSTORE(indexOf(local), javaType(local.kind)) - - case STORE_THIS(_) => - // this only works for impl classes because the self parameter comes first - // in the method signature. If that changes, this code has to be revisited. - jcode.emitASTORE_0() - - case STORE_FIELD(field, isStatic) => - val owner = javaName(field.owner) - if (isStatic) - jcode.emitPUTSTATIC(owner, - javaName(field), - javaType(field)) - else - jcode.emitPUTFIELD(owner, - javaName(field), - javaType(field)) - - case CALL_PRIMITIVE(primitive) => - genPrimitive(primitive, instr.pos) - - /** Special handling to access native Array.clone() */ - case call @ CALL_METHOD(definitions.Array_clone, Dynamic) => - val target: String = javaType(call.targetTypeKind).getSignature() - jcode.emitINVOKEVIRTUAL(target, "clone", arrayCloneType) - - case call @ CALL_METHOD(method, style) => - genCallMethod(call) - - case BOX(kind) => - val boxedType = definitions.boxedClass(kind.toType.typeSymbol) - val mtype = new JMethodType(javaType(boxedType), Array(javaType(kind))) - jcode.emitINVOKESTATIC(BoxesRunTime, "boxTo" + boxedType.decodedName, mtype) - - case UNBOX(kind) => - val mtype = new JMethodType(javaType(kind), Array(JAVA_LANG_OBJECT)) - jcode.emitINVOKESTATIC(BoxesRunTime, "unboxTo" + kind.toType.typeSymbol.decodedName, mtype) - - case NEW(REFERENCE(cls)) => - val className = javaName(cls) - jcode emitNEW className - - case CREATE_ARRAY(elem, 1) => elem match { - case REFERENCE(_) | ARRAY(_) => - jcode emitANEWARRAY javaType(elem).asInstanceOf[JReferenceType] - case _ => - jcode emitNEWARRAY javaType(elem) - } + case LOAD_LOCAL(local) => jcode.emitLOAD(indexOf(local), javaType(local.kind)) + + case lf @ LOAD_FIELD(field, isStatic) => + var owner = javaName(lf.hostClass) + debuglog("LOAD_FIELD with owner: " + owner + + " flags: " + Flags.flagsToString(field.owner.flags)) + val fieldJName = javaName(field) + val fieldJType = javaType(field) + if (isStatic) jcode.emitGETSTATIC(owner, fieldJName, fieldJType) + else jcode.emitGETFIELD( owner, fieldJName, fieldJType) + + case LOAD_MODULE(module) => + // assert(module.isModule, "Expected module: " + module) + debuglog("generating LOAD_MODULE for: " + module + " flags: " + Flags.flagsToString(module.flags)); + if (clasz.symbol == module.moduleClass && jmethod.getName() != nme.readResolve.toString) + jcode.emitALOAD_0() + else + jcode.emitGETSTATIC(javaName(module) /* + "$" */ , + nme.MODULE_INSTANCE_FIELD.toString, + javaType(module)) + + case STORE_ARRAY_ITEM(kind) => + if(kind.isRefOrArrayType) { jcode.emitAASTORE() } + else { + (kind: @unchecked) match { + case UNIT => throw new IllegalArgumentException("invalid type for astore " + kind) + case BOOL | BYTE => jcode.emitBASTORE() + case SHORT => jcode.emitSASTORE() + case CHAR => jcode.emitCASTORE() + case INT => jcode.emitIASTORE() + case LONG => jcode.emitLASTORE() + case FLOAT => jcode.emitFASTORE() + case DOUBLE => jcode.emitDASTORE() + } + } - case CREATE_ARRAY(elem, dims) => - jcode.emitMULTIANEWARRAY(javaType(ArrayN(elem, dims)).asInstanceOf[JReferenceType], dims) + case STORE_LOCAL(local) => + jcode.emitSTORE(indexOf(local), javaType(local.kind)) - case IS_INSTANCE(tpe) => - tpe match { - case REFERENCE(cls) => - jcode emitINSTANCEOF new JObjectType(javaName(cls)) - case ARRAY(elem) => - jcode emitINSTANCEOF new JArrayType(javaType(elem)) - case _ => - abort("Unknown reference type in IS_INSTANCE: " + tpe) - } + case STORE_THIS(_) => + // this only works for impl classes because the self parameter comes first + // in the method signature. If that changes, this code has to be revisited. + jcode.emitASTORE_0() - case CHECK_CAST(tpe) => - tpe match { - case REFERENCE(cls) => - // No need to checkcast for Objects - if (cls != ObjectClass) - jcode emitCHECKCAST new JObjectType(javaName(cls)) - case ARRAY(elem) => - jcode emitCHECKCAST new JArrayType(javaType(elem)) - case _ => - abort("Unknown reference type in IS_INSTANCE: " + tpe) - } + case STORE_FIELD(field, isStatic) => + val owner = javaName(field.owner) + val fieldJName = javaName(field) + val fieldJType = javaType(field) + if (isStatic) jcode.emitPUTSTATIC(owner, fieldJName, fieldJType) + else jcode.emitPUTFIELD( owner, fieldJName, fieldJType) - case SWITCH(tags, branches) => - val tagArray = new Array[Array[Int]](tags.length) - var caze = tags - var i = 0 + case CALL_PRIMITIVE(primitive) => genPrimitive(primitive, instr.pos) - while (i < tagArray.length) { - tagArray(i) = new Array[Int](caze.head.length) - caze.head.copyToArray(tagArray(i), 0) - i += 1 - caze = caze.tail - } - val branchArray = jcode.newLabels(tagArray.length) - i = 0 - while (i < branchArray.length) { - branchArray(i) = labels(branches(i)) - i += 1 - } - debuglog("Emitting SWITCH:\ntags: " + tags + "\nbranches: " + branches) - jcode.emitSWITCH(tagArray, - branchArray, - labels(branches.last), - MIN_SWITCH_DENSITY) - () - - case JUMP(whereto) => - if (nextBlock != whereto) - jcode.emitGOTO_maybe_W(labels(whereto), false) // default to short jumps - - case CJUMP(success, failure, cond, kind) => - kind match { - case BOOL | BYTE | CHAR | SHORT | INT => + /** Special handling to access native Array.clone() */ + case call @ CALL_METHOD(definitions.Array_clone, Dynamic) => + val target: String = javaType(call.targetTypeKind).getSignature() + jcode.emitINVOKEVIRTUAL(target, "clone", arrayCloneType) + + case call @ CALL_METHOD(method, style) => genCallMethod(call) + + case BOX(kind) => + val Pair(mname, mtype) = jBoxTo(kind) + jcode.emitINVOKESTATIC(BoxesRunTime, mname, mtype) + + case UNBOX(kind) => + val Pair(mname, mtype) = jUnboxTo(kind) + jcode.emitINVOKESTATIC(BoxesRunTime, mname, mtype) + + case NEW(REFERENCE(cls)) => + val className = javaName(cls) + jcode emitNEW className + + case CREATE_ARRAY(elem, 1) => + if(elem.isRefOrArrayType) { jcode emitANEWARRAY javaType(elem).asInstanceOf[JReferenceType] } + else { jcode emitNEWARRAY javaType(elem) } + + case CREATE_ARRAY(elem, dims) => + jcode.emitMULTIANEWARRAY(javaType(ArrayN(elem, dims)).asInstanceOf[JReferenceType], dims) + + case IS_INSTANCE(tpe) => + tpe match { + case REFERENCE(cls) => jcode emitINSTANCEOF new JObjectType(javaName(cls)) + case ARRAY(elem) => jcode emitINSTANCEOF new JArrayType(javaType(elem)) + case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe) + } + + case CHECK_CAST(tpe) => + tpe match { + case REFERENCE(cls) => if (cls != ObjectClass) { jcode emitCHECKCAST new JObjectType(javaName(cls)) } // No need to checkcast for Objects + case ARRAY(elem) => jcode emitCHECKCAST new JArrayType(javaType(elem)) + case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe) + } + + case SWITCH(tags, branches) => + val tagArray = new Array[Array[Int]](tags.length) + var caze = tags + var i = 0 + + while (i < tagArray.length) { + tagArray(i) = new Array[Int](caze.head.length) + caze.head.copyToArray(tagArray(i), 0) + i += 1 + caze = caze.tail + } + val branchArray = jcode.newLabels(tagArray.length) + i = 0 + while (i < branchArray.length) { + branchArray(i) = labels(branches(i)) + i += 1 + } + debuglog("Emitting SWITCH:\ntags: " + tags + "\nbranches: " + branches) + jcode.emitSWITCH(tagArray, + branchArray, + labels(branches.last), + MIN_SWITCH_DENSITY) + () + + case JUMP(whereto) => + if (nextBlock != whereto) + jcode.emitGOTO_maybe_W(labels(whereto), false) // default to short jumps + + case CJUMP(success, failure, cond, kind) => + if(kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT if (nextBlock == success) { - jcode.emitIF_ICMP(conds(negate(cond)), labels(failure)) + jcode.emitIF_ICMP(conds(cond.negate()), labels(failure)) // .. and fall through to success label } else { jcode.emitIF_ICMP(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - - case REFERENCE(_) | ARRAY(_) => + } else if(kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_) if (nextBlock == success) { - jcode.emitIF_ACMP(conds(negate(cond)), labels(failure)) + jcode.emitIF_ACMP(conds(cond.negate()), labels(failure)) // .. and fall through to success label } else { jcode.emitIF_ACMP(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - - case _ => + } else { (kind: @unchecked) match { case LONG => jcode.emitLCMP() case FLOAT => @@ -1443,38 +1483,32 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with else jcode.emitDCMPL() } if (nextBlock == success) { - jcode.emitIF(conds(negate(cond)), labels(failure)) + jcode.emitIF(conds(cond.negate()), labels(failure)) // .. and fall through to success label } else { jcode.emitIF(conds(cond), labels(success)); if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - } + } - case CZJUMP(success, failure, cond, kind) => - kind match { - case BOOL | BYTE | CHAR | SHORT | INT => + case CZJUMP(success, failure, cond, kind) => + if(kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT if (nextBlock == success) { - jcode.emitIF(conds(negate(cond)), labels(failure)) + jcode.emitIF(conds(cond.negate()), labels(failure)) } else { jcode.emitIF(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - - case REFERENCE(_) | ARRAY(_) => + } else if(kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_) val Success = success val Failure = failure (cond, nextBlock) match { - case (EQ, Success) => - jcode emitIFNONNULL labels(failure) - case (NE, Failure) => - jcode emitIFNONNULL labels(success) - case (EQ, Failure) => - jcode emitIFNULL labels(success) - case (NE, Success) => - jcode emitIFNULL labels(failure) + case (EQ, Success) => jcode emitIFNONNULL labels(failure) + case (NE, Failure) => jcode emitIFNONNULL labels(success) + case (EQ, Failure) => jcode emitIFNULL labels(success) + case (NE, Success) => jcode emitIFNULL labels(failure) case (EQ, _) => jcode emitIFNULL labels(success) jcode.emitGOTO_maybe_W(labels(failure), false) @@ -1482,11 +1516,11 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with jcode emitIFNONNULL labels(success) jcode.emitGOTO_maybe_W(labels(failure), false) } - - case _ => + } else { (kind: @unchecked) match { case LONG => - jcode.emitLCONST_0(); jcode.emitLCMP() + jcode.emitLCONST_0() + jcode.emitLCMP() case FLOAT => jcode.emitFCONST_0() if (cond == LT || cond == LE) jcode.emitFCMPG() @@ -1497,263 +1531,254 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with else jcode.emitDCMPL() } if (nextBlock == success) { - jcode.emitIF(conds(negate(cond)), labels(failure)) + jcode.emitIF(conds(cond.negate()), labels(failure)) } else { jcode.emitIF(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - } + } - case RETURN(kind) => - jcode emitRETURN javaType(kind) + case RETURN(kind) => jcode emitRETURN javaType(kind) - case THROW(_) => - jcode.emitATHROW() + case THROW(_) => jcode.emitATHROW() - case DROP(kind) => - kind match { - case LONG | DOUBLE => jcode.emitPOP2() - case _ => jcode.emitPOP() - } + case DROP(kind) => + if(kind.isWideType) jcode.emitPOP2() + else jcode.emitPOP() - case DUP(kind) => - kind match { - case LONG | DOUBLE => jcode.emitDUP2() - case _ => jcode.emitDUP() - } + case DUP(kind) => + if(kind.isWideType) jcode.emitDUP2() + else jcode.emitDUP() - case MONITOR_ENTER() => - jcode.emitMONITORENTER() + case MONITOR_ENTER() => jcode.emitMONITORENTER() - case MONITOR_EXIT() => - jcode.emitMONITOREXIT() + case MONITOR_EXIT() => jcode.emitMONITOREXIT() - case SCOPE_ENTER(lv) => - varsInBlock += lv - lv.start = jcode.getPC() + case SCOPE_ENTER(lv) => + varsInBlock += lv + lv.start = jcode.getPC() - case SCOPE_EXIT(lv) => - if (varsInBlock(lv)) { - lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges - varsInBlock -= lv - } - else if (b.varsInScope(lv)) { - lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges - b.varsInScope -= lv - } - else dumpMethodAndAbort(method, "Illegal local var nesting") + case SCOPE_EXIT(lv) => + if (varsInBlock(lv)) { + lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges + varsInBlock -= lv + } + else if (b.varsInScope(lv)) { + lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges + b.varsInScope -= lv + } + else dumpMethodAndAbort(method, "Illegal local var nesting") - case LOAD_EXCEPTION(_) => - () - } + case LOAD_EXCEPTION(_) => + () + } - crtPC = jcode.getPC() + crtPC = jcode.getPC() -// assert(instr.pos.source.isEmpty || instr.pos.source.get == (clasz.cunit.source), "sources don't match") -// val crtLine = instr.pos.line.get(lastLineNr); + // assert(instr.pos.source.isEmpty || instr.pos.source.get == (clasz.cunit.source), "sources don't match") + // val crtLine = instr.pos.line.get(lastLineNr); - val crtLine = try { - if (instr.pos == NoPosition) lastLineNr else (instr.pos).line // check NoPosition to avoid costly exception - } catch { - case _: UnsupportedOperationException => - log("Warning: wrong position in: " + method) - lastLineNr - } + val crtLine = try { + if (instr.pos == NoPosition) lastLineNr else (instr.pos).line // check NoPosition to avoid costly exception + } catch { + case _: UnsupportedOperationException => + log("Warning: wrong position in: " + method) + lastLineNr + } - if (b.lastInstruction == instr) - endPC(b) = jcode.getPC() + if (instr eq lastInstr) { endPC(b) = jcode.getPC() } - //System.err.println("CRTLINE: " + instr.pos + " " + - // /* (if (instr.pos < clasz.cunit.source.content.length) clasz.cunit.source.content(instr.pos) else '*') + */ " " + crtLine); + //System.err.println("CRTLINE: " + instr.pos + " " + + // /* (if (instr.pos < clasz.cunit.source.content.length) clasz.cunit.source.content(instr.pos) else '*') + */ " " + crtLine); - if (crtPC > lastMappedPC) { - jcode.completeLineNumber(lastMappedPC, crtPC, crtLine) - lastMappedPC = crtPC - lastLineNr = crtLine + if (crtPC > lastMappedPC) { + jcode.completeLineNumber(lastMappedPC, crtPC, crtLine) + lastMappedPC = crtPC + lastLineNr = crtLine + } } - } - // local vars that survived this basic block - for (lv <- varsInBlock) { - lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges - } - for (lv <- b.varsInScope) { - lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges + // local vars that survived this basic block + for (lv <- varsInBlock) { + lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges + } + for (lv <- b.varsInScope) { + lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges + } } - } - - /** - * @param primitive ... - * @param pos ... - */ - def genPrimitive(primitive: Primitive, pos: Position) { - primitive match { - case Negation(kind) => - kind match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitINEG() - case LONG => jcode.emitLNEG() - case FLOAT => jcode.emitFNEG() - case DOUBLE => jcode.emitDNEG() - case _ => abort("Impossible to negate a " + kind) - } - case Arithmetic(op, kind) => - op match { - case ADD => jcode.emitADD(javaType(kind)) - case SUB => - (kind: @unchecked) match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitISUB() - case LONG => jcode.emitLSUB() - case FLOAT => jcode.emitFSUB() - case DOUBLE => jcode.emitDSUB() + /** + * @param primitive ... + * @param pos ... + */ + def genPrimitive(primitive: Primitive, pos: Position) { + primitive match { + case Negation(kind) => + if(kind.isIntSizedType) { jcode.emitINEG() } + else { + kind match { + case LONG => jcode.emitLNEG() + case FLOAT => jcode.emitFNEG() + case DOUBLE => jcode.emitDNEG() + case _ => abort("Impossible to negate a " + kind) } + } - case MUL => - (kind: @unchecked) match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitIMUL() - case LONG => jcode.emitLMUL() - case FLOAT => jcode.emitFMUL() - case DOUBLE => jcode.emitDMUL() - } + case Arithmetic(op, kind) => + op match { + case ADD => + if(kind.isIntSizedType) { jcode.emitIADD() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLADD() + case FLOAT => jcode.emitFADD() + case DOUBLE => jcode.emitDADD() + } + } - case DIV => - (kind: @unchecked) match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitIDIV() - case LONG => jcode.emitLDIV() - case FLOAT => jcode.emitFDIV() - case DOUBLE => jcode.emitDDIV() - } + case SUB => + if(kind.isIntSizedType) { jcode.emitISUB() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLSUB() + case FLOAT => jcode.emitFSUB() + case DOUBLE => jcode.emitDSUB() + } + } - case REM => - (kind: @unchecked) match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitIREM() - case LONG => jcode.emitLREM() - case FLOAT => jcode.emitFREM() - case DOUBLE => jcode.emitDREM() - } + case MUL => + if(kind.isIntSizedType) { jcode.emitIMUL() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLMUL() + case FLOAT => jcode.emitFMUL() + case DOUBLE => jcode.emitDMUL() + } + } - case NOT => - kind match { - case BOOL | BYTE | CHAR | SHORT | INT => + case DIV => + if(kind.isIntSizedType) { jcode.emitIDIV() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLDIV() + case FLOAT => jcode.emitFDIV() + case DOUBLE => jcode.emitDDIV() + } + } + + case REM => + if(kind.isIntSizedType) { jcode.emitIREM() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLREM() + case FLOAT => jcode.emitFREM() + case DOUBLE => jcode.emitDREM() + } + } + + case NOT => + if(kind.isIntSizedType) { jcode.emitPUSH(-1) jcode.emitIXOR() - case LONG => + } else if(kind == LONG) { jcode.emitPUSH(-1l) jcode.emitLXOR() - case _ => + } else { abort("Impossible to negate an " + kind) - } - - case _ => - abort("Unknown arithmetic primitive " + primitive) - } - - case Logical(op, kind) => (op, kind) match { - case (AND, LONG) => - jcode.emitLAND() - case (AND, INT) => - jcode.emitIAND() - case (AND, _) => - jcode.emitIAND() - if (kind != BOOL) - jcode.emitT2T(javaType(INT), javaType(kind)); - - case (OR, LONG) => - jcode.emitLOR() - case (OR, INT) => - jcode.emitIOR() - case (OR, _) => - jcode.emitIOR() - if (kind != BOOL) - jcode.emitT2T(javaType(INT), javaType(kind)); - - case (XOR, LONG) => - jcode.emitLXOR() - case (XOR, INT) => - jcode.emitIXOR() - case (XOR, _) => - jcode.emitIXOR() - if (kind != BOOL) - jcode.emitT2T(javaType(INT), javaType(kind)); - } - - case Shift(op, kind) => (op, kind) match { - case (LSL, LONG) => - jcode.emitLSHL() - case (LSL, INT) => - jcode.emitISHL() - case (LSL, _) => - jcode.emitISHL() - jcode.emitT2T(javaType(INT), javaType(kind)) - - case (ASR, LONG) => - jcode.emitLSHR() - case (ASR, INT) => - jcode.emitISHR() - case (ASR, _) => - jcode.emitISHR() - jcode.emitT2T(javaType(INT), javaType(kind)) - - case (LSR, LONG) => - jcode.emitLUSHR() - case (LSR, INT) => - jcode.emitIUSHR() - case (LSR, _) => - jcode.emitIUSHR() - jcode.emitT2T(javaType(INT), javaType(kind)) - } + } - case Comparison(op, kind) => ((op, kind): @unchecked) match { - case (CMP, LONG) => jcode.emitLCMP() - case (CMPL, FLOAT) => jcode.emitFCMPL() - case (CMPG, FLOAT) => jcode.emitFCMPG() - case (CMPL, DOUBLE) => jcode.emitDCMPL() - case (CMPG, DOUBLE) => jcode.emitDCMPL() - } + case _ => + abort("Unknown arithmetic primitive " + primitive) + } - case Conversion(src, dst) => - debuglog("Converting from: " + src + " to: " + dst) - if (dst == BOOL) { - println("Illegal conversion at: " + clasz + - " at: " + pos.source + ":" + pos.line) - } else - jcode.emitT2T(javaType(src), javaType(dst)) + case Logical(op, kind) => (op, kind) match { + case (AND, LONG) => jcode.emitLAND() + case (AND, INT) => jcode.emitIAND() + case (AND, _) => + jcode.emitIAND() + if (kind != BOOL) + jcode.emitT2T(javaType(INT), javaType(kind)); + + case (OR, LONG) => jcode.emitLOR() + case (OR, INT) => jcode.emitIOR() + case (OR, _) => + jcode.emitIOR() + if (kind != BOOL) + jcode.emitT2T(javaType(INT), javaType(kind)); + + case (XOR, LONG) => jcode.emitLXOR() + case (XOR, INT) => jcode.emitIXOR() + case (XOR, _) => + jcode.emitIXOR() + if (kind != BOOL) + jcode.emitT2T(javaType(INT), javaType(kind)); + } - case ArrayLength(_) => - jcode.emitARRAYLENGTH() + case Shift(op, kind) => (op, kind) match { + case (LSL, LONG) => jcode.emitLSHL() + case (LSL, INT) => jcode.emitISHL() + case (LSL, _) => + jcode.emitISHL() + jcode.emitT2T(javaType(INT), javaType(kind)) + + case (ASR, LONG) => jcode.emitLSHR() + case (ASR, INT) => jcode.emitISHR() + case (ASR, _) => + jcode.emitISHR() + jcode.emitT2T(javaType(INT), javaType(kind)) + + case (LSR, LONG) => jcode.emitLUSHR() + case (LSR, INT) => jcode.emitIUSHR() + case (LSR, _) => + jcode.emitIUSHR() + jcode.emitT2T(javaType(INT), javaType(kind)) + } - case StartConcat => - jcode emitNEW StringBuilderClassName - jcode.emitDUP() - jcode.emitINVOKESPECIAL(StringBuilderClassName, - JMethod.INSTANCE_CONSTRUCTOR_NAME, - JMethodType.ARGLESS_VOID_FUNCTION) - - case StringConcat(el) => - val jtype = el match { - case REFERENCE(_) | ARRAY(_) => JAVA_LANG_OBJECT - case _ => javaType(el) + case Comparison(op, kind) => ((op, kind): @unchecked) match { + case (CMP, LONG) => jcode.emitLCMP() + case (CMPL, FLOAT) => jcode.emitFCMPL() + case (CMPG, FLOAT) => jcode.emitFCMPG() + case (CMPL, DOUBLE) => jcode.emitDCMPL() + case (CMPG, DOUBLE) => jcode.emitDCMPL() } - jcode.emitINVOKEVIRTUAL(StringBuilderClassName, - "append", - new JMethodType(StringBuilderType, - Array(jtype))) - case EndConcat => - jcode.emitINVOKEVIRTUAL(StringBuilderClassName, - "toString", - toStringType) - case _ => - abort("Unimplemented primitive " + primitive) + case Conversion(src, dst) => + debuglog("Converting from: " + src + " to: " + dst) + if (dst == BOOL) { + println("Illegal conversion at: " + clasz + " at: " + pos.source + ":" + pos.line) + } else + jcode.emitT2T(javaType(src), javaType(dst)) + + case ArrayLength(_) => + jcode.emitARRAYLENGTH() + + case StartConcat => + jcode emitNEW StringBuilderClassName + jcode.emitDUP() + jcode.emitINVOKESPECIAL(StringBuilderClassName, + JMethod.INSTANCE_CONSTRUCTOR_NAME, + JMethodType.ARGLESS_VOID_FUNCTION) + + case StringConcat(el) => + val jtype = el match { + case REFERENCE(_) | ARRAY(_) => JAVA_LANG_OBJECT + case _ => javaType(el) + } + jcode.emitINVOKEVIRTUAL(StringBuilderClassName, + "append", + new JMethodType(StringBuilderType, + Array(jtype))) + case EndConcat => + jcode.emitINVOKEVIRTUAL(StringBuilderClassName, + "toString", + toStringType) + + case _ => + abort("Unimplemented primitive " + primitive) + } } - } // genCode starts here genBlocks(linearization) @@ -1823,10 +1848,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with def sizeOf(sym: Symbol): Int = sizeOf(toTypeKind(sym.tpe)) - def sizeOf(k: TypeKind): Int = k match { - case DOUBLE | LONG => 2 - case _ => 1 - } + def sizeOf(k: TypeKind): Int = if(k.isWideType) 2 else 1 def indexOf(m: IMethod, sym: Symbol): Int = { val Some(local) = m lookupLocal sym @@ -1843,9 +1865,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with * method. *Does not assume the parameters come first!* */ def computeLocalVarsIndex(m: IMethod) { - var idx = 1 - if (m.symbol.isStaticMember) - idx = 0; + var idx = if (m.symbol.isStaticMember) 0 else 1; for (l <- m.params) { debuglog("Index value for " + l + "{" + l.## + "}: " + idx) @@ -1904,6 +1924,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with ((sym.rawflags & (Flags.FINAL | Flags.MODULE)) != 0) && !sym.enclClass.isInterface && !sym.isClassConstructor + && !sym.isMutable // fix for SI-3569, it is too broad? ) mkFlags( diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala index 93d3d19ac8..b74981b999 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala @@ -54,14 +54,6 @@ trait GenJVMUtil { LE -> JExtendedCode.COND_LE, GE -> JExtendedCode.COND_GE ) - val negate = immutable.Map[TestOp, TestOp]( - EQ -> NE, - NE -> EQ, - LT -> GE, - GT -> LE, - LE -> GT, - GE -> LT - ) /** Specialized array conversion to prevent calling * java.lang.reflect.Array.newInstance via TraversableOnce.toArray @@ -85,12 +77,10 @@ trait GenJVMUtil { */ def javaName(sym: Symbol): String = javaNameCache.getOrElseUpdate(sym, { - sym.name.newName( - if (sym.isClass || (sym.isModule && !sym.isMethod)) - sym.javaBinaryName - else - sym.javaSimpleName - ) + if (sym.isClass || (sym.isModule && !sym.isMethod)) + sym.javaBinaryName + else + sym.javaSimpleName }).toString def javaType(t: TypeKind): JType = (t: @unchecked) match { diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index e8abee7d06..ff45bb8fd1 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -108,7 +108,7 @@ abstract class ClosureElimination extends SubComponent { case LOAD_LOCAL(l) if info.bindings isDefinedAt LocalVar(l) => val t = info.getBinding(l) t match { - case Deref(LocalVar(_)) | Deref(This) | Const(_) => + case Deref(This) | Const(_) => bb.replaceInstruction(i, valueToInstruction(t)); log("replaced " + i + " with " + t) diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index e91bab8367..a734b2b92b 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -707,7 +707,8 @@ abstract class Inliners extends SubComponent { } def isStampedForInlining(stackLength: Int) = - !sameSymbols && inc.m.hasCode && shouldInline && isSafeToInline(stackLength) && !inc.m.symbol.hasFlag(Flags.SYNCHRONIZED) + !sameSymbols && inc.m.hasCode && shouldInline && + isSafeToInline(stackLength) // `isSafeToInline()` must be invoked last in this AND expr bc it mutates the `knownSafe` and `knownUnsafe` maps for good. def logFailure(stackLength: Int) = log( """|inline failed for %s: @@ -765,8 +766,8 @@ abstract class Inliners extends SubComponent { true } - if (!inc.m.hasCode || inc.isRecursive) - return false + if (!inc.m.hasCode || inc.isRecursive) { return false } + if (inc.m.symbol.hasFlag(Flags.SYNCHRONIZED)) { return false } val accessNeeded = usesNonPublics.getOrElseUpdate(inc.m, { // Avoiding crashing the compiler if there are open blocks. diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index f2d59206e0..1b91b06942 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -10,6 +10,8 @@ import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.util.{SourceFile, Position, WorkScheduler} import scala.tools.nsc.symtab._ import scala.tools.nsc.ast._ +import scala.tools.nsc.util.FailedInterrupt +import scala.tools.nsc.util.EmptyAction /** Interface of interactive compiler to a client such as an IDE * The model the presentation compiler consists of the following parts: @@ -48,7 +50,7 @@ trait CompilerControl { self: Global => /** The scheduler by which client and compiler communicate * Must be initialized before starting compilerRunner */ - protected[interactive] val scheduler = new WorkScheduler + @volatile protected[interactive] var scheduler = new WorkScheduler /** Return the compilation unit attached to a source file, or None * if source is not loaded. @@ -374,6 +376,25 @@ trait CompilerControl { self: Global => response raise new MissingResponse } + /** A do-nothing work scheduler that responds immediately with MissingResponse. + * + * Used during compiler shutdown. + */ + class NoWorkScheduler extends WorkScheduler { + + override def postWorkItem(action: Action) = synchronized { + action match { + case w: WorkItem => w.raiseMissing() + case e: EmptyAction => // do nothing + case _ => println("don't know what to do with this " + action.getClass) + } + } + + override def doQuickly[A](op: () => A): A = { + throw new FailedInterrupt(new Exception("Posted a work item to a compiler that's shutting down")) + } + } + } // ---------------- Interpreted exceptions ------------------- diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 477cec8c8e..166b38f503 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -357,6 +357,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") checkNoResponsesOutstanding() log.flush(); + scheduler = new NoWorkScheduler throw ShutdownReq } @@ -609,6 +610,15 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } response raise ex throw ex + + case ex @ ShutdownReq => + if (debugIDE) { + println("ShutdownReq thrown during response") + ex.printStackTrace() + } + response raise ex + throw ex + case ex => if (debugIDE) { println("exception thrown during response: "+ex) diff --git a/src/compiler/scala/tools/nsc/io/Pickler.scala b/src/compiler/scala/tools/nsc/io/Pickler.scala index 5bb8bdda35..80b6e086da 100644 --- a/src/compiler/scala/tools/nsc/io/Pickler.scala +++ b/src/compiler/scala/tools/nsc/io/Pickler.scala @@ -165,7 +165,7 @@ object Pickler { def pkl[T: Pickler] = implicitly[Pickler[T]] /** A class represenenting `~`-pairs */ - case class ~[S, T](fst: S, snd: T) + case class ~[+S, +T](fst: S, snd: T) /** A wrapper class to be able to use `~` s an infix method */ class TildeDecorator[S](x: S) { diff --git a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala index 5e46960d04..371f4bc4d8 100644 --- a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala +++ b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala @@ -115,6 +115,10 @@ trait MatchSupport extends ast.TreeDSL { self: ParallelMatching => println(fmt.format(xs: _*) + " == " + x) x } + private[nsc] def debugging[T](fmt: String, xs: Any*)(x: T): T = { + if (settings.debug.value) printing(fmt, xs: _*)(x) + else x + } def indent(s: Any) = s.toString() split "\n" map (" " + _) mkString "\n" def indentAll(s: Seq[Any]) = s map (" " + _.toString() + "\n") mkString diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index d81f05cd51..e1ff88557e 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -198,6 +198,10 @@ trait Matrix extends MatrixAdditions { class PatternVar(val lhs: Symbol, val rhs: Tree, val checked: Boolean) { def sym = lhs def tpe = lhs.tpe + if (checked) + lhs resetFlag NO_EXHAUSTIVE + else + lhs setFlag NO_EXHAUSTIVE // See #1427 for an example of a crash which occurs unless we retype: // in that instance there is an existential in the pattern. @@ -207,11 +211,6 @@ trait Matrix extends MatrixAdditions { override def toString() = "%s: %s = %s".format(lhs, tpe, rhs) } - /** Sets the rhs to EmptyTree, which makes the valDef ignored in Scrutinee. - */ - def specialVar(lhs: Symbol, checked: Boolean) = - new PatternVar(lhs, EmptyTree, checked) - /** Given a tree, creates a new synthetic variable of the same type * and assigns the tree to it. */ diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala index 24d3c38e74..e72a0007a0 100644 --- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala +++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala @@ -131,23 +131,11 @@ trait MatrixAdditions extends ast.TreeDSL { import Flags.{ MUTABLE, ABSTRACT, SEALED } - private case class Combo(index: Int, sym: Symbol) { - val isBaseClass = sym.tpe.baseClasses.toSet - - // is this combination covered by the given pattern? - def isCovered(p: Pattern) = { - def coversSym = isBaseClass(decodedEqualsType(p.tpe).typeSymbol) - - cond(p.tree) { - case _: UnApply | _: ArrayValue => true - case x => p.isDefault || coversSym - } - } - } + private case class Combo(index: Int, sym: Symbol) { } /* True if the patterns in 'row' cover the given type symbol combination, and has no guard. */ private def rowCoversCombo(row: Row, combos: List[Combo]) = - row.guard.isEmpty && (combos forall (c => c isCovered row.pats(c.index))) + row.guard.isEmpty && combos.forall(c => row.pats(c.index) covers c.sym) private def requiresExhaustive(sym: Symbol) = { (sym.isMutable) && // indicates that have not yet checked exhaustivity diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 9d4c9b4411..1285e29d4a 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -745,7 +745,7 @@ trait ParallelMatching extends ast.TreeDSL (others.head :: _column.tail, make(_tvars, _rows)) def mix() = { - val newScrut = new Scrutinee(specialVar(_pv.sym, _pv.checked)) + val newScrut = new Scrutinee(new PatternVar(_pv.sym, EmptyTree, _pv.checked)) PatternMatch(newScrut, _ncol) mkRule _nrep } } diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala index 5dd7d8f3ee..56297f0195 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala @@ -19,9 +19,10 @@ trait PatternBindings extends ast.TreeDSL import Debug._ /** EqualsPattern **/ - def isEquals(tpe: Type) = cond(tpe) { case TypeRef(_, EqualsPatternClass, _) => true } + def isEquals(tpe: Type) = tpe.typeSymbol == EqualsPatternClass def mkEqualsRef(tpe: Type) = typeRef(NoPrefix, EqualsPatternClass, List(tpe)) - def decodedEqualsType(tpe: Type) = condOpt(tpe) { case TypeRef(_, EqualsPatternClass, List(arg)) => arg } getOrElse (tpe) + def decodedEqualsType(tpe: Type) = + if (tpe.typeSymbol == EqualsPatternClass) tpe.typeArgs.head else tpe // A subtype test which creates fresh existentials for type // parameters on the right hand side. diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 18409cfffe..8bdf83fda4 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -26,19 +26,6 @@ trait Patterns extends ast.TreeDSL { type PatternMatch = MatchMatrix#PatternMatch private type PatternVar = MatrixContext#PatternVar - // private def unapplyArgs(x: Any) = x match { - // case UnApply(Apply(TypeApply(_, targs), args), _) => (targs map (_.symbol), args map (_.symbol)) - // case _ => (Nil, Nil) - // } - // - // private def unapplyCall(x: Any) = x match { - // case UnApply(t, _) => treeInfo.methPart(t).symbol - // case _ => NoSymbol - // } - - private lazy val dummyMethod = - NoSymbol.newTermSymbol(newTermName("matching$dummy")) - // Fresh patterns def emptyPatterns(i: Int): List[Pattern] = List.fill(i)(NoPattern) def emptyTrees(i: Int): List[Tree] = List.fill(i)(EmptyTree) @@ -56,13 +43,14 @@ trait Patterns extends ast.TreeDSL { case class VariablePattern(tree: Ident) extends NamePattern { lazy val Ident(name) = tree require(isVarPattern(tree) && name != nme.WILDCARD) - + override def covers(sym: Symbol) = true override def description = "%s".format(name) } // 8.1.1 (b) case class WildcardPattern() extends Pattern { def tree = EmptyTree + override def covers(sym: Symbol) = true override def isDefault = true override def description = "_" } @@ -71,6 +59,8 @@ trait Patterns extends ast.TreeDSL { case class TypedPattern(tree: Typed) extends Pattern { lazy val Typed(expr, tpt) = tree + override def covers(sym: Symbol) = newMatchesPattern(sym, tpt.tpe) + override def sufficientType = tpt.tpe override def subpatternsForVars: List[Pattern] = List(Pattern(expr)) override def simplify(pv: PatternVar) = Pattern(expr) match { case ExtractorPattern(ua) if pv.sym.tpe <:< tpt.tpe => this rebindTo expr @@ -115,6 +105,7 @@ trait Patterns extends ast.TreeDSL { } } + override def covers(sym: Symbol) = newMatchesPattern(sym, sufficientType) override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = backticked match { case Some(s) => "this." + s @@ -133,13 +124,15 @@ trait Patterns extends ast.TreeDSL { case class ObjectPattern(tree: Apply) extends ApplyPattern { // NamePattern? require(!fn.isType && isModule) + override def covers(sym: Symbol) = newMatchesPattern(sym, sufficientType) override def sufficientType = tpe.narrow override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = "Obj(%s)".format(fn) } // 8.1.4 (e) case class SimpleIdPattern(tree: Ident) extends NamePattern { - lazy val Ident(name) = tree + val Ident(name) = tree + override def covers(sym: Symbol) = newMatchesPattern(sym, tpe.narrow) override def description = "Id(%s)".format(name) } @@ -163,6 +156,11 @@ trait Patterns extends ast.TreeDSL { if (args.isEmpty) this rebindToEmpty tree.tpe else this + override def covers(sym: Symbol) = { + debugging("[constructor] Does " + this + " cover " + sym + " ? ") { + sym.tpe.typeSymbol == this.tpe.typeSymbol + } + } override def description = { if (isColonColon) "%s :: %s".format(Pattern(args(0)), Pattern(args(1))) else "%s(%s)".format(name, toPats(args).mkString(", ")) @@ -175,17 +173,12 @@ trait Patterns extends ast.TreeDSL { // 8.1.7 / 8.1.8 (unapply and unapplySeq calls) case class ExtractorPattern(tree: UnApply) extends UnapplyPattern { - override def simplify(pv: PatternVar) = { - if (pv.sym hasFlag NO_EXHAUSTIVE) () - else { - TRACE("Setting NO_EXHAUSTIVE on " + pv.sym + " due to extractor " + tree) - pv.sym setFlag NO_EXHAUSTIVE - } + private def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe + override def simplify(pv: PatternVar) = { if (pv.tpe <:< arg.tpe) this else this rebindTo uaTyped } - override def description = "Unapply(%s => %s)".format(necessaryType, resTypesString) } @@ -208,6 +201,7 @@ trait Patterns extends ast.TreeDSL { private def listFolder(hd: Tree, tl: Tree): Tree = unbind(hd) match { case t @ Star(_) => moveBindings(hd, WILD(t.tpe)) case _ => + val dummyMethod = NoSymbol.newTermSymbol(newTermName("matching$dummy")) val consType = MethodType(dummyMethod newSyntheticValueParams List(packedType, listRef), consRef) Apply(TypeTree(consType), List(hd, tl)) setType consRef @@ -376,7 +370,7 @@ trait Patterns extends ast.TreeDSL { case _: This if isVariableName(name) => Some("`%s`".format(name)) case _ => None } - + override def covers(sym: Symbol) = newMatchesPattern(sym, tree.tpe) protected def getPathSegments(t: Tree): List[Name] = t match { case Select(q, name) => name :: getPathSegments(q) case Apply(f, Nil) => getPathSegments(f) @@ -395,7 +389,13 @@ trait Patterns extends ast.TreeDSL { lazy val UnApply(unfn, args) = tree lazy val Apply(fn, _) = unfn lazy val MethodType(List(arg, _*), _) = fn.tpe - protected def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe + + // Covers if the symbol matches the unapply method's argument type, + // and the return type of the unapply is Some. + override def covers(sym: Symbol) = newMatchesPattern(sym, arg.tpe) + + // TODO: for alwaysCovers: + // fn.tpe.finalResultType.typeSymbol == SomeClass override def necessaryType = arg.tpe override def subpatternsForVars = args match { @@ -419,6 +419,7 @@ trait Patterns extends ast.TreeDSL { else emptyPatterns(sufficientType.typeSymbol.caseFieldAccessors.size) def isConstructorPattern = fn.isType + override def covers(sym: Symbol) = newMatchesPattern(sym, fn.tpe) } sealed abstract class Pattern extends PatternBindingLogic { @@ -443,6 +444,15 @@ trait Patterns extends ast.TreeDSL { // the subpatterns for this pattern (at the moment, that means constructor arguments) def subpatterns(pm: MatchMatrix#PatternMatch): List[Pattern] = pm.dummies + // if this pattern should be considered to cover the given symbol + def covers(sym: Symbol): Boolean = newMatchesPattern(sym, sufficientType) + def newMatchesPattern(sym: Symbol, pattp: Type) = { + debugging("[" + kindString + "] Does " + pattp + " cover " + sym + " ? ") { + (sym.isModuleClass && (sym.tpe.typeSymbol eq pattp.typeSymbol)) || + (sym.tpe.baseTypeSeq exists (_ matchesPattern pattp)) + } + } + def sym = tree.symbol def tpe = tree.tpe def isEmpty = tree.isEmpty @@ -475,6 +485,7 @@ trait Patterns extends ast.TreeDSL { final override def toString = description def toTypeString() = "%s <: x <: %s".format(necessaryType, sufficientType) + def kindString = "" } /*** Extractors ***/ diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 2412c90962..d54ce78e18 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -257,7 +257,7 @@ abstract class Erasure extends AddInterfaces // Anything which could conceivably be a module (i.e. isn't known to be // a type parameter or similar) must go through here or the signature is // likely to end up with Foo<T>.Empty where it needs Foo<T>.Empty$. - def fullNameInSig(sym: Symbol) = "L" + beforeIcode(sym.javaBinaryName) + def fullNameInSig(sym: Symbol) = "L" + beforeIcode(sym.javaBinaryName.toString) def jsig(tp0: Type, existentiallyBound: List[Symbol] = Nil, toplevel: Boolean = false, primitiveOK: Boolean = true): String = { val tp = tp0.dealias diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 0851dad0c2..88ad458748 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -511,7 +511,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * was both already used for a map and mucho long. So "sClass" is the * specialized subclass of "clazz" throughout this file. */ - val sClass = clazz.owner.newClass(specializedName(clazz, env0).toTypeName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE) + + // SI-5545: Eliminate classes with the same name loaded from the bytecode already present - all we need to do is + // to force .info on them, as their lazy type will be evaluated and the symbols will be eliminated. Unfortunately + // evaluating the info after creating the specialized class will mess the specialized class signature, so we'd + // better evaluate it before creating the new class symbol + val clazzName = specializedName(clazz, env0).toTypeName + val bytecodeClazz = clazz.owner.info.decl(clazzName) + debuglog("Specializing " + clazz + " found " + bytecodeClazz + " already there") + bytecodeClazz.info + + val sClass = clazz.owner.newClass(clazzName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE) def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long) = member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED)) diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 848d6be47b..fdb5c7e52e 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -223,8 +223,25 @@ abstract class TailCalls extends Transform { } tree match { - case dd @ DefDef(_, _, _, vparamss0, _, rhs0) => + case ValDef(_, _, _, _) => + if (tree.symbol.isLazy && tree.symbol.hasAnnotation(TailrecClass)) + unit.error(tree.pos, "lazy vals are not tailcall transformed") + + super.transform(tree) + + case dd @ DefDef(_, _, _, vparamss0, _, rhs0) if !dd.symbol.hasAccessorFlag => val newCtx = new Context(dd) + def isRecursiveCall(t: Tree) = { + val sym = t.symbol + (sym != null) && { + sym.isMethod && (dd.symbol.name == sym.name) && (dd.symbol.enclClass isSubClass sym.enclClass) + } + } + if (newCtx.isMandatory) { + if (!rhs0.exists(isRecursiveCall)) { + unit.error(tree.pos, "@tailrec annotated method contains no recursive calls") + } + } debuglog("Considering " + dd.name + " for tailcalls") val newRHS = transform(rhs0, newCtx) @@ -248,7 +265,7 @@ abstract class TailCalls extends Transform { )) } else { - if (newCtx.isMandatory) + if (newCtx.isMandatory && newRHS.exists(isRecursiveCall)) newCtx.tailrecFailure() newRHS diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index afe0b42167..d7b4171c65 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -726,7 +726,6 @@ trait ContextErrors { // we have to set the type of tree to ErrorType only in the very last // fallback action that is done in the inference (tracking it manually is error prone). // This avoids entering infinite loop in doTypeApply. - // TODO: maybe we should do the same thing with inferExprAlternative. if (implicitly[Context].reportErrors) setError(tree) } @@ -736,6 +735,8 @@ trait ContextErrors { "argument types " + argtpes.mkString("(", ",", ")") + (if (pt == WildcardType) "" else " and expected result type " + pt) val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, msg0) + // discover last attempt in a similar way as for NoBestMethodAlternativeError + if (implicitly[Context].ambiguousErrors) setError(tree) issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg)) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 90e07023bb..2c564c097f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -312,13 +312,14 @@ trait Contexts { self: Analyzer => unit.error(pos, if (checking) "\n**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg) def issue(err: AbsTypeError) { - if (settings.debug.value) println("issue error: " + err.errMsg) + debugwarn("issue error: " + err.errMsg) if (reportErrors) unitError(err.errPos, addDiagString(err.errMsg)) else if (bufferErrors) { buffer += err } else throw new TypeError(err.errPos, err.errMsg) } def issueAmbiguousError(pre: Type, sym1: Symbol, sym2: Symbol, err: AbsTypeError) { + debugwarn("issue ambiguous error: " + err.errMsg) if (ambiguousErrors) { if (!pre.isErroneous && !sym1.isErroneous && !sym2.isErroneous) unitError(err.errPos, err.errMsg) @@ -327,6 +328,7 @@ trait Contexts { self: Analyzer => } def issueAmbiguousError(err: AbsTypeError) { + debugwarn("issue ambiguous error: " + err.errMsg) if (ambiguousErrors) unitError(err.errPos, addDiagString(err.errMsg)) else if (bufferErrors) { buffer += err } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index c09e535117..c0c801910c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1051,49 +1051,74 @@ trait Infer { * @param pt the expected result type of the instance */ def inferConstructorInstance(tree: Tree, undetparams: List[Symbol], pt0: Type) { - val pt = widen(pt0) - //println("infer constr inst "+tree+"/"+undetparams+"/"+pt0) - var restpe = tree.tpe.finalResultType - var tvars = undetparams map freshVar + val pt = widen(pt0) + val ptparams = freeTypeParamsOfTerms.collect(pt) + val ctorTp = tree.tpe + val resTp = ctorTp.finalResultType - /** Compute type arguments for undetermined params and substitute them in given tree. + debuglog("infer constr inst "+ tree +"/"+ undetparams +"/ pt= "+ pt +" pt0= "+ pt0 +" resTp: "+ resTp) + + /** Compute type arguments for undetermined params */ - def computeArgs = - try { - val targs = solvedTypes(tvars, undetparams, undetparams map varianceInType(restpe), - true, lubDepth(List(restpe, pt))) -// checkBounds(tree, NoPrefix, NoSymbol, undetparams, targs, "inferred ") -// no checkBounds here. If we enable it, test bug602 fails. - new TreeTypeSubstituter(undetparams, targs).traverse(tree) - } catch ifNoInstance{ msg => - NoConstructorInstanceError(tree, restpe, pt, msg) + def inferFor(pt: Type): Option[List[Type]] = { + val tvars = undetparams map freshVar + val resTpV = resTp.instantiateTypeParams(undetparams, tvars) + + if (resTpV <:< pt) { + try { + // debuglog("TVARS "+ (tvars map (_.constr))) + // look at the argument types of the primary constructor corresponding to the pattern + val variances = undetparams map varianceInType(ctorTp.paramTypes.headOption getOrElse ctorTp) + val targs = solvedTypes(tvars, undetparams, variances, true, lubDepth(List(resTp, pt))) + // checkBounds(tree, NoPrefix, NoSymbol, undetparams, targs, "inferred ") + // no checkBounds here. If we enable it, test bug602 fails. + // TODO: reinstate checkBounds, return params that fail to meet their bounds to undetparams + Some(targs) + } catch ifNoInstance { msg => + debuglog("NO INST "+ (tvars, tvars map (_.constr))) + NoConstructorInstanceError(tree, resTp, pt, msg) + None + } + } else { + debuglog("not a subtype: "+ resTpV +" </:< "+ pt) + None } - def instError = { - if (settings.debug.value) Console.println("ici " + tree + " " + undetparams + " " + pt) - if (settings.explaintypes.value) explainTypes(restpe.instantiateTypeParams(undetparams, tvars), pt) - ConstrInstantiationError(tree, restpe, pt) } - if (restpe.instantiateTypeParams(undetparams, tvars) <:< pt) { - computeArgs - } else if (isFullyDefined(pt)) { - debuglog("infer constr " + tree + ":" + restpe + ", pt = " + pt) - var ptparams = freeTypeParamsOfTerms.collect(pt) - debuglog("free type params = " + ptparams) - val ptWithWildcards = pt.instantiateTypeParams(ptparams, ptparams map (ptparam => WildcardType)) - tvars = undetparams map freshVar - if (restpe.instantiateTypeParams(undetparams, tvars) <:< ptWithWildcards) { - computeArgs - restpe = skipImplicit(tree.tpe.resultType) - debuglog("new tree = " + tree + ":" + restpe) - val ptvars = ptparams map freshVar - val pt1 = pt.instantiateTypeParams(ptparams, ptvars) - if (isPopulated(restpe, pt1)) { - ptvars foreach instantiateTypeVar - } else { if (settings.debug.value) Console.println("no instance: "); instError } - } else { if (settings.debug.value) Console.println("not a subtype " + restpe.instantiateTypeParams(undetparams, tvars) + " of " + ptWithWildcards); instError } - } else { if (settings.debug.value) Console.println("not fully defined: " + pt); instError } + + def inferForApproxPt = + if (isFullyDefined(pt)) { + inferFor(pt.instantiateTypeParams(ptparams, ptparams map (x => WildcardType))) flatMap { targs => + val ctorTpInst = tree.tpe.instantiateTypeParams(undetparams, targs) + val resTpInst = skipImplicit(ctorTpInst.finalResultType) + val ptvars = + ptparams map { + // since instantiateTypeVar wants to modify the skolem that corresponds to the method's type parameter, + // and it uses the TypeVar's origin to locate it, deskolemize the existential skolem to the method tparam skolem + // (the existential skolem was created by adaptConstrPattern to introduce the type slack necessary to soundly deal with variant type parameters) + case skolem if skolem.isExistentialSkolem => freshVar(skolem.deSkolemize.asInstanceOf[TypeSymbol]) + case p => freshVar(p) + } + + val ptV = pt.instantiateTypeParams(ptparams, ptvars) + + if (isPopulated(resTpInst, ptV)) { + ptvars foreach instantiateTypeVar + debuglog("isPopulated "+ resTpInst +", "+ ptV +" vars= "+ ptvars) + Some(targs) + } else None + } + } else None + + (inferFor(pt) orElse inferForApproxPt) map { targs => + new TreeTypeSubstituter(undetparams, targs).traverse(tree) + } getOrElse { + debugwarn("failed inferConstructorInstance for "+ tree +" : "+ tree.tpe +" under "+ undetparams +" pt = "+ pt +(if(isFullyDefined(pt)) " (fully defined)" else " (not fully defined)")) + // if (settings.explaintypes.value) explainTypes(resTp.instantiateTypeParams(undetparams, tvars), pt) + ConstrInstantiationError(tree, resTp, pt) + } } + def instBounds(tvar: TypeVar): (Type, Type) = { val tparam = tvar.origin.typeSymbol val instType = toOrigin(tvar.constr.inst) @@ -1385,9 +1410,10 @@ trait Infer { case _ => } } + // todo: missing test case NoBestExprAlternativeError(tree, pt) } else if (!competing.isEmpty) { - if (secondTry) NoBestExprAlternativeError(tree, pt) + if (secondTry) { NoBestExprAlternativeError(tree, pt); setError(tree) } else if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt) } else { // val applicable = alts1 filter (alt => @@ -1492,14 +1518,12 @@ trait Infer { if (improves(alt, best)) alt else best) val competing = applicable.dropWhile(alt => best == alt || improves(best, alt)) if (best == NoSymbol) { - if (pt == WildcardType) - NoBestMethodAlternativeError(tree, argtpes, pt) - else - inferMethodAlternative(tree, undetparams, argtpes, WildcardType) + if (pt == WildcardType) NoBestMethodAlternativeError(tree, argtpes, pt) + else inferMethodAlternative(tree, undetparams, argtpes, WildcardType) } else if (!competing.isEmpty) { if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous) AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt) - setError(tree) + else setError(tree) () } else { // checkNotShadowed(tree.pos, pre, best, applicable) diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 161e4b7a9a..e43b1fab0b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -139,7 +139,7 @@ trait Macros { self: Analyzer => sym.fullName + suffix case sym => val separator = if (sym.owner.isModuleClass) "" else "$" - recur(sym.owner) + separator + sym.javaSimpleName + recur(sym.owner) + separator + sym.javaSimpleName.toString } if (sym.isClass || sym.isModule) recur(sym) diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 5318268bf2..243e685b13 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -24,7 +24,7 @@ import symtab.Flags._ */ abstract class SuperAccessors extends transform.Transform with transform.TypingTransformers { import global._ - import definitions.{ UnitClass, isRepeatedParamType, isByNameParamType, Any_asInstanceOf } + import definitions.{ UnitClass, ObjectClass, isRepeatedParamType, isByNameParamType, Any_asInstanceOf } import analyzer.{ restrictionError } /** the following two members override abstract members in Transform */ @@ -34,6 +34,12 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT new SuperAccTransformer(unit) class SuperAccTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { + /** validCurrentOwner arrives undocumented, but I reverse engineer it to be + * a flag for needsProtectedAccessor which is false while transforming either + * a by-name argument block or a closure. This excludes them from being + * considered able to access protected members via subclassing (why?) which in turn + * increases the frequency with which needsProtectedAccessor will be true. + */ private var validCurrentOwner = true private val accDefs = mutable.Map[Symbol, ListBuffer[Tree]]() @@ -41,6 +47,25 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val buf = accDefs.getOrElse(clazz, sys.error("no acc def buf for "+clazz)) buf += typers(clazz) typed tree } + private def ensureAccessor(sel: Select) = { + val Select(qual, name) = sel + val sym = sel.symbol + val clazz = qual.symbol + val supername = nme.superName(name) + val superAcc = clazz.info.decl(supername).suchThat(_.alias == sym) orElse { + debuglog("add super acc " + sym + sym.locationString + " to `" + clazz);//debug + val acc = clazz.newMethod(supername, sel.pos, SUPERACCESSOR | PRIVATE) setAlias sym + val tpe = clazz.thisType memberType sym match { + case t if sym.isModule && !sym.isMethod => NullaryMethodType(t) + case t => t + } + acc setInfoAndEnter (tpe cloneInfo acc) + storeAccessorDefinition(clazz, DefDef(acc, EmptyTree)) + acc + } + + atPos(sel.pos)(Select(gen.mkAttributedThis(clazz), superAcc) setType sel.tpe) + } private def transformArgs(params: List[Symbol], args: List[Tree]) = { treeInfo.mapMethodParamsAndArgs(params, args) { (param, arg) => @@ -88,42 +113,21 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } } - private def transformSuperSelect(tree: Tree): Tree = tree match { - case Select(sup @ Super(_, mix), name) => - val sym = tree.symbol - val clazz = sup.symbol - - if (sym.isDeferred) { - val member = sym.overridingSymbol(clazz); - if (mix != tpnme.EMPTY || member == NoSymbol || - !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz))) - unit.error(tree.pos, ""+sym+sym.locationString+" is accessed from super. It may not be abstract "+ - "unless it is overridden by a member declared `abstract' and `override'"); - } - if (tree.isTerm && mix == tpnme.EMPTY && - (clazz.isTrait || clazz != currentOwner.enclClass || !validCurrentOwner)) { - val supername = nme.superName(sym.name) - var superAcc = clazz.info.decl(supername).suchThat(_.alias == sym) - if (superAcc == NoSymbol) { - debuglog("add super acc " + sym + sym.locationString + " to `" + clazz);//debug - superAcc = clazz.newMethod(supername, tree.pos, SUPERACCESSOR | PRIVATE) setAlias sym - var superAccTpe = clazz.thisType.memberType(sym) - if (sym.isModule && !sym.isMethod) { - // the super accessor always needs to be a method. See #231 - superAccTpe = NullaryMethodType(superAccTpe) - } - superAcc setInfoAndEnter (superAccTpe cloneInfo superAcc) - storeAccessorDefinition(clazz, DefDef(superAcc, EmptyTree)) - } - atPos(sup.pos) { - Select(gen.mkAttributedThis(clazz), superAcc) setType tree.tpe; - } - } else { - tree - } - case _ => - assert(tree.tpe.isError, tree) - tree + private def transformSuperSelect(sel: Select): Tree = { + val Select(sup @ Super(_, mix), name) = sel + val sym = sel.symbol + val clazz = sup.symbol + + if (sym.isDeferred) { + val member = sym.overridingSymbol(clazz); + if (mix != tpnme.EMPTY || member == NoSymbol || + !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz))) + unit.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+ + "unless it is overridden by a member declared `abstract' and `override'"); + } + if (name.isTermName && mix == tpnme.EMPTY && (clazz.isTrait || clazz != currentClass || !validCurrentOwner)) + ensureAccessor(sel) + else sel } // Disallow some super.XX calls targeting Any methods which would @@ -156,9 +160,11 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT for (s <- decls) { if (s.privateWithin.isClass && !s.isProtected && !s.privateWithin.isModuleClass && !s.hasFlag(EXPANDEDNAME) && !s.isConstructor) { + val savedName = s.name decls.unlink(s) s.expandName(s.privateWithin) decls.enter(s) + log("Expanded '%s' to '%s' in %s".format(savedName, s.name, sym)) } } if (settings.verbose.value && forScaladoc && !sym.isAnonymousClass) { @@ -218,24 +224,47 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT // direct calls to aliases of param accessors to the superclass in order to avoid // duplicating fields. if (sym.isParamAccessor && sym.alias != NoSymbol) { - val result = localTyper.typed { - Select( - Super(qual, tpnme.EMPTY/*qual.symbol.info.parents.head.symbol.name*/) setPos qual.pos, - sym.alias) setPos tree.pos - } + val result = (localTyper.typedPos(tree.pos) { + Select(Super(qual, tpnme.EMPTY) setPos qual.pos, sym.alias) + }).asInstanceOf[Select] debuglog("alias replacement: " + tree + " ==> " + result);//debug localTyper.typed(gen.maybeMkAsInstanceOf(transformSuperSelect(result), sym.tpe, sym.alias.tpe, true)) } - else mayNeedProtectedAccessor(sel, List(EmptyTree), false) + else { + /** A trait which extends a class and accesses a protected member + * of that class cannot implement the necessary accessor method + * because its implementation is in an implementation class (e.g. + * Foo$class) which inherits nothing, and jvm access restrictions + * require the call site to be in an actual subclass. So non-trait + * classes inspect their ancestors for any such situations and + * generate the accessors. See SI-2296. + */ + // FIXME - this should be unified with needsProtectedAccessor, but some + // subtlety which presently eludes me is foiling my attempts. + val shouldEnsureAccessor = ( + currentClass.isTrait + && sym.isProtected + && sym.enclClass != currentClass + && !sym.owner.isTrait + && (sym.owner.enclosingPackageClass != currentPackage) + && (qual.symbol.info.member(sym.name) ne NoSymbol) + ) + if (shouldEnsureAccessor) { + log("Ensuring accessor for call to protected " + sym.fullLocationString + " from " + currentClass) + ensureAccessor(sel) + } + else + mayNeedProtectedAccessor(sel, List(EmptyTree), false) + } - case Select(Super(_, mix), name) => + case sel @ Select(Super(_, mix), name) => if (sym.isValue && !sym.isMethod || sym.hasAccessorFlag) { unit.error(tree.pos, "super may be not be used on "+ sym.accessedOrSelf) } else if (isDisallowed(sym)) { unit.error(tree.pos, "super not allowed here: use this." + name.decode + " instead") } - transformSuperSelect(tree) + transformSuperSelect(sel) case TypeApply(sel @ Select(qual, name), args) => mayNeedProtectedAccessor(sel, args, true) @@ -280,11 +309,10 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } private def withInvalidOwner[A](trans: => A): A = { - val prevValidCurrentOwner = validCurrentOwner + val saved = validCurrentOwner validCurrentOwner = false - val result = trans - validCurrentOwner = prevValidCurrentOwner - result + try trans + finally validCurrentOwner = saved } /** Add a protected accessor, if needed, and return a tree that calls @@ -294,7 +322,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT private def makeAccessor(tree: Select, targs: List[Tree]): Tree = { val Select(qual, name) = tree val sym = tree.symbol - val clazz = hostForAccessorOf(sym, currentOwner.enclClass) + val clazz = hostForAccessorOf(sym, currentClass) assert(clazz != NoSymbol, sym) debuglog("Decided for host class: " + clazz) @@ -373,7 +401,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT */ private def makeSetter(tree: Select): Tree = { val field = tree.symbol - val clazz = hostForAccessorOf(field, currentOwner.enclClass) + val clazz = hostForAccessorOf(field, currentClass) assert(clazz != NoSymbol, field) debuglog("Decided for host class: " + clazz) @@ -393,7 +421,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT atPos(tree.pos)(Select(This(clazz), protectedAccessor)) } - /** Does `sym` need an accessor when accessed from `currentOwner`? + /** Does `sym` need an accessor when accessed from `currentClass`? * A special case arises for classes with explicit self-types. If the * self type is a Java class, and a protected accessor is needed, we issue * an error. If the self type is a Scala class, we don't add an accessor. @@ -407,23 +435,20 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT * classes, this has to be signaled as error. */ private def needsProtectedAccessor(sym: Symbol, pos: Position): Boolean = { - val clazz = currentOwner.enclClass + val clazz = currentClass def accessibleThroughSubclassing = validCurrentOwner && clazz.thisSym.isSubClass(sym.owner) && !clazz.isTrait - def packageAccessBoundry(sym: Symbol) = { - val b = sym.accessBoundary(sym.owner) - if (b.isPackageClass) b - else b.enclosingPackageClass - } + def packageAccessBoundry(sym: Symbol) = + sym.accessBoundary(sym.enclosingPackageClass) val isCandidate = ( sym.isProtected && sym.isJavaDefined && !sym.isDefinedInPackage && !accessibleThroughSubclassing - && (sym.owner.enclosingPackageClass != currentOwner.enclosingPackageClass) - && (sym.owner.enclosingPackageClass == packageAccessBoundry(sym)) + && (sym.enclosingPackageClass != currentPackage) + && (sym.enclosingPackageClass == sym.accessBoundary(sym.enclosingPackageClass)) ) val host = hostForAccessorOf(sym, clazz) def isSelfType = !(host.tpe <:< host.typeOfThis) && { @@ -433,15 +458,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT ) true } - def isJavaProtected = host.isTrait && sym.isJavaDefined && { - restrictionError(pos, unit, - """|%s accesses protected %s inside a concrete trait method. - |Add an accessor in a class extending %s as a workaround.""".stripMargin.format( - clazz, sym, sym.enclClass) - ) - true - } - isCandidate && !host.isPackageClass && !isSelfType && !isJavaProtected + isCandidate && !host.isPackageClass && !isSelfType } /** Return the innermost enclosing class C of referencingClass for which either diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 556c680cda..9ff86e69eb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -604,6 +604,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { * 1. Check that non-function pattern expressions are stable * 2. Check that packages and static modules are not used as values * 3. Turn tree type into stable type if possible and required by context. + * 4. Give getClass calls a more precise type based on the type of the target of the call. */ private def stabilize(tree: Tree, pre: Type, mode: Int, pt: Type): Tree = { if (tree.symbol.isOverloaded && !inFunMode(mode)) @@ -627,7 +628,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (sym.isStable && pre.isStable && !isByNameParamType(tree.tpe) && (isStableContext(tree, mode, pt) || sym.isModule && !sym.isMethod)) tree.setType(singleType(pre, sym)) - else tree + // To fully benefit from special casing the return type of + // getClass, we have to catch it immediately so expressions + // like x.getClass().newInstance() are typed with the type of x. + else if ( tree.symbol.name == nme.getClass_ + && tree.tpe.params.isEmpty + // TODO: If the type of the qualifier is inaccessible, we can cause private types + // to escape scope here, e.g. pos/t1107. I'm not sure how to properly handle this + // so for now it requires the type symbol be public. + && pre.typeSymbol.isPublic) + tree setType MethodType(Nil, erasure.getClassReturnType(pre)) + else + tree } } @@ -852,6 +864,33 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } + /** + * To deal with the type slack between actual (run-time) types and statically known types, for each abstract type T, + * reflect its variance as a skolem that is upper-bounded by T (covariant position), or lower-bounded by T (contravariant). + * + * Consider the following example: + * + * class AbsWrapperCov[+A] + * case class Wrapper[B](x: Wrapped[B]) extends AbsWrapperCov[B] + * + * def unwrap[T](x: AbsWrapperCov[T]): Wrapped[T] = x match { + * case Wrapper(wrapped) => // Wrapper's type parameter must not be assumed to be equal to T, it's *upper-bounded* by it + * wrapped // : Wrapped[_ <: T] + * } + * + * this method should type check if and only if Wrapped is covariant in its type parameter + * + * when inferring Wrapper's type parameter B from x's type AbsWrapperCov[T], + * we must take into account that x's actual type is AbsWrapperCov[Tactual] forSome {type Tactual <: T} + * as AbsWrapperCov is covariant in A -- in other words, we must not assume we know T exactly, all we know is its upper bound + * + * since method application is the only way to generate this slack between run-time and compile-time types (TODO: right!?), + * we can simply replace skolems that represent method type parameters as seen from the method's body + * by other skolems that are (upper/lower)-bounded by that type-parameter skolem + * (depending on the variance position of the skolem in the statically assumed type of the scrutinee, pt) + * + * see test/files/../t5189*.scala + */ def adaptConstrPattern(): Tree = { // (5) val extractor = tree.symbol.filter(sym => reallyExists(unapplyMember(sym.tpe))) if (extractor != NoSymbol) { @@ -865,7 +904,32 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner)) .setOriginal(tree) - inferConstructorInstance(tree1, clazz.typeParams, pt) + val skolems = new mutable.ListBuffer[TypeSymbol] + object variantToSkolem extends VariantTypeMap { + def apply(tp: Type) = mapOver(tp) match { + case TypeRef(NoPrefix, tpSym, Nil) if variance != 0 && tpSym.isTypeParameterOrSkolem && tpSym.owner.isTerm => + val bounds = if (variance == 1) TypeBounds.upper(tpSym.tpe) else TypeBounds.lower(tpSym.tpe) + val skolem = context.owner.newExistentialSkolem(tpSym, tpSym, unit.freshTypeName("?"+tpSym.name), bounds) + // println("mapping "+ tpSym +" to "+ skolem + " : "+ bounds +" -- pt= "+ pt) + skolems += skolem + skolem.tpe + case tp1 => tp1 + } + } + + // have to open up the existential and put the skolems in scope + // can't simply package up pt in an ExistentialType, because that takes us back to square one (List[_ <: T] == List[T] due to covariance) + val ptSafe = variantToSkolem(pt) // TODO: pt.skolemizeExistential(context.owner, tree) ? + val freeVars = skolems.toList + + // use "tree" for the context, not context.tree: don't make another CaseDef context, + // as instantiateTypeVar's bounds would end up there + val ctorContext = context.makeNewScope(tree, context.owner) + freeVars foreach ctorContext.scope.enter + newTyper(ctorContext).infer.inferConstructorInstance(tree1, clazz.typeParams, ptSafe) + + // tree1's type-slack skolems will be deskolemized (to the method type parameter skolems) + // once the containing CaseDef has been type checked (see typedCase) tree1 } else { tree @@ -1986,15 +2050,35 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val guard1: Tree = if (cdef.guard == EmptyTree) EmptyTree else typed(cdef.guard, BooleanClass.tpe) var body1: Tree = typed(cdef.body, pt) - if (!context.savedTypeBounds.isEmpty) { - body1.tpe = context.restoreTypeBounds(body1.tpe) - if (isFullyDefined(pt) && !(body1.tpe <:< pt)) { - // @M no need for pt.normalize here, is done in erasure + + val contextWithTypeBounds = context.nextEnclosing(_.tree.isInstanceOf[CaseDef]) + if (contextWithTypeBounds.savedTypeBounds nonEmpty) { + body1.tpe = contextWithTypeBounds restoreTypeBounds body1.tpe + + // insert a cast if something typechecked under the GADT constraints, + // but not in real life (i.e., now that's we've reset the method's type skolems' + // infos back to their pre-GADT-constraint state) + if (isFullyDefined(pt) && !(body1.tpe <:< pt)) body1 = typedPos(body1.pos)(gen.mkCast(body1, pt)) - } + } + // body1 = checkNoEscaping.locals(context.scope, pt, body1) - treeCopy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe + val treeWithSkolems = treeCopy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe + + // undo adaptConstrPattern's evil deeds, as they confuse the old pattern matcher + // TODO: Paul, can we do the deskolemization lazily in the old pattern matcher + object deskolemizeOnce extends TypeMap { + def apply(tp: Type): Type = mapOver(tp) match { + case TypeRef(pre, sym, args) if sym.isExistentialSkolem && sym.deSkolemize.isSkolem && sym.deSkolemize.owner.isTerm => + typeRef(NoPrefix, sym.deSkolemize, args) + case tp1 => tp1 + } + } + + new TypeMapTreeSubstituter(deskolemizeOnce).traverse(treeWithSkolems) + + treeWithSkolems // now without skolems, actually } def typedCases(cases: List[CaseDef], pattp: Type, pt: Type): List[CaseDef] = @@ -3802,7 +3886,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (settings.warnSelectNullable.value && isPotentialNullDeference && unit != null) unit.warning(tree.pos, "potential null pointer dereference: "+tree) - val selection = result match { + result match { // could checkAccessible (called by makeAccessible) potentially have skipped checking a type application in qual? case SelectFromTypeTree(qual@TypeTree(), name) if qual.tpe.typeArgs nonEmpty => // TODO: somehow the new qual is not checked in refchecks treeCopy.SelectFromTypeTree( @@ -3824,22 +3908,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case _ => result } - // To fully benefit from special casing the return type of - // getClass, we have to catch it immediately so expressions - // like x.getClass().newInstance() are typed with the type of x. - val isRefinableGetClass = ( - !selection.isErrorTyped - && selection.symbol.name == nme.getClass_ - && selection.tpe.params.isEmpty - // TODO: If the type of the qualifier is inaccessible, we can cause private types - // to escape scope here, e.g. pos/t1107. I'm not sure how to properly handle this - // so for now it requires the type symbol be public. - && qual.tpe.typeSymbol.isPublic - ) - if (isRefinableGetClass) - selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe)) - else - selection } } diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala index 0382304bad..af0d768607 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala @@ -336,29 +336,31 @@ abstract class CPSAnnotationChecker extends CPSUtils { def single(xs: List[AnnotationInfo]) = xs match { case List(x) => x case _ => - global.globalError("not a single cps annotation: " + xs)// FIXME: error message + global.globalError("not a single cps annotation: " + xs) xs(0) } + + def emptyOrSingleList(xs: List[AnnotationInfo]) = if (xs.isEmpty) Nil else List(single(xs)) def transChildrenInOrder(tree: Tree, tpe: Type, childTrees: List[Tree], byName: List[Tree]) = { def inspect(t: Tree): List[AnnotationInfo] = { if (t.tpe eq null) Nil else { val extra: List[AnnotationInfo] = t.tpe match { case _: MethodType | _: PolyType | _: OverloadedType => - // method types, poly types and overloaded types do not obtain cps annotions by propagat - // need to reconstruct transitively from their children. - t match { - case Select(qual, name) => inspect(qual) - case Apply(fun, args) => (fun::args) flatMap inspect - case TypeApply(fun, args) => (fun::args) flatMap inspect - case _ => Nil - } + // method types, poly types and overloaded types do not obtain cps annotions by propagation + // need to reconstruct transitively from their children. + t match { + case Select(qual, name) => inspect(qual) + case Apply(fun, args) => (fun::(transArgList(fun,args).flatten)) flatMap inspect + case TypeApply(fun, args) => (fun::(transArgList(fun,args).flatten)) flatMap inspect + case _ => Nil + } case _ => Nil } val types = cpsParamAnnotation(t.tpe) // TODO: check that it has been adapted and if so correctly - extra ++ (if (types.isEmpty) Nil else List(single(types))) + extra ++ emptyOrSingleList(types) } } val children = childTrees flatMap inspect diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index d98169f21a..1189cc2e38 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -97,13 +97,17 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with case vd @ ValDef(mods, name, tpt, rhs) => // object-level valdefs debuglog("transforming valdef " + vd.symbol) - atOwner(vd.symbol) { + if (getExternalAnswerTypeAnn(tpt.tpe).isEmpty) { + + atOwner(vd.symbol) { - assert(getExternalAnswerTypeAnn(tpt.tpe) == None) + val rhs1 = transExpr(rhs, None, None) - val rhs1 = transExpr(rhs, None, None) - - treeCopy.ValDef(vd, mods, name, transform(tpt), rhs1) + treeCopy.ValDef(vd, mods, name, transform(tpt), rhs1) + } + } else { + unit.error(tree.pos, "cps annotations not allowed on by-value parameters or value definitions") + super.transform(tree) } case TypeTree() => diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index 8ca312afc5..1b01355108 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -46,10 +46,10 @@ case class StringContext(parts: String*) { checkLengths(args: _*) val pi = parts.iterator val ai = args.iterator - val bldr = new java.lang.StringBuilder(treatEscapes(pi.next)) + val bldr = new java.lang.StringBuilder(treatEscapes(pi.next())) while (ai.hasNext) { bldr append ai.next - bldr append treatEscapes(pi.next) + bldr append treatEscapes(pi.next()) } bldr.toString } @@ -89,11 +89,12 @@ case class StringContext(parts: String*) { val bldr = new java.lang.StringBuilder val args1 = new ArrayBuffer[Any] def copyString(first: Boolean): Unit = { - val str = treatEscapes(pi.next) + val str = treatEscapes(pi.next()) + val strIsEmpty = str.length == 0 var start = 0 var idx = 0 if (!first) { - if ((str charAt 0) != '%') + if (strIsEmpty || (str charAt 0) != '%') bldr append "%s" idx = 1 } @@ -106,11 +107,11 @@ case class StringContext(parts: String*) { } idx += 1 } - bldr append (str substring (start, idx)) + if (!strIsEmpty) bldr append (str substring (start, idx)) } copyString(first = true) while (pi.hasNext) { - args1 += ai.next + args1 += ai.next() copyString(first = false) } bldr.toString format (args1: _*) diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index d5011fc6aa..50919e506a 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -69,7 +69,7 @@ object JavaConversions { * @return A Java Iterator view of the argument. */ implicit def asJavaIterator[A](it: Iterator[A]): ju.Iterator[A] = it match { - case JIteratorWrapper(wrapped) => wrapped + case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] case _ => IteratorWrapper(it) } @@ -87,7 +87,7 @@ object JavaConversions { * @return A Java Enumeration view of the argument. */ implicit def asJavaEnumeration[A](it: Iterator[A]): ju.Enumeration[A] = it match { - case JEnumerationWrapper(wrapped) => wrapped + case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]] case _ => IteratorWrapper(it) } @@ -105,7 +105,7 @@ object JavaConversions { * @return A Java Iterable view of the argument. */ implicit def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match { - case JIterableWrapper(wrapped) => wrapped + case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] case _ => IterableWrapper(i) } @@ -121,7 +121,7 @@ object JavaConversions { * @return A Java Collection view of the argument. */ implicit def asJavaCollection[A](it: Iterable[A]): ju.Collection[A] = it match { - case JCollectionWrapper(wrapped) => wrapped + case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] case _ => new IterableWrapper(it) } @@ -179,7 +179,7 @@ object JavaConversions { * @return A Java List view of the argument. */ implicit def seqAsJavaList[A](seq: Seq[A]): ju.List[A] = seq match { - case JListWrapper(wrapped) => wrapped + case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] case _ => new SeqWrapper(seq) } @@ -286,7 +286,7 @@ object JavaConversions { */ implicit def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match { //case JConcurrentMapWrapper(wrapped) => wrapped - case JMapWrapper(wrapped) => wrapped + case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]] case _ => new MapWrapper(m) } diff --git a/src/library/scala/collection/immutable/IntMap.scala b/src/library/scala/collection/immutable/IntMap.scala index dd6b066878..3c9c0c2f24 100644 --- a/src/library/scala/collection/immutable/IntMap.scala +++ b/src/library/scala/collection/immutable/IntMap.scala @@ -353,19 +353,19 @@ extends AbstractMap[Int, T] def unionWith[S >: T](that : IntMap[S], f : (Int, S, S) => S) : IntMap[S] = (this, that) match{ case (IntMap.Bin(p1, m1, l1, r1), that@(IntMap.Bin(p2, m2, l2, r2))) => if (shorter(m1, m2)) { - if (!hasMatch(p2, p1, m1)) join(p1, this, p2, that); + if (!hasMatch(p2, p1, m1)) join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed else if (zero(p2, m1)) IntMap.Bin(p1, m1, l1.unionWith(that, f), r1); else IntMap.Bin(p1, m1, l1, r1.unionWith(that, f)); } else if (shorter(m2, m1)){ - if (!hasMatch(p1, p2, m2)) join(p1, this, p2, that); + if (!hasMatch(p1, p2, m2)) join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed else if (zero(p1, m2)) IntMap.Bin(p2, m2, this.unionWith(l2, f), r2); else IntMap.Bin(p2, m2, l2, this.unionWith(r2, f)); } else { if (p1 == p2) IntMap.Bin(p1, m1, l1.unionWith(l2,f), r1.unionWith(r2, f)); - else join(p1, this, p2, that); + else join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed } - case (IntMap.Tip(key, value), x) => x.updateWith(key, value, (x, y) => f(key, y, x)); + case (IntMap.Tip(key, value), x) => x.updateWith[S](key, value, (x, y) => f(key, y, x)); case (x, IntMap.Tip(key, value)) => x.updateWith[S](key, value, (x, y) => f(key, x, y)); case (IntMap.Nil, x) => x; case (x, IntMap.Nil) => x; diff --git a/src/library/scala/collection/immutable/LongMap.scala b/src/library/scala/collection/immutable/LongMap.scala index 963ddac762..11b5d1e311 100644 --- a/src/library/scala/collection/immutable/LongMap.scala +++ b/src/library/scala/collection/immutable/LongMap.scala @@ -349,19 +349,19 @@ extends AbstractMap[Long, T] def unionWith[S >: T](that : LongMap[S], f : (Long, S, S) => S) : LongMap[S] = (this, that) match{ case (LongMap.Bin(p1, m1, l1, r1), that@(LongMap.Bin(p2, m2, l2, r2))) => if (shorter(m1, m2)) { - if (!hasMatch(p2, p1, m1)) join(p1, this, p2, that); + if (!hasMatch(p2, p1, m1)) join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed else if (zero(p2, m1)) LongMap.Bin(p1, m1, l1.unionWith(that, f), r1); else LongMap.Bin(p1, m1, l1, r1.unionWith(that, f)); } else if (shorter(m2, m1)){ - if (!hasMatch(p1, p2, m2)) join(p1, this, p2, that); + if (!hasMatch(p1, p2, m2)) join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed else if (zero(p1, m2)) LongMap.Bin(p2, m2, this.unionWith(l2, f), r2); else LongMap.Bin(p2, m2, l2, this.unionWith(r2, f)); } else { if (p1 == p2) LongMap.Bin(p1, m1, l1.unionWith(l2,f), r1.unionWith(r2, f)); - else join(p1, this, p2, that); + else join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed } - case (LongMap.Tip(key, value), x) => x.updateWith(key, value, (x, y) => f(key, y, x)); + case (LongMap.Tip(key, value), x) => x.updateWith[S](key, value, (x, y) => f(key, y, x)); // TODO: remove [S] when SI-5548 is fixed case (x, LongMap.Tip(key, value)) => x.updateWith[S](key, value, (x, y) => f(key, x, y)); case (LongMap.Nil, x) => x; case (x, LongMap.Nil) => x; diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index 585f71f3cf..0087b71ea8 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -80,8 +80,10 @@ object Promise { def EmptyPending[T](): FState[T] = emptyPendingValue.asInstanceOf[FState[T]] /** Represents the internal state. + * + * [adriaan] it's unsound to make FState covariant (tryComplete won't type check) */ - sealed trait FState[+T] { def value: Option[Try[T]] } + sealed trait FState[T] { def value: Option[Try[T]] } case class Pending[T](listeners: List[Try[T] => Any] = Nil) extends FState[T] { def value: Option[Try[T]] = None @@ -155,7 +157,11 @@ object Promise { def tryComplete(v: Try[T]): List[Try[T] => Any] = { getState match { case cur @ Pending(listeners) => - if (updateState(cur, if (v.isFailure) Failure(Some(v.asInstanceOf[util.Failure[T]])) else Success(Some(v.asInstanceOf[util.Success[T]])))) listeners + val newState = + if (v.isFailure) Failure(Some(v.asInstanceOf[util.Failure[T]])) + else Success(Some(v.asInstanceOf[util.Success[T]])) + + if (updateState(cur, newState)) listeners else tryComplete(v) case _ => null } diff --git a/src/library/scala/reflect/ClassManifest.scala b/src/library/scala/reflect/ClassManifest.scala index 466b57dea7..d393ac47fa 100644 --- a/src/library/scala/reflect/ClassManifest.scala +++ b/src/library/scala/reflect/ClassManifest.scala @@ -46,7 +46,9 @@ trait ClassManifest[T] extends OptManifest[T] with Equals with Serializable { /** The Scala type described by this manifest. */ - lazy val tpe: mirror.Type = reflect.mirror.classToType(erasure) + lazy val tpe: mirror.Type = mirror.classToType(erasure) + + def symbol: mirror.Symbol = mirror.classToSymbol(erasure) private def subtype(sub: jClass[_], sup: jClass[_]): Boolean = { def loop(left: Set[jClass[_]], seen: Set[jClass[_]]): Boolean = { diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index 6c02878b19..e5df487be9 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -76,6 +76,8 @@ abstract class AnyValManifest[T <: AnyVal](override val toString: String) extend * in client code. */ object Manifest { + import mirror.{ definitions => mdefs } + def valueManifests: List[AnyValManifest[_]] = List(Byte, Short, Char, Int, Long, Float, Double, Boolean, Unit) @@ -152,34 +154,40 @@ object Manifest { } val Any: Manifest[scala.Any] = new PhantomManifest[scala.Any]("Any") { + override def symbol = mdefs.AnyClass override def <:<(that: ClassManifest[_]): Boolean = (that eq this) private def readResolve(): Any = Manifest.Any } val Object: Manifest[java.lang.Object] = new PhantomManifest[java.lang.Object]("Object") { + override def symbol = mdefs.ObjectClass override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) private def readResolve(): Any = Manifest.Object } val AnyVal: Manifest[scala.AnyVal] = new PhantomManifest[scala.AnyVal]("AnyVal") { + override def symbol = mdefs.AnyValClass override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) private def readResolve(): Any = Manifest.AnyVal } val Null: Manifest[scala.Null] = new PhantomManifest[scala.Null]("Null") { + override def symbol = mdefs.NullClass override def <:<(that: ClassManifest[_]): Boolean = (that ne null) && (that ne Nothing) && !(that <:< AnyVal) private def readResolve(): Any = Manifest.Null } val Nothing: Manifest[scala.Nothing] = new PhantomManifest[scala.Nothing]("Nothing") { + override def symbol = mdefs.NothingClass override def <:<(that: ClassManifest[_]): Boolean = (that ne null) private def readResolve(): Any = Manifest.Nothing } private class SingletonTypeManifest[T <: AnyRef](value: AnyRef) extends Manifest[T] { lazy val erasure = value.getClass - override lazy val tpe = mirror.SingleType(mirror.NoPrefix, InstanceRefSymbol(value)) // todo: change to freevar + override lazy val symbol = InstanceRefSymbol(value) // todo: change to freevar + override lazy val tpe = mirror.SingleType(mirror.NoPrefix, symbol) override lazy val toString = value.toString + ".type" } @@ -208,8 +216,12 @@ object Manifest { def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = new ClassTypeManifest[T](Some(prefix), clazz, args.toList) + /** Phantom types have no runtime representation; they all erase to Object, + * but the Symbol preserves their identity. + */ private abstract class PhantomManifest[T](override val toString: String) extends ClassTypeManifest[T](None, classOf[java.lang.Object], Nil) { - override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override lazy val tpe = namedType(mirror.NoPrefix, symbol, Nil) + override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] override val hashCode = System.identityHashCode(this) } @@ -218,13 +230,13 @@ object Manifest { private class ClassTypeManifest[T](prefix: Option[Manifest[_]], val erasure: Predef.Class[_], override val typeArguments: List[Manifest[_]]) extends Manifest[T] { + override lazy val tpe = { - val clazz = classToSymbol(erasure) val pre = prefix match { case Some(pm) => pm.tpe - case None => clazz.owner.thisPrefix + case None => symbol.owner.thisPrefix } - namedType(pre, clazz, typeArguments map (_.tpe)) + namedType(pre, symbol, typeArguments map (_.tpe)) } override def toString = @@ -282,8 +294,9 @@ object Manifest { * instead of in scala-compiler.jar. */ def apply[T](_tpe: mirror.Type): Manifest[T] = new Manifest[T] { + override def symbol = _tpe.typeSymbol override lazy val tpe = _tpe - override def erasure = mirror.typeToClass(_tpe.erasedType) + override def erasure = mirror.typeToClass(_tpe.erasedType) override def toString = _tpe.toString } } diff --git a/src/library/scala/util/parsing/combinator/Parsers.scala b/src/library/scala/util/parsing/combinator/Parsers.scala index 27e9112fce..9aaf0aeb54 100644 --- a/src/library/scala/util/parsing/combinator/Parsers.scala +++ b/src/library/scala/util/parsing/combinator/Parsers.scala @@ -794,7 +794,7 @@ trait Parsers { */ def chainl1[T, U](first: => Parser[T], p: => Parser[U], q: => Parser[(T, U) => T]): Parser[T] = first ~ rep(q ~ p) ^^ { - case x ~ xs => xs.foldLeft(x){(_, _) match {case (a, f ~ b) => f(a, b)}} + case x ~ xs => xs.foldLeft(x: T){case (a, f ~ b) => f(a, b)} // x's type annotation is needed to deal with changed type inference due to SI-5189 } /** A parser generator that generalises the `rep1sep` generator so that `q`, @@ -812,8 +812,7 @@ trait Parsers { */ def chainr1[T, U](p: => Parser[T], q: => Parser[(T, U) => U], combine: (T, U) => U, first: U): Parser[U] = p ~ rep(q ~ p) ^^ { - case x ~ xs => (new ~(combine, x) :: xs). - foldRight(first){(_, _) match {case (f ~ a, b) => f(a, b)}} + case x ~ xs => (new ~(combine, x) :: xs).foldRight(first){case (f ~ a, b) => f(a, b)} } /** A parser generator for optional sub-phrases. diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala index 43f9c20b1d..70926208b3 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala @@ -130,7 +130,7 @@ trait StateRules { def rep(in : S, t : T) : Result[S, T, X] = { if (finished(t)) Success(in, t) else rule(in) match { - case Success(out, f) => rep(out, f(t)) + case Success(out, f) => rep(out, f(t)) // SI-5189 f.asInstanceOf[T => T] case Failure => Failure case Error(x) => Error(x) } diff --git a/test/files/continuations-neg/t5445.check b/test/files/continuations-neg/t5445.check new file mode 100644 index 0000000000..eb2943b6a6 --- /dev/null +++ b/test/files/continuations-neg/t5445.check @@ -0,0 +1,4 @@ +t5445.scala:4: error: cps annotations not allowed on by-value parameters or value definitions + def foo(block: Unit @suspendable ): Unit @suspendable = {} + ^ +one error found diff --git a/test/files/continuations-neg/t5445.scala b/test/files/continuations-neg/t5445.scala new file mode 100644 index 0000000000..cb6f8f686d --- /dev/null +++ b/test/files/continuations-neg/t5445.scala @@ -0,0 +1,5 @@ +import scala.util.continuations._ + +object Test { + def foo(block: Unit @suspendable ): Unit @suspendable = {} +} diff --git a/test/files/continuations-run/t5538.check b/test/files/continuations-run/t5538.check new file mode 100644 index 0000000000..457721d5e0 --- /dev/null +++ b/test/files/continuations-run/t5538.check @@ -0,0 +1 @@ +Future(Future(Future(Future(Future(List(1, 2, 3, 4, 5)))))) diff --git a/test/files/continuations-run/t5538.scala b/test/files/continuations-run/t5538.scala new file mode 100644 index 0000000000..42f8163caf --- /dev/null +++ b/test/files/continuations-run/t5538.scala @@ -0,0 +1,50 @@ +import scala.util.continuations._ +import scala.collection.generic.CanBuildFrom + +object Test { + + class ExecutionContext + + implicit def defaultExecutionContext = new ExecutionContext + + case class Future[+T](x:T) { + final def map[A](f: T => A): Future[A] = new Future[A](f(x)) + final def flatMap[A](f: T => Future[A]): Future[A] = f(x) + } + + class PromiseStream[A] { + override def toString = xs.toString + + var xs: List[A] = Nil + + final def +=(elem: A): this.type = { xs :+= elem; this } + + final def ++=(elem: Traversable[A]): this.type = { xs ++= elem; this } + + final def <<(elem: Future[A]): PromiseStream[A] @cps[Future[Any]] = + shift { cont: (PromiseStream[A] => Future[Any]) => elem map (a => cont(this += a)) } + + final def <<(elem1: Future[A], elem2: Future[A], elems: Future[A]*): PromiseStream[A] @cps[Future[Any]] = + shift { cont: (PromiseStream[A] => Future[Any]) => Future.flow(this << elem1 << elem2 <<< Future.sequence(elems.toSeq)) map cont } + + final def <<<(elems: Traversable[A]): PromiseStream[A] @cps[Future[Any]] = + shift { cont: (PromiseStream[A] => Future[Any]) => cont(this ++= elems) } + + final def <<<(elems: Future[Traversable[A]]): PromiseStream[A] @cps[Future[Any]] = + shift { cont: (PromiseStream[A] => Future[Any]) => elems map (as => cont(this ++= as)) } + } + + object Future { + + def sequence[A, M[_] <: Traversable[_]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = + new Future(in.asInstanceOf[Traversable[Future[A]]].map((f:Future[A])=>f.x)(cbf.asInstanceOf[CanBuildFrom[Traversable[Future[A]], A, M[A]]])) + + def flow[A](body: => A @cps[Future[Any]])(implicit executor: ExecutionContext): Future[A] = reset(Future(body)).asInstanceOf[Future[A]] + + } + + def main(args: Array[String]) = { + val p = new PromiseStream[Int] + println(Future.flow(p << (Future(1), Future(2), Future(3), Future(4), Future(5)))) + } +}
\ No newline at end of file diff --git a/test/files/jvm/typerep.scala b/test/files/jvm/typerep.scala index 49a216c05c..3befc7ff3f 100644 --- a/test/files/jvm/typerep.scala +++ b/test/files/jvm/typerep.scala @@ -161,7 +161,7 @@ object TypeRep { }).asInstanceOf[TypeRep[Option[A]]] def getType[A](x: List[A])(implicit rep: TypeRep[A]): TypeRep[List[A]] = (x match { - case h :: t => ListRep(getType(h)) + case h :: t => ListRep(rep) case Nil => NilRep }).asInstanceOf[TypeRep[List[A]]] diff --git a/test/files/neg/t3275.check b/test/files/neg/t3275.check new file mode 100644 index 0000000000..117c792321 --- /dev/null +++ b/test/files/neg/t3275.check @@ -0,0 +1,4 @@ +t3275.scala:2: error: @tailrec annotated method contains no recursive calls + @annotation.tailrec def foo() = 5 + ^ +one error found diff --git a/test/files/neg/t3275.scala b/test/files/neg/t3275.scala new file mode 100644 index 0000000000..18e38a1a97 --- /dev/null +++ b/test/files/neg/t3275.scala @@ -0,0 +1,3 @@ +object Test { + @annotation.tailrec def foo() = 5 +} diff --git a/test/files/neg/t5189.check b/test/files/neg/t5189.check new file mode 100644 index 0000000000..7762f465dc --- /dev/null +++ b/test/files/neg/t5189.check @@ -0,0 +1,6 @@ +t5189.scala:3: error: type mismatch; + found : Nothing => Any + required: Any => Any + def f(x: Any): Any => Any = x match { case Foo(bar) => bar } + ^ +one error found
\ No newline at end of file diff --git a/test/files/neg/t5189.scala b/test/files/neg/t5189.scala new file mode 100644 index 0000000000..19e8e74667 --- /dev/null +++ b/test/files/neg/t5189.scala @@ -0,0 +1,5 @@ +class TestNeg1 { + case class Foo[T, U](f: T => U) + def f(x: Any): Any => Any = x match { case Foo(bar) => bar } + // uh-oh, Any => Any should be Nothing => Any. +} diff --git a/test/files/neg/t5189b.check b/test/files/neg/t5189b.check new file mode 100644 index 0000000000..7f78cbb438 --- /dev/null +++ b/test/files/neg/t5189b.check @@ -0,0 +1,8 @@ +t5189b.scala:25: error: type mismatch; + found : TestNeg.Wrapped[?T2] where type ?T2 <: T + required: TestNeg.Wrapped[T] +Note: ?T2 <: T, but class Wrapped is invariant in type W. +You may wish to define W as +W instead. (SLS 4.5) + case Wrapper/*[_ <: T ]*/(wrapped) => wrapped // : Wrapped[_ <: T], which is a subtype of Wrapped[T] if and only if Wrapped is covariant in its type parameter + ^ +one error found diff --git a/test/files/neg/t5189b.scala b/test/files/neg/t5189b.scala new file mode 100644 index 0000000000..1750f14084 --- /dev/null +++ b/test/files/neg/t5189b.scala @@ -0,0 +1,62 @@ +class TestPos { + class AbsWrapperCov[+A] + case class Wrapper[B](x: B) extends AbsWrapperCov[B] + + def unwrap[T](x: AbsWrapperCov[T]): T = x match { + case Wrapper/*[_ <: T ]*/(x) => x // _ <: T, which is a subtype of T + } +} + +object TestNeg extends App { + class AbsWrapperCov[+A] + case class Wrapper[B](x: Wrapped[B]) extends AbsWrapperCov[B] + + /* + when inferring Wrapper's type parameter B from x's type AbsWrapperCov[T], + we must take into account that x's actual type is AbsWrapperCov[Tactual] forSome {type Tactual <: T} + as AbsWrapperCov is covariant in A -- in other words, we must not assume we know T exactly, all we know is its upper bound + + since method application is the only way to generate this slack between run-time and compile-time types, + we'll simply replace the skolems that represent method type parameters as seen from the method's body by + other skolems that are (upper/lower)-bounded by the type-parameter skolems + (depending on whether the skolem appears in a covariant/contravariant position) + */ + def unwrap[T](x: AbsWrapperCov[T]): Wrapped[T] = x match { + case Wrapper/*[_ <: T ]*/(wrapped) => wrapped // : Wrapped[_ <: T], which is a subtype of Wrapped[T] if and only if Wrapped is covariant in its type parameter + } + + class Wrapped[W](var cell: W) // must be invariant (to trigger the bug) + + // class A { def imNotAB = println("notB")} + // class B + // + // val w = new Wrapped(new A) + // unwrap[Any](Wrapper(w)).cell = new B + // w.cell.imNotAB +} + +// class TestPos1 { +// class Base[T] +// case class C[T](x: T) extends Base[T] +// def foo[T](b: Base[T]): T = b match { case C(x) => x } +// +// case class Span[K <: Ordered[K]](low: Option[K], high: Option[K]) extends Function1[K, Boolean] { +// override def equals(x$1: Any): Boolean = x$1 match { +// case Span((low$0 @ _), (high$0 @ _)) if low$0.equals(low).$amp$amp(high$0.equals(high)) => true +// case _ => false +// } +// def apply(k: K): Boolean = this match { +// case Span(Some(low), Some(high)) => (k >= low && k <= high) +// case Span(Some(low), None) => (k >= low) +// case Span(None, Some(high)) => (k <= high) +// case _ => false +// } +// } +// } +// +// class TestNeg1 { +// case class Foo[T, U](f: T => U) +// def f(x: Any): Any => Any = x match { case Foo(bar) => bar } +// // uh-oh, Any => Any should be Nothing => Any. +// } + diff --git a/test/files/neg/t5455.check b/test/files/neg/t5455.check new file mode 100644 index 0000000000..788daf99fa --- /dev/null +++ b/test/files/neg/t5455.check @@ -0,0 +1,4 @@ +t5455.scala:4: error: lazy vals are not tailcall transformed + @annotation.tailrec final lazy val bar: Thing[Int] = { + ^ +one error found diff --git a/test/files/neg/t5455.scala b/test/files/neg/t5455.scala new file mode 100644 index 0000000000..22d6c442c9 --- /dev/null +++ b/test/files/neg/t5455.scala @@ -0,0 +1,16 @@ +trait Test { + def root: Test + + @annotation.tailrec final lazy val bar: Thing[Int] = { + if (this eq root) + Thing(() => System.identityHashCode(bar)) + else + root.bar + } + + def f = bar.f() +} + +case class Thing[A](f: () => A) { + override def toString = "" + f() +} diff --git a/test/files/neg/t5553_1.check b/test/files/neg/t5553_1.check new file mode 100644 index 0000000000..afd6489888 --- /dev/null +++ b/test/files/neg/t5553_1.check @@ -0,0 +1,54 @@ +t5553_1.scala:18: error: ambiguous reference to overloaded definition, +both method apply in object Foo1 of type (z: String)Base[T] +and method apply in object Foo1 of type (a: Int)Base[T] +match expected type ? + def test1[T] = Foo1[T] + ^ +t5553_1.scala:19: error: type mismatch; + found : [T](z: String)Base[T] <and> (a: Int)Base[T] + required: Int + def test2[T]: Int = Foo1[T] + ^ +t5553_1.scala:20: error: type mismatch; + found : [T(in method apply)](z: String)Base[T(in method apply)] <and> (a: Int)Base[T(in method apply)] + required: Base[T(in method test3)] + def test3[T]: Base[T] = Foo1[T] + ^ +t5553_1.scala:24: error: ambiguous reference to overloaded definition, +both method apply in object Foo2 of type (z: String)Base[T] +and method apply in object Foo2 of type (a: Int)Base[T] +match expected type ? + def test4[T] = Foo2[T] + ^ +t5553_1.scala:25: error: type mismatch; + found : [T](z: String)Base[T] <and> (a: Int)Base[T] + required: Int + def test5[T]: Int = Foo2[T] + ^ +t5553_1.scala:26: error: type mismatch; + found : [T(in method apply)](z: String)Base[T(in method apply)] <and> (a: Int)Base[T(in method apply)] + required: Base[T(in method test6)] + def test6[T]: Base[T] = Foo2[T] + ^ +t5553_1.scala:30: error: ambiguous reference to overloaded definition, +both method apply in object Foo3 of type (z: String)String +and method apply in object Foo3 of type (a: Int)Base[T] +match expected type ? + def test7[T] = Foo3[T] + ^ +t5553_1.scala:31: error: type mismatch; + found : [T](z: String)String <and> (a: Int)Base[T] + required: String + def test8[T]: String = Foo3[T] + ^ +t5553_1.scala:32: error: type mismatch; + found : [T](z: String)String <and> (a: Int)Base[T] + required: Int + def test9[T]: Int = Foo3[T] + ^ +t5553_1.scala:33: error: type mismatch; + found : [T(in method apply)](z: String)String <and> (a: Int)Base[T(in method apply)] + required: Base[T(in method test10)] + def test10[T]: Base[T] = Foo3[T] + ^ +10 errors found diff --git a/test/files/neg/t5553_1.scala b/test/files/neg/t5553_1.scala new file mode 100644 index 0000000000..32d61ec852 --- /dev/null +++ b/test/files/neg/t5553_1.scala @@ -0,0 +1,34 @@ +class Base[T] + +object Foo1 { + def apply[T](a: Int): Base[T] = new Base[T] + def apply[T](z: String): Base[T] = new Base[T] +} + +object Foo2 { + def apply[T](a: Int): Base[T] = new Base[T] + def apply[T](z: String="abc"): Base[T] = new Base[T] +} + +object Foo3 { + def apply[T](a: Int): Base[T] = new Base[T] + def apply[T](z: String="abc"): String = z +} +object Test { + def test1[T] = Foo1[T] + def test2[T]: Int = Foo1[T] + def test3[T]: Base[T] = Foo1[T] +} + +object Test2 { + def test4[T] = Foo2[T] + def test5[T]: Int = Foo2[T] + def test6[T]: Base[T] = Foo2[T] +} + +object Test3{ + def test7[T] = Foo3[T] + def test8[T]: String = Foo3[T] + def test9[T]: Int = Foo3[T] + def test10[T]: Base[T] = Foo3[T] +} diff --git a/test/files/neg/t5553_2.check b/test/files/neg/t5553_2.check new file mode 100644 index 0000000000..599fdb0523 --- /dev/null +++ b/test/files/neg/t5553_2.check @@ -0,0 +1,50 @@ +t5553_2.scala:27: error: type mismatch; + found : Base[T] + required: Int + def test4[T]: Int = Foo1[T](1) + ^ +t5553_2.scala:34: error: type mismatch; + found : String + required: Base[T] + def test7[T]: Base[T] = Foo2[T] + ^ +t5553_2.scala:35: error: type mismatch; + found : String + required: Int + def test8[T]: Int = Foo2[T] + ^ +t5553_2.scala:40: error: type mismatch; + found : String + required: Int + def test9[T]: Int = Foo3[T] + ^ +t5553_2.scala:41: error: type mismatch; + found : String + required: Base[T] + def test10[T]: Base[T] = Foo3[T] + ^ +t5553_2.scala:47: error: could not find implicit value for parameter z: String + def test13[T]: Int = Foo3[T] + ^ +t5553_2.scala:48: error: could not find implicit value for parameter z: String + def test14[T]: Base[T] = Foo3[T] + ^ +t5553_2.scala:49: error: could not find implicit value for parameter z: String + def test15[T]: String = Foo3[T] + ^ +t5553_2.scala:50: error: could not find implicit value for parameter z: String + def test16[T] = Foo3[T] + ^ +t5553_2.scala:54: error: ambiguous reference to overloaded definition, +both method apply in object Foo4 of type (x: Int)(implicit z: String)Base[T] +and method apply in object Foo4 of type (x: Int)Base[T] +match argument types (Int) + def test17[T] = Foo4[T](1) + ^ +t5553_2.scala:55: error: ambiguous reference to overloaded definition, +both method apply in object Foo4 of type (x: Int)(implicit z: String)Base[T] +and method apply in object Foo4 of type (x: Int)Base[T] +match argument types (Int) and expected result type Base[T] + def test18[T]: Base[T] = Foo4[T](1) + ^ +11 errors found diff --git a/test/files/neg/t5553_2.scala b/test/files/neg/t5553_2.scala new file mode 100644 index 0000000000..16958aec8e --- /dev/null +++ b/test/files/neg/t5553_2.scala @@ -0,0 +1,59 @@ +class Base[T] + +object Foo1 { + def apply[T](x: Int): Base[T] = new Base[T] + def apply[T](x: Int, z: String="abc"): String = z +} + +object Foo2 { + def apply[T](a: Int): Base[T] = new Base[T] + def apply[T]: String = "abc" +} + +object Foo3 { + def apply[T](x: Int): Base[T] = new Base[T] + def apply[T](implicit z: String): String = z +} + +object Foo4 { + def apply[T](x: Int): Base[T] = new Base[T] + def apply[T](x: Int)(implicit z: String): Base[T] = new Base[T] +} + +object Test1 { + def test1[T] = Foo1[T](1) + def test2[T]: String = Foo1[T](1) + def test3[T]: Base[T] = Foo1[T](1) + def test4[T]: Int = Foo1[T](1) + +} + +object Test2 { + def test5[T] = Foo2[T] + def test6[T]: String = Foo2[T] + def test7[T]: Base[T] = Foo2[T] + def test8[T]: Int = Foo2[T] +} + +object Test3 { + implicit val v: String = "abc" + def test9[T]: Int = Foo3[T] + def test10[T]: Base[T] = Foo3[T] + def test11[T]: String = Foo3[T] + def test12[T] = Foo3[T] +} + +object Test4 { + def test13[T]: Int = Foo3[T] + def test14[T]: Base[T] = Foo3[T] + def test15[T]: String = Foo3[T] + def test16[T] = Foo3[T] +} + +object Test5 { + def test17[T] = Foo4[T](1) + def test18[T]: Base[T] = Foo4[T](1) + //def test19[T]: String = Foo4[T](1) // #5554 +} + + diff --git a/test/files/neg/t5554.check b/test/files/neg/t5554.check new file mode 100644 index 0000000000..8f657fd32f --- /dev/null +++ b/test/files/neg/t5554.check @@ -0,0 +1,67 @@ +t5554.scala:14: error: ambiguous reference to overloaded definition, +both method apply in object Foo1 of type (x: Int)(implicit z: String)String +and method apply in object Foo1 of type (x: Int)Base[T] +match argument types (Int) + def test1[T]: Int = Foo1[T](1) + ^ +t5554.scala:16: error: ambiguous reference to overloaded definition, +both method apply in object Foo1 of type (x: Int)(implicit z: String)String +and method apply in object Foo1 of type (x: Int)Base[T] +match argument types (Int) + def test3[T]: String = Foo1[T](1) + ^ +t5554.scala:17: error: ambiguous reference to overloaded definition, +both method apply in object Foo1 of type (x: Int)(implicit z: String)String +and method apply in object Foo1 of type (x: Int)Base[T] +match argument types (Int) + def test4[T] = Foo1[T](1) + ^ +t5554.scala:22: error: ambiguous reference to overloaded definition, +both method apply in object Foo1 of type (x: Int)(implicit z: String)String +and method apply in object Foo1 of type (x: Int)Base[T] +match argument types (Int) + def test5[T]: Int = Foo1[T](1) + ^ +t5554.scala:25: error: ambiguous reference to overloaded definition, +both method apply in object Foo1 of type (x: Int)(implicit z: String)String +and method apply in object Foo1 of type (x: Int)Base[T] +match argument types (Int) + def test8[T] = Foo1[T](1) + ^ +t5554.scala:29: error: ambiguous reference to overloaded definition, +both method apply in object Foo2 of type (x: Int)(implicit z: String)Base[T] +and method apply in object Foo2 of type (x: Int)Base[T] +match argument types (Int) + def test9[T]: String = Foo2[T](1) + ^ +t5554.scala:30: error: ambiguous reference to overloaded definition, +both method apply in object Foo2 of type (x: Int)(implicit z: String)Base[T] +and method apply in object Foo2 of type (x: Int)Base[T] +match argument types (Int) and expected result type Base[T] + def test10[T]: Base[T] = Foo2[T](1) + ^ +t5554.scala:31: error: ambiguous reference to overloaded definition, +both method apply in object Foo2 of type (x: Int)(implicit z: String)Base[T] +and method apply in object Foo2 of type (x: Int)Base[T] +match argument types (Int) + def test11[T] = Foo2[T](1) + ^ +t5554.scala:36: error: ambiguous reference to overloaded definition, +both method apply in object Foo2 of type (x: Int)(implicit z: String)Base[T] +and method apply in object Foo2 of type (x: Int)Base[T] +match argument types (Int) + def test12[T]: String = Foo2[T](1) + ^ +t5554.scala:37: error: ambiguous reference to overloaded definition, +both method apply in object Foo2 of type (x: Int)(implicit z: String)Base[T] +and method apply in object Foo2 of type (x: Int)Base[T] +match argument types (Int) and expected result type Base[T] + def test13[T]: Base[T] = Foo2[T](1) + ^ +t5554.scala:38: error: ambiguous reference to overloaded definition, +both method apply in object Foo2 of type (x: Int)(implicit z: String)Base[T] +and method apply in object Foo2 of type (x: Int)Base[T] +match argument types (Int) + def test14[T] = Foo2[T](1) + ^ +11 errors found diff --git a/test/files/neg/t5554.scala b/test/files/neg/t5554.scala new file mode 100644 index 0000000000..d279abea7f --- /dev/null +++ b/test/files/neg/t5554.scala @@ -0,0 +1,39 @@ +class Base[T] + +object Foo1 { + def apply[T](x: Int): Base[T] = new Base[T] + def apply[T](x: Int)(implicit z: String): String = z +} + +object Foo2 { + def apply[T](x: Int): Base[T] = new Base[T] + def apply[T](x: Int)(implicit z: String): Base[T] = new Base[T] +} + +object Test1 { + def test1[T]: Int = Foo1[T](1) + def test2[T]: Base[T] = Foo1[T](1) + def test3[T]: String = Foo1[T](1) + def test4[T] = Foo1[T](1) +} + +object Test2 { + implicit val v: String = "foo" + def test5[T]: Int = Foo1[T](1) + def test6[T]: Base[T] = Foo1[T](1) + def test7[T]: String = Foo1[T](1) + def test8[T] = Foo1[T](1) +} + +object Test3 { + def test9[T]: String = Foo2[T](1) + def test10[T]: Base[T] = Foo2[T](1) + def test11[T] = Foo2[T](1) +} + +object Test4 { + implicit val v: String = "foo" + def test12[T]: String = Foo2[T](1) + def test13[T]: Base[T] = Foo2[T](1) + def test14[T] = Foo2[T](1) +} diff --git a/test/files/neg/tailrec-2.check b/test/files/neg/tailrec-2.check index 4f763a1c8d..a918858773 100644 --- a/test/files/neg/tailrec-2.check +++ b/test/files/neg/tailrec-2.check @@ -1,4 +1,7 @@ -tailrec-2.scala:6: error: could not optimize @tailrec annotated method f: it contains a recursive call targetting a supertype +tailrec-2.scala:8: error: could not optimize @tailrec annotated method f: it contains a recursive call targetting a supertype @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Super[A]).f(mem) ^ -one error found +tailrec-2.scala:9: error: @tailrec annotated method contains no recursive calls + @annotation.tailrec final def f1[B >: A](mem: List[B]): List[B] = this.g(mem) + ^ +two errors found diff --git a/test/files/neg/tailrec-2.scala b/test/files/neg/tailrec-2.scala index 342cd85323..9eb3af2f07 100644 --- a/test/files/neg/tailrec-2.scala +++ b/test/files/neg/tailrec-2.scala @@ -1,9 +1,12 @@ sealed abstract class Super[+A] { def f[B >: A](mem: List[B]) : List[B] + def g(mem: List[_]) = ??? } // This one should fail, target is a supertype class Bop1[+A](val element: A) extends Super[A] { + @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Super[A]).f(mem) + @annotation.tailrec final def f1[B >: A](mem: List[B]): List[B] = this.g(mem) } // These succeed class Bop2[+A](val element: A) extends Super[A] { diff --git a/test/files/pos/t5541.scala b/test/files/pos/t5541.scala new file mode 100644 index 0000000000..39682a2fff --- /dev/null +++ b/test/files/pos/t5541.scala @@ -0,0 +1,61 @@ +package philips.adolf.paul + +trait Sys[ S <: Sys[ S ]] { + type Tx +} + +object HASkipList { + sealed trait NodeLike[ S <: Sys[ S ], @specialized( Int ) A ] { + def size : Int + def key( i: Int ): A + } + sealed trait Node[ S <: Sys[ S ], @specialized( Int ) A ] extends NodeLike[ S, A ] { + def isLeaf : Boolean + def isBranch : Boolean + def asBranch : Branch[ S, A ] + } + sealed trait BranchLike[ S <: Sys[ S ], @specialized( Int ) A ] extends NodeLike[ S, A ] { + def down( i: Int )( implicit tx: S#Tx ) : Node[ S, A ] = sys.error("") + } + sealed trait HeadOrBranch[ S <: Sys[ S ], A ] + final class Branch[ S <: Sys[ S ], @specialized( Int ) A ]() + extends BranchLike[ S, A ] with HeadOrBranch[ S, A ] with Node[ S, A ] { + def size:Int=1234 + def key(i: Int):A=sys.error("TODO") + def isLeaf : Boolean = false + def isBranch : Boolean = true + def asBranch : Branch[ S, A ] = this + } +} +sealed trait HASkipList[ S <: Sys[ S ], @specialized( Int ) A ] + +class HASkipListView[ S <: Sys[ S ], A ]( private val l: HASkipList[ S, A ])( implicit system: S ) { + import HASkipList.Node + private def buildBoxMap( n: Node[ S, A ], isRight: Boolean )( implicit tx: S#Tx ) : (Box, NodeBox) = { + val sz = n.size + val szm = sz - 1 + val keys = IndexedSeq.tabulate( sz ) { i => + val key = n.key( i ) + (key, if( isRight && i == szm ) "M" else key.toString) + } + val chbo = if( n.isLeaf ) None else { + val nb = n.asBranch + Some( IndexedSeq.tabulate( sz )( i => buildBoxMap( nb.down( i ), isRight && (i == szm) ))) + } + val b = NodeBox( n, keys, chbo.map( _.map( _._2 ))) + val bb = chbo match { + case Some( chbt ) => + val chb = chbt.map( _._1 ) + val h = Horiz( bs = chb ) + Vert( bs = IndexedSeq[Box]( b, h )) + case None => b + } + + (bb, b) + } + + private trait Box + private case class Horiz( spacing: Int = 20, bs: IndexedSeq[ Box ]) extends Box + private final case class Vert( spacing: Int = 20, bs: IndexedSeq[ Box ]) extends Box + private final case class NodeBox( n: Node[ S, A ], keys: IndexedSeq[ (A, String) ], downs: Option[ IndexedSeq[ NodeBox ]]) extends Box +} diff --git a/test/files/pos/t5546.scala b/test/files/pos/t5546.scala new file mode 100644 index 0000000000..4b0b0589b6 --- /dev/null +++ b/test/files/pos/t5546.scala @@ -0,0 +1 @@ +class A { def foo: Class[_ <: A] = getClass }
\ No newline at end of file diff --git a/test/files/presentation/shutdown-deadlock.check b/test/files/presentation/shutdown-deadlock.check new file mode 100644 index 0000000000..ddcb4ff59b --- /dev/null +++ b/test/files/presentation/shutdown-deadlock.check @@ -0,0 +1,3 @@ +reload: arrays.scala +reload: arrays.scala +No timeouts diff --git a/test/files/presentation/shutdown-deadlock/ShutdownDeadlockTest.scala b/test/files/presentation/shutdown-deadlock/ShutdownDeadlockTest.scala new file mode 100644 index 0000000000..53af84541a --- /dev/null +++ b/test/files/presentation/shutdown-deadlock/ShutdownDeadlockTest.scala @@ -0,0 +1,45 @@ +import scala.tools.nsc.interactive._ +import tests._ + +object Test extends InteractiveTest { + val Reps = 30 + import compiler._ + + def askSomething(): Response[Tree] = { + // println("*") + Thread.sleep(50) + ask { compiler.askStructure(true)(sourceFiles.head, _) } + } + + def fireAsks() { + val jobs1 = for (i <- 1 until Reps) yield { + if (i % 10 == 0) { + askReload(sourceFiles) + } + askSomething + } + + for ((j, i) <- jobs1.zipWithIndex) { + j.get(5000) match { + case None => + println(i + ": TIMEOUT") + exit(1) // no need to delay the test any longer + case r => + } + } + compiler.askShutdown() + + println("No timeouts") + } + + override def main(args: Array[String]) { + new Thread("Asking") { + override def run() { + fireAsks() + } + }.start() + + Thread.sleep(800) + compiler.askShutdown() + } +}
\ No newline at end of file diff --git a/test/files/presentation/shutdown-deadlock/src/arrays.scala b/test/files/presentation/shutdown-deadlock/src/arrays.scala new file mode 100644 index 0000000000..ecebc78a6f --- /dev/null +++ b/test/files/presentation/shutdown-deadlock/src/arrays.scala @@ -0,0 +1,937 @@ +//############################################################################ +// Arrays +//############################################################################ + +//############################################################################ + +object Test { + + //########################################################################## + // Types + + type Strings = List[String] + type Map = scala.collection.Map[Int, Any] + type HashMap = scala.collection.mutable.HashMap[Int, Any] + type TreeMap = scala.collection.immutable.TreeMap[Int, Any] + + //########################################################################## + // Identity Functions + + def id_Ta_T[T <: Any ](x: T): T = x; + def id_Tr_T[T <: AnyRef ](x: T): T = x; + def id_To_T[T <: Object ](x: T): T = x; + + def id_Ta_a[T <: Any ](x: T): Any = x; + def id_Tr_a[T <: AnyRef ](x: T): Any = x; + def id_To_a[T <: Object ](x: T): Any = x; + + def id_Tr_r[T <: AnyRef ](x: T): AnyRef = x; + def id_To_r[T <: Object ](x: T): AnyRef = x; + + def id_To_o[T <: Object ](x: T): Object = x; + + def id_TSa_T [S <: Any , T <: Array[S]](x: T): T = x; + def id_TSv_T [S <: AnyVal , T <: Array[S]](x: T): T = x; + def id_TSr_T [S <: AnyRef , T <: Array[S]](x: T): T = x; + def id_TSo_T [S <: Object , T <: Array[S]](x: T): T = x; + def id_TSm_T [S <: Map , T <: Array[S]](x: T): T = x; + def id_TSn_T [S <: Strings, T <: Array[S]](x: T): T = x; + + def id_TSa_Ss[S <: Any , T <: Array[S]](x: T): Array[S] = x; + def id_TSv_Ss[S <: AnyVal , T <: Array[S]](x: T): Array[S] = x; + def id_TSr_Ss[S <: AnyRef , T <: Array[S]](x: T): Array[S] = x; + def id_TSo_Ss[S <: Object , T <: Array[S]](x: T): Array[S] = x; + def id_TSm_Ss[S <: Map , T <: Array[S]](x: T): Array[S] = x; + def id_TSn_Ss[S <: Strings, T <: Array[S]](x: T): Array[S] = x; + + def id_TSa_a [S <: Any , T <: Array[S]](x: T): Any = x; + def id_TSv_a [S <: AnyVal , T <: Array[S]](x: T): Any = x; + def id_TSr_a [S <: AnyRef , T <: Array[S]](x: T): Any = x; + def id_TSo_a [S <: Object , T <: Array[S]](x: T): Any = x; + def id_TSm_a [S <: Map , T <: Array[S]](x: T): Any = x; + def id_TSn_a [S <: Strings, T <: Array[S]](x: T): Any = x; + + def id_TSa_r [S <: Any , T <: Array[S]](x: T): AnyRef = x; + def id_TSv_r [S <: AnyVal , T <: Array[S]](x: T): AnyRef = x; + def id_TSr_r [S <: AnyRef , T <: Array[S]](x: T): AnyRef = x; + def id_TSo_r [S <: Object , T <: Array[S]](x: T): AnyRef = x; + def id_TSm_r [S <: Map , T <: Array[S]](x: T): AnyRef = x; + def id_TSn_r [S <: Strings, T <: Array[S]](x: T): AnyRef = x; + + def id_TSa_o [S <: Any , T <: Array[S]](x: T): Object = x; + def id_TSv_o [S <: AnyVal , T <: Array[S]](x: T): Object = x; + def id_TSr_o [S <: AnyRef , T <: Array[S]](x: T): Object = x; + def id_TSo_o [S <: Object , T <: Array[S]](x: T): Object = x; + def id_TSm_o [S <: Map , T <: Array[S]](x: T): Object = x; + def id_TSn_o [S <: Strings, T <: Array[S]](x: T): Object = x; + + def id_Sas_Ss[S <: Any ](xs: Array[S]): Array[S] = xs; + def id_Svs_Ss[S <: AnyVal ](xs: Array[S]): Array[S] = xs; + def id_Srs_Ss[S <: AnyRef ](xs: Array[S]): Array[S] = xs; + def id_Sos_Ss[S <: Object ](xs: Array[S]): Array[S] = xs; + def id_Sms_Ss[S <: Map ](xs: Array[S]): Array[S] = xs; + def id_Sns_Ss[S <: Strings](xs: Array[S]): Array[S] = xs; + + def id_Sas_a [S <: Any ](xs: Array[S]): Any = xs; + def id_Svs_a [S <: AnyVal ](xs: Array[S]): Any = xs; + def id_Srs_a [S <: AnyRef ](xs: Array[S]): Any = xs; + def id_Sos_a [S <: Object ](xs: Array[S]): Any = xs; + def id_Sms_a [S <: Map ](xs: Array[S]): Any = xs; + def id_Sns_a [S <: Strings](xs: Array[S]): Any = xs; + + def id_Sas_r [S <: Any ](xs: Array[S]): AnyRef = xs; + def id_Svs_r [S <: AnyVal ](xs: Array[S]): AnyRef = xs; + def id_Srs_r [S <: AnyRef ](xs: Array[S]): AnyRef = xs; + def id_Sos_r [S <: Object ](xs: Array[S]): AnyRef = xs; + def id_Sms_r [S <: Map ](xs: Array[S]): AnyRef = xs; + def id_Sns_r [S <: Strings](xs: Array[S]): AnyRef = xs; + + def id_Sas_o [S <: Any ](xs: Array[S]): Object = xs; + def id_Svs_o [S <: AnyVal ](xs: Array[S]): Object = xs; + def id_Srs_o [S <: AnyRef ](xs: Array[S]): Object = xs; + def id_Sos_o [S <: Object ](xs: Array[S]): Object = xs; + def id_Sms_o [S <: Map ](xs: Array[S]): Object = xs; + def id_Sns_o [S <: Strings](xs: Array[S]): Object = xs; + + //########################################################################## + // Generic Checks + + type Check[T] = Array[T] => Unit; + + var checks: Int = 0; + + def check(test0: Boolean, actual: Any, expected: Any) { + val test1: Boolean = actual == expected; + if (!test0 || !test1) { + val s0 = if (test0) "ok" else "KO"; + val s1 = if (test1) "ok" else "KO"; + val s2 = actual.toString(); + val s3 = expected.toString(); + error(s0 + " - " + s1 + ": " + s2 + " != " + s3); + } + checks += 1 + } + + def check_Ta[T <: Any ](xs: Array[T], l: Int, x0: T, c: Check[T]) { + check(xs.length == l, xs.length, l); + check(xs(0) == x0, xs(0), x0); + c(xs); + } + + def check_Tv[T <: AnyVal ](xs: Array[T], l: Int, x0: T, c: Check[T]) { + check(xs.length == l, xs.length, l); + check(xs(0) == x0, xs(0), x0); + check_Ta(xs, l, x0, c); + c(xs); + } + + def check_Tr[T <: AnyRef ](xs: Array[T], l: Int, x0: T, c: Check[T]) { + check(xs.length == l, xs.length, l); + check(xs(0) == x0, xs(0), x0); + check_Ta(xs, l, x0, c); + c(xs); + } + + def check_To[T <: Object ](xs: Array[T], l: Int, x0: T, c: Check[T]) { + check(xs.length == l, xs.length, l); + check(xs(0) == x0, xs(0), x0); + check_Ta(xs, l, x0, c); + check_Tr(xs, l, x0, c); + c(xs); + } + + def check_Tm[T <: Map ](xs: Array[T], l: Int, x0: T, c: Check[T]) { + check(xs.length == l, xs.length, l) + check(xs(0) == x0, xs(0), x0) + check_Ta(xs, l, x0, c) + check_Tr(xs, l, x0, c) + check_To(xs, l, x0, c) + c(xs) + } + + def check_Tn[T <: Strings](xs: Array[T], l: Int, x0: T, c: Check[T]) { + check(xs.length == l, xs.length, l) + check(xs(0) == x0, xs(0), x0) + check_Ta(xs, l, x0, c) + check_Tr(xs, l, x0, c) + check_To(xs, l, x0, c) + c(xs) + } + + def checkT2368() { + val arr = Array(1, 2, 3) + arr(0) += 1 + assert(arr(0) == 2) + } + + //########################################################################## + // Values + + val u0: Unit = (); + val u1: Unit = (); + + val z0: Boolean = false; + val z1: Boolean = true; + + val b0: Byte = Byte.MinValue; + val b1: Byte = 1; + val b2: Byte = Byte.MaxValue; + + val s0: Short = Short.MinValue; + val s1: Short = 2; + val s2: Short = Short.MaxValue; + + val c0: Char = Char.MinValue; + val c1: Char = '3'; + val c2: Char = Char.MaxValue; + + val i0: Int = Int.MinValue; + val i1: Int = 4; + val i2: Int = Int.MinValue; + + val l0: Long = Long.MinValue; + val l1: Int = 5; + val l2: Long = Long.MaxValue; + + val f0: Float = Float.MinValue; + val f1: Int = 6; + val f2: Float = Float.MaxValue; + + val d0: Double = Double.MinValue; + val d1: Int = 7; + val d2: Double = Double.MaxValue; + + val a0: Unit = (); + val a1: Boolean = false; + val a2: Int = 0; + val a3: Null = null; + val a4: String = "a-z"; + val a5: Symbol = 'token; + val a6: HashMap = new HashMap(); + val a7: TreeMap = scala.collection.immutable.TreeMap.empty[Int, Any]; + val a8: Strings = List("a", "z"); + + val v0: Unit = (); + val v1: Boolean = false; + val v2: Int = 0; + val v3: Long = l2; + val v4: Float = f2; + val v5: Double = d2; + + val r0: Null = a3; + val r1: String = a4; + val r2: Symbol = a5; + val r3: HashMap = a6; + val r4: TreeMap = a7; + val r5: Strings = a8; + + val o0: Null = r0; + val o1: String = r1; + val o2: Symbol = r2; + val o3: HashMap = r3; + val o4: TreeMap = r4; + val o5: Strings = r5; + + val m0: Null = r0; + val m1: HashMap = r3; + val m2: TreeMap = r4; + + val n0: Null = r0; + val n1: Strings = r5; + val n2: Nil.type= Nil; + + //########################################################################## + // Specific Checks + + def ucheck(xs: Array[Unit ]): Unit = { + check(xs.length == 2, xs.length, 2); + check(xs(0) == u0, xs(0), u0); + check(xs(1) == u1, xs(1), u1); + } + + def zcheck(xs: Array[Boolean]): Unit = { + check(xs.length == 2, xs.length, 2); + check(xs(0) == z0, xs(0), z0); + check(xs(1) == z1, xs(1), z1); + } + + def bcheck(xs: Array[Byte ]): Unit = { + check(xs.length == 3, xs.length, 3); + check(xs(0) == b0, xs(0), b0); + check(xs(1) == b1, xs(1), b1); + check(xs(2) == b2, xs(2), b2); + } + + def scheck(xs: Array[Short ]): Unit = { + check(xs.length == 3, xs.length, 3); + check(xs(0) == s0, xs(0), s0); + check(xs(1) == s1, xs(1), s1); + check(xs(2) == s2, xs(2), s2); + } + + def ccheck(xs: Array[Char ]): Unit = { + check(xs.length == 3, xs.length, 3); + check(xs(0) == c0, xs(0), c0); + check(xs(1) == c1, xs(1), c1); + check(xs(2) == c2, xs(2), c2); + } + + def icheck(xs: Array[Int ]): Unit = { + check(xs.length == 3, xs.length, 3); + check(xs(0) == i0, xs(0), i0); + check(xs(1) == i1, xs(1), i1); + check(xs(2) == i2, xs(2), i2); + } + + def lcheck(xs: Array[Long ]): Unit = { + check(xs.length == 3, xs.length, 3); + check(xs(0) == l0, xs(0), l0); + check(xs(1) == l1, xs(1), l1: Long); // !!! : Long + check(xs(2) == l2, xs(2), l2); + } + + def fcheck(xs: Array[Float ]): Unit = { + check(xs.length == 3, xs.length, 3); + check(xs(0) == f0, xs(0), f0); + check(xs(1) == f1, xs(1), f1: Float); // !!! : Float + check(xs(2) == f2, xs(2), f2); + } + + def dcheck(xs: Array[Double ]): Unit = { + check(xs.length == 3, xs.length, 3); + check(xs(0) == d0, xs(0), d0); + check(xs(1) == d1, xs(1), d1: Double); // !!! : Double + check(xs(2) == d2, xs(2), d2); + } + + def rcheck(xs: Array[AnyRef ]): Unit = { + check(xs.length == 6, xs.length, 6); + check(xs(0) == r0, xs(0), r0); + check(xs(1) == r1, xs(1), r1); + check(xs(2) == r2, xs(2), r2); + check(xs(3) == r3, xs(3), r3); + check(xs(4) == r4, xs(4), r4); + check(xs(5) == r5, xs(5), r5); + } + + def ocheck(xs: Array[Object ]): Unit = { + check(xs.length == 6, xs.length, 6); + check(xs(0) == o0, xs(0), o0); + check(xs(1) == o1, xs(1), o1); + check(xs(2) == o2, xs(2), o2); + check(xs(3) == o3, xs(3), o3); + check(xs(4) == o4, xs(4), o4); + check(xs(5) == o5, xs(5), o5); + } + + def mcheck(xs: Array[Map ]): Unit = { + check(xs.length == 3, xs.length, 3); + check(xs(0) == m0, xs(0), m0); + check(xs(1) == m1, xs(1), m1); + check(xs(2) == m2, xs(2), m2); + } + + def ncheck(xs: Array[Strings]) { + check(xs.length == 3, xs.length, 3) + check(xs(0) == n0, xs(0), n0) + check(xs(1) == n1, xs(1), n1) + check(xs(2) == n2, xs(2), n2) + } + + //########################################################################## + // Miscellaneous checks + + def checkZip { + val zipped = Array("a", "b", "c").zip(Array(1, 2)) + val expected = Array(("a",1), ("b",2)) + check(zipped sameElements expected, zipped.toList, expected.toList) + } + + def checkConcat { // ticket #713 + val x1 = Array.concat(Array(1, 2), Array(3, 4)) + val y1 = Array(1, 2, 3, 4) + check(x1 sameElements y1, x1.toList, y1.toList) + } + + //########################################################################## + // Arrays + + val uarray: Array[Unit ] = Array(u0, u1); + val zarray: Array[Boolean] = Array(z0, z1); + val barray: Array[Byte ] = Array(b0, b1, b2); + val sarray: Array[Short ] = Array(s0, s1, s2); + val carray: Array[Char ] = Array(c0, c1, c2); + val iarray: Array[Int ] = Array(i0, i1, i2); + val larray: Array[Long ] = Array(l0, l1, l2); + val farray: Array[Float ] = Array(f0, f1, f2); + val darray: Array[Double ] = Array(d0, d1, d2); + val rarray: Array[AnyRef ] = Array(r0, r1, r2, r4, r4, r5); + val oarray: Array[Object ] = Array(o0, o1, o2, o4, o4, o5); + val marray: Array[Map ] = Array(m0, m1, m2); + val narray: Array[Strings] = Array(n0, n1, n2); + + //########################################################################## + // Main + + def main(args: Array[String]): Unit = { + + //###################################################################### + + ucheck(uarray); + zcheck(zarray); + bcheck(barray); + scheck(sarray); + ccheck(carray); + icheck(iarray); + lcheck(larray); + fcheck(farray); + dcheck(darray); + rcheck(rarray); + ocheck(oarray); + mcheck(marray); + ncheck(narray); + + //###################################################################### + + ucheck(id_Ta_T(uarray)); + zcheck(id_Ta_T(zarray)); + bcheck(id_Ta_T(barray)); + scheck(id_Ta_T(sarray)); + ccheck(id_Ta_T(carray)); + icheck(id_Ta_T(iarray)); + lcheck(id_Ta_T(larray)); + fcheck(id_Ta_T(farray)); + dcheck(id_Ta_T(darray)); + rcheck(id_Ta_T(rarray)); + ocheck(id_Ta_T(oarray)); + mcheck(id_Ta_T(marray)); + ncheck(id_Ta_T(narray)); + + ucheck(id_Tr_T(uarray)); + zcheck(id_Tr_T(zarray)); + bcheck(id_Tr_T(barray)); + scheck(id_Tr_T(sarray)); + ccheck(id_Tr_T(carray)); + icheck(id_Tr_T(iarray)); + lcheck(id_Tr_T(larray)); + fcheck(id_Tr_T(farray)); + dcheck(id_Tr_T(darray)); + rcheck(id_Tr_T(rarray)); + ocheck(id_Tr_T(oarray)); + mcheck(id_Tr_T(marray)); + ncheck(id_Tr_T(narray)); + + ucheck(id_To_T(uarray)); + zcheck(id_To_T(zarray)); + bcheck(id_To_T(barray)); + scheck(id_To_T(sarray)); + ccheck(id_To_T(carray)); + icheck(id_To_T(iarray)); + lcheck(id_To_T(larray)); + fcheck(id_To_T(farray)); + dcheck(id_To_T(darray)); + rcheck(id_To_T(rarray)); + ocheck(id_To_T(oarray)); + mcheck(id_To_T(marray)); + ncheck(id_To_T(narray)); + + ucheck(id_Ta_a(uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_Ta_a(zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_Ta_a(barray).asInstanceOf[Array[Byte ]]); + scheck(id_Ta_a(sarray).asInstanceOf[Array[Short ]]); + ccheck(id_Ta_a(carray).asInstanceOf[Array[Char ]]); + icheck(id_Ta_a(iarray).asInstanceOf[Array[Int ]]); + lcheck(id_Ta_a(larray).asInstanceOf[Array[Long ]]); + fcheck(id_Ta_a(farray).asInstanceOf[Array[Float ]]); + dcheck(id_Ta_a(darray).asInstanceOf[Array[Double ]]); + rcheck(id_Ta_a(rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_Ta_a(oarray).asInstanceOf[Array[Object ]]); + mcheck(id_Ta_a(marray).asInstanceOf[Array[Map ]]); + ncheck(id_Ta_a(narray).asInstanceOf[Array[Strings]]); + + ucheck(id_Tr_a(uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_Tr_a(zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_Tr_a(barray).asInstanceOf[Array[Byte ]]); + scheck(id_Tr_a(sarray).asInstanceOf[Array[Short ]]); + ccheck(id_Tr_a(carray).asInstanceOf[Array[Char ]]); + icheck(id_Tr_a(iarray).asInstanceOf[Array[Int ]]); + lcheck(id_Tr_a(larray).asInstanceOf[Array[Long ]]); + fcheck(id_Tr_a(farray).asInstanceOf[Array[Float ]]); + dcheck(id_Tr_a(darray).asInstanceOf[Array[Double ]]); + rcheck(id_Tr_a(rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_Tr_a(oarray).asInstanceOf[Array[Object ]]); + mcheck(id_Tr_a(marray).asInstanceOf[Array[Map ]]); + ncheck(id_Tr_a(narray).asInstanceOf[Array[Strings]]); + + ucheck(id_To_a(uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_To_a(zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_To_a(barray).asInstanceOf[Array[Byte ]]); + scheck(id_To_a(sarray).asInstanceOf[Array[Short ]]); + ccheck(id_To_a(carray).asInstanceOf[Array[Char ]]); + icheck(id_To_a(iarray).asInstanceOf[Array[Int ]]); + lcheck(id_To_a(larray).asInstanceOf[Array[Long ]]); + fcheck(id_To_a(farray).asInstanceOf[Array[Float ]]); + dcheck(id_To_a(darray).asInstanceOf[Array[Double ]]); + rcheck(id_To_a(rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_To_a(oarray).asInstanceOf[Array[Object ]]); + mcheck(id_To_a(marray).asInstanceOf[Array[Map ]]); + ncheck(id_To_a(narray).asInstanceOf[Array[Strings]]); + + ucheck(id_Tr_r(uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_Tr_r(zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_Tr_r(barray).asInstanceOf[Array[Byte ]]); + scheck(id_Tr_r(sarray).asInstanceOf[Array[Short ]]); + ccheck(id_Tr_r(carray).asInstanceOf[Array[Char ]]); + icheck(id_Tr_r(iarray).asInstanceOf[Array[Int ]]); + lcheck(id_Tr_r(larray).asInstanceOf[Array[Long ]]); + fcheck(id_Tr_r(farray).asInstanceOf[Array[Float ]]); + dcheck(id_Tr_r(darray).asInstanceOf[Array[Double ]]); + rcheck(id_Tr_r(rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_Tr_r(oarray).asInstanceOf[Array[Object ]]); + mcheck(id_Tr_r(marray).asInstanceOf[Array[Map ]]); + ncheck(id_Tr_r(narray).asInstanceOf[Array[Strings]]); + + ucheck(id_To_r(uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_To_r(zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_To_r(barray).asInstanceOf[Array[Byte ]]); + scheck(id_To_r(sarray).asInstanceOf[Array[Short ]]); + ccheck(id_To_r(carray).asInstanceOf[Array[Char ]]); + icheck(id_To_r(iarray).asInstanceOf[Array[Int ]]); + lcheck(id_To_r(larray).asInstanceOf[Array[Long ]]); + fcheck(id_To_r(farray).asInstanceOf[Array[Float ]]); + dcheck(id_To_r(darray).asInstanceOf[Array[Double ]]); + rcheck(id_To_r(rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_To_r(oarray).asInstanceOf[Array[Object ]]); + mcheck(id_To_r(marray).asInstanceOf[Array[Map ]]); + ncheck(id_To_r(narray).asInstanceOf[Array[Strings]]); + + ucheck(id_To_o(uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_To_o(zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_To_o(barray).asInstanceOf[Array[Byte ]]); + scheck(id_To_o(sarray).asInstanceOf[Array[Short ]]); + ccheck(id_To_o(carray).asInstanceOf[Array[Char ]]); + icheck(id_To_o(iarray).asInstanceOf[Array[Int ]]); + lcheck(id_To_o(larray).asInstanceOf[Array[Long ]]); + fcheck(id_To_o(farray).asInstanceOf[Array[Float ]]); + dcheck(id_To_o(darray).asInstanceOf[Array[Double ]]); + rcheck(id_To_o(rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_To_o(oarray).asInstanceOf[Array[Object ]]); + mcheck(id_To_o(marray).asInstanceOf[Array[Map ]]); + ncheck(id_To_o(narray).asInstanceOf[Array[Strings]]); + + //###################################################################### + + ucheck(id_TSa_T [Unit , Array[Unit ]](uarray)); + zcheck(id_TSa_T [Boolean, Array[Boolean]](zarray)); + bcheck(id_TSa_T [Byte , Array[Byte ]](barray)); + scheck(id_TSa_T [Short , Array[Short ]](sarray)); + ccheck(id_TSa_T [Char , Array[Char ]](carray)); + icheck(id_TSa_T [Int , Array[Int ]](iarray)); + lcheck(id_TSa_T [Long , Array[Long ]](larray)); + fcheck(id_TSa_T [Float , Array[Float ]](farray)); + dcheck(id_TSa_T [Double , Array[Double ]](darray)); + rcheck(id_TSa_T [AnyRef , Array[AnyRef ]](rarray)); + ocheck(id_TSa_T [Object , Array[Object ]](oarray)); + mcheck(id_TSa_T [Map , Array[Map ]](marray)); + ncheck(id_TSa_T [Strings, Array[Strings]](narray)); + + ucheck(id_TSv_T [Unit , Array[Unit ]](uarray)); + zcheck(id_TSv_T [Boolean, Array[Boolean]](zarray)); + bcheck(id_TSv_T [Byte , Array[Byte ]](barray)); + scheck(id_TSv_T [Short , Array[Short ]](sarray)); + ccheck(id_TSv_T [Char , Array[Char ]](carray)); + icheck(id_TSv_T [Int , Array[Int ]](iarray)); + lcheck(id_TSv_T [Long , Array[Long ]](larray)); + fcheck(id_TSv_T [Float , Array[Float ]](farray)); + dcheck(id_TSv_T [Double , Array[Double ]](darray)); + + rcheck(id_TSr_T [AnyRef , Array[AnyRef ]](rarray)); + ocheck(id_TSr_T [Object , Array[Object ]](oarray)); + mcheck(id_TSr_T [Map , Array[Map ]](marray)); + ncheck(id_TSr_T [Strings, Array[Strings]](narray)); + + rcheck(id_TSo_T [AnyRef , Array[AnyRef ]](rarray)); + ocheck(id_TSo_T [Object , Array[Object ]](oarray)); + mcheck(id_TSo_T [Map , Array[Map ]](marray)); + ncheck(id_TSo_T [Strings, Array[Strings]](narray)); + + mcheck(id_TSm_T [Map , Array[Map ]](marray)); + + ncheck(id_TSn_T [Strings, Array[Strings]](narray)); + + //###################################################################### + + ucheck(id_TSa_Ss[Unit , Array[Unit ]](uarray)); + zcheck(id_TSa_Ss[Boolean, Array[Boolean]](zarray)); + bcheck(id_TSa_Ss[Byte , Array[Byte ]](barray)); + scheck(id_TSa_Ss[Short , Array[Short ]](sarray)); + ccheck(id_TSa_Ss[Char , Array[Char ]](carray)); + icheck(id_TSa_Ss[Int , Array[Int ]](iarray)); + lcheck(id_TSa_Ss[Long , Array[Long ]](larray)); + fcheck(id_TSa_Ss[Float , Array[Float ]](farray)); + dcheck(id_TSa_Ss[Double , Array[Double ]](darray)); + rcheck(id_TSa_Ss[AnyRef , Array[AnyRef ]](rarray)); + ocheck(id_TSa_Ss[Object , Array[Object ]](oarray)); + mcheck(id_TSa_Ss[Map , Array[Map ]](marray)); + ncheck(id_TSa_Ss[Strings, Array[Strings]](narray)); + + ucheck(id_TSv_Ss[Unit , Array[Unit ]](uarray)); + zcheck(id_TSv_Ss[Boolean, Array[Boolean]](zarray)); + bcheck(id_TSv_Ss[Byte , Array[Byte ]](barray)); + scheck(id_TSv_Ss[Short , Array[Short ]](sarray)); + ccheck(id_TSv_Ss[Char , Array[Char ]](carray)); + icheck(id_TSv_Ss[Int , Array[Int ]](iarray)); + lcheck(id_TSv_Ss[Long , Array[Long ]](larray)); + fcheck(id_TSv_Ss[Float , Array[Float ]](farray)); + dcheck(id_TSv_Ss[Double , Array[Double ]](darray)); + + rcheck(id_TSr_Ss[AnyRef , Array[AnyRef ]](rarray)); + ocheck(id_TSr_Ss[Object , Array[Object ]](oarray)); + mcheck(id_TSr_Ss[Map , Array[Map ]](marray)); + ncheck(id_TSr_Ss[Strings, Array[Strings]](narray)); + + rcheck(id_TSo_Ss[AnyRef , Array[AnyRef ]](rarray)); + ocheck(id_TSo_Ss[Object , Array[Object ]](oarray)); + mcheck(id_TSo_Ss[Map , Array[Map ]](marray)); + ncheck(id_TSo_Ss[Strings, Array[Strings]](narray)); + + mcheck(id_TSm_Ss[Map , Array[Map ]](marray)); + + ncheck(id_TSn_Ss[Strings, Array[Strings]](narray)); + + //###################################################################### + + ucheck(id_TSa_a [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSa_a [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSa_a [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSa_a [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSa_a [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSa_a [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSa_a [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSa_a [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSa_a [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + rcheck(id_TSa_a [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSa_a [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSa_a [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSa_a [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + ucheck(id_TSv_a [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSv_a [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSv_a [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSv_a [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSv_a [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSv_a [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSv_a [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSv_a [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSv_a [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + + rcheck(id_TSr_a [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSr_a [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSr_a [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSr_a [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + rcheck(id_TSo_a [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSo_a [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSo_a [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSo_a [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + mcheck(id_TSm_a [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + + ncheck(id_TSn_a [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + //###################################################################### + + ucheck(id_TSa_r [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSa_r [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSa_r [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSa_r [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSa_r [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSa_r [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSa_r [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSa_r [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSa_r [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + rcheck(id_TSa_r [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSa_r [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSa_r [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSa_r [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + ucheck(id_TSv_r [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSv_r [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSv_r [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSv_r [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSv_r [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSv_r [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSv_r [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSv_r [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSv_r [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + + rcheck(id_TSr_r [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSr_r [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSr_r [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSr_r [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + rcheck(id_TSo_r [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSo_r [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSo_r [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSo_r [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + mcheck(id_TSm_r [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + + ncheck(id_TSn_r [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + //###################################################################### + + ucheck(id_TSa_o [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSa_o [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSa_o [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSa_o [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSa_o [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSa_o [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSa_o [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSa_o [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSa_o [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + rcheck(id_TSa_o [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSa_o [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSa_o [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSa_o [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + ucheck(id_TSv_o [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSv_o [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSv_o [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSv_o [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSv_o [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSv_o [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSv_o [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSv_o [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSv_o [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + + rcheck(id_TSr_o [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSr_o [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSr_o [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSr_o [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + rcheck(id_TSo_o [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSo_o [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSo_o [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSo_o [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + mcheck(id_TSm_o [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + + ncheck(id_TSn_o [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + //###################################################################### + + ucheck(id_Sas_Ss[Unit ](uarray)); + zcheck(id_Sas_Ss[Boolean](zarray)); + bcheck(id_Sas_Ss[Byte ](barray)); + scheck(id_Sas_Ss[Short ](sarray)); + ccheck(id_Sas_Ss[Char ](carray)); + icheck(id_Sas_Ss[Int ](iarray)); + lcheck(id_Sas_Ss[Long ](larray)); + fcheck(id_Sas_Ss[Float ](farray)); + dcheck(id_Sas_Ss[Double ](darray)); + rcheck(id_Sas_Ss[AnyRef ](rarray)); + ocheck(id_Sas_Ss[Object ](oarray)); + mcheck(id_Sas_Ss[Map ](marray)); + ncheck(id_Sas_Ss[Strings](narray)); + + ucheck(id_Svs_Ss[Unit ](uarray)); + zcheck(id_Svs_Ss[Boolean](zarray)); + bcheck(id_Svs_Ss[Byte ](barray)); + scheck(id_Svs_Ss[Short ](sarray)); + ccheck(id_Svs_Ss[Char ](carray)); + icheck(id_Svs_Ss[Int ](iarray)); + lcheck(id_Svs_Ss[Long ](larray)); + fcheck(id_Svs_Ss[Float ](farray)); + dcheck(id_Svs_Ss[Double ](darray)); + + rcheck(id_Srs_Ss[AnyRef ](rarray)); + ocheck(id_Srs_Ss[Object ](oarray)); + mcheck(id_Srs_Ss[Map ](marray)); + ncheck(id_Srs_Ss[Strings](narray)); + + rcheck(id_Sos_Ss[AnyRef ](rarray)); + ocheck(id_Sos_Ss[Object ](oarray)); + mcheck(id_Sos_Ss[Map ](marray)); + ncheck(id_Sos_Ss[Strings](narray)); + + mcheck(id_Sms_Ss[Map ](marray)); + + ncheck(id_Sns_Ss[Strings](narray)); + + //###################################################################### + + ucheck(id_TSa_a [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSa_a [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSa_a [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSa_a [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSa_a [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSa_a [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSa_a [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSa_a [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSa_a [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + rcheck(id_TSa_a [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSa_a [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSa_a [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSa_a [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + ucheck(id_TSv_a [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSv_a [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSv_a [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSv_a [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSv_a [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSv_a [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSv_a [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSv_a [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSv_a [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + + rcheck(id_TSr_a [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSr_a [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSr_a [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSr_a [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + rcheck(id_TSo_a [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSo_a [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSo_a [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSo_a [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + mcheck(id_TSm_a [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + + ncheck(id_TSn_a [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + //###################################################################### + + ucheck(id_TSa_r [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSa_r [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSa_r [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSa_r [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSa_r [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSa_r [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSa_r [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSa_r [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSa_r [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + rcheck(id_TSa_r [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSa_r [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSa_r [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSa_r [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + ucheck(id_TSv_r [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSv_r [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSv_r [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSv_r [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSv_r [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSv_r [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSv_r [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSv_r [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSv_r [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + + rcheck(id_TSr_r [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSr_r [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSr_r [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSr_r [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + rcheck(id_TSo_r [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSo_r [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSo_r [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSo_r [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + mcheck(id_TSm_r [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + + ncheck(id_TSn_r [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + //###################################################################### + + ucheck(id_TSa_o [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSa_o [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSa_o [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSa_o [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSa_o [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSa_o [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSa_o [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSa_o [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSa_o [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + rcheck(id_TSa_o [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSa_o [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSa_o [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSa_o [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + ucheck(id_TSv_o [Unit , Array[Unit ]](uarray).asInstanceOf[Array[Unit ]]); + zcheck(id_TSv_o [Boolean, Array[Boolean]](zarray).asInstanceOf[Array[Boolean]]); + bcheck(id_TSv_o [Byte , Array[Byte ]](barray).asInstanceOf[Array[Byte ]]); + scheck(id_TSv_o [Short , Array[Short ]](sarray).asInstanceOf[Array[Short ]]); + ccheck(id_TSv_o [Char , Array[Char ]](carray).asInstanceOf[Array[Char ]]); + icheck(id_TSv_o [Int , Array[Int ]](iarray).asInstanceOf[Array[Int ]]); + lcheck(id_TSv_o [Long , Array[Long ]](larray).asInstanceOf[Array[Long ]]); + fcheck(id_TSv_o [Float , Array[Float ]](farray).asInstanceOf[Array[Float ]]); + dcheck(id_TSv_o [Double , Array[Double ]](darray).asInstanceOf[Array[Double ]]); + + rcheck(id_TSr_o [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSr_o [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSr_o [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSr_o [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + rcheck(id_TSo_o [AnyRef , Array[AnyRef ]](rarray).asInstanceOf[Array[AnyRef ]]); + ocheck(id_TSo_o [Object , Array[Object ]](oarray).asInstanceOf[Array[Object ]]); + mcheck(id_TSo_o [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + ncheck(id_TSo_o [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + mcheck(id_TSm_o [Map , Array[Map ]](marray).asInstanceOf[Array[Map ]]); + + ncheck(id_TSn_o [Strings, Array[Strings]](narray).asInstanceOf[Array[Strings]]); + + //###################################################################### + + check_Ta(uarray, 2, u0, ucheck) + check_Ta(zarray, 2, z0, zcheck) + check_Ta(barray, 3, b0, bcheck) + check_Ta(sarray, 3, s0, scheck) + check_Ta(carray, 3, c0, ccheck) + check_Ta(iarray, 3, i0, icheck) + check_Ta(larray, 3, l0, lcheck) + check_Ta(farray, 3, f0, fcheck) + check_Ta(darray, 3, d0, dcheck) + check_Ta(rarray, 6, r0, rcheck) + check_Ta(oarray, 6, o0, ocheck) + check_Ta(marray, 3, m0, mcheck) + check_Ta(narray, 3, n0, ncheck) + + check_Tv(uarray, 2, u0, ucheck) + check_Tv(zarray, 2, z0, zcheck) + check_Tv(barray, 3, b0, bcheck) + check_Tv(sarray, 3, s0, scheck) + check_Tv(carray, 3, c0, ccheck) + check_Tv(iarray, 3, i0, icheck) + check_Tv(larray, 3, l0, lcheck) + check_Tv(farray, 3, f0, fcheck) + check_Tv(darray, 3, d0, dcheck) + + check_Tr(rarray, 6, r0, rcheck) + check_Tr(oarray, 6, o0, ocheck) + check_Tr(marray, 3, m0, mcheck) + check_Tr(narray, 3, n0, ncheck) + + check_To(rarray, 6, r0, rcheck) + check_To(oarray, 6, o0, ocheck) + check_To(marray, 3, m0, mcheck) + check_To(narray, 3, n0, ncheck) + + check_Tm(marray, 3, m0, mcheck) + + check_Tn(narray, 3, n0, ncheck) + + //###################################################################### + + checkZip + checkConcat + checkT2368() + + //###################################################################### + + println("checks: " + checks) + + //###################################################################### + } + + //########################################################################## +} + diff --git a/test/files/run/interpolation.check b/test/files/run/interpolation.check index 09579a800a..997abb4497 100644 --- a/test/files/run/interpolation.check +++ b/test/files/run/interpolation.check @@ -24,3 +24,9 @@ Best price: 13.345 Best price: 13.35 13.345% discount included 13.35% discount included + +0 +00 + +0 +00 diff --git a/test/files/run/interpolation.scala b/test/files/run/interpolation.scala index a0a185eaab..f443bd5feb 100644 --- a/test/files/run/interpolation.scala +++ b/test/files/run/interpolation.scala @@ -23,4 +23,10 @@ object Test extends App { test2(10.0f) test2(13.345f) + println(s"") + println(s"${0}") + println(s"${0}${0}") + println(f"") + println(f"${0}") + println(f"${0}${0}") } diff --git a/test/files/run/interpolationMultiline2.check b/test/files/run/interpolationMultiline2.check index 7584aee9f7..2218c93a99 100644 --- a/test/files/run/interpolationMultiline2.check +++ b/test/files/run/interpolationMultiline2.check @@ -1,26 +1,26 @@ Bob is 1 years old! -java.lang.StringIndexOutOfBoundsException: String index out of range: 0 Bob is 1 years old! -java.lang.StringIndexOutOfBoundsException: String index out of range: 0 +Bob is 1 years old! +Bob is 1 years old! Bob is 1 years old! Bob is 1%2d years old! Bob is 1 years old! Bob is 1%2d years old! =============== Bob is 12 years old! -java.lang.StringIndexOutOfBoundsException: String index out of range: 0 Bob is 12 years old! -java.lang.StringIndexOutOfBoundsException: String index out of range: 0 +Bob is 12 years old! +Bob is 12 years old! Bob is 12 years old! Bob is 12%2d years old! Bob is 12 years old! Bob is 12%2d years old! =============== Bob is 123 years old! -java.lang.StringIndexOutOfBoundsException: String index out of range: 0 Bob is 123 years old! -java.lang.StringIndexOutOfBoundsException: String index out of range: 0 +Bob is 123 years old! +Bob is 123 years old! Bob is 123 years old! Bob is 123%2d years old! Bob is 123 years old! -Bob is 123%2d years old!
\ No newline at end of file +Bob is 123%2d years old! diff --git a/test/files/run/lub-visibility.check b/test/files/run/lub-visibility.check new file mode 100644 index 0000000000..3461d1bf6b --- /dev/null +++ b/test/files/run/lub-visibility.check @@ -0,0 +1,14 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> // should infer List[scala.collection.immutable.Seq[Nothing]] + +scala> // but reverted that for SI-5534. + +scala> val x = List(List(), Vector()) +x: List[scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq{def dropRight(n: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]; def takeRight(n: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]; def drop(n: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]; def take(n: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]; def slice(from: Int,until: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]}]; def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.Ab... +scala> + +scala> diff --git a/test/files/run/lub-visibility.scala b/test/files/run/lub-visibility.scala new file mode 100644 index 0000000000..8d5d3ae11a --- /dev/null +++ b/test/files/run/lub-visibility.scala @@ -0,0 +1,8 @@ +import scala.tools.partest.ReplTest +object Test extends ReplTest { + def code = """ + |// should infer List[scala.collection.immutable.Seq[Nothing]] + |// but reverted that for SI-5534. + |val x = List(List(), Vector()) + """.stripMargin +} diff --git a/test/files/run/manifests.scala b/test/files/run/manifests.scala index 1da06b8aee..6b6ea80b34 100644 --- a/test/files/run/manifests.scala +++ b/test/files/run/manifests.scala @@ -46,11 +46,20 @@ object Test def showsContravariance[T, U, CC[_]](implicit ev1: Manifest[T], ev2: Manifest[U], ev3: Manifest[CC[T]], ev4: Manifest[CC[U]]) = new VarianceTester[T, U, CC](CONTRA) showsExpectedVariance - def typeCompare[T, U](implicit ev1: Manifest[T], ev2: Manifest[U]) = (ev1 <:< ev2, ev2 <:< ev1) match { - case (true, true) => SAME - case (true, false) => SUB - case (false, true) => SUPER - case (false, false) => NONE + def typeCompare[T, U](implicit ev1: Manifest[T], ev2: Manifest[U]) = { + // checking types as well + if ((ev1 <:< ev2) != (ev1.tpe <:< ev2.tpe)) + println("Failed! " + ((ev1, ev2))) + + if ((ev2 <:< ev1) != (ev2.tpe <:< ev1.tpe)) + println("Failed! " + ((ev2, ev1))) + + (ev1 <:< ev2, ev2 <:< ev1) match { + case (true, true) => SAME + case (true, false) => SUB + case (false, true) => SUPER + case (false, false) => NONE + } } def assertAnyRef[T: Manifest] = List( diff --git a/test/files/run/t2296a.check b/test/files/run/t2296a.check new file mode 100644 index 0000000000..f75aec9d81 --- /dev/null +++ b/test/files/run/t2296a.check @@ -0,0 +1,2 @@ +J.foo() +J.foo() diff --git a/test/files/run/t2296a/J.java b/test/files/run/t2296a/J.java new file mode 100644 index 0000000000..78ff3e9804 --- /dev/null +++ b/test/files/run/t2296a/J.java @@ -0,0 +1,7 @@ +package j; + +public class J { + protected void foo() { + System.out.println("J.foo()"); + } +}
\ No newline at end of file diff --git a/test/files/run/t2296a/S.scala b/test/files/run/t2296a/S.scala new file mode 100644 index 0000000000..532d038a42 --- /dev/null +++ b/test/files/run/t2296a/S.scala @@ -0,0 +1,18 @@ +package s { + import j.J + + trait S extends J { + def bar() { + foo() + } + } + + class SC extends J with S +} + +object Test { + def main(args : Array[String]) { + (new s.SC).bar() + (new s.S { }).bar() + } +}
\ No newline at end of file diff --git a/test/files/run/t2296b.check b/test/files/run/t2296b.check new file mode 100644 index 0000000000..f75aec9d81 --- /dev/null +++ b/test/files/run/t2296b.check @@ -0,0 +1,2 @@ +J.foo() +J.foo() diff --git a/test/files/run/t2296b/J_1.java b/test/files/run/t2296b/J_1.java new file mode 100644 index 0000000000..4c91d47073 --- /dev/null +++ b/test/files/run/t2296b/J_1.java @@ -0,0 +1,7 @@ +package j; + +public class J_1 { + protected void foo() { + System.out.println("J.foo()"); + } +}
\ No newline at end of file diff --git a/test/files/run/t2296b/S_2.scala b/test/files/run/t2296b/S_2.scala new file mode 100644 index 0000000000..6cdb0cfaba --- /dev/null +++ b/test/files/run/t2296b/S_2.scala @@ -0,0 +1,18 @@ +package s { + import j.J_1 + + trait S extends J_1 { + def bar() { + foo() + } + } + + class SC extends J_1 with S +} + +object Test { + def main(args : Array[String]) { + (new s.SC).bar() + (new s.S { }).bar() + } +} diff --git a/test/files/run/t3569.check b/test/files/run/t3569.check new file mode 100644 index 0000000000..24cee4bf00 --- /dev/null +++ b/test/files/run/t3569.check @@ -0,0 +1,17 @@ +1 +private final int Test$X.val1 +private final int Test$X.val2 +private final int Test$X.val3 +private int Test$X.lval1 +private int Test$X.lval2 +private int Test$X.lval3 +private int Test$X.var1 +private int Test$X.var2 +private int Test$X.var3 +private volatile int Test$X.bitmap$priv$0 +public int Test$X.x +public volatile int Test$X.bitmap$0 +public final int Test$Y.z1 +public final int Test$Y.z2 +public int Test$Y.x +public int Test$Y.y diff --git a/test/files/run/t3569.flags b/test/files/run/t3569.flags new file mode 100644 index 0000000000..6933d924d3 --- /dev/null +++ b/test/files/run/t3569.flags @@ -0,0 +1 @@ +-Yinline
\ No newline at end of file diff --git a/test/files/run/t3569.scala b/test/files/run/t3569.scala new file mode 100644 index 0000000000..4699aeaab3 --- /dev/null +++ b/test/files/run/t3569.scala @@ -0,0 +1,32 @@ +object Test { + final val bippy1 = 1 + final lazy val bippy2 = 2 + + lazy val lv = scala.util.Random.nextInt() + + class X(final var x: Int) { + final var var1: Int = 0 + final private var var2: Int = 0 + final private[this] var var3: Int = 0 + + final val val1: Int = 1 + final private val val2: Int = 1 + final private[this] val val3: Int = 1 + + final lazy val lval1: Int = 2 + final private lazy val lval2: Int = 2 + final private[this] lazy val lval3: Int = 2 + } + case class Y(final var x: Int, final private var y: Int, final val z1: Int, final private val z2: Int) { } + + def f = new X(0).x += 1 + def main(args: Array[String]) { + f + val s = new X(0) + s.x += 1 + println(s.x) + + (classOf[X].getDeclaredFields map ("" + _)).sorted foreach println + (classOf[Y].getDeclaredFields map ("" + _)).sorted foreach println + } +} diff --git a/test/files/run/si4147.scala b/test/files/run/t4147.scala index c1e2d746a9..c1e2d746a9 100644 --- a/test/files/run/si4147.scala +++ b/test/files/run/t4147.scala diff --git a/test/files/run/t4777.check b/test/files/run/t4777.check new file mode 100644 index 0000000000..11f1f59d43 --- /dev/null +++ b/test/files/run/t4777.check @@ -0,0 +1,2 @@ +28 +28 diff --git a/test/files/run/t4777.scala b/test/files/run/t4777.scala new file mode 100644 index 0000000000..4a811d3b9a --- /dev/null +++ b/test/files/run/t4777.scala @@ -0,0 +1,8 @@ +class A(val a: Int = 13) +class DefaultsTest(x: Int = 25) extends A(28) +object DefaultsTest extends DefaultsTest(12) + +object Test extends App { + println(new DefaultsTest() a) + println(DefaultsTest a) +} diff --git a/test/files/run/si5171.check b/test/files/run/t5171.check index 159606d35c..159606d35c 100644 --- a/test/files/run/si5171.check +++ b/test/files/run/t5171.check diff --git a/test/files/run/si5171.scala b/test/files/run/t5171.scala index eb8029df80..eb8029df80 100644 --- a/test/files/run/si5171.scala +++ b/test/files/run/t5171.scala diff --git a/test/files/run/si5262.check b/test/files/run/t5262.check index 4c7a875de5..4c7a875de5 100644 --- a/test/files/run/si5262.check +++ b/test/files/run/t5262.check diff --git a/test/files/run/si5262.scala b/test/files/run/t5262.scala index fc4e57aa96..fc4e57aa96 100644 --- a/test/files/run/si5262.scala +++ b/test/files/run/t5262.scala diff --git a/test/files/run/si5374.check b/test/files/run/t5374.check index 6be88d77ec..6be88d77ec 100644 --- a/test/files/run/si5374.check +++ b/test/files/run/t5374.check diff --git a/test/files/run/si5374.scala b/test/files/run/t5374.scala index 9b1671e795..9b1671e795 100644 --- a/test/files/run/si5374.scala +++ b/test/files/run/t5374.scala diff --git a/test/files/run/si5375.check b/test/files/run/t5375.check index 7d3002ffda..7d3002ffda 100644 --- a/test/files/run/si5375.check +++ b/test/files/run/t5375.check diff --git a/test/files/run/si5375.scala b/test/files/run/t5375.scala index e4b329deae..e4b329deae 100644 --- a/test/files/run/si5375.scala +++ b/test/files/run/t5375.scala diff --git a/test/files/run/si5380.scala b/test/files/run/t5380.scala index 6083161a9b..6083161a9b 100644 --- a/test/files/run/si5380.scala +++ b/test/files/run/t5380.scala diff --git a/test/files/run/t5527.check b/test/files/run/t5527.check index bdd5ac8295..4a8a9ce602 100644 --- a/test/files/run/t5527.check +++ b/test/files/run/t5527.check @@ -1,11 +1,12 @@ [[syntax trees at end of parser]]// Scala source: newSource1 package <empty> { - abstract trait Test extends scala.ScalaObject { - def $init$() = { + object UselessComments extends scala.ScalaObject { + def <init>() = { + super.<init>(); () }; - def sth: scala.Unit = { - /** Some comment here */ + var z = 0; + def test1 = { object Maybe extends scala.ScalaObject { def <init>() = { super.<init>(); @@ -15,6 +16,83 @@ package <empty> { def nothing() = () }; () + }; + def test2 = { + var x = 4; + if (true) + { + x = 5; + val y = 6; + () + } + else + () + }; + def test3 = { + if (true) + z = 3 + else + (); + val t = 4; + 0.to(4).foreach(((i) => println(i))) + }; + val test4 = 'a' match { + case ('0'| '1'| '2'| '3'| '4'| '5'| '6'| '7'| '8'| '9') => true + case _ => false + } + }; + /** comments that we should keep */ + object UsefulComments extends scala.ScalaObject { + def <init>() = { + super.<init>(); + () + }; + /** class A */ + class A extends scala.ScalaObject { + def <init>() = { + super.<init>(); + () + }; + /** f */ + def f(i: Int) = i; + /** v */ + val v = 1; + /** u */ + var u = 2 + }; + /** trait B */ + abstract trait B extends scala.ScalaObject { + def $init$() = { + () + }; + /** T */ + type T >: _root_.scala.Nothing <: _root_.scala.Any; + /** f */ + def f(i: Int): scala.Unit; + /** v */ + val v = 1; + /** u */ + var u = 2 + }; + /** object C */ + object C extends scala.ScalaObject { + def <init>() = { + super.<init>(); + () + }; + /** f */ + def f(i: Int) = i; + /** v */ + val v = 1; + /** u */ + var u = 2 + }; + /** class D */ + @new deprecated("use ... instead", "2.10.0") class D extends scala.ScalaObject { + def <init>() = { + super.<init>(); + () + } } } } diff --git a/test/files/run/t5527.scala b/test/files/run/t5527.scala index 8280ee06ba..2449ff60c3 100644 --- a/test/files/run/t5527.scala +++ b/test/files/run/t5527.scala @@ -11,14 +11,80 @@ object Test extends DirectTest { override def code = """ // SI-5527 - trait Test { - def sth { + object UselessComments { + + var z = 0 + + def test1 = { /** Some comment here */ object Maybe { /** Some comment inside */ def nothing() = () } } + + def test2 = { + var x = 4 + if (true) { + /** Testing 123 */ + x = 5 + val y = 6 + } + } + + def test3 = { + if (true) + z = 3 + + /** Calculate this result. */ + val t = 4 + for (i <- 0 to 4) + println(i) + } + + val test4 = ('a') match { + /** Another digit is a giveaway. */ + case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => + true + case _ => + false + } + } + + /** comments that we should keep */ + object UsefulComments { + /** class A */ + class A { + /** f */ + def f(i: Int) = i + /** v */ + val v = 1 + /** u */ + var u = 2 + } + /** trait B */ + trait B { + /** T */ + type T + /** f */ + def f(i: Int) + /** v */ + val v = 1 + /** u */ + var u = 2 + } + /** object C */ + object C { + /** f */ + def f(i: Int) = i + /** v */ + val v = 1 + /** u */ + var u = 2 + } + /** class D */ + @deprecated("use ... instead", "2.10.0") + class D } """.trim diff --git a/test/files/run/t5537.check b/test/files/run/t5537.check new file mode 100644 index 0000000000..68c3ebf2e2 --- /dev/null +++ b/test/files/run/t5537.check @@ -0,0 +1,20 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> List[Predef.type]() +res0: List[scala.Predef.type] = List() + +scala> List[scala.`package`.type]() +res1: List[scala.type] = List() + +scala> List[List.type]() +res2: List[scala.collection.immutable.List.type] = List() + +scala> List[Set.type]() +res3: List[Set.type] = List() + +scala> + +scala> diff --git a/test/files/run/t5537.scala b/test/files/run/t5537.scala new file mode 100644 index 0000000000..ae88dcc11f --- /dev/null +++ b/test/files/run/t5537.scala @@ -0,0 +1,10 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ +List[Predef.type]() +List[scala.`package`.type]() +List[List.type]() +List[Set.type]() + """ +} diff --git a/test/files/run/t5545.check b/test/files/run/t5545.check new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/files/run/t5545.check diff --git a/test/files/run/t5545.scala b/test/files/run/t5545.scala new file mode 100644 index 0000000000..7efa6d84f1 --- /dev/null +++ b/test/files/run/t5545.scala @@ -0,0 +1,27 @@ +import scala.tools.partest._ +import java.io._ + +object Test extends DirectTest { + + override def extraSettings: String = "-usejavacp -d " + testOutput.path + " -cp " + testOutput.path + + override def code = """ + // SI-5545 + trait F[@specialized(Int) T1, R] { + def f(v1: T1): R + def g = v1 => f(v1) + } + """.trim + + override def show(): Unit = { + // redirect err to out, for logging + val prevErr = System.err + System.setErr(System.out) + compile() + // the bug manifests at the second compilation, when the bytecode is already there + compile() + System.setErr(prevErr) + } + + override def isDebug = false // so we don't get the newSettings warning +} diff --git a/test/files/run/test-cpp.check b/test/files/run/test-cpp.check new file mode 100644 index 0000000000..40a976119f --- /dev/null +++ b/test/files/run/test-cpp.check @@ -0,0 +1,73 @@ +37c37 +< locals: value args, value x, value y +--- +> locals: value args +42,43d41 +< 52 CONSTANT(2) +< 52 STORE_LOCAL(value x) +45,46d42 +< 53 LOAD_LOCAL(value x) +< 53 STORE_LOCAL(value y) +49c45 +< 54 LOAD_LOCAL(value y) +--- +> 54 CONSTANT(2) +92c88 +< locals: value args, value x, value y +--- +> locals: value args, value x +101,102d96 +< 82 LOAD_LOCAL(value x) +< 82 STORE_LOCAL(value y) +105c99 +< 83 LOAD_LOCAL(value y) +--- +> 83 LOAD_LOCAL(value x) +135c129 +< locals: value args, value x, value y +--- +> locals: value args +140,141d133 +< 66 THIS(TestAliasChainDerefThis) +< 66 STORE_LOCAL(value x) +143,144d134 +< 67 LOAD_LOCAL(value x) +< 67 STORE_LOCAL(value y) +147c137 +< 68 LOAD_LOCAL(value y) +--- +> 68 THIS(Object) +176c166 +< locals: value x, value y +--- +> locals: value x +181,182d170 +< 29 LOAD_LOCAL(value x) +< 29 STORE_LOCAL(value y) +185c173 +< 30 LOAD_LOCAL(value y) +--- +> 30 LOAD_LOCAL(value x) +223,224d210 +< 97 LOAD_LOCAL(variable x) +< 97 STORE_LOCAL(variable y) +227c213 +< 98 LOAD_LOCAL(variable y) +--- +> 98 LOAD_LOCAL(variable x) +233,234d218 +< 101 LOAD_LOCAL(variable y) +< 101 STORE_LOCAL(variable x) +236c220 +< 102 LOAD_LOCAL(variable x) +--- +> 102 LOAD_LOCAL(variable y) +345c329 +< 41 THIS(TestSetterInline) +--- +> 41 THIS(Object) +347c331 +< 41 CALL_METHOD TestSetterInline._postSetHook_$eq (static-instance) +--- +> 41 STORE_FIELD variable _postSetHook (dynamic) + diff --git a/test/files/run/test-cpp.scala b/test/files/run/test-cpp.scala new file mode 100644 index 0000000000..5b3bc7b746 --- /dev/null +++ b/test/files/run/test-cpp.scala @@ -0,0 +1,104 @@ +/** + * The only change is in the decision to replace a LOAD_LOCAL(l) + * in the copy-propagation performed before ClosureElimination. + * + * In the general case, the local variable 'l' is connected through + * a alias chain with other local variables and at the end of the + * alias chain there may be a Value, call it 'v'. + * + * If 'v' is cheaper to access (it is a Deref(This) or Const(_)), then + * replace the instruction to load it from the cheaper place. + * Otherwise, we use the local variable at the end of the alias chain + * instead of 'l'. + */ + +import scala.tools.partest.IcodeTest + +object Test extends IcodeTest { + override def printIcodeAfterPhase = "dce" +} + +import scala.util.Random._ + +/** + * The example in the bug report (Issue-5321): an alias chain which store + * an Unknown. Should remove local variable 'y'. + */ +object TestBugReport { + def test(x: Int) = { + val y = x + println(y) + } +} + +/** + * The code taken from scala.tools.nsc.settings.Settings: + * After inlining of the setter is performed, there is an opportunity for + * copy-propagation to eliminate some local variables. + */ +object TestSetterInline { + private var _postSetHook: this.type => Unit = (x: this.type) => () + def withPostSetHook(f: this.type => Unit): this.type = { _postSetHook = f ; this } +} + + +/** + * The access of the local variable 'y' should be replaced by the + * constant. + */ +object TestAliasChainConstat { + + def main(args: Array[String]): Unit = { + val x = 2 + val y = x + println(y) + } +} + +/** + * At the end of the alias chain we have a reference to 'this'. + * The local variables should be all discarded and replace by a + * direct reference to this + */ +class TestAliasChainDerefThis { + + def main(args: Array[String]): Unit = { + val x = this + val y = x + println(y) + } +} + +/** + * At the end of the alias chain, there is the value of a field. + * The use of variable 'y' should be replaced by 'x', not by an access + * to the field 'f' since it is more costly. + */ +object TestAliasChainDerefField { + def f = nextInt + + def main(args: Array[String]): Unit = { + val x = f + val y = x + println(y) + } +} + + +/** + * The first time 'println' is called, 'x' is replaced by 'y' + * and the second time, 'y' is replaced by 'x'. But none of them + * can be removed. + */ +object TestDifferentBindings { + + def main(args: Array[String]): Unit = { + var x = nextInt + var y = x + println(y) + + y = nextInt + x = y + println(x) + } +} diff --git a/test/pending/run/t3702.scala b/test/pending/run/t3702.scala new file mode 100644 index 0000000000..e08fc12e76 --- /dev/null +++ b/test/pending/run/t3702.scala @@ -0,0 +1,10 @@ +object Test { + def main(args: Array[String]) { + foo(Nil, Nil) + } + + def foo(h: Any, t: List[Any]) = h match { + case 5 :: _ => () + case List(from) => List(from, from, from) + } +} diff --git a/test/pending/run/t3705.scala b/test/pending/run/t3705.scala new file mode 100644 index 0000000000..fcc020f28c --- /dev/null +++ b/test/pending/run/t3705.scala @@ -0,0 +1,17 @@ +// package foo + +import scala.xml._ +object Test { + def updateNodes(ns: Seq[Node]): Seq[Node] = + for(subnode <- ns) yield subnode match { + case <d>{_}</d> if true => <d>abc</d> + case Elem(prefix, label, attribs, scope, children @ _*) => + Elem(prefix, label, attribs, scope, updateNodes(children) : _*) + case other => other + } + def main(args: Array[String]): Unit = { + updateNodes(<b />) + + } +} + diff --git a/test/pending/run/t3832.scala b/test/pending/run/t3832.scala new file mode 100644 index 0000000000..f081d5b3af --- /dev/null +++ b/test/pending/run/t3832.scala @@ -0,0 +1,7 @@ +class Test { + def this(un: Int) = { + this() + def test(xs: List[Int]) = xs map (x => x) + () + } +}
\ No newline at end of file diff --git a/test/pending/run/t4098.scala b/test/pending/run/t4098.scala new file mode 100644 index 0000000000..b74ccf9bff --- /dev/null +++ b/test/pending/run/t4098.scala @@ -0,0 +1,9 @@ +class A(a: Any) { + def this() = { this(b) ; def b = new {} } +} + +object Test { + def main(args: Array[String]): Unit = { + new A ("") + } +} diff --git a/test/pending/run/t4415.scala b/test/pending/run/t4415.scala new file mode 100644 index 0000000000..f96031d650 --- /dev/null +++ b/test/pending/run/t4415.scala @@ -0,0 +1,86 @@ +/** + * Demonstration of issue with Extractors. If lines 15/16 are not present, get at runtime: + * + * Exception in thread "main" java.lang.VerifyError: (class: ExtractorIssue$$, method: convert signature: (LTopProperty;)LMyProp;) Accessing value from uninitialized register 5 + * at ExtractorIssue.main(ExtractorIssue.scala) + * at com.intellij.rt.execution.application.AppMain.main(AppMain.java:115)] + * + * If lines 15/16 are present, the compiler crashes: + * + * fatal error (server aborted): not enough arguments for method body%3: (val p: MyProp[java.lang.String])MyProp[_33]. + * Unspecified value parameter p. + */ +object Test { + + def main(args: Array[String]) { + convert(new SubclassProperty) + } + + def convert(prop: TopProperty): MyProp[_] = { + prop match { + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //case SubclassSecondMatch(p) => p // if these lines are present, the compiler crashes. If commented, unsafe byte + //case SecondMatch(p) => p // byte code is generated, which causes a java.lang.VerifyError at runtime + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + case SubclassMatch(p) => p + case StandardMatch(p) => p + } + } +} + +class TopProperty + +class StandardProperty extends TopProperty +class SubclassProperty extends StandardProperty + +class SecondProperty extends TopProperty +class SubclassSecondProperty extends StandardProperty + +trait MyProp[T] +case class MyPropImpl[T] extends MyProp[T] + +object SubclassMatch { + + def unapply(prop: SubclassProperty) : Option[MyProp[String]] = { + Some(new MyPropImpl) + } + + def apply(prop: MyProp[String]) : SubclassProperty = { + new SubclassProperty() + } +} + +object StandardMatch { + + def unapply(prop: StandardProperty) : Option[MyProp[String]] = { + Some(new MyPropImpl) + } + + def apply(prop: MyProp[String]) : StandardProperty = { + new StandardProperty() + } +} + +object SubclassSecondMatch { + + def unapply(prop: SubclassSecondProperty) : Option[MyProp[BigInt]] = { + Some(new MyPropImpl) + } + + def apply(prop: MyProp[String]) : SubclassSecondProperty = { + new SubclassSecondProperty() + } +} + +object SecondMatch { + + def unapply(prop: SecondProperty) : Option[MyProp[BigInt]] = { + Some(new MyPropImpl) + } + + def apply(prop: MyProp[String]) : SecondProperty = { + new SecondProperty() + } +}
\ No newline at end of file diff --git a/test/pending/run/t4460.scala b/test/pending/run/t4460.scala new file mode 100644 index 0000000000..324e2f5bef --- /dev/null +++ b/test/pending/run/t4460.scala @@ -0,0 +1,12 @@ +trait A + +class B(val x: Int) { + self: A => + + def this() = this() +} + +object Test extends B(2) with A { + def main(args: Array[String]) { } +} + |