summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-06-06 13:33:53 +1000
committerJason Zaugg <jzaugg@gmail.com>2016-06-06 13:33:53 +1000
commit361f3f1540c755e36aaed22484924bb44eabc83b (patch)
tree267d174bf072dcc1a40faf7f6a7c91dcec690466
parentaf93c7a147156f69cad78cc80a36aeaeb89cbe0c (diff)
parent3f685073923d76de08ffdba78075f2267ee56133 (diff)
downloadscala-361f3f1540c755e36aaed22484924bb44eabc83b.tar.gz
scala-361f3f1540c755e36aaed22484924bb44eabc83b.tar.bz2
scala-361f3f1540c755e36aaed22484924bb44eabc83b.zip
Merge pull request #5157 from retronym/topic/lambda-statics
Lambda impl methods static and more stably named
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala50
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala16
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Delambdafy.scala29
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala19
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Duplicators.scala7
-rw-r--r--src/reflect/scala/reflect/api/Internals.scala6
-rw-r--r--src/reflect/scala/reflect/internal/Internals.scala2
-rw-r--r--src/reflect/scala/reflect/internal/StdAttachments.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala1
-rw-r--r--test/files/run/delambdafy_t6028.check8
-rw-r--r--test/files/run/delambdafy_t6555.check4
-rw-r--r--test/files/run/delambdafy_uncurry_byname_method.check4
-rw-r--r--test/files/run/delambdafy_uncurry_method.check4
-rw-r--r--test/files/run/t9097.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala14
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala6
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala52
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala2
-rw-r--r--test/junit/scala/tools/testing/BytecodeTesting.scala10
27 files changed, 172 insertions, 81 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 0786ceb7c2..14ee7d7a78 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -238,7 +238,8 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
* (outside the synchronized block).
*
* The idiom works only if the condition is using a volatile field.
- * @see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
+ *
+ * @see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
*/
def mkSynchronizedCheck(clazz: Symbol, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree =
mkSynchronizedCheck(mkAttributedThis(clazz), cond, syncBody, stats)
@@ -274,8 +275,19 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
}
// used to create the lifted method that holds a function's body
- def mkLiftedFunctionBodyMethod(localTyper: analyzer.Typer)(owner: Symbol, fun: Function) =
- mkMethodForFunctionBody(localTyper)(owner, fun, nme.ANON_FUN_NAME)(additionalFlags = ARTIFACT)
+ def mkLiftedFunctionBodyMethod(localTyper: global.analyzer.Typer)(owner: global.Symbol, fun: global.Function) = {
+ def nonLocalEnclosingMember(sym: Symbol): Symbol = {
+ if (sym.isLocalDummy) sym.enclClass.primaryConstructor
+ else if (sym.isLocalToBlock) nonLocalEnclosingMember(sym.originalOwner)
+ else sym
+ }
+ val ownerName = nonLocalEnclosingMember(fun.symbol.originalOwner).name match {
+ case nme.CONSTRUCTOR => nme.NEWkw // do as javac does for the suffix, prefer "new" to "$lessinit$greater$1"
+ case x => x.dropLocal
+ }
+ val newName = nme.ANON_FUN_NAME.append(nme.NAME_JOIN_STRING).append(ownerName)
+ mkMethodForFunctionBody(localTyper)(owner, fun, newName)(additionalFlags = ARTIFACT)
+ }
/**
@@ -310,6 +322,38 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
newDefDef(methSym, moveToMethod(useMethodParams(fun.body)))(tpt = TypeTree(resTp))
}
+ /**
+ * Create a new `DefDef` based on `orig` with an explicit self parameter.
+ *
+ * Details:
+ * - Must by run after erasure
+ * - If `maybeClone` is the identity function, this runs "in place"
+ * and mutates the symbol of `orig`. `orig` should be discarded
+ * - Symbol owners and returns are substituted, as are parameter symbols
+ * - Recursive calls are not rewritten. This is correct if we assume
+ * that we either:
+ * - are in "in-place" mode, but can guarantee that no recursive calls exists
+ * - are associating the RHS with a cloned symbol, but intend for the original
+ * method to remain and for recursive calls to target it.
+ */
+ final def mkStatic(orig: DefDef, maybeClone: Symbol => Symbol): DefDef = {
+ assert(phase.erasedTypes, phase)
+ assert(!orig.symbol.hasFlag(SYNCHRONIZED), orig.symbol.defString)
+ val origSym = orig.symbol
+ val origParams = orig.symbol.info.params
+ val newSym = maybeClone(orig.symbol)
+ newSym.setFlag(STATIC)
+ // Add an explicit self parameter
+ val selfParamSym = newSym.newSyntheticValueParam(newSym.owner.typeConstructor, nme.SELF).setFlag(ARTIFACT)
+ newSym.updateInfo(newSym.info match {
+ case mt @ MethodType(params, res) => copyMethodType(mt, selfParamSym :: params, res)
+ })
+ val selfParam = ValDef(selfParamSym)
+ val rhs = orig.rhs.substituteThis(newSym.owner, atPos(newSym.pos)(gen.mkAttributedIdent(selfParamSym)))
+ .substituteSymbols(origParams, newSym.info.params.drop(1)).changeOwner(origSym -> newSym)
+ treeCopy.DefDef(orig, orig.mods, orig.name, orig.tparams, (selfParam :: orig.vparamss.head) :: Nil, orig.tpt, rhs).setSymbol(newSym)
+ }
+
// TODO: the rewrite to AbstractFunction is superfluous once we compile FunctionN to a SAM type (aka functional interface)
def functionClassType(fun: Function): Type =
if (isFunctionType(fun.tpe)) abstractFunctionType(fun.vparams.map(_.symbol.tpe), fun.body.tpe.deconst)
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 f94642389d..6d3c3f3863 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
@@ -121,7 +121,7 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
def getBoxedUnit: FieldInsnNode = new FieldInsnNode(GETSTATIC, srBoxedUnitRef.internalName, "UNIT", srBoxedUnitRef.descriptor)
- private val anonfunAdaptedName = """.*\$anonfun\$\d+\$adapted""".r
+ private val anonfunAdaptedName = """.*\$anonfun\$.*\$\d+\$adapted""".r
def hasAdaptedImplMethod(closureInit: ClosureInstantiation): Boolean = {
isBuiltinFunctionType(Type.getReturnType(closureInit.lambdaMetaFactoryCall.indy.desc).getInternalName) &&
anonfunAdaptedName.pattern.matcher(closureInit.lambdaMetaFactoryCall.implMethod.getName).matches
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala
index 30e73f8ac2..01afd0d2ef 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala
@@ -5,8 +5,8 @@ package analysis
import java.util
import scala.annotation.switch
-import scala.tools.asm.{Type, Opcodes}
-import scala.tools.asm.tree.{MethodInsnNode, LdcInsnNode, AbstractInsnNode}
+import scala.tools.asm.{Opcodes, Type}
+import scala.tools.asm.tree.{AbstractInsnNode, LdcInsnNode, MethodInsnNode, MethodNode}
import scala.tools.asm.tree.analysis._
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils
import BytecodeUtils._
@@ -63,7 +63,7 @@ object NullnessValue {
def unknown(insn: AbstractInsnNode) = if (BytecodeUtils.instructionResultSize(insn) == 2) UnknownValue2 else UnknownValue1
}
-final class NullnessInterpreter(bTypes: BTypes) extends Interpreter[NullnessValue](Opcodes.ASM5) {
+final class NullnessInterpreter(bTypes: BTypes, method: MethodNode) extends Interpreter[NullnessValue](Opcodes.ASM5) {
def newValue(tp: Type): NullnessValue = {
// ASM loves giving semantics to null. The behavior here is the same as in SourceInterpreter,
// which is provided by the framework.
@@ -80,7 +80,13 @@ final class NullnessInterpreter(bTypes: BTypes) extends Interpreter[NullnessValu
override def newParameterValue(isInstanceMethod: Boolean, local: Int, tp: Type): NullnessValue = {
// For instance methods, the `this` parameter is known to be not null.
- if (isInstanceMethod && local == 0) NotNullValue
+ val isThis = local == 0 && (isInstanceMethod || {
+ method.parameters != null && !method.parameters.isEmpty && {
+ val p = method.parameters.get(0)
+ (p.access & Opcodes.ACC_SYNTHETIC) != 0 && p.name == "$this"
+ }
+ })
+ if (isThis) NotNullValue
else super.newParameterValue(isInstanceMethod, local, tp)
}
@@ -197,7 +203,7 @@ class NullnessFrame(nLocals: Int, nStack: Int) extends AliasingFrame[NullnessVal
* This class is required to override the `newFrame` methods, which makes makes sure the analyzer
* uses NullnessFrames.
*/
-class NullnessAnalyzer(bTypes: BTypes) extends Analyzer[NullnessValue](new NullnessInterpreter(bTypes)) {
+class NullnessAnalyzer(bTypes: BTypes, method: MethodNode) extends Analyzer[NullnessValue](new NullnessInterpreter(bTypes, method)) {
override def newFrame(nLocals: Int, nStack: Int): NullnessFrame = new NullnessFrame(nLocals, nStack)
override def newFrame(src: Frame[_ <: NullnessValue]): NullnessFrame = new NullnessFrame(src)
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
index e8d1bf203a..d4ff6493a3 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -103,7 +103,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
val analyzer = {
if (compilerSettings.optNullnessTracking && AsmAnalyzer.sizeOKForNullness(methodNode)) {
- Some(new AsmAnalyzer(methodNode, definingClass.internalName, new NullnessAnalyzer(btypes)))
+ Some(new AsmAnalyzer(methodNode, definingClass.internalName, new NullnessAnalyzer(btypes, methodNode)))
} else if (AsmAnalyzer.sizeOKForBasicValue(methodNode)) {
Some(new AsmAnalyzer(methodNode, definingClass.internalName))
} else None
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
index 5ca0ad2773..447ee209b5 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
@@ -397,7 +397,7 @@ class LocalOpt[BT <: BTypes](val btypes: BT) {
*/
def nullnessOptimizations(method: MethodNode, ownerClassName: InternalName): Boolean = {
AsmAnalyzer.sizeOKForNullness(method) && {
- lazy val nullnessAnalyzer = new AsmAnalyzer(method, ownerClassName, new NullnessAnalyzer(btypes))
+ lazy val nullnessAnalyzer = new AsmAnalyzer(method, ownerClassName, new NullnessAnalyzer(btypes, method))
// When running nullness optimizations the method may still have unreachable code. Analyzer
// frames of unreachable instructions are `null`.
diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
index d350ca8e17..1dfc1330c6 100644
--- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
+++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
@@ -61,6 +61,9 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
private def mkLambdaMetaFactoryCall(fun: Function, target: Symbol, functionalInterface: Symbol, samUserDefined: Symbol, isSpecialized: Boolean): Tree = {
val pos = fun.pos
+ def isSelfParam(p: Symbol) = p.isSynthetic && p.name == nme.SELF
+ val hasSelfParam = isSelfParam(target.firstParam)
+
val allCapturedArgRefs = {
// find which variables are free in the lambda because those are captures that need to be
// passed into the constructor of the anonymous function class
@@ -68,7 +71,8 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
gen.mkAttributedRef(capture) setPos pos
).toList
- if (target hasFlag STATIC) captureArgs // no `this` reference needed
+ if (!hasSelfParam) captureArgs.filterNot(arg => isSelfParam(arg.symbol))
+ else if (currentMethod.hasFlag(Flags.STATIC)) captureArgs
else (gen.mkAttributedThis(fun.symbol.enclClass) setPos pos) :: captureArgs
}
@@ -179,7 +183,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
val numCaptures = targetParams.length - functionParamTypes.length
val (targetCapturedParams, targetFunctionParams) = targetParams.splitAt(numCaptures)
- val methSym = oldClass.newMethod(target.name.append("$adapted").toTermName, target.pos, target.flags | FINAL | ARTIFACT)
+ val methSym = oldClass.newMethod(target.name.append("$adapted").toTermName, target.pos, target.flags | FINAL | ARTIFACT | STATIC)
val bridgeCapturedParams = targetCapturedParams.map(param => methSym.newSyntheticValueParam(param.tpe, param.name.toTermName))
val bridgeFunctionParams =
map2(targetFunctionParams, bridgeParamTypes)((param, tp) => methSym.newSyntheticValueParam(tp, param.name.toTermName))
@@ -223,10 +227,8 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
private def transformFunction(originalFunction: Function): Tree = {
val target = targetMethod(originalFunction)
- target.makeNotPrivate(target.owner)
-
- // must be done before calling createBoxingBridgeMethod and mkLambdaMetaFactoryCall
- if (!(target hasFlag STATIC) && !methodReferencesThis(target)) target setFlag STATIC
+ assert(target.hasFlag(Flags.STATIC))
+ target.setFlag(notPRIVATE)
val funSym = originalFunction.tpe.typeSymbolDirect
// The functional interface that can be used to adapt the lambda target method `target` to the given function type.
@@ -252,11 +254,22 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
// here's the main entry point of the transform
override def transform(tree: Tree): Tree = tree match {
// the main thing we care about is lambdas
- case fun: Function => super.transform(transformFunction(fun))
+ case fun: Function =>
+ super.transform(transformFunction(fun))
case Template(_, _, _) =>
+ def pretransform(tree: Tree): Tree = tree match {
+ case dd: DefDef if dd.symbol.isDelambdafyTarget =>
+ if (!dd.symbol.hasFlag(STATIC) && methodReferencesThis(dd.symbol)) {
+ gen.mkStatic(dd, sym => sym)
+ } else {
+ dd.symbol.setFlag(STATIC)
+ dd
+ }
+ case t => t
+ }
try {
// during this call boxingBridgeMethods will be populated from the Function case
- val Template(parents, self, body) = super.transform(tree)
+ val Template(parents, self, body) = super.transform(deriveTemplate(tree)(_.mapConserve(pretransform)))
Template(parents, self, body ++ boxingBridgeMethods)
} finally boxingBridgeMethods.clear()
case _ => super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index e894c58b1a..40ab8c0cf8 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -1329,6 +1329,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
class SpecializationDuplicator(casts: Map[Symbol, Type]) extends Duplicator(casts) {
override def retyped(context: Context, tree: Tree, oldThis: Symbol, newThis: Symbol, env: scala.collection.Map[Symbol, Type]): Tree =
enteringSpecialize(super.retyped(context, tree, oldThis, newThis, env))
+
}
/** A tree symbol substituter that substitutes on type skolems.
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index e0b1543f24..374e8430d8 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -213,6 +213,7 @@ abstract class UnCurry extends InfoTransform
// Expand the function body into an anonymous class
gen.expandFunction(localTyper)(fun, inConstructorFlag)
} else {
+ val mustExpand = mustExpandFunction(fun)
// method definition with the same arguments, return type, and body as the original lambda
val liftedMethod = gen.mkLiftedFunctionBodyMethod(localTyper)(fun.symbol.owner, fun)
@@ -221,11 +222,18 @@ abstract class UnCurry extends InfoTransform
gen.mkForwarder(gen.mkAttributedRef(liftedMethod.symbol), (fun.vparams map (_.symbol)) :: Nil)
))
+ if (!mustExpand) {
+ liftedMethod.symbol.updateAttachment(DelambdafyTarget)
+ liftedMethod.updateAttachment(DelambdafyTarget)
+ }
+
val typedNewFun = localTyper.typedPos(fun.pos)(Block(liftedMethod, super.transform(newFun)))
- if (mustExpandFunction(fun)) {
+ if (mustExpand) {
val Block(stats, expr : Function) = typedNewFun
treeCopy.Block(typedNewFun, stats, gen.expandFunction(localTyper)(expr, inConstructorFlag))
- } else typedNewFun
+ } else {
+ typedNewFun
+ }
}
def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = {
@@ -341,13 +349,18 @@ abstract class UnCurry extends InfoTransform
private def isSelfSynchronized(ddef: DefDef) = ddef.rhs match {
case Apply(fn @ TypeApply(Select(sel, _), _), _) =>
- fn.symbol == Object_synchronized && sel.symbol == ddef.symbol.enclClass && !ddef.symbol.enclClass.isTrait
+ fn.symbol == Object_synchronized && sel.symbol == ddef.symbol.enclClass && !ddef.symbol.enclClass.isTrait &&
+ !ddef.symbol.isDelambdafyTarget /* these become static later, unsuitable for ACC_SYNCHRONIZED */
case _ => false
}
/** If an eligible method is entirely wrapped in a call to synchronized
* locked on the same instance, remove the synchronized scaffolding and
* mark the method symbol SYNCHRONIZED for bytecode generation.
+ *
+ * Delambdafy targets are deemed ineligible as the Delambdafy phase will
+ * replace `this.synchronized` with `$this.synchronzed` now that it emits
+ * all lambda impl methods as static.
*/
private def translateSynchronized(tree: Tree) = tree match {
case dd @ DefDef(_, _, _, _, _, Apply(fn, body :: Nil)) if isSelfSynchronized(dd) =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
index 0c10242950..78e72cf771 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
@@ -229,7 +229,12 @@ abstract class Duplicators extends Analyzer {
case ddef @ DefDef(_, _, _, _, tpt, rhs) =>
ddef.tpt modifyType fixType
- super.typed(ddef.clearType(), mode, pt)
+ val result = super.typed(ddef.clearType(), mode, pt)
+ // TODO this is a hack, we really need a cleaner way to transport symbol attachments to duplicated methods
+ // bodies in specialized subclasses.
+ if (ddef.hasAttachment[DelambdafyTarget.type])
+ result.symbol.updateAttachment(DelambdafyTarget)
+ result
case fun: Function =>
debuglog("Clearing the type and retyping Function: " + fun)
diff --git a/src/reflect/scala/reflect/api/Internals.scala b/src/reflect/scala/reflect/api/Internals.scala
index 9b7112f011..2c8f84be0b 100644
--- a/src/reflect/scala/reflect/api/Internals.scala
+++ b/src/reflect/scala/reflect/api/Internals.scala
@@ -116,7 +116,7 @@ trait Internals { self: Universe =>
/** Substitute given tree `to` for occurrences of nodes that represent
* `C.this`, where `C` refers to the given class `clazz`.
*/
- def substituteThis(tree: Tree, clazz: Symbol, to: Tree): Tree
+ def substituteThis(tree: Tree, clazz: Symbol, to: => Tree): Tree
/** A factory method for `ClassDef` nodes.
*/
@@ -391,7 +391,7 @@ trait Internals { self: Universe =>
def substituteTypes(from: List[Symbol], to: List[Type]): Tree = internal.substituteTypes(tree, from, to)
/** @see [[internal.substituteThis]] */
- def substituteThis(clazz: Symbol, to: Tree): Tree = internal.substituteThis(tree, clazz, to)
+ def substituteThis(clazz: Symbol, to: => Tree): Tree = internal.substituteThis(tree, clazz, to)
}
/** Extension methods for symbols */
@@ -1143,7 +1143,7 @@ trait Internals { self: Universe =>
/** @see [[InternalApi.substituteThis]] */
@deprecated("use `internal.substituteThis` instead or import `internal.decorators._` for infix syntax", "2.11.0")
- def substituteThis(clazz: Symbol, to: Tree): Tree = internal.substituteThis(tree, clazz, to)
+ def substituteThis(clazz: Symbol, to: => Tree): Tree = internal.substituteThis(tree, clazz, to)
}
/** Scala 2.10 compatibility enrichments for Tree. */
diff --git a/src/reflect/scala/reflect/internal/Internals.scala b/src/reflect/scala/reflect/internal/Internals.scala
index 1a48701ca7..a07441e3ca 100644
--- a/src/reflect/scala/reflect/internal/Internals.scala
+++ b/src/reflect/scala/reflect/internal/Internals.scala
@@ -29,7 +29,7 @@ trait Internals extends api.Internals {
def freeTypes(tree: Tree): List[FreeTypeSymbol] = tree.freeTypes
def substituteSymbols(tree: Tree, from: List[Symbol], to: List[Symbol]): Tree = tree.substituteSymbols(from, to)
def substituteTypes(tree: Tree, from: List[Symbol], to: List[Type]): Tree = tree.substituteTypes(from, to)
- def substituteThis(tree: Tree, clazz: Symbol, to: Tree): Tree = tree.substituteThis(clazz, to)
+ def substituteThis(tree: Tree, clazz: Symbol, to: => Tree): Tree = tree.substituteThis(clazz, to)
def attachments(tree: Tree): Attachments { type Pos = Position } = tree.attachments
def updateAttachment[T: ClassTag](tree: Tree, attachment: T): tree.type = tree.updateAttachment(attachment)
def removeAttachment[T: ClassTag](tree: Tree): tree.type = tree.removeAttachment[T]
diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala
index 0243dd48d2..ef95b38843 100644
--- a/src/reflect/scala/reflect/internal/StdAttachments.scala
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -51,6 +51,8 @@ trait StdAttachments {
*/
case class SAMFunction(samTp: Type, sam: Symbol) extends PlainAttachment
+ case object DelambdafyTarget extends PlainAttachment
+
/** When present, indicates that the host `Ident` has been created from a backquoted identifier.
*/
case object BackquotedIdentifierAttachment extends PlainAttachment
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 97b7f239f0..ba195363c1 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -807,7 +807,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME)
final def isDelambdafyFunction = isSynthetic && (name containsName tpnme.DELAMBDAFY_LAMBDA_CLASS_NAME)
- final def isDelambdafyTarget = isArtifact && isMethod && (name containsName tpnme.ANON_FUN_NAME)
+ final def isDelambdafyTarget = isArtifact && isMethod && hasAttachment[DelambdafyTarget.type]
final def isDefinedInPackage = effectiveOwner.isPackageClass
final def needsFlatClasses = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index c9dfd0c337..77097d892d 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -181,7 +181,7 @@ trait Trees extends api.Trees {
def substituteTypes(from: List[Symbol], to: List[Type]): Tree =
new TreeTypeSubstituter(from, to)(this)
- def substituteThis(clazz: Symbol, to: Tree): Tree =
+ def substituteThis(clazz: Symbol, to: => Tree): Tree =
new ThisSubstituter(clazz, to) transform this
def hasExistingSymbol = (symbol ne null) && (symbol ne NoSymbol)
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index d50debd7ee..28222cf9a7 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -38,6 +38,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.FixedMirrorTypeCreator
this.CompoundTypeTreeOriginalAttachment
this.SAMFunction
+ this.DelambdafyTarget
this.BackquotedIdentifierAttachment
this.ForAttachment
this.SyntheticUnitAttachment
diff --git a/test/files/run/delambdafy_t6028.check b/test/files/run/delambdafy_t6028.check
index b90dea62ed..8b0ae7e9b9 100644
--- a/test/files/run/delambdafy_t6028.check
+++ b/test/files/run/delambdafy_t6028.check
@@ -11,7 +11,7 @@ package <empty> {
def foo(methodParam: String): Function0 = {
val methodLocal: String = "";
{
- (() => T.this.$anonfun$1(methodParam, methodLocal))
+ (() => T.this.$anonfun$foo$1(methodParam, methodLocal))
}
};
def bar(barParam: String): Object = {
@@ -21,10 +21,10 @@ package <empty> {
def tryy(tryyParam: String): Function0 = {
var tryyLocal: runtime.ObjectRef = scala.runtime.ObjectRef.create("");
{
- (() => T.this.$anonfun$2(tryyParam, tryyLocal))
+ (() => T.this.$anonfun$tryy$1(tryyParam, tryyLocal))
}
};
- final <artifact> private[this] def $anonfun$1(methodParam$1: String, methodLocal$1: String): String = T.this.classParam.+(T.this.field()).+(methodParam$1).+(methodLocal$1);
+ final <artifact> private[this] def $anonfun$foo$1(methodParam$1: String, methodLocal$1: String): String = T.this.classParam.+(T.this.field()).+(methodParam$1).+(methodLocal$1);
abstract trait MethodLocalTrait$1 extends Object {
def /*MethodLocalTrait$1*/$init$(barParam$1: String): Unit = {
()
@@ -54,7 +54,7 @@ package <empty> {
T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1)
else
MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]();
- final <artifact> private[this] def $anonfun$2(tryyParam$1: String, tryyLocal$1: runtime.ObjectRef): Unit = try {
+ final <artifact> private[this] def $anonfun$tryy$1(tryyParam$1: String, tryyLocal$1: runtime.ObjectRef): Unit = try {
tryyLocal$1.elem = tryyParam$1
} finally ()
}
diff --git a/test/files/run/delambdafy_t6555.check b/test/files/run/delambdafy_t6555.check
index b6ccebde78..d8b834edc7 100644
--- a/test/files/run/delambdafy_t6555.check
+++ b/test/files/run/delambdafy_t6555.check
@@ -6,8 +6,8 @@ package <empty> {
()
};
private[this] val f: String => String = {
- final <artifact> def $anonfun(param: String): String = param;
- ((param: String) => $anonfun(param))
+ final <artifact> def $anonfun$f(param: String): String = param;
+ ((param: String) => $anonfun$f(param))
};
<stable> <accessor> def f(): String => String = Foo.this.f
}
diff --git a/test/files/run/delambdafy_uncurry_byname_method.check b/test/files/run/delambdafy_uncurry_byname_method.check
index e0f281b1cd..71e404ce64 100644
--- a/test/files/run/delambdafy_uncurry_byname_method.check
+++ b/test/files/run/delambdafy_uncurry_byname_method.check
@@ -7,8 +7,8 @@ package <empty> {
};
def bar(x: () => String): String = x.apply();
def foo(): String = Foo.this.bar({
- final <artifact> def $anonfun(): String = "";
- (() => $anonfun())
+ final <artifact> def $anonfun$foo(): String = "";
+ (() => $anonfun$foo())
})
}
}
diff --git a/test/files/run/delambdafy_uncurry_method.check b/test/files/run/delambdafy_uncurry_method.check
index 5ee3d174b3..8aa0b92054 100644
--- a/test/files/run/delambdafy_uncurry_method.check
+++ b/test/files/run/delambdafy_uncurry_method.check
@@ -7,8 +7,8 @@ package <empty> {
};
def bar(): Unit = {
val f: Int => Int = {
- final <artifact> def $anonfun(x: Int): Int = x.+(1);
- ((x: Int) => $anonfun(x))
+ final <artifact> def $anonfun|(x: Int): Int = x.+(1);
+ ((x: Int) => $anonfun|(x))
};
()
}
diff --git a/test/files/run/t9097.scala b/test/files/run/t9097.scala
index 49c0bbe79a..49c9e2f2e5 100644
--- a/test/files/run/t9097.scala
+++ b/test/files/run/t9097.scala
@@ -28,6 +28,6 @@ object Test extends StoreReporterDirectTest {
assert(!storeReporter.hasErrors, message = filteredInfos map (_.msg) mkString "; ")
val out = baos.toString("UTF-8")
// was 2 before the fix, the two PackageDefs for a would both contain the ClassDef for the closure
- assert(out.lines.count(_ contains "def $anonfun$1(x$1: Int): String") == 1, out)
+ assert(out.lines.count(_ contains "def $anonfun$hihi$1(x$1: Int): String") == 1, out)
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala
index 2bcbcc870c..1ad02c10cf 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala
@@ -43,7 +43,7 @@ class IndySammyTest extends BytecodeTesting {
val c = compileClass(s"class C { ${lamDef(from, to, body)}; ${appDef(arg)} }", allowMessage = allowMessage)
val applySig = getAsmMethod(funClass, "apply").desc
- val anonfun = getMethod(c, "C$$$anonfun$1")
+ val anonfun = getMethod(c, "$anonfun$lam$1")
val lamInsn = getInstructions(c, "lam").dropNonOp
val applyInvoke = getMethod(c, "app")
diff --git a/test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala
index 8cf6a655d2..9a0899ffc5 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala
@@ -43,9 +43,9 @@ class OptimizedBytecodeTest extends BytecodeTesting {
val c = compileClass(code)
assertSameSummary(getMethod(c, "t"), List(
- LDC, ASTORE, ALOAD /*0*/, ALOAD /*1*/, "C$$$anonfun$1", IRETURN))
- assertSameSummary(getMethod(c, "C$$$anonfun$1"), List(LDC, "C$$$anonfun$2", IRETURN))
- assertSameSummary(getMethod(c, "C$$$anonfun$2"), List(-1 /*A*/, GOTO /*A*/))
+ LDC, ASTORE, ALOAD /*0*/, ALOAD /*1*/, "$anonfun$t$1", IRETURN))
+ assertSameSummary(getMethod(c, "$anonfun$t$1"), List(LDC, "$anonfun$t$2", IRETURN))
+ assertSameSummary(getMethod(c, "$anonfun$t$2"), List(-1 /*A*/, GOTO /*A*/))
}
@Test
@@ -295,9 +295,9 @@ class OptimizedBytecodeTest extends BytecodeTesting {
|}
""".stripMargin
val c = compileClass(code, allowMessage = _.msg.contains("exception handler declared in the inlined method"))
- assertInvoke(getMethod(c, "f1a"), "C", "C$$$anonfun$1")
+ assertInvoke(getMethod(c, "f1a"), "C", "$anonfun$f1a$1")
assertInvoke(getMethod(c, "f1b"), "C", "wrapper1")
- assertInvoke(getMethod(c, "f2a"), "C", "C$$$anonfun$3")
+ assertInvoke(getMethod(c, "f2a"), "C", "$anonfun$f2a$1")
assertInvoke(getMethod(c, "f2b"), "C", "wrapper2")
}
@@ -331,7 +331,7 @@ class OptimizedBytecodeTest extends BytecodeTesting {
|class Listt
""".stripMargin
val List(c, nil, nilMod, listt) = compileClasses(code)
- assertInvoke(getMethod(c, "t"), "C", "C$$$anonfun$1")
+ assertInvoke(getMethod(c, "t"), "C", "$anonfun$t$1")
}
@Test
@@ -357,6 +357,6 @@ class OptimizedBytecodeTest extends BytecodeTesting {
def optimiseEnablesNewOpt(): Unit = {
val code = """class C { def t = (1 to 10) foreach println }"""
val List(c) = readAsmClasses(newCompiler(extraArgs = "-optimise -deprecation").compileToBytes(code, allowMessage = _.msg.contains("is deprecated")))
- assertInvoke(getMethod(c, "t"), "C", "C$$$anonfun$1") // range-foreach inlined from classpath
+ assertInvoke(getMethod(c, "t"), "C", "$anonfun$t$1") // range-foreach inlined from classpath
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
index 1de5aa28ca..c173bacd46 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
@@ -21,7 +21,7 @@ class NullnessAnalyzerTest extends BytecodeTesting {
import compiler._
import global.genBCode.bTypes.backendUtils._
- def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C") = new AsmAnalyzer(methodNode, classInternalName, new NullnessAnalyzer(global.genBCode.bTypes))
+ def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C") = new AsmAnalyzer(methodNode, classInternalName, new NullnessAnalyzer(global.genBCode.bTypes, methodNode))
def testNullness(analyzer: AsmAnalyzer[NullnessValue], method: MethodNode, query: String, index: Int, nullness: NullnessValue): Unit = {
for (i <- findInstrs(method, query)) {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
index 2da2ecdb72..f672237f10 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
@@ -28,7 +28,7 @@ class ClosureOptimizerTest extends BytecodeTesting {
val c = compileClass(code)
val t = getAsmMethod(c, "t")
- val bodyCall = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Nothing$")
+ val bodyCall = findInstr(t, "INVOKESTATIC C.$anonfun$t$1 ()Lscala/runtime/Nothing$")
assert(bodyCall.getNext.getOpcode == ATHROW)
}
@@ -44,7 +44,7 @@ class ClosureOptimizerTest extends BytecodeTesting {
val c = compileClass(code)
val t = getAsmMethod(c, "t")
- val bodyCall = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Null$")
+ val bodyCall = findInstr(t, "INVOKESTATIC C.$anonfun$t$1 ()Lscala/runtime/Null$")
assert(bodyCall.getNext.getOpcode == POP)
assert(bodyCall.getNext.getNext.getOpcode == ACONST_NULL)
}
@@ -62,7 +62,7 @@ class ClosureOptimizerTest extends BytecodeTesting {
val c = compileClass(code)
assertSameCode(getMethod(c, "t"),
List(VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "scala/collection/immutable/List", "head", "()Ljava/lang/Object;", false),
- TypeOp(CHECKCAST, "java/lang/String"), Invoke(INVOKESTATIC, "C", "C$$$anonfun$1", "(Ljava/lang/String;)Ljava/lang/String;", false),
+ TypeOp(CHECKCAST, "java/lang/String"), Invoke(INVOKESTATIC, "C", "$anonfun$t$1", "(Ljava/lang/String;)Ljava/lang/String;", false),
Op(ARETURN)))
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index 333792677a..7234659a1d 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -945,11 +945,11 @@ class InlinerTest extends BytecodeTesting {
val t1 = getMethod(c, "t1")
assertNoIndy(t1)
// the indy call is inlined into t, and the closure elimination rewrites the closure invocation to the body method
- assertInvoke(t1, "C", "C$$$anonfun$2")
+ assertInvoke(t1, "C", "$anonfun$m$2")
val t2 = getMethod(c, "t2")
assertNoIndy(t2)
- assertInvoke(t2, "M$", "M$$$anonfun$1")
+ assertInvoke(t2, "M$", "$anonfun$m$1")
}
@Test
@@ -1033,7 +1033,7 @@ class InlinerTest extends BytecodeTesting {
""".stripMargin
val List(c) = compile(code)
- assertInvoke(getMethod(c, "t1"), "C", "C$$$anonfun$1")
+ assertInvoke(getMethod(c, "t1"), "C", "$anonfun$t1$1")
assertInvoke(getMethod(c, "t2"), "C", "a")
assertInvoke(getMethod(c, "t3"), "C", "b")
assertNoInvoke(getMethod(c, "t4"))
@@ -1097,8 +1097,8 @@ class InlinerTest extends BytecodeTesting {
""".stripMargin
val List(c) = compile(code)
- assertInvoke(getMethod(c, "t1"), "C", "C$$$anonfun$1")
- assertInvoke(getMethod(c, "t2"), "C", "C$$$anonfun$2")
+ assertInvoke(getMethod(c, "t1"), "C", "$anonfun$t1$1")
+ assertInvoke(getMethod(c, "t2"), "C", "$anonfun$t2$1")
assertInvoke(getMethod(c, "t3"), "scala/Function1", "apply$mcII$sp")
assertInvoke(getMethod(c, "t4"), "scala/Function1", "apply$mcII$sp")
assertInvoke(getMethod(c, "t5"), "C", "h")
@@ -1273,39 +1273,39 @@ class InlinerTest extends BytecodeTesting {
""".stripMargin
val List(c, _, _) = compile(code)
- assertSameSummary(getMethod(c, "t1"), List(BIPUSH, "C$$$anonfun$1", IRETURN))
- assertSameSummary(getMethod(c, "t1a"), List(LCONST_1, "C$$$anonfun$2", IRETURN))
- assertSameSummary(getMethod(c, "t2"), List(ICONST_1, ICONST_2, "C$$$anonfun$3",IRETURN))
+ assertSameSummary(getMethod(c, "t1"), List(BIPUSH, "$anonfun$t1$1", IRETURN))
+ assertSameSummary(getMethod(c, "t1a"), List(LCONST_1, "$anonfun$t1a$1", IRETURN))
+ assertSameSummary(getMethod(c, "t2"), List(ICONST_1, ICONST_2, "$anonfun$t2$1",IRETURN))
// val a = new ValKl(n); new ValKl(anonfun(a.x)).x
// value class instantiation-extraction should be optimized by boxing elim
assertSameSummary(getMethod(c, "t3"), List(
NEW, DUP, ICONST_1, "<init>", ASTORE,
NEW, DUP, ALOAD, "x",
- "C$$$anonfun$4",
+ "$anonfun$t3$1",
"<init>",
"x", IRETURN))
- assertSameSummary(getMethod(c, "t4"), List(BIPUSH, "C$$$anonfun$5", "boxToInteger", ARETURN))
- assertSameSummary(getMethod(c, "t4a"), List(ICONST_1, LDC, "C$$$anonfun$6", LRETURN))
- assertSameSummary(getMethod(c, "t5"), List(BIPUSH, ICONST_3, "C$$$anonfun$7", "boxToInteger", ARETURN))
- assertSameSummary(getMethod(c, "t5a"), List(BIPUSH, BIPUSH, I2B, "C$$$anonfun$8", IRETURN))
- assertSameSummary(getMethod(c, "t6"), List(BIPUSH, "C$$$anonfun$9", RETURN))
- assertSameSummary(getMethod(c, "t7"), List(ICONST_1, "C$$$anonfun$10", RETURN))
- assertSameSummary(getMethod(c, "t8"), List(ICONST_1, LDC, "C$$$anonfun$11", LRETURN))
- assertSameSummary(getMethod(c, "t9"), List(ICONST_1, "boxToInteger", "C$$$anonfun$12", RETURN))
+ assertSameSummary(getMethod(c, "t4"), List(BIPUSH, "$anonfun$t4$1", "boxToInteger", ARETURN))
+ assertSameSummary(getMethod(c, "t4a"), List(ICONST_1, LDC, "$anonfun$t4a$1", LRETURN))
+ assertSameSummary(getMethod(c, "t5"), List(BIPUSH, ICONST_3, "$anonfun$t5$1", "boxToInteger", ARETURN))
+ assertSameSummary(getMethod(c, "t5a"), List(BIPUSH, BIPUSH, I2B, "$anonfun$t5a$1", IRETURN))
+ assertSameSummary(getMethod(c, "t6"), List(BIPUSH, "$anonfun$t6$1", RETURN))
+ assertSameSummary(getMethod(c, "t7"), List(ICONST_1, "$anonfun$t7$1", RETURN))
+ assertSameSummary(getMethod(c, "t8"), List(ICONST_1, LDC, "$anonfun$t8$1", LRETURN))
+ assertSameSummary(getMethod(c, "t9"), List(ICONST_1, "boxToInteger", "$anonfun$t9$1", RETURN))
// t9a inlines Range.foreach, which is quite a bit of code, so just testing the core
- assertInvoke(getMethod(c, "t9a"), "C", "C$$$anonfun$13")
+ assertInvoke(getMethod(c, "t9a"), "C", "$anonfun$t9a$1")
assertInvoke(getMethod(c, "t9a"), "scala/runtime/BoxesRunTime", "boxToInteger")
assertSameSummary(getMethod(c, "t10"), List(
ICONST_1, ISTORE,
ALOAD, ILOAD,
- "C$$$anonfun$14", RETURN))
+ "$anonfun$t10$1", RETURN))
// t10a inlines Range.foreach
- assertInvoke(getMethod(c, "t10a"), "C", "C$$$anonfun$15")
+ assertInvoke(getMethod(c, "t10a"), "C", "$anonfun$t10a$1")
assertDoesNotInvoke(getMethod(c, "t10a"), "boxToInteger")
}
@@ -1330,8 +1330,8 @@ class InlinerTest extends BytecodeTesting {
""".stripMargin
val List(c) = compile(code)
assertSameCode(getMethod(c, "t1"), List(Op(ICONST_0), Op(ICONST_1), Op(IADD), Op(IRETURN)))
- assertEquals(getInstructions(c, "t2") collect { case i: Invoke => i.owner +"."+ i.name }, List(
- "scala/runtime/IntRef.create", "C.C$$$anonfun$1"))
+ assertEquals(getMethod(c, "t2").instructions collect { case i: Invoke => i.owner +"."+ i.name }, List(
+ "scala/runtime/IntRef.create", "C.$anonfun$t2$1"))
}
@Test
@@ -1449,9 +1449,9 @@ class InlinerTest extends BytecodeTesting {
// box-unbox will clean it up
assertSameSummary(getMethod(c, "t"), List(
- ALOAD, "C$$$anonfun$1", IFEQ /*A*/,
- "C$$$anonfun$2", IRETURN,
- -1 /*A*/, "C$$$anonfun$3", IRETURN))
+ ALOAD, "$anonfun$t$1", IFEQ /*A*/,
+ "$anonfun$t$2", IRETURN,
+ -1 /*A*/, "$anonfun$t$3", IRETURN))
}
@Test
@@ -1501,7 +1501,7 @@ class InlinerTest extends BytecodeTesting {
val List(c) = compile(code)
val t = getMethod(c, "t")
assertNoIndy(t)
- assertInvoke(t, "C", "C$$$anonfun$1")
+ assertInvoke(t, "C", "$anonfun$t$1")
}
@Test
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
index 9675e2e445..938bc7b846 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
@@ -221,7 +221,7 @@ class MethodLevelOptsTest extends BytecodeTesting {
VarOp(ILOAD, 1),
VarOp(ILOAD, 2),
VarOp(ILOAD, 3),
- Invoke(INVOKESTATIC, "C", "C$$$anonfun$1", "(III)I", false), Op(IRETURN)))
+ Invoke(INVOKESTATIC, "C", "$anonfun$t$1", "(III)I", false), Op(IRETURN)))
}
@Test
diff --git a/test/junit/scala/tools/testing/BytecodeTesting.scala b/test/junit/scala/tools/testing/BytecodeTesting.scala
index b11ad27148..1a0c1e210a 100644
--- a/test/junit/scala/tools/testing/BytecodeTesting.scala
+++ b/test/junit/scala/tools/testing/BytecodeTesting.scala
@@ -1,5 +1,6 @@
package scala.tools.testing
+import junit.framework.AssertionFailedError
import org.junit.Assert._
import scala.collection.JavaConverters._
@@ -245,8 +246,13 @@ object BytecodeTesting {
getAsmMethods(c, _ == name)
def getAsmMethod(c: ClassNode, name: String): MethodNode = {
- val List(m) = getAsmMethods(c, name)
- m
+ val methods = getAsmMethods(c, name)
+ methods match {
+ case List(m) => m
+ case ms =>
+ val allNames = getAsmMethods(c, _ => true).map(_.name)
+ throw new AssertionFailedError(s"Could not find method named $name among ${allNames}")
+ }
}
def getMethods(c: ClassNode, name: String): List[Method] =