summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-05-04 21:16:41 +1000
committerJason Zaugg <jzaugg@gmail.com>2016-06-01 11:15:48 +1000
commit0533a3df71e9c855ac68e10d060c2c87d16994e0 (patch)
tree4aa840fb0367b00a0a2dc0c1108b064e7166669c /test
parent7b132f39b82e4fc47cd95eadce9e3f22da8c8d82 (diff)
downloadscala-0533a3df71e9c855ac68e10d060c2c87d16994e0.tar.gz
scala-0533a3df71e9c855ac68e10d060c2c87d16994e0.tar.bz2
scala-0533a3df71e9c855ac68e10d060c2c87d16994e0.zip
Lambda impl methods static and more stably named
The body of lambdas is compiled into a synthetic method in the enclosing class. Previously, this method was a public virtual method named `fully$qualified$Class$$anonfun$n`. For lambdas that didn't capture a `this` reference, a static method was used. This commit changes two aspects. Firstly, all lambda impl methods are now emitted static. An extra parameter is added to those that require a this reference. This is an improvement as it: - allows, shorter, more readable names for the lambda impl method - avoids pollution of the vtable of the class. Note that javac uses private instance methods, rather than public static methods. If we followed its lead, we would be unable to support important use cases in our inliner Secondly, the name of the enclosing method has been included in the name of the lambda impl method to improve debuggability and to improve serialization compatibility. The serialization improvement comes from the way that fresh names for the impl methods are allocated: adding or removing lambdas in methods not named "foo" won't change the numbering of the `anonfun$foo$n` impl methods from methods named "foo". This is in line with user expectations about anonymous class and lambda serialization stability. Brian Goetz has described this tricky area well in: http://cr.openjdk.java.net/~briangoetz/eg-attachments/lambda-serialization.html This commit doesn't go as far a Javac, we don't use the hash of the lambda type info, param names, etc to map to a lambda impl method name. As such, we are more prone to the type-1 and -2 failures described there. However, our Scala 2.11.8 has similar characteristics, so we aren't going backwards. Special case in the naming: Use "new" rather than "<init>" for constructor enclosed lambdas, as javac does. I have also changed the way that "delambdafy target" methods are identifed. Rather than relying on the naming convention, I have switched to using a symbol attachment. The assumption is that we only need to identify them from within the same compilation unit. This means we can distinguish impl metbods for expanded functions (ones called from an `apply` method of an ahead-of-time expanded anonfun class), from those that truly end up as targets for lambda metafactory. Only the latter are translated to static methods in this patch.
Diffstat (limited to 'test')
-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/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
11 files changed, 57 insertions, 51 deletions
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..b64a5ae3ce 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(ALOAD, IFNONNULL, ACONST_NULL, ATHROW, -1, 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/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] =