summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala82
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala121
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala32
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala28
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala34
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala173
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala155
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala6
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala32
-rw-r--r--test/files/jvm/innerClassAttribute/Classes_1.scala6
-rw-r--r--test/files/jvm/innerClassAttribute/Test.scala2
-rw-r--r--test/files/run/stringinterpolation_macro-run.check71
-rw-r--r--test/files/run/stringinterpolation_macro-run.scala122
-rw-r--r--test/junit/scala/StringContextTest.scala160
17 files changed, 504 insertions, 542 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index c4eb6e1b42..adaf870c46 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -96,12 +96,12 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val thrownKind = tpeTK(expr)
// `throw null` is valid although scala.Null (as defined in src/library-aux) isn't a subtype of Throwable.
// Similarly for scala.Nothing (again, as defined in src/library-aux).
- assert(thrownKind.isNullType || thrownKind.isNothingType || thrownKind.asClassBType.isSubtypeOf(ThrowableReference).get)
+ assert(thrownKind.isNullType || thrownKind.isNothingType || thrownKind.asClassBType.isSubtypeOf(jlThrowableRef).get)
genLoad(expr, thrownKind)
lineNumber(expr)
emit(asm.Opcodes.ATHROW) // ICode enters here into enterIgnoreMode, we'll rely instead on DCE at ClassNode level.
- RT_NOTHING // always returns the same, the invoker should know :)
+ srNothingRef // always returns the same, the invoker should know :)
}
/* Generate code for primitive arithmetic operations. */
@@ -325,7 +325,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
else {
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
generatedType =
- if (tree.symbol == ArrayClass) ObjectReference
+ if (tree.symbol == ArrayClass) ObjectRef
else classBTypeFromSymbol(claszSymbol)
}
@@ -368,7 +368,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
if (value.tag != UnitTag) (value.tag, expectedType) match {
case (IntTag, LONG ) => bc.lconst(value.longValue); generatedType = LONG
case (FloatTag, DOUBLE) => bc.dconst(value.doubleValue); generatedType = DOUBLE
- case (NullTag, _ ) => bc.emit(asm.Opcodes.ACONST_NULL); generatedType = RT_NULL
+ case (NullTag, _ ) => bc.emit(asm.Opcodes.ACONST_NULL); generatedType = srNullRef
case _ => genConstant(value); generatedType = tpeTK(tree)
}
@@ -464,7 +464,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case ClazzTag =>
val toPush: BType = {
- toTypeKind(const.typeValue) match {
+ typeToBType(const.typeValue) match {
case kind: PrimitiveBType => boxedClassOfPrimitive(kind)
case kind => kind
}
@@ -475,7 +475,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val sym = const.symbolValue
val ownerName = internalName(sym.owner)
val fieldName = sym.javaSimpleName.toString
- val fieldDesc = toTypeKind(sym.tpe.underlying).descriptor
+ val fieldDesc = typeToBType(sym.tpe.underlying).descriptor
mnode.visitFieldInsn(
asm.Opcodes.GETSTATIC,
ownerName,
@@ -553,8 +553,8 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
else if (l.isPrimitive) {
bc drop l
if (cast) {
- mnode.visitTypeInsn(asm.Opcodes.NEW, classCastExceptionReference.internalName)
- bc dup ObjectReference
+ mnode.visitTypeInsn(asm.Opcodes.NEW, jlClassCastExceptionRef.internalName)
+ bc dup ObjectRef
emit(asm.Opcodes.ATHROW)
} else {
bc boolconst false
@@ -588,7 +588,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
genLoadArguments(args, paramTKs(app))
genCallMethod(fun.symbol, invokeStyle, app.pos)
- generatedType = asmMethodType(fun.symbol).returnType
+ generatedType = methodBTypeFromSymbol(fun.symbol).returnType
// 'new' constructor call: Note: since constructors are
// thought to return an instance of what they construct,
@@ -638,21 +638,21 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val attachment = app.attachments.get[delambdafy.LambdaMetaFactoryCapable].get
genLoadArguments(args, paramTKs(app))
genInvokeDynamicLambda(attachment.target, attachment.arity, attachment.functionalInterface)
- generatedType = asmMethodType(fun.symbol).returnType
+ generatedType = methodBTypeFromSymbol(fun.symbol).returnType
case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isBox(fun.symbol) =>
val nativeKind = tpeTK(expr)
genLoad(expr, nativeKind)
val MethodNameAndType(mname, methodType) = asmBoxTo(nativeKind)
- bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor, app.pos)
- generatedType = boxResultType(fun.symbol) // was toTypeKind(fun.symbol.tpe.resultType)
+ bc.invokestatic(srBoxesRunTimeRef.internalName, mname, methodType.descriptor, app.pos)
+ generatedType = boxResultType(fun.symbol) // was typeToBType(fun.symbol.tpe.resultType)
case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isUnbox(fun.symbol) =>
genLoad(expr)
- val boxType = unboxResultType(fun.symbol) // was toTypeKind(fun.symbol.owner.linkedClassOfClass.tpe)
+ val boxType = unboxResultType(fun.symbol) // was typeToBType(fun.symbol.owner.linkedClassOfClass.tpe)
generatedType = boxType
val MethodNameAndType(mname, methodType) = asmUnboxTo(boxType)
- bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor, app.pos)
+ bc.invokestatic(srBoxesRunTimeRef.internalName, mname, methodType.descriptor, app.pos)
case app @ Apply(fun, args) =>
val sym = fun.symbol
@@ -728,7 +728,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
genNormalMethodCall()
- generatedType = asmMethodType(sym).returnType
+ generatedType = methodBTypeFromSymbol(sym).returnType
}
}
@@ -958,7 +958,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
asm.Opcodes.GETSTATIC,
mbt.internalName /* + "$" */ ,
strMODULE_INSTANCE_FIELD,
- mbt.descriptor // for nostalgics: toTypeKind(module.tpe).descriptor
+ mbt.descriptor // for nostalgics: typeToBType(module.tpe).descriptor
)
}
}
@@ -997,7 +997,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
// Optimization for expressions of the form "" + x. We can avoid the StringBuilder.
case List(Literal(Constant("")), arg) =>
- genLoad(arg, ObjectReference)
+ genLoad(arg, ObjectRef)
genCallMethod(String_valueOf, icodes.opcodes.Static(onInstance = false), arg.pos)
case concatenations =>
@@ -1011,7 +1011,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}
- StringReference
+ StringRef
}
def genCallMethod(method: Symbol, style: InvokeStyle, pos: Position, hostClass0: Symbol = null) {
@@ -1037,7 +1037,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val receiver = if (useMethodOwner) methodOwner else hostSymbol
val jowner = internalName(receiver)
val jname = method.javaSimpleName.toString
- val bmType = asmMethodType(method)
+ val bmType = methodBTypeFromSymbol(method)
val mdescr = bmType.descriptor
def initModule() {
@@ -1076,7 +1076,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
/* Generate the scala ## method. */
def genScalaHash(tree: Tree, applyPos: Position): BType = {
genLoadModule(ScalaRunTimeModule) // TODO why load ScalaRunTimeModule if ## has InvokeStyle of Static(false) ?
- genLoad(tree, ObjectReference)
+ genLoad(tree, ObjectRef)
genCallMethod(hashMethodSym, icodes.opcodes.Static(onInstance = false), applyPos)
INT
@@ -1164,8 +1164,8 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
if (scalaPrimitives.isReferenceEqualityOp(code) &&
{ nonNullSide = ifOneIsNull(l, r); nonNullSide != null }
) {
- genLoad(nonNullSide, ObjectReference)
- genCZJUMP(success, failure, op, ObjectReference)
+ genLoad(nonNullSide, ObjectRef)
+ genCZJUMP(success, failure, op, ObjectRef)
}
else {
val tk = tpeTK(l).maxType(tpeTK(r))
@@ -1252,42 +1252,42 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
else platform.externalEqualsNumObject
} else platform.externalEquals
}
- genLoad(l, ObjectReference)
- genLoad(r, ObjectReference)
+ genLoad(l, ObjectRef)
+ genLoad(r, ObjectRef)
genCallMethod(equalsMethod, icodes.opcodes.Static(onInstance = false), pos)
genCZJUMP(success, failure, icodes.NE, BOOL)
}
else {
if (isNull(l)) {
// null == expr -> expr eq null
- genLoad(r, ObjectReference)
- genCZJUMP(success, failure, icodes.EQ, ObjectReference)
+ genLoad(r, ObjectRef)
+ genCZJUMP(success, failure, icodes.EQ, ObjectRef)
} else if (isNull(r)) {
// expr == null -> expr eq null
- genLoad(l, ObjectReference)
- genCZJUMP(success, failure, icodes.EQ, ObjectReference)
+ genLoad(l, ObjectRef)
+ genCZJUMP(success, failure, icodes.EQ, ObjectRef)
} else if (isNonNullExpr(l)) {
// SI-7852 Avoid null check if L is statically non-null.
- genLoad(l, ObjectReference)
- genLoad(r, ObjectReference)
+ genLoad(l, ObjectRef)
+ genLoad(r, ObjectRef)
genCallMethod(Object_equals, icodes.opcodes.Dynamic, pos)
genCZJUMP(success, failure, icodes.NE, BOOL)
} else {
// l == r -> if (l eq null) r eq null else l.equals(r)
- val eqEqTempLocal = locals.makeLocal(ObjectReference, nme.EQEQ_LOCAL_VAR.toString)
+ val eqEqTempLocal = locals.makeLocal(ObjectRef, nme.EQEQ_LOCAL_VAR.toString)
val lNull = new asm.Label
val lNonNull = new asm.Label
- genLoad(l, ObjectReference)
- genLoad(r, ObjectReference)
+ genLoad(l, ObjectRef)
+ genLoad(r, ObjectRef)
locals.store(eqEqTempLocal)
- bc dup ObjectReference
- genCZJUMP(lNull, lNonNull, icodes.EQ, ObjectReference)
+ bc dup ObjectRef
+ genCZJUMP(lNull, lNonNull, icodes.EQ, ObjectRef)
markProgramPoint(lNull)
- bc drop ObjectReference
+ bc drop ObjectRef
locals.load(eqEqTempLocal)
- genCZJUMP(success, failure, icodes.EQ, ObjectReference)
+ genCZJUMP(success, failure, icodes.EQ, ObjectRef)
markProgramPoint(lNonNull)
locals.load(eqEqTempLocal)
@@ -1309,16 +1309,16 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
new asm.Handle(if (lambdaTarget.hasFlag(Flags.STATIC)) asm.Opcodes.H_INVOKESTATIC else asm.Opcodes.H_INVOKEVIRTUAL,
classBTypeFromSymbol(lambdaTarget.owner).internalName,
lambdaTarget.name.toString,
- asmMethodType(lambdaTarget).descriptor)
+ methodBTypeFromSymbol(lambdaTarget).descriptor)
val receiver = if (isStaticMethod) Nil else lambdaTarget.owner :: Nil
val (capturedParams, lambdaParams) = lambdaTarget.paramss.head.splitAt(lambdaTarget.paramss.head.length - arity)
// Requires https://github.com/scala/scala-java8-compat on the runtime classpath
- val invokedType = asm.Type.getMethodDescriptor(asmType(functionalInterface), (receiver ::: capturedParams).map(sym => toTypeKind(sym.info).toASMType): _*)
+ val invokedType = asm.Type.getMethodDescriptor(asmType(functionalInterface), (receiver ::: capturedParams).map(sym => typeToBType(sym.info).toASMType): _*)
- val constrainedType = new MethodBType(lambdaParams.map(p => toTypeKind(p.tpe)), toTypeKind(lambdaTarget.tpe.resultType)).toASMType
+ val constrainedType = new MethodBType(lambdaParams.map(p => typeToBType(p.tpe)), typeToBType(lambdaTarget.tpe.resultType)).toASMType
val sam = functionalInterface.info.decls.find(_.isDeferred).getOrElse(functionalInterface.info.member(nme.apply))
val samName = sam.name.toString
- val samMethodType = asmMethodType(sam).toASMType
+ val samMethodType = methodBTypeFromSymbol(sam).toASMType
val flags = LambdaMetafactory.FLAG_SERIALIZABLE | LambdaMetafactory.FLAG_MARKERS
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 3cdc37ad21..d501d4239b 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -192,20 +192,18 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
}
/*
- * Populates the InnerClasses JVM attribute with `refedInnerClasses`.
- * In addition to inner classes mentioned somewhere in `jclass` (where `jclass` is a class file being emitted)
- * `refedInnerClasses` should contain those inner classes defined as direct member classes of `jclass`
- * but otherwise not mentioned in `jclass`.
+ * Populates the InnerClasses JVM attribute with `refedInnerClasses`. See also the doc on inner
+ * classes in BTypes.scala.
*
- * `refedInnerClasses` may contain duplicates,
- * need not contain the enclosing inner classes of each inner class it lists (those are looked up for consistency).
+ * `refedInnerClasses` may contain duplicates, need not contain the enclosing inner classes of
+ * each inner class it lists (those are looked up and included).
*
- * This method serializes in the InnerClasses JVM attribute in an appropriate order,
- * not necessarily that given by `refedInnerClasses`.
+ * This method serializes in the InnerClasses JVM attribute in an appropriate order, not
+ * necessarily that given by `refedInnerClasses`.
*
* can-multi-thread
*/
- final def addInnerClassesASM(jclass: asm.ClassVisitor, refedInnerClasses: List[ClassBType]) {
+ final def addInnerClasses(jclass: asm.ClassVisitor, refedInnerClasses: List[ClassBType]) {
val allNestedClasses = refedInnerClasses.flatMap(_.enclosingNestedClassesChain.get).distinct
// sorting ensures nested classes are listed after their enclosing class thus satisfying the Eclipse Java compiler
@@ -311,78 +309,28 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
final val emitLines = debugLevel >= 2
final val emitVars = debugLevel >= 3
- /*
- * Contains class-symbols that:
- * (a) are known to denote inner classes
- * (b) are mentioned somewhere in the class being generated.
- *
- * In other words, the lifetime of `innerClassBufferASM` is associated to "the class being generated".
- */
- final val innerClassBufferASM = mutable.Set.empty[ClassBType]
-
/**
- * The class internal name for a given class symbol. If the symbol describes a nested class, the
- * ClassBType is added to the innerClassBufferASM.
+ * The class internal name for a given class symbol.
*/
final def internalName(sym: Symbol): String = {
// For each java class, the scala compiler creates a class and a module (thus a module class).
- // If the `sym` is a java module class, we use the java class instead. This ensures that we
- // register the class (instead of the module class) in innerClassBufferASM.
+ // If the `sym` is a java module class, we use the java class instead. This ensures that the
+ // ClassBType is created from the main class (instead of the module class).
// The two symbols have the same name, so the resulting internalName is the same.
// Phase travel (exitingPickler) required for SI-6613 - linkedCoC is only reliable in early phases (nesting)
val classSym = if (sym.isJavaDefined && sym.isModuleClass) exitingPickler(sym.linkedClassOfClass) else sym
- getClassBTypeAndRegisterInnerClass(classSym).internalName
+ classBTypeFromSymbol(classSym).internalName
}
/**
- * The ClassBType for a class symbol. If the class is nested, the ClassBType is added to the
- * innerClassBufferASM.
- *
- * TODO: clean up the way we track referenced inner classes.
- * doing it during code generation is not correct when the optimizer changes the code.
+ * The jvm descriptor of a type.
*/
- final def getClassBTypeAndRegisterInnerClass(sym: Symbol): ClassBType = {
- val r = classBTypeFromSymbol(sym)
- if (r.isNestedClass.get) innerClassBufferASM += r
- r
- }
+ final def descriptor(t: Type): String = typeToBType(t).descriptor
/**
- * The BType for a type reference. If the result is a ClassBType for a nested class, it is added
- * to the innerClassBufferASM.
- * TODO: clean up the way we track referenced inner classes.
+ * The jvm descriptor for a symbol.
*/
- final def toTypeKind(t: Type): BType = typeToBType(t) match {
- case c: ClassBType if c.isNestedClass.get =>
- innerClassBufferASM += c
- c
- case r => r
- }
-
- /**
- * Class components that are nested classes are added to the innerClassBufferASM.
- * TODO: clean up the way we track referenced inner classes.
- */
- final def asmMethodType(msym: Symbol): MethodBType = {
- val r = methodBTypeFromSymbol(msym)
- (r.returnType :: r.argumentTypes) foreach {
- case c: ClassBType if c.isNestedClass.get => innerClassBufferASM += c
- case _ =>
- }
- r
- }
-
- /**
- * The jvm descriptor of a type. If `t` references a nested class, its ClassBType is added to
- * the innerClassBufferASM.
- */
- final def descriptor(t: Type): String = { toTypeKind(t).descriptor }
-
- /**
- * The jvm descriptor for a symbol. If `sym` represents a nested class, its ClassBType is added
- * to the innerClassBufferASM.
- */
- final def descriptor(sym: Symbol): String = { getClassBTypeAndRegisterInnerClass(sym).descriptor }
+ final def descriptor(sym: Symbol): String = classBTypeFromSymbol(sym).descriptor
} // end of trait BCInnerClassGen
@@ -421,7 +369,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
case StringTag =>
assert(const.value != null, const) // TODO this invariant isn't documented in `case class Constant`
av.visit(name, const.stringValue) // `stringValue` special-cases null, but that execution path isn't exercised for a const with StringTag
- case ClazzTag => av.visit(name, toTypeKind(const.typeValue).toASMType)
+ case ClazzTag => av.visit(name, typeToBType(const.typeValue).toASMType)
case EnumTag =>
val edesc = descriptor(const.tpe) // the class descriptor of the enumeration class.
val evalue = const.symbolValue.name.toString // value the actual enumeration value.
@@ -565,7 +513,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
private def addForwarder(isRemoteClass: Boolean, jclass: asm.ClassVisitor, module: Symbol, m: Symbol) {
val moduleName = internalName(module)
val methodInfo = module.thisType.memberInfo(m)
- val paramJavaTypes: List[BType] = methodInfo.paramTypes map toTypeKind
+ val paramJavaTypes: List[BType] = methodInfo.paramTypes map typeToBType
// val paramNames = 0 until paramJavaTypes.length map ("x_" + _)
/* Forwarders must not be marked final,
@@ -584,7 +532,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
val (throws, others) = m.annotations partition (_.symbol == definitions.ThrowsClass)
val thrownExceptions: List[String] = getExceptions(throws)
- val jReturnType = toTypeKind(methodInfo.resultType)
+ val jReturnType = typeToBType(methodInfo.resultType)
val mdesc = MethodBType(paramJavaTypes, jReturnType).descriptor
val mirrorMethodName = m.javaSimpleName.toString
val mirrorMethod: asm.MethodVisitor = jclass.visitMethod(
@@ -609,7 +557,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
index += jparamType.size
}
- mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, asmMethodType(m).descriptor, false)
+ mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, methodBTypeFromSymbol(m).descriptor, false)
mirrorMethod.visitInsn(jReturnType.typedOpcode(asm.Opcodes.IRETURN))
mirrorMethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
@@ -716,7 +664,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
def genMirrorClass(moduleClass: Symbol, cunit: CompilationUnit): asm.tree.ClassNode = {
assert(moduleClass.isModuleClass)
assert(moduleClass.companionClass == NoSymbol, moduleClass)
- innerClassBufferASM.clear()
this.cunit = cunit
val bType = mirrorClassClassBType(moduleClass)
@@ -726,7 +673,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
bType.info.get.flags,
bType.internalName,
null /* no java-generic-signature */,
- ObjectReference.internalName,
+ ObjectRef.internalName,
EMPTY_STRING_ARRAY
)
@@ -739,9 +686,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
addForwarders(isRemote(moduleClass), mirrorClass, bType.internalName, moduleClass)
- innerClassBufferASM ++= bType.info.get.nestedClasses
- addInnerClassesASM(mirrorClass, innerClassBufferASM.toList)
-
mirrorClass.visitEnd()
("" + moduleClass.name) // this side-effect is necessary, really.
@@ -765,18 +709,15 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
def javaSimpleName(s: Symbol): String = { s.javaSimpleName.toString }
- innerClassBufferASM.clear()
-
- val flags = javaFlags(cls)
+ val beanInfoType = beanInfoClassClassBType(cls)
- val beanInfoName = (internalName(cls) + "BeanInfo")
val beanInfoClass = new asm.tree.ClassNode
beanInfoClass.visit(
classfileVersion,
- flags,
- beanInfoName,
+ beanInfoType.info.get.flags,
+ beanInfoType.internalName,
null, // no java-generic-signature
- "scala/beans/ScalaBeanInfo",
+ sbScalaBeanInfoRef.internalName,
EMPTY_STRING_ARRAY
)
@@ -813,7 +754,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
EMPTY_STRING_ARRAY // no throwable exceptions
)
- val stringArrayJType: BType = ArrayBType(StringReference)
+ val stringArrayJType: BType = ArrayBType(StringRef)
val conJType: BType = MethodBType(
classBTypeFromSymbol(definitions.ClassClass) :: stringArrayJType :: stringArrayJType :: Nil,
UNIT
@@ -826,7 +767,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
constructor.visitLdcInsn(new java.lang.Integer(fi))
if (f == null) { constructor.visitInsn(asm.Opcodes.ACONST_NULL) }
else { constructor.visitLdcInsn(f) }
- constructor.visitInsn(StringReference.typedOpcode(asm.Opcodes.IASTORE))
+ constructor.visitInsn(StringRef.typedOpcode(asm.Opcodes.IASTORE))
fi += 1
}
}
@@ -839,12 +780,12 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
// push the string array of field information
constructor.visitLdcInsn(new java.lang.Integer(fieldList.length))
- constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, StringReference.internalName)
+ constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, StringRef.internalName)
push(fieldList)
// push the string array of method information
constructor.visitLdcInsn(new java.lang.Integer(methodList.length))
- constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, StringReference.internalName)
+ constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, StringRef.internalName)
push(methodList)
// invoke the superclass constructor, which will do the
@@ -855,9 +796,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
constructor.visitMaxs(0, 0) // just to follow protocol, dummy arguments
constructor.visitEnd()
- innerClassBufferASM ++= classBTypeFromSymbol(cls).info.get.nestedClasses
- addInnerClassesASM(beanInfoClass, innerClassBufferASM.toList)
-
beanInfoClass.visitEnd()
beanInfoClass
@@ -886,8 +824,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
* must-single-thread
*/
def legacyAddCreatorCode(clinit: asm.MethodVisitor, cnode: asm.tree.ClassNode, thisName: String) {
- // this tracks the inner class in innerClassBufferASM, if needed.
- val androidCreatorType = getClassBTypeAndRegisterInnerClass(AndroidCreatorClass)
+ val androidCreatorType = classBTypeFromSymbol(AndroidCreatorClass)
val tdesc_creator = androidCreatorType.descriptor
cnode.visitField(
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
index 535e1a8620..c78f422bf0 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
@@ -220,10 +220,10 @@ abstract class BCodeIdiomatic extends SubComponent {
final def genStringConcat(el: BType, pos: Position): Unit = {
val jtype =
- if (el.isArray || el.isClass) ObjectReference
+ if (el.isArray || el.isClass) ObjectRef
else el
- val bt = MethodBType(List(jtype), StringBuilderReference)
+ val bt = MethodBType(List(jtype), jlStringBuilderRef)
invokevirtual(StringBuilderClassName, "append", bt.descriptor, pos)
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
index b22fdf7c2c..3fe56dd962 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
@@ -72,14 +72,12 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
def paramTKs(app: Apply): List[BType] = {
val Apply(fun, _) = app
val funSym = fun.symbol
- (funSym.info.paramTypes map toTypeKind) // this tracks mentioned inner classes (in innerClassBufferASM)
+ funSym.info.paramTypes map typeToBType
}
- def symInfoTK(sym: Symbol): BType = {
- toTypeKind(sym.info) // this tracks mentioned inner classes (in innerClassBufferASM)
- }
+ def symInfoTK(sym: Symbol): BType = typeToBType(sym.info)
- def tpeTK(tree: Tree): BType = { toTypeKind(tree.tpe) }
+ def tpeTK(tree: Tree): BType = typeToBType(tree.tpe)
def log(msg: => AnyRef) {
global synchronized { global.log(msg) }
@@ -91,7 +89,6 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
def genPlainClass(cd: ClassDef) {
assert(cnode == null, "GenBCode detected nested methods.")
- innerClassBufferASM.clear()
claszSymbol = cd.symbol
isCZParcelable = isAndroidParcelableClass(claszSymbol)
@@ -118,7 +115,6 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
addClassFields()
- innerClassBufferASM ++= classBType.info.get.nestedClasses
gen(cd.impl)
@@ -130,8 +126,6 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (shouldAddLambdaDeserialize)
backendUtils.addLambdaDeserialize(cnode)
- addInnerClassesASM(cnode, innerClassBufferASM.toList)
-
cnode.visitAttribute(classBType.inlineInfoAttribute.get)
if (AsmUtils.traceClassEnabled && cnode.name.contains(AsmUtils.traceClassPattern))
@@ -146,12 +140,8 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
private def initJClass(jclass: asm.ClassVisitor) {
val bType = classBTypeFromSymbol(claszSymbol)
- val superClass = bType.info.get.superClass.getOrElse(ObjectReference).internalName
- val interfaceNames = bType.info.get.interfaces map {
- case classBType =>
- if (classBType.isNestedClass.get) { innerClassBufferASM += classBType }
- classBType.internalName
- }
+ val superClass = bType.info.get.superClass.getOrElse(ObjectRef).internalName
+ val interfaceNames = bType.info.get.interfaces.map(_.internalName)
val flags = javaFlags(claszSymbol)
@@ -164,7 +154,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
cnode.visitSource(cunit.source.toString, null /* SourceDebugExtension */)
}
- enclosingMethodAttribute(claszSymbol, internalName, asmMethodType(_).descriptor) match {
+ enclosingMethodAttribute(claszSymbol, internalName, methodBTypeFromSymbol(_).descriptor) match {
case Some(EnclosingMethodEntry(className, methodName, methodDescriptor)) =>
cnode.visitOuterClass(className, methodName, methodDescriptor)
case _ => ()
@@ -536,7 +526,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (isMethSymStaticCtor) CLASS_CONSTRUCTOR_NAME
else jMethodName
- val mdesc = asmMethodType(methSymbol).descriptor
+ val mdesc = methodBTypeFromSymbol(methSymbol).descriptor
mnode = cnode.visitMethod(
flags,
bytecodeName,
@@ -560,7 +550,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
methSymbol = dd.symbol
jMethodName = methSymbol.javaSimpleName.toString
- returnType = asmMethodType(dd.symbol).returnType
+ returnType = methodBTypeFromSymbol(dd.symbol).returnType
isMethSymStaticCtor = methSymbol.isStaticConstructor
resetMethodBookkeeping(dd)
@@ -689,7 +679,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val callee = methSymbol.enclClass.primaryConstructor
val jname = callee.javaSimpleName.toString
val jowner = internalName(callee.owner)
- val jtype = asmMethodType(callee).descriptor
+ val jtype = methodBTypeFromSymbol(callee).descriptor
insnModB = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESPECIAL, jowner, jname, jtype, false)
}
@@ -698,7 +688,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
// android creator code
if (isCZParcelable) {
// add a static field ("CREATOR") to this class to cache android.os.Parcelable$Creator
- val andrFieldDescr = getClassBTypeAndRegisterInnerClass(AndroidCreatorClass).descriptor
+ val andrFieldDescr = classBTypeFromSymbol(AndroidCreatorClass).descriptor
cnode.visitField(
asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL,
"CREATOR",
@@ -710,7 +700,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val callee = definitions.getMember(claszSymbol.companionModule, androidFieldName)
val jowner = internalName(callee.owner)
val jname = callee.javaSimpleName.toString
- val jtype = asmMethodType(callee).descriptor
+ val jtype = methodBTypeFromSymbol(callee).descriptor
insnParcA = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESTATIC, jowner, jname, jtype, false)
// PUTSTATIC `thisName`.CREATOR;
insnParcB = new asm.tree.FieldInsnNode(asm.Opcodes.PUTSTATIC, thisName, "CREATOR", andrFieldDescr)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
index b94208c1a5..3e53419573 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
@@ -30,7 +30,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
def genSynchronized(tree: Apply, expectedType: BType): BType = {
val Apply(fun, args) = tree
- val monitor = locals.makeLocal(ObjectReference, "monitor")
+ val monitor = locals.makeLocal(ObjectRef, "monitor")
val monCleanup = new asm.Label
// if the synchronized block returns a result, store it in a local variable.
@@ -40,7 +40,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
/* ------ (1) pushing and entering the monitor, also keeping a reference to it in a local var. ------ */
genLoadQualifier(fun)
- bc dup ObjectReference
+ bc dup ObjectRef
locals.store(monitor)
emit(asm.Opcodes.MONITORENTER)
@@ -75,7 +75,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
* Protected by whatever protects the whole synchronized expression.
* ------
*/
- protect(startProtected, endProtected, currProgramPoint(), ThrowableReference)
+ protect(startProtected, endProtected, currProgramPoint(), jlThrowableRef)
locals.load(monitor)
emit(asm.Opcodes.MONITOREXIT)
emit(asm.Opcodes.ATHROW)
@@ -184,7 +184,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
for (CaseDef(pat, _, caseBody) <- catches) yield {
pat match {
case Typed(Ident(nme.WILDCARD), tpt) => NamelessEH(tpeTK(tpt).asClassBType, caseBody)
- case Ident(nme.WILDCARD) => NamelessEH(ThrowableReference, caseBody)
+ case Ident(nme.WILDCARD) => NamelessEH(jlThrowableRef, caseBody)
case Bind(_, _) => BoundEH (pat.symbol, caseBody)
}
}
@@ -290,7 +290,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
nopIfNeeded(startTryBody)
val finalHandler = currProgramPoint() // version of the finally-clause reached via unhandled exception.
protect(startTryBody, finalHandler, finalHandler, null)
- val Local(eTK, _, eIdx, _) = locals(locals.makeLocal(ThrowableReference, "exc"))
+ val Local(eTK, _, eIdx, _) = locals(locals.makeLocal(jlThrowableRef, "exc"))
bc.store(eIdx, eTK)
emitFinalizer(finalizer, null, isDuplicate = true)
bc.load(eIdx, eTK)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
index 92aaf991bf..ef3fab7617 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -157,7 +157,7 @@ abstract class BTypes {
val res = ClassBType(internalName)
byteCodeRepository.classNode(internalName) match {
case Left(msg) => res.info = Left(NoClassBTypeInfoMissingBytecode(msg)); res
- case Right(c) => setClassInfoFromParsedClassfile(c, res)
+ case Right(c) => setClassInfoFromClassNode(c, res)
}
})
}
@@ -167,14 +167,14 @@ abstract class BTypes {
*/
def classBTypeFromClassNode(classNode: ClassNode): ClassBType = {
classBTypeFromInternalName.getOrElse(classNode.name, {
- setClassInfoFromParsedClassfile(classNode, ClassBType(classNode.name))
+ setClassInfoFromClassNode(classNode, ClassBType(classNode.name))
})
}
- private def setClassInfoFromParsedClassfile(classNode: ClassNode, classBType: ClassBType): ClassBType = {
+ private def setClassInfoFromClassNode(classNode: ClassNode, classBType: ClassBType): ClassBType = {
val superClass = classNode.superName match {
case null =>
- assert(classNode.name == ObjectReference.internalName, s"class with missing super type: ${classNode.name}")
+ assert(classNode.name == ObjectRef.internalName, s"class with missing super type: ${classNode.name}")
None
case superName =>
Some(classBTypeFromParsedClassfile(superName))
@@ -321,8 +321,8 @@ abstract class BTypes {
final def isNonVoidPrimitiveType = isPrimitive && this != UNIT
- final def isNullType = this == RT_NULL
- final def isNothingType = this == RT_NOTHING
+ final def isNullType = this == srNullRef
+ final def isNothingType = this == srNothingRef
final def isBoxed = this.isClass && boxedClasses(this.asClassBType)
@@ -345,7 +345,7 @@ abstract class BTypes {
this match {
case ArrayBType(component) =>
- if (other == ObjectReference || other == jlCloneableReference || other == jioSerializableReference) true
+ if (other == ObjectRef || other == jlCloneableRef || other == jiSerializableRef) true
else other match {
case ArrayBType(otherComponent) => component.conformsTo(otherComponent).orThrow
case _ => false
@@ -354,7 +354,7 @@ abstract class BTypes {
case classType: ClassBType =>
if (isBoxed) {
if (other.isBoxed) this == other
- else if (other == ObjectReference) true
+ else if (other == ObjectRef) true
else other match {
case otherClassType: ClassBType => classType.isSubtypeOf(otherClassType).orThrow // e.g., java/lang/Double conforms to java/lang/Number
case _ => false
@@ -397,7 +397,7 @@ abstract class BTypes {
assert(other.isRef, s"Cannot compute maxType: $this, $other")
// Approximate `lub`. The common type of two references is always ObjectReference.
- ObjectReference
+ ObjectRef
case _: MethodBType =>
assertionError(s"unexpected method type when computing maxType: $this")
@@ -869,7 +869,7 @@ abstract class BTypes {
// best-effort verification. also we don't report an error if the info is a Left.
def ifInit(c: ClassBType)(p: ClassBType => Boolean): Boolean = c._info == null || c.info.isLeft || p(c)
- def isJLO(t: ClassBType) = t.internalName == ObjectReference.internalName
+ def isJLO(t: ClassBType) = t.internalName == ObjectRef.internalName
assert(!ClassBType.isInternalPhantomType(internalName), s"Cannot create ClassBType for phantom type $this")
@@ -949,7 +949,7 @@ abstract class BTypes {
def isSubtypeOf(other: ClassBType): Either[NoClassBTypeInfo, Boolean] = try {
if (this == other) return Right(true)
if (isInterface.orThrow) {
- if (other == ObjectReference) return Right(true) // interfaces conform to Object
+ if (other == ObjectRef) return Right(true) // interfaces conform to Object
if (!other.isInterface.orThrow) return Right(false) // this is an interface, the other is some class other than object. interfaces cannot extend classes, so the result is false.
// else: this and other are both interfaces. continue to (*)
} else {
@@ -982,13 +982,13 @@ abstract class BTypes {
// exercised by test/files/run/t4761.scala
if (other.isSubtypeOf(this).orThrow) this
else if (this.isSubtypeOf(other).orThrow) other
- else ObjectReference
+ else ObjectRef
case (true, false) =>
- if (other.isSubtypeOf(this).orThrow) this else ObjectReference
+ if (other.isSubtypeOf(this).orThrow) this else ObjectRef
case (false, true) =>
- if (this.isSubtypeOf(other).orThrow) other else ObjectReference
+ if (this.isSubtypeOf(other).orThrow) other else ObjectRef
case _ =>
// TODO @lry I don't really understand the reasoning here.
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index 79b5e6a2fb..a2bf8e5725 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -110,8 +110,8 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
assert(classSym.isClass, s"Cannot create ClassBType from non-class symbol $classSym")
assertClassNotArrayNotPrimitive(classSym)
assert(!primitiveTypeMap.contains(classSym) || isCompilingPrimitive, s"Cannot create ClassBType for primitive class symbol $classSym")
- if (classSym == NothingClass) RT_NOTHING
- else if (classSym == NullClass) RT_NULL
+ if (classSym == NothingClass) srNothingRef
+ else if (classSym == NullClass) srNullRef
else {
val internalName = classSym.javaBinaryName.toString
classBTypeFromInternalName.getOrElse(internalName, {
@@ -164,7 +164,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
*/
def nonClassTypeRefToBType(sym: Symbol): ClassBType = {
assert(sym.isType && isCompilingArray, sym)
- ObjectReference
+ ObjectRef
}
t.dealiasWiden match {
@@ -201,7 +201,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
"If possible, please file a bug on issues.scala-lang.org.")
tp match {
- case ThisType(ArrayClass) => ObjectReference // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test
+ case ThisType(ArrayClass) => ObjectRef // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test
case ThisType(sym) => classBTypeFromSymbol(sym)
case SingleType(_, sym) => primitiveOrClassToBType(sym)
case ConstantType(_) => typeToBType(t.underlying)
@@ -256,13 +256,6 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
/* The InnerClass table of a class C must contain all nested classes of C, even if they are only
* declared but not otherwise referenced in C (from the bytecode or a method / field signature).
* We collect them here.
- *
- * Nested classes that are also referenced in C will be added to the innerClassBufferASM during
- * code generation, but those duplicates will be eliminated when emitting the InnerClass
- * attribute.
- *
- * Why do we need to collect classes into innerClassBufferASM at all? To collect references to
- * nested classes, but NOT nested in C, that are used within C.
*/
val nestedClassSymbols = {
val linkedClass = exitingPickler(classSym.linkedClassOfClass) // linkedCoC does not work properly in late phases
@@ -455,7 +448,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
}
/**
- * For top-level objects without a companion class, the compilere generates a mirror class with
+ * For top-level objects without a companion class, the compiler generates a mirror class with
* static forwarders (Java compat). There's no symbol for the mirror class, but we still need a
* ClassBType (its info.nestedClasses will hold the InnerClass entries, see comment in BTypes).
*/
@@ -467,7 +460,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
// class info consistent with BCodeHelpers.genMirrorClass
val nested = exitingPickler(memberClassesForInnerClassTable(moduleClassSym)) map classBTypeFromSymbol
c.info = Right(ClassInfo(
- superClass = Some(ObjectReference),
+ superClass = Some(ObjectRef),
interfaces = Nil,
flags = asm.Opcodes.ACC_SUPER | asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_FINAL,
nestedClasses = nested,
@@ -477,6 +470,21 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
})
}
+ def beanInfoClassClassBType(mainClass: Symbol): ClassBType = {
+ val internalName = mainClass.javaBinaryName.toString + "BeanInfo"
+ classBTypeFromInternalName.getOrElse(internalName, {
+ val c = ClassBType(internalName)
+ c.info = Right(ClassInfo(
+ superClass = Some(sbScalaBeanInfoRef),
+ interfaces = Nil,
+ flags = javaFlags(mainClass),
+ nestedClasses = Nil,
+ nestedInfo = None,
+ inlineInfo = EmptyInlineInfo))
+ c
+ })
+ }
+
/**
* True for module classes of package level objects. The backend will generate a mirror class for
* such objects.
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
index 48e43c74f4..79aa4308c5 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
@@ -29,7 +29,7 @@ import scala.annotation.switch
class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
import bTypes._
import global._
- import rootMirror.{requiredClass, getClassIfDefined}
+ import rootMirror.{requiredClass, requiredModule, getClassIfDefined}
import definitions._
/**
@@ -48,15 +48,15 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
DoubleClass -> DOUBLE
)
- lazy val BOXED_UNIT : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.Void])
- lazy val BOXED_BOOLEAN : ClassBType = classBTypeFromSymbol(BoxedBooleanClass)
- lazy val BOXED_BYTE : ClassBType = classBTypeFromSymbol(BoxedByteClass)
- lazy val BOXED_SHORT : ClassBType = classBTypeFromSymbol(BoxedShortClass)
- lazy val BOXED_CHAR : ClassBType = classBTypeFromSymbol(BoxedCharacterClass)
- lazy val BOXED_INT : ClassBType = classBTypeFromSymbol(BoxedIntClass)
- lazy val BOXED_LONG : ClassBType = classBTypeFromSymbol(BoxedLongClass)
- lazy val BOXED_FLOAT : ClassBType = classBTypeFromSymbol(BoxedFloatClass)
- lazy val BOXED_DOUBLE : ClassBType = classBTypeFromSymbol(BoxedDoubleClass)
+ private lazy val BOXED_UNIT : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.Void])
+ private lazy val BOXED_BOOLEAN : ClassBType = classBTypeFromSymbol(BoxedBooleanClass)
+ private lazy val BOXED_BYTE : ClassBType = classBTypeFromSymbol(BoxedByteClass)
+ private lazy val BOXED_SHORT : ClassBType = classBTypeFromSymbol(BoxedShortClass)
+ private lazy val BOXED_CHAR : ClassBType = classBTypeFromSymbol(BoxedCharacterClass)
+ private lazy val BOXED_INT : ClassBType = classBTypeFromSymbol(BoxedIntClass)
+ private lazy val BOXED_LONG : ClassBType = classBTypeFromSymbol(BoxedLongClass)
+ private lazy val BOXED_FLOAT : ClassBType = classBTypeFromSymbol(BoxedFloatClass)
+ private lazy val BOXED_DOUBLE : ClassBType = classBTypeFromSymbol(BoxedDoubleClass)
/**
* Map from primitive types to their boxed class type. Useful when pushing class literals onto the
@@ -95,35 +95,30 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
/*
* RT_NOTHING and RT_NULL exist at run-time only. They are the bytecode-level manifestation (in
- * method signatures only) of what shows up as NothingClass resp. NullClass in Scala ASTs.
+ * method signatures only) of what shows up as NothingClass (scala.Nothing) resp. NullClass
+ * (scala.Null) in Scala ASTs.
*
* Therefore, when RT_NOTHING or RT_NULL are to be emitted, a mapping is needed: the internal
* names of NothingClass and NullClass can't be emitted as-is.
*/
- lazy val RT_NOTHING : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.Nothing$])
- lazy val RT_NULL : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.Null$])
-
- lazy val ObjectReference : ClassBType = classBTypeFromSymbol(ObjectClass)
- lazy val objArrayReference : ArrayBType = ArrayBType(ObjectReference)
-
- lazy val StringReference : ClassBType = classBTypeFromSymbol(StringClass)
- lazy val StringBuilderReference : ClassBType = classBTypeFromSymbol(StringBuilderClass)
- lazy val ThrowableReference : ClassBType = classBTypeFromSymbol(ThrowableClass)
- lazy val jlCloneableReference : ClassBType = classBTypeFromSymbol(JavaCloneableClass) // java/lang/Cloneable
- lazy val jlNPEReference : ClassBType = classBTypeFromSymbol(NullPointerExceptionClass) // java/lang/NullPointerException
- lazy val jioSerializableReference : ClassBType = classBTypeFromSymbol(JavaSerializableClass) // java/io/Serializable
- lazy val scalaSerializableReference : ClassBType = classBTypeFromSymbol(SerializableClass) // scala/Serializable
- lazy val classCastExceptionReference : ClassBType = classBTypeFromSymbol(ClassCastExceptionClass) // java/lang/ClassCastException
- lazy val javaUtilMapReference : ClassBType = classBTypeFromSymbol(JavaUtilMap) // java/util/Map
- lazy val javaUtilHashMapReference : ClassBType = classBTypeFromSymbol(JavaUtilHashMap) // java/util/HashMap
-
- lazy val srBooleanRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BooleanRef])
- lazy val srByteRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.ByteRef])
- lazy val srCharRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.CharRef])
- lazy val srIntRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.IntRef])
- lazy val srLongRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.LongRef])
- lazy val srFloatRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.FloatRef])
- lazy val srDoubleRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.DoubleRef])
+ lazy val srNothingRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.Nothing$])
+ lazy val srNullRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.Null$])
+
+ lazy val ObjectRef : ClassBType = classBTypeFromSymbol(ObjectClass)
+ lazy val StringRef : ClassBType = classBTypeFromSymbol(StringClass)
+ lazy val jlStringBuilderRef : ClassBType = classBTypeFromSymbol(StringBuilderClass)
+ lazy val jlThrowableRef : ClassBType = classBTypeFromSymbol(ThrowableClass)
+ lazy val jlCloneableRef : ClassBType = classBTypeFromSymbol(JavaCloneableClass) // java/lang/Cloneable
+ lazy val jiSerializableRef : ClassBType = classBTypeFromSymbol(JavaSerializableClass) // java/io/Serializable
+ lazy val jlClassCastExceptionRef : ClassBType = classBTypeFromSymbol(ClassCastExceptionClass) // java/lang/ClassCastException
+ lazy val juMapRef : ClassBType = classBTypeFromSymbol(JavaUtilMap) // java/util/Map
+ lazy val juHashMapRef : ClassBType = classBTypeFromSymbol(JavaUtilHashMap) // java/util/HashMap
+ lazy val sbScalaBeanInfoRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.beans.ScalaBeanInfo])
+ lazy val jliSerializedLambdaRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.SerializedLambda])
+ lazy val jliMethodHandlesRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodHandles])
+ lazy val jliMethodHandlesLookupRef : ClassBType = classBTypeFromSymbol(exitingPickler(rootMirror.getRequiredClass("java.lang.invoke.MethodHandles.Lookup"))) // didn't find a reliable non-stringly-typed way that works for inner classes in the backend
+ lazy val srLambdaDeserializerRef : ClassBType = classBTypeFromSymbol(requiredModule[scala.runtime.LambdaDeserializer.type].moduleClass)
+ lazy val srBoxesRunTimeRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxesRunTime])
lazy val hashMethodSym: Symbol = getMember(ScalaRunTimeModule, nme.hash_)
@@ -141,16 +136,6 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
})
}
- // scala.FunctionX and scala.runtim.AbstractFunctionX
- lazy val FunctionReference : Vector[ClassBType] = (0 to MaxFunctionArity).map(i => classBTypeFromSymbol(FunctionClass(i)))(collection.breakOut)
- lazy val AbstractFunctionReference : Vector[ClassBType] = (0 to MaxFunctionArity).map(i => classBTypeFromSymbol(AbstractFunctionClass(i)))(collection.breakOut)
- lazy val AbstractFunctionArityMap : Map[ClassBType, Int] = AbstractFunctionReference.zipWithIndex.toMap
-
- lazy val PartialFunctionReference : ClassBType = classBTypeFromSymbol(PartialFunctionClass)
- lazy val AbstractPartialFunctionReference : ClassBType = classBTypeFromSymbol(AbstractPartialFunctionClass)
-
- lazy val BoxesRunTime: ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxesRunTime])
-
/**
* Methods in scala.runtime.BoxesRuntime
*/
@@ -166,14 +151,14 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
)
lazy val asmUnboxTo: Map[BType, MethodNameAndType] = Map(
- BOOL -> MethodNameAndType("unboxToBoolean", MethodBType(List(ObjectReference), BOOL)),
- BYTE -> MethodNameAndType("unboxToByte", MethodBType(List(ObjectReference), BYTE)),
- CHAR -> MethodNameAndType("unboxToChar", MethodBType(List(ObjectReference), CHAR)),
- SHORT -> MethodNameAndType("unboxToShort", MethodBType(List(ObjectReference), SHORT)),
- INT -> MethodNameAndType("unboxToInt", MethodBType(List(ObjectReference), INT)),
- LONG -> MethodNameAndType("unboxToLong", MethodBType(List(ObjectReference), LONG)),
- FLOAT -> MethodNameAndType("unboxToFloat", MethodBType(List(ObjectReference), FLOAT)),
- DOUBLE -> MethodNameAndType("unboxToDouble", MethodBType(List(ObjectReference), DOUBLE))
+ BOOL -> MethodNameAndType("unboxToBoolean", MethodBType(List(ObjectRef), BOOL)),
+ BYTE -> MethodNameAndType("unboxToByte", MethodBType(List(ObjectRef), BYTE)),
+ CHAR -> MethodNameAndType("unboxToChar", MethodBType(List(ObjectRef), CHAR)),
+ SHORT -> MethodNameAndType("unboxToShort", MethodBType(List(ObjectRef), SHORT)),
+ INT -> MethodNameAndType("unboxToInt", MethodBType(List(ObjectRef), INT)),
+ LONG -> MethodNameAndType("unboxToLong", MethodBType(List(ObjectRef), LONG)),
+ FLOAT -> MethodNameAndType("unboxToFloat", MethodBType(List(ObjectRef), FLOAT)),
+ DOUBLE -> MethodNameAndType("unboxToDouble", MethodBType(List(ObjectRef), DOUBLE))
)
lazy val typeOfArrayOp: Map[Int, BType] = {
@@ -187,7 +172,7 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
(List(LARRAY_LENGTH, LARRAY_GET, LARRAY_SET) map (_ -> LONG)) ++
(List(FARRAY_LENGTH, FARRAY_GET, FARRAY_SET) map (_ -> FLOAT)) ++
(List(DARRAY_LENGTH, DARRAY_GET, DARRAY_SET) map (_ -> DOUBLE)) ++
- (List(OARRAY_LENGTH, OARRAY_GET, OARRAY_SET) map (_ -> ObjectReference)) : _*
+ (List(OARRAY_LENGTH, OARRAY_GET, OARRAY_SET) map (_ -> ObjectRef)) : _*
)
}
}
@@ -206,14 +191,17 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
def boxedClasses: Set[ClassBType]
- def RT_NOTHING: ClassBType
- def RT_NULL : ClassBType
-
- def ObjectReference : ClassBType
- def jlCloneableReference : ClassBType
- def jioSerializableReference: ClassBType
- def javaUtilHashMapReference: ClassBType
- def javaUtilMapReference : ClassBType
+ def ObjectRef : ClassBType
+ def srNothingRef : ClassBType
+ def srNullRef : ClassBType
+ def jlCloneableRef : ClassBType
+ def jiSerializableRef : ClassBType
+ def juHashMapRef : ClassBType
+ def juMapRef : ClassBType
+ def jliSerializedLambdaRef : ClassBType
+ def jliMethodHandlesRef : ClassBType
+ def jliMethodHandlesLookupRef : ClassBType
+ def srLambdaDeserializerRef : ClassBType
}
/**
@@ -230,48 +218,30 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
def primitiveTypeMap: Map[Symbol, PrimitiveBType] = _coreBTypes.primitiveTypeMap
- def BOXED_UNIT : ClassBType = _coreBTypes.BOXED_UNIT
- def BOXED_BOOLEAN : ClassBType = _coreBTypes.BOXED_BOOLEAN
- def BOXED_BYTE : ClassBType = _coreBTypes.BOXED_BYTE
- def BOXED_SHORT : ClassBType = _coreBTypes.BOXED_SHORT
- def BOXED_CHAR : ClassBType = _coreBTypes.BOXED_CHAR
- def BOXED_INT : ClassBType = _coreBTypes.BOXED_INT
- def BOXED_LONG : ClassBType = _coreBTypes.BOXED_LONG
- def BOXED_FLOAT : ClassBType = _coreBTypes.BOXED_FLOAT
- def BOXED_DOUBLE : ClassBType = _coreBTypes.BOXED_DOUBLE
-
def boxedClasses: Set[ClassBType] = _coreBTypes.boxedClasses
def boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType] = _coreBTypes.boxedClassOfPrimitive
def boxResultType: Map[Symbol, ClassBType] = _coreBTypes.boxResultType
-
def unboxResultType: Map[Symbol, PrimitiveBType] = _coreBTypes.unboxResultType
- def RT_NOTHING : ClassBType = _coreBTypes.RT_NOTHING
- def RT_NULL : ClassBType = _coreBTypes.RT_NULL
-
- def ObjectReference : ClassBType = _coreBTypes.ObjectReference
- def objArrayReference : ArrayBType = _coreBTypes.objArrayReference
-
- def StringReference : ClassBType = _coreBTypes.StringReference
- def StringBuilderReference : ClassBType = _coreBTypes.StringBuilderReference
- def ThrowableReference : ClassBType = _coreBTypes.ThrowableReference
- def jlCloneableReference : ClassBType = _coreBTypes.jlCloneableReference
- def jlNPEReference : ClassBType = _coreBTypes.jlNPEReference
- def jioSerializableReference : ClassBType = _coreBTypes.jioSerializableReference
- def scalaSerializableReference : ClassBType = _coreBTypes.scalaSerializableReference
- def classCastExceptionReference : ClassBType = _coreBTypes.classCastExceptionReference
- def javaUtilMapReference : ClassBType = _coreBTypes.javaUtilMapReference
- def javaUtilHashMapReference : ClassBType = _coreBTypes.javaUtilHashMapReference
-
- def srBooleanRef : ClassBType = _coreBTypes.srBooleanRef
- def srByteRef : ClassBType = _coreBTypes.srByteRef
- def srCharRef : ClassBType = _coreBTypes.srCharRef
- def srIntRef : ClassBType = _coreBTypes.srIntRef
- def srLongRef : ClassBType = _coreBTypes.srLongRef
- def srFloatRef : ClassBType = _coreBTypes.srFloatRef
- def srDoubleRef : ClassBType = _coreBTypes.srDoubleRef
+ def ObjectRef : ClassBType = _coreBTypes.ObjectRef
+ def StringRef : ClassBType = _coreBTypes.StringRef
+ def jlStringBuilderRef : ClassBType = _coreBTypes.jlStringBuilderRef
+ def srNothingRef : ClassBType = _coreBTypes.srNothingRef
+ def srNullRef : ClassBType = _coreBTypes.srNullRef
+ def jlThrowableRef : ClassBType = _coreBTypes.jlThrowableRef
+ def jlCloneableRef : ClassBType = _coreBTypes.jlCloneableRef
+ def jiSerializableRef : ClassBType = _coreBTypes.jiSerializableRef
+ def jlClassCastExceptionRef : ClassBType = _coreBTypes.jlClassCastExceptionRef
+ def juMapRef : ClassBType = _coreBTypes.juMapRef
+ def juHashMapRef : ClassBType = _coreBTypes.juHashMapRef
+ def sbScalaBeanInfoRef : ClassBType = _coreBTypes.sbScalaBeanInfoRef
+ def jliSerializedLambdaRef : ClassBType = _coreBTypes.jliSerializedLambdaRef
+ def jliMethodHandlesRef : ClassBType = _coreBTypes.jliMethodHandlesRef
+ def jliMethodHandlesLookupRef : ClassBType = _coreBTypes.jliMethodHandlesLookupRef
+ def srLambdaDeserializerRef : ClassBType = _coreBTypes.srLambdaDeserializerRef
+ def srBoxesRunTimeRef : ClassBType = _coreBTypes.srBoxesRunTimeRef
def hashMethodSym: Symbol = _coreBTypes.hashMethodSym
@@ -282,15 +252,6 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
def String_valueOf: Symbol = _coreBTypes.String_valueOf
- def FunctionReference : Vector[ClassBType] = _coreBTypes.FunctionReference
- def AbstractFunctionReference : Vector[ClassBType] = _coreBTypes.AbstractFunctionReference
- def AbstractFunctionArityMap : Map[ClassBType, Int] = _coreBTypes.AbstractFunctionArityMap
-
- def PartialFunctionReference : ClassBType = _coreBTypes.PartialFunctionReference
- def AbstractPartialFunctionReference : ClassBType = _coreBTypes.AbstractPartialFunctionReference
-
- def BoxesRunTime: ClassBType = _coreBTypes.BoxesRunTime
-
def asmBoxTo : Map[BType, MethodNameAndType] = _coreBTypes.asmBoxTo
def asmUnboxTo: Map[BType, MethodNameAndType] = _coreBTypes.asmUnboxTo
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index e1a724f1cb..35e4db33bc 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -245,6 +245,11 @@ abstract class GenBCode extends BCodeSyncAndTry {
BackendStats.timed(BackendStats.methodOptTimer)(localOpt.methodOptimizations(classNode))
}
+ def setInnerClasses(classNode: ClassNode): Unit = if (classNode != null) {
+ classNode.innerClasses.clear()
+ addInnerClasses(classNode, bTypes.backendUtils.collectNestedClasses(classNode))
+ }
+
def run() {
runGlobalOptimizations()
@@ -257,6 +262,9 @@ abstract class GenBCode extends BCodeSyncAndTry {
else {
try {
localOptimizations(item.plain)
+ setInnerClasses(item.plain)
+ setInnerClasses(item.mirror)
+ setInnerClasses(item.bean)
addToQ3(item)
} catch {
case e: java.lang.RuntimeException if e.getMessage != null && (e.getMessage contains "too large!") =>
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
index 793235c131..1da32bc7a8 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
@@ -2,12 +2,14 @@ package scala.tools.nsc
package backend.jvm
package analysis
-import scala.tools.asm.Label
+import scala.annotation.switch
+import scala.tools.asm.{Handle, Type, Label}
import scala.tools.asm.tree._
import scala.tools.asm.tree.analysis.{Frame, BasicInterpreter, Analyzer, Value}
import scala.tools.nsc.backend.jvm.BTypes._
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._
import java.lang.invoke.LambdaMetafactory
+import scala.collection.mutable
import scala.collection.convert.decorateAsJava._
import scala.collection.convert.decorateAsScala._
@@ -67,41 +69,45 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
def addLambdaDeserialize(classNode: ClassNode): Unit = {
val cw = classNode
import scala.tools.asm.Opcodes._
+ import btypes.coreBTypes._
- // Need to force creation of BTypes for these as `getCommonSuperClass` is called on
- // automatically computing the max stack size (`visitMaxs`) during method writing.
- btypes.coreBTypes.javaUtilHashMapReference
- btypes.coreBTypes.javaUtilMapReference
+ // Make sure to reference the ClassBTypes of all types that are used in the code generated
+ // here (e.g. java/util/Map) are initialized. Initializing a ClassBType adds it to the
+ // `classBTypeFromInternalName` map. When writing the classfile, the asm ClassWriter computes
+ // stack map frames and invokes the `getCommonSuperClass` method. This method expects all
+ // ClassBTypes mentioned in the source code to exist in the map.
- // This is fine, even if `visitInnerClass` was called before for MethodHandles.Lookup: duplicates are not emitted.
- cw.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles", "Lookup", ACC_PUBLIC + ACC_FINAL + ACC_STATIC)
+ val mapDesc = juMapRef.descriptor
+ val nilLookupDesc = MethodBType(Nil, jliMethodHandlesLookupRef).descriptor
+ val serlamObjDesc = MethodBType(jliSerializedLambdaRef :: Nil, ObjectRef).descriptor
+ val lookupMapSerlamObjDesc = MethodBType(jliMethodHandlesLookupRef :: juMapRef :: jliSerializedLambdaRef :: Nil, ObjectRef).descriptor
{
- val fv = cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambdaCache$", "Ljava/util/Map;", null, null)
+ val fv = cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambdaCache$", mapDesc, null, null)
fv.visitEnd()
}
{
- val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", "(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", null, null)
+ val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", serlamObjDesc, null, null)
mv.visitCode()
// javaBinaryName returns the internal name of a class. Also used in BTypesFromsymbols.classBTypeFromSymbol.
- mv.visitFieldInsn(GETSTATIC, classNode.name, "$deserializeLambdaCache$", "Ljava/util/Map;")
+ mv.visitFieldInsn(GETSTATIC, classNode.name, "$deserializeLambdaCache$", mapDesc)
mv.visitVarInsn(ASTORE, 1)
mv.visitVarInsn(ALOAD, 1)
val l0 = new Label()
mv.visitJumpInsn(IFNONNULL, l0)
- mv.visitTypeInsn(NEW, "java/util/HashMap")
+ mv.visitTypeInsn(NEW, juHashMapRef.internalName)
mv.visitInsn(DUP)
- mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V", false)
+ mv.visitMethodInsn(INVOKESPECIAL, juHashMapRef.internalName, "<init>", "()V", false)
mv.visitVarInsn(ASTORE, 1)
mv.visitVarInsn(ALOAD, 1)
- mv.visitFieldInsn(PUTSTATIC, classNode.name, "$deserializeLambdaCache$", "Ljava/util/Map;")
+ mv.visitFieldInsn(PUTSTATIC, classNode.name, "$deserializeLambdaCache$", mapDesc)
mv.visitLabel(l0)
- mv.visitFieldInsn(GETSTATIC, "scala/runtime/LambdaDeserializer$", "MODULE$", "Lscala/runtime/LambdaDeserializer$;")
- mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false)
+ mv.visitFieldInsn(GETSTATIC, srLambdaDeserializerRef.internalName, "MODULE$", srLambdaDeserializerRef.descriptor)
+ mv.visitMethodInsn(INVOKESTATIC, jliMethodHandlesRef.internalName, "lookup", nilLookupDesc, false)
mv.visitVarInsn(ALOAD, 1)
mv.visitVarInsn(ALOAD, 0)
- mv.visitMethodInsn(INVOKEVIRTUAL, "scala/runtime/LambdaDeserializer$", "deserializeLambda", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/util/Map;Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", false)
+ mv.visitMethodInsn(INVOKEVIRTUAL, srLambdaDeserializerRef.internalName, "deserializeLambda", lookupMapSerlamObjDesc, false)
mv.visitInsn(ARETURN)
mv.visitEnd()
}
@@ -133,4 +139,121 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
}
(result, map, hasSerializableClosureInstantiation)
}
+
+ /**
+ * Visit the class node and collect all referenced nested classes.
+ */
+ def collectNestedClasses(classNode: ClassNode): List[ClassBType] = {
+ val innerClasses = mutable.Set.empty[ClassBType]
+
+ def visitInternalName(internalName: InternalName): Unit = if (internalName != null) {
+ val t = classBTypeFromParsedClassfile(internalName)
+ if (t.isNestedClass.get) innerClasses += t
+ }
+
+ // either an internal/Name or [[Linternal/Name; -- there are certain references in classfiles
+ // that are either an internal name (without the surrounding `L;`) or an array descriptor
+ // `[Linternal/Name;`.
+ def visitInternalNameOrArrayReference(ref: String): Unit = if (ref != null) {
+ val bracket = ref.lastIndexOf('[')
+ if (bracket == -1) visitInternalName(ref)
+ else if (ref.charAt(bracket + 1) == 'L') visitInternalName(ref.substring(bracket + 2, ref.length - 1))
+ }
+
+ // we are only interested in the class references in the descriptor, so we can skip over
+ // primitves and the brackets of array descriptors
+ def visitDescriptor(desc: String): Unit = (desc.charAt(0): @switch) match {
+ case '(' =>
+ val internalNames = mutable.ListBuffer.empty[String]
+ var i = 1
+ while (i < desc.length) {
+ if (desc.charAt(i) == 'L') {
+ val start = i + 1 // skip the L
+ while (desc.charAt(i) != ';') i += 1
+ internalNames append desc.substring(start, i)
+ }
+ // skips over '[', ')', primitives
+ i += 1
+ }
+ internalNames foreach visitInternalName
+
+ case 'L' =>
+ visitInternalName(desc.substring(1, desc.length - 1))
+
+ case '[' =>
+ visitInternalNameOrArrayReference(desc)
+
+ case _ => // skip over primitive types
+ }
+
+ def visitConstant(const: AnyRef): Unit = const match {
+ case t: Type => visitDescriptor(t.getDescriptor)
+ case _ =>
+ }
+
+ // in principle we could references to annotation types, as they only end up as strings in the
+ // constant pool, not as class references. however, the java compiler still includes nested
+ // annotation classes in the innerClass table, so we do the same. explained in detail in the
+ // large comment in class BTypes.
+ def visitAnnotation(annot: AnnotationNode): Unit = {
+ visitDescriptor(annot.desc)
+ if (annot.values != null) annot.values.asScala foreach visitConstant
+ }
+
+ def visitAnnotations(annots: java.util.List[_ <: AnnotationNode]) = if (annots != null) annots.asScala foreach visitAnnotation
+ def visitAnnotationss(annotss: Array[java.util.List[AnnotationNode]]) = if (annotss != null) annotss foreach visitAnnotations
+
+ def visitHandle(handle: Handle): Unit = {
+ visitInternalNameOrArrayReference(handle.getOwner)
+ visitDescriptor(handle.getDesc)
+ }
+
+ visitInternalName(classNode.name)
+ innerClasses ++= classBTypeFromParsedClassfile(classNode.name).info.get.nestedClasses
+
+ visitInternalName(classNode.superName)
+ classNode.interfaces.asScala foreach visitInternalName
+ visitInternalName(classNode.outerClass)
+
+ visitAnnotations(classNode.visibleAnnotations)
+ visitAnnotations(classNode.visibleTypeAnnotations)
+ visitAnnotations(classNode.invisibleAnnotations)
+ visitAnnotations(classNode.invisibleTypeAnnotations)
+
+ for (f <- classNode.fields.asScala) {
+ visitDescriptor(f.desc)
+ visitAnnotations(f.visibleAnnotations)
+ visitAnnotations(f.visibleTypeAnnotations)
+ visitAnnotations(f.invisibleAnnotations)
+ visitAnnotations(f.invisibleTypeAnnotations)
+ }
+
+ for (m <- classNode.methods.asScala) {
+ visitDescriptor(m.desc)
+
+ visitAnnotations(m.visibleAnnotations)
+ visitAnnotations(m.visibleTypeAnnotations)
+ visitAnnotations(m.invisibleAnnotations)
+ visitAnnotations(m.invisibleTypeAnnotations)
+ visitAnnotationss(m.visibleParameterAnnotations)
+ visitAnnotationss(m.invisibleParameterAnnotations)
+ visitAnnotations(m.visibleLocalVariableAnnotations)
+ visitAnnotations(m.invisibleLocalVariableAnnotations)
+
+ m.exceptions.asScala foreach visitInternalName
+ for (tcb <- m.tryCatchBlocks.asScala) visitInternalName(tcb.`type`)
+
+ val iter = m.instructions.iterator()
+ while (iter.hasNext) iter.next() match {
+ case ti: TypeInsnNode => visitInternalNameOrArrayReference(ti.desc)
+ case fi: FieldInsnNode => visitInternalNameOrArrayReference(fi.owner); visitDescriptor(fi.desc)
+ case mi: MethodInsnNode => visitInternalNameOrArrayReference(mi.owner); visitDescriptor(mi.desc)
+ case id: InvokeDynamicInsnNode => visitDescriptor(id.desc); visitHandle(id.bsm); id.bsmArgs foreach visitConstant
+ case ci: LdcInsnNode => visitConstant(ci.cst)
+ case ma: MultiANewArrayInsnNode => visitDescriptor(ma.desc)
+ case _ =>
+ }
+ }
+ innerClasses.toList
+ }
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
index 65a8c45813..e543a8c3e0 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
@@ -20,7 +20,7 @@ import scala.collection.convert.decorateAsScala._
object BytecodeUtils {
// http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.9.1
- final val maxJVMMethodSize = 65535
+ final val maxJVMMethodSize = 65535
// 5% margin, more than enough for the instructions added by the inliner (store / load args, null check for instance methods)
final val maxMethodSizeAfterInline = maxJVMMethodSize - (maxJVMMethodSize / 20)
@@ -310,9 +310,9 @@ object BytecodeUtils {
* method which explains the issue with such phantom values.
*/
def fixLoadedNothingOrNullValue(loadedType: Type, loadInstr: AbstractInsnNode, methodNode: MethodNode, bTypes: BTypes): Unit = {
- if (loadedType == bTypes.coreBTypes.RT_NOTHING.toASMType) {
+ if (loadedType == bTypes.coreBTypes.srNothingRef.toASMType) {
methodNode.instructions.insert(loadInstr, new InsnNode(Opcodes.ATHROW))
- } else if (loadedType == bTypes.coreBTypes.RT_NULL.toASMType) {
+ } else if (loadedType == bTypes.coreBTypes.srNullRef.toASMType) {
methodNode.instructions.insert(loadInstr, new InsnNode(Opcodes.ACONST_NULL))
methodNode.instructions.insert(loadInstr, new InsnNode(Opcodes.POP))
}
diff --git a/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala b/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala
index 07d619bca5..cf055e0758 100644
--- a/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala
@@ -30,37 +30,5 @@ trait ReplGlobal extends Global {
val virtualDirectory = globalSettings.outputDirs.getSingleOutput.get
new util.AbstractFileClassLoader(virtualDirectory, loader) {}
}
-
- override def newTyper(context: Context): Typer = new Typer(context) {
- override def typed(tree: Tree, mode: Mode, pt: Type): Tree = {
- val res = super.typed(tree, mode, pt)
- tree match {
- case Ident(name) if !tree.symbol.hasPackageFlag && !name.toString.startsWith("$") =>
- repldbg("typed %s: %s".format(name, res.tpe))
- case _ =>
- }
- res
- }
- }
- }
-
- object replPhase extends SubComponent {
- val global: ReplGlobal.this.type = ReplGlobal.this
- val phaseName = "repl"
- val runsAfter = List[String]("typer")
- val runsRightAfter = None
- def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) {
- def apply(unit: CompilationUnit) {
- repldbg("Running replPhase on " + unit.body)
- // newNamer(rootContext(unit)).enterSym(unit.body)
- }
- }
- // add to initial or terminal phase to sanity check Run at construction
- override val requires = List("typer") // ensure they didn't -Ystop-after:parser
- }
-
- override protected def computePhaseDescriptors: List[SubComponent] = {
- addToPhasesSet(replPhase, "repl")
- super.computePhaseDescriptors
}
}
diff --git a/test/files/jvm/innerClassAttribute/Classes_1.scala b/test/files/jvm/innerClassAttribute/Classes_1.scala
index 2b690bdd7b..5b821d43f8 100644
--- a/test/files/jvm/innerClassAttribute/Classes_1.scala
+++ b/test/files/jvm/innerClassAttribute/Classes_1.scala
@@ -13,7 +13,7 @@ object A3 {
class A4 {
def f(l: List[String]): List[String] = {
- l map (_ + "1")
+ l map (_ + "1") : @noinline // inlining adds a reference to the nested class scala/collection/generic/GenTraversableFactory$GenericCanBuildFrom
}
}
@@ -274,8 +274,8 @@ object NestedInValueClass {
class A(val arg: String) extends AnyVal {
// A has InnerClass entries for the two closures (and for A and A$). not for B / C
def f = {
- def g = List().map(x => ((s: String) => x)) // outer class A, no outer method (g is moved to the companion, doesn't exist in A)
- g.map(x => ((s: String) => x)) // outer class A, outer method f
+ def g = List().map(x => ((s: String) => x)): @noinline // outer class A, no outer method (g is moved to the companion, doesn't exist in A)
+ g.map(x => ((s: String) => x)): @noinline // outer class A, outer method f
}
// statements and field declarations are not allowed in value classes
}
diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala
index 702e5e279a..903d08f72d 100644
--- a/test/files/jvm/innerClassAttribute/Test.scala
+++ b/test/files/jvm/innerClassAttribute/Test.scala
@@ -23,7 +23,7 @@ object Test extends BytecodeTest {
def testInner(cls: String, fs: (InnerClassNode => Unit)*) = {
val ns = innerClassNodes(cls)
- assert(ns.length == fs.length, ns)
+ assert(ns.length == fs.length, ns.map(_.name))
(ns zip fs.toList) foreach { case (n, f) => f(n) }
}
diff --git a/test/files/run/stringinterpolation_macro-run.check b/test/files/run/stringinterpolation_macro-run.check
deleted file mode 100644
index c7f46bac87..0000000000
--- a/test/files/run/stringinterpolation_macro-run.check
+++ /dev/null
@@ -1,71 +0,0 @@
-false
-false
-true
-false
-true
-FALSE
-FALSE
-TRUE
-FALSE
-TRUE
-true
-false
-null
-0
-80000000
-4c01926
-NULL
-4C01926
-null
-NULL
-Scala
-SCALA
-5
-x
-x
-x
-x
-x
-x
-x
-x
-x
-x
-x
-x
-S
-120
-120
-120
-120
-120
-120
-120
-120
-120
-120
-120
-120
- 0X4
-She is 4 feet tall.
-120
-42
-3.400000e+00
-3.400000e+00
-3.400000e+00
-3.400000e+00
-3.400000e+00
-3.400000e+00
-3.000000e+00
-3.000000e+00
-05/26/12
-05/26/12
-05/26/12
-05/26/12
-%
- mind
-------
-matter
-
-7 7 9
-7 9 9
diff --git a/test/files/run/stringinterpolation_macro-run.scala b/test/files/run/stringinterpolation_macro-run.scala
deleted file mode 100644
index ae7c0e5d7a..0000000000
--- a/test/files/run/stringinterpolation_macro-run.scala
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * filter: inliner warnings; re-run with
- */
-object Test extends App {
-
-// 'b' / 'B' (category: general)
-// -----------------------------
-println(f"${null}%b")
-println(f"${false}%b")
-println(f"${true}%b")
-println(f"${new java.lang.Boolean(false)}%b")
-println(f"${new java.lang.Boolean(true)}%b")
-
-println(f"${null}%B")
-println(f"${false}%B")
-println(f"${true}%B")
-println(f"${new java.lang.Boolean(false)}%B")
-println(f"${new java.lang.Boolean(true)}%B")
-
-implicit val stringToBoolean = java.lang.Boolean.parseBoolean(_: String)
-println(f"${"true"}%b")
-println(f"${"false"}%b")
-
-// 'h' | 'H' (category: general)
-// -----------------------------
-println(f"${null}%h")
-println(f"${0.0}%h")
-println(f"${-0.0}%h")
-println(f"${"Scala"}%h")
-
-println(f"${null}%H")
-println(f"${"Scala"}%H")
-
-// 's' | 'S' (category: general)
-// -----------------------------
-println(f"${null}%s")
-println(f"${null}%S")
-println(f"${"Scala"}%s")
-println(f"${"Scala"}%S")
-println(f"${5}")
-
-// 'c' | 'C' (category: character)
-// -------------------------------
-println(f"${120:Char}%c")
-println(f"${120:Byte}%c")
-println(f"${120:Short}%c")
-println(f"${120:Int}%c")
-println(f"${new java.lang.Character('x')}%c")
-println(f"${new java.lang.Byte(120:Byte)}%c")
-println(f"${new java.lang.Short(120:Short)}%c")
-println(f"${new java.lang.Integer(120)}%c")
-
-println(f"${'x' : java.lang.Character}%c")
-println(f"${(120:Byte) : java.lang.Byte}%c")
-println(f"${(120:Short) : java.lang.Short}%c")
-println(f"${120 : java.lang.Integer}%c")
-
-implicit val stringToChar = (x: String) => x(0)
-println(f"${"Scala"}%c")
-
-// 'd' | 'o' | 'x' | 'X' (category: integral)
-// ------------------------------------------
-println(f"${120:Byte}%d")
-println(f"${120:Short}%d")
-println(f"${120:Int}%d")
-println(f"${120:Long}%d")
-println(f"${new java.lang.Byte(120:Byte)}%d")
-println(f"${new java.lang.Short(120:Short)}%d")
-println(f"${new java.lang.Integer(120)}%d")
-println(f"${new java.lang.Long(120)}%d")
-println(f"${120 : java.lang.Integer}%d")
-println(f"${120 : java.lang.Long}%d")
-println(f"${BigInt(120)}%d")
-println(f"${new java.math.BigInteger("120")}%d")
-println(f"${4}%#10X")
-
-locally {
- val fff = new java.util.Formattable {
- def formatTo(f: java.util.Formatter, g: Int, w: Int, p: Int) = f.format("4")
- }
- println(f"She is ${fff}%#s feet tall.")
-}
-
-{
- implicit val strToShort = (s: String) => java.lang.Short.parseShort(s)
- println(f"${"120"}%d")
- implicit val strToInt = (s: String) => 42
- println(f"${"120"}%d")
-}
-
-// 'e' | 'E' | 'g' | 'G' | 'f' | 'a' | 'A' (category: floating point)
-// ------------------------------------------------------------------
-println(f"${3.4f}%e")
-println(f"${3.4}%e")
-println(f"${3.4f : java.lang.Float}%e")
-println(f"${3.4 : java.lang.Double}%e")
-println(f"${BigDecimal(3.4)}%e")
-println(f"${new java.math.BigDecimal(3.4)}%e")
-println(f"${3}%e")
-println(f"${3L}%e")
-
-// 't' | 'T' (category: date/time)
-// -------------------------------
-import java.util.Calendar
-import java.util.Locale
-val c = Calendar.getInstance(Locale.US)
-c.set(2012, Calendar.MAY, 26)
-println(f"${c}%TD")
-println(f"${c.getTime}%TD")
-println(f"${c.getTime.getTime}%TD")
-
-implicit val strToDate = (x: String) => c
-println(f"""${"1234"}%TD""")
-
-
-// literals and arg indexes
-println(f"%%")
-println(f" mind%n------%nmatter%n")
-println(f"${7}%d %<d ${9}%d")
-println(f"${7}%d %2$$d ${9}%d")
-
-}
diff --git a/test/junit/scala/StringContextTest.scala b/test/junit/scala/StringContextTest.scala
index 7e9e775d58..900852fcc6 100644
--- a/test/junit/scala/StringContextTest.scala
+++ b/test/junit/scala/StringContextTest.scala
@@ -1,6 +1,8 @@
package scala
+import language.implicitConversions
+
import org.junit.Test
import org.junit.Assert._
import org.junit.runner.RunWith
@@ -84,4 +86,162 @@ class StringContextTest {
// Use this method to avoid problems with a locale-dependent decimal mark.
// The string interpolation is not used here intentionally as this method is used to test string interpolation.
private def formatUsingCurrentLocale(number: Double, decimalPlaces: Int = 2) = ("%." + decimalPlaces + "f").format(number)
+
+ @Test def `f interpolator baseline`(): Unit = {
+
+ implicit def stringToBoolean(s: String): Boolean = java.lang.Boolean.parseBoolean(s)
+ implicit def stringToChar(s: String): Char = s(0)
+ implicit def str2fmt(s: String): java.util.Formattable = new java.util.Formattable {
+ def formatTo(f: java.util.Formatter, g: Int, w: Int, p: Int) = f.format("%s", s)
+ }
+
+ val b_true = true
+ val b_false = false
+
+ val i = 42
+
+ val f_zero = 0.0
+ val f_zero_- = -0.0
+
+ val s = "Scala"
+
+ val fff = new java.util.Formattable {
+ def formatTo(f: java.util.Formatter, g: Int, w: Int, p: Int) = f.format("4")
+ }
+ import java.util.{ Calendar, Locale }
+ val c = Calendar.getInstance(Locale.US)
+ c.set(2012, Calendar.MAY, 26)
+ implicit def strToDate(x: String): Calendar = c
+
+ val ss = List[(String, String)] (
+ // 'b' / 'B' (category: general)
+ // -----------------------------
+ f"${b_false}%b" -> "false",
+ f"${b_true}%b" -> "true",
+
+ f"${null}%b" -> "false",
+ f"${false}%b" -> "false",
+ f"${true}%b" -> "true",
+ f"${true && false}%b" -> "false",
+ f"${new java.lang.Boolean(false)}%b" -> "false",
+ f"${new java.lang.Boolean(true)}%b" -> "true",
+
+ f"${null}%B" -> "FALSE",
+ f"${false}%B" -> "FALSE",
+ f"${true}%B" -> "TRUE",
+ f"${new java.lang.Boolean(false)}%B" -> "FALSE",
+ f"${new java.lang.Boolean(true)}%B" -> "TRUE",
+
+ f"${"true"}%b" -> "true",
+ f"${"false"}%b"-> "false",
+
+ // 'h' | 'H' (category: general)
+ // -----------------------------
+ f"${null}%h" -> "null",
+ f"${f_zero}%h" -> "0",
+ f"${f_zero_-}%h" -> "80000000",
+ f"${s}%h" -> "4c01926",
+
+ f"${null}%H" -> "NULL",
+ f"${s}%H" -> "4C01926",
+
+ // 's' | 'S' (category: general)
+ // -----------------------------
+ f"${null}%s" -> "null",
+ f"${null}%S" -> "NULL",
+ f"${s}%s" -> "Scala",
+ f"${s}%S" -> "SCALA",
+ f"${5}" -> "5",
+ f"${i}" -> "42",
+ f"${'foo}" -> "'foo",
+
+ f"${Thread.State.NEW}" -> "NEW",
+
+ // 'c' | 'C' (category: character)
+ // -------------------------------
+ f"${120:Char}%c" -> "x",
+ f"${120:Byte}%c" -> "x",
+ f"${120:Short}%c" -> "x",
+ f"${120:Int}%c" -> "x",
+ f"${new java.lang.Character('x')}%c" -> "x",
+ f"${new java.lang.Byte(120:Byte)}%c" -> "x",
+ f"${new java.lang.Short(120:Short)}%c" -> "x",
+ f"${new java.lang.Integer(120)}%c" -> "x",
+
+ f"${'x' : java.lang.Character}%c" -> "x",
+ f"${(120:Byte) : java.lang.Byte}%c" -> "x",
+ f"${(120:Short) : java.lang.Short}%c" -> "x",
+ f"${120 : java.lang.Integer}%c" -> "x",
+
+ f"${"Scala"}%c" -> "S",
+
+ // 'd' | 'o' | 'x' | 'X' (category: integral)
+ // ------------------------------------------
+ f"${120:Byte}%d" -> "120",
+ f"${120:Short}%d" -> "120",
+ f"${120:Int}%d" -> "120",
+ f"${120:Long}%d" -> "120",
+ f"${60 * 2}%d" -> "120",
+ f"${new java.lang.Byte(120:Byte)}%d" -> "120",
+ f"${new java.lang.Short(120:Short)}%d" -> "120",
+ f"${new java.lang.Integer(120)}%d" -> "120",
+ f"${new java.lang.Long(120)}%d" -> "120",
+ f"${120 : java.lang.Integer}%d" -> "120",
+ f"${120 : java.lang.Long}%d" -> "120",
+ f"${BigInt(120)}%d" -> "120",
+
+ f"${new java.math.BigInteger("120")}%d" -> "120",
+
+ f"${4}%#10X" -> " 0X4",
+
+ f"She is ${fff}%#s feet tall." -> "She is 4 feet tall.",
+
+ f"Just want to say ${"hello, world"}%#s..." -> "Just want to say hello, world...",
+
+ { implicit val strToShort = (s: String) => java.lang.Short.parseShort(s) ; f"${"120"}%d" } -> "120",
+ { implicit val strToInt = (s: String) => 42 ; f"${"120"}%d" } -> "42",
+
+ // 'e' | 'E' | 'g' | 'G' | 'f' | 'a' | 'A' (category: floating point)
+ // ------------------------------------------------------------------
+ f"${3.4f}%e" -> "3.400000e+00",
+ f"${3.4}%e" -> "3.400000e+00",
+ f"${3.4f : java.lang.Float}%e" -> "3.400000e+00",
+ f"${3.4 : java.lang.Double}%e" -> "3.400000e+00",
+
+ f"${BigDecimal(3.4)}%e" -> "3.400000e+00",
+
+ f"${new java.math.BigDecimal(3.4)}%e" -> "3.400000e+00",
+
+ f"${3}%e" -> "3.000000e+00",
+ f"${3L}%e" -> "3.000000e+00",
+
+ // 't' | 'T' (category: date/time)
+ // -------------------------------
+ f"${c}%TD" -> "05/26/12",
+ f"${c.getTime}%TD" -> "05/26/12",
+ f"${c.getTime.getTime}%TD" -> "05/26/12",
+ f"""${"1234"}%TD""" -> "05/26/12",
+
+ // literals and arg indexes
+ f"%%" -> "%",
+ f" mind%n------%nmatter%n" ->
+ """| mind
+ |------
+ |matter
+ |""".stripMargin,
+ f"${i}%d %<d ${9}%d" -> "42 42 9",
+ f"${7}%d %<d ${9}%d" -> "7 7 9",
+ f"${7}%d %2$$d ${9}%d" -> "7 9 9",
+
+ f"${null}%d %<B" -> "null FALSE",
+
+ f"${5: Any}" -> "5",
+ f"${5}%s%<d" -> "55",
+ f"${3.14}%s,%<f" -> "3.14,3.140000",
+
+ f"z" -> "z"
+ )
+
+ for ((f, s) <- ss) assertEquals(s, f)
+ }
}