summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-10-13 09:52:08 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2015-10-20 15:59:03 +0200
commit62be5705b91cb233bf922021f102a08bccc95af5 (patch)
tree684f42edc5e42319910f1e6d4b98a4192e5fbaa1
parent19ee72193b6d3d4b1dc1e3bba430d3d741db97e3 (diff)
downloadscala-62be5705b91cb233bf922021f102a08bccc95af5.tar.gz
scala-62be5705b91cb233bf922021f102a08bccc95af5.tar.bz2
scala-62be5705b91cb233bf922021f102a08bccc95af5.zip
Allow @inline/noinline at callsites (in addition to def-site)
Allow annotating individual callsites @inline / @noinline using an annotation ascription c.foo(): @inline
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala16
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala17
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala17
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala8
-rw-r--r--src/library/scala/inline.scala26
-rw-r--r--src/library/scala/noinline.scala26
-rw-r--r--src/reflect/scala/reflect/internal/StdAttachments.scala4
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala6
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala75
13 files changed, 175 insertions, 41 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index a42332f7f2..c4eb6e1b42 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -16,6 +16,7 @@ import java.lang.invoke.LambdaMetafactory
import scala.tools.asm
import GenBCode._
import BackendReporting._
+import scala.tools.asm.tree.MethodInsnNode
/*
*
@@ -706,6 +707,21 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}
else {
genCallMethod(sym, invokeStyle, app.pos, hostClass)
+ // Check if the Apply tree has an InlineAnnotatedAttachment, added by the typer
+ // for callsites marked `f(): @inline/noinline`. For nullary calls, the attachment
+ // is on the Select node (not on the Apply node added by UnCurry).
+ def checkInlineAnnotated(t: Tree): Unit = {
+ if (t.hasAttachment[InlineAnnotatedAttachment]) bc.jmethod.instructions.getLast match {
+ case m: MethodInsnNode =>
+ if (app.hasAttachment[NoInlineCallsiteAttachment.type]) noInlineAnnotatedCallsites += m
+ else inlineAnnotatedCallsites += m
+ case _ =>
+ } else t match {
+ case Apply(fun, _) => checkInlineAnnotated(fun)
+ case _ =>
+ }
+ }
+ checkInlineAnnotated(app)
}
} // end of genNormalMethodCall()
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
index f1b515910f..92aaf991bf 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -82,6 +82,14 @@ abstract class BTypes {
val callsitePositions: concurrent.Map[MethodInsnNode, Position] = recordPerRunCache(TrieMap.empty)
/**
+ * Stores callsite instructions of invocatinos annotated `f(): @inline/noinline`.
+ * Instructions are added during code generation (BCodeBodyBuilder). The maps are then queried
+ * when building the CallGraph, every Callsite object has an annotated(No)Inline field.
+ */
+ val inlineAnnotatedCallsites: mutable.Set[MethodInsnNode] = recordPerRunCache(mutable.Set.empty)
+ val noInlineAnnotatedCallsites: mutable.Set[MethodInsnNode] = recordPerRunCache(mutable.Set.empty)
+
+ /**
* Contains the internal names of all classes that are defined in Java source files of the current
* compilation run (mixed compilation). Used for more detailed error reporting.
*/
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 c804c228f5..66810176a1 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -161,7 +161,9 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
argInfos = argInfos,
callsiteStackHeight = a.frameAt(call).getStackSize,
receiverKnownNotNull = receiverNotNull,
- callsitePosition = callsitePositions.getOrElse(call, NoPosition)
+ callsitePosition = callsitePositions.getOrElse(call, NoPosition),
+ annotatedInline = inlineAnnotatedCallsites(call),
+ annotatedNoInline = noInlineAnnotatedCallsites(call)
)
case LambdaMetaFactoryCall(indy, samMethodType, implMethod, instantiatedMethodType) if a.frameAt(indy) != null =>
@@ -348,7 +350,8 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
*/
final case class Callsite(callsiteInstruction: MethodInsnNode, callsiteMethod: MethodNode, callsiteClass: ClassBType,
callee: Either[OptimizerWarning, Callee], argInfos: IntMap[ArgInfo],
- callsiteStackHeight: Int, receiverKnownNotNull: Boolean, callsitePosition: Position) {
+ callsiteStackHeight: Int, receiverKnownNotNull: Boolean, callsitePosition: Position,
+ annotatedInline: Boolean, annotatedNoInline: Boolean) {
/**
* Contains callsites that were created during inlining by cloning this callsite. Used to find
* corresponding callsites when inlining post-inline requests.
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala
index a7c4c27a97..4203a93f2e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala
@@ -263,7 +263,9 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) {
argInfos = argInfos,
callsiteStackHeight = invocationStackHeight,
receiverKnownNotNull = true, // see below (*)
- callsitePosition = originalCallsite.map(_.callsitePosition).getOrElse(NoPosition)
+ callsitePosition = originalCallsite.map(_.callsitePosition).getOrElse(NoPosition),
+ annotatedInline = false,
+ annotatedNoInline = false
)
// (*) The documentation in class LambdaMetafactory says:
// "if implMethod corresponds to an instance method, the first capture argument
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
index 261b736029..449a56fdd1 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
@@ -154,10 +154,8 @@ class Inliner[BT <: BTypes](val btypes: BT) {
if (selfParamType.info.get.inlineInfo.sam.isEmpty) samParamTypes - 0
else samParamTypes.updated(0, selfParamType)
}
- val staticCallsite = Callsite(
+ val staticCallsite = callsite.copy(
callsiteInstruction = newCallsiteInstruction,
- callsiteMethod = callsite.callsiteMethod,
- callsiteClass = callsite.callsiteClass,
callee = Right(Callee(
callee = implClassMethod,
calleeDeclarationClass = implClassBType,
@@ -166,11 +164,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
annotatedInline = annotatedInline,
annotatedNoInline = annotatedNoInline,
samParamTypes = staticCallSamParamTypes,
- calleeInfoWarning = infoWarning)),
- argInfos = callsite.argInfos,
- callsiteStackHeight = callsite.callsiteStackHeight,
- receiverKnownNotNull = callsite.receiverKnownNotNull,
- callsitePosition = callsite.callsitePosition
+ calleeInfoWarning = infoWarning))
)
callGraph.addCallsite(staticCallsite)
}
@@ -501,15 +495,12 @@ class Inliner[BT <: BTypes](val btypes: BT) {
callGraph.callsites(callee).valuesIterator foreach { originalCallsite =>
val newCallsiteIns = instructionMap(originalCallsite.callsiteInstruction).asInstanceOf[MethodInsnNode]
val argInfos = originalCallsite.argInfos flatMap mapArgInfo
- val newCallsite = Callsite(
+ val newCallsite = originalCallsite.copy(
callsiteInstruction = newCallsiteIns,
callsiteMethod = callsiteMethod,
callsiteClass = callsiteClass,
- callee = originalCallsite.callee,
argInfos = argInfos,
- callsiteStackHeight = callsiteStackHeight + originalCallsite.callsiteStackHeight,
- receiverKnownNotNull = originalCallsite.receiverKnownNotNull,
- callsitePosition = originalCallsite.callsitePosition
+ callsiteStackHeight = callsiteStackHeight + originalCallsite.callsiteStackHeight
)
originalCallsite.inlinedClones += ClonedCallsite(newCallsite, callsite)
callGraph.addCallsite(newCallsite)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
index 52627e77e6..89a768fd9c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
@@ -41,18 +41,18 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) {
compilingMethods.map(methodNode => {
var requests = Set.empty[InlineRequest]
callGraph.callsites(methodNode).valuesIterator foreach {
- case callsite @ Callsite(_, _, _, Right(Callee(callee, calleeDeclClass, safeToInline, _, annotatedInline, _, _, callsiteWarning)), _, _, _, pos) =>
+ case callsite @ Callsite(_, _, _, Right(Callee(callee, calleeDeclClass, safeToInline, _, calleeAnnotatedInline, _, _, callsiteWarning)), _, _, _, pos, _, _) =>
inlineRequest(callsite) match {
case Some(Right(req)) => requests += req
case Some(Left(w)) =>
- if ((annotatedInline && bTypes.compilerSettings.YoptWarningEmitAtInlineFailed) || w.emitWarning(compilerSettings)) {
- val annotWarn = if (annotatedInline) " is annotated @inline but" else ""
+ if ((calleeAnnotatedInline && bTypes.compilerSettings.YoptWarningEmitAtInlineFailed) || w.emitWarning(compilerSettings)) {
+ val annotWarn = if (calleeAnnotatedInline) " is annotated @inline but" else ""
val msg = s"${BackendReporting.methodSignature(calleeDeclClass.internalName, callee)}$annotWarn could not be inlined:\n$w"
backendReporting.inlinerWarning(callsite.callsitePosition, msg)
}
case None =>
- if (annotatedInline && bTypes.compilerSettings.YoptWarningEmitAtInlineFailed) {
+ if (calleeAnnotatedInline && !callsite.annotatedNoInline && bTypes.compilerSettings.YoptWarningEmitAtInlineFailed) {
// if the callsite is annotated @inline, we report an inline warning even if the underlying
// reason is, for example, mixed compilation (which has a separate -Yopt-warning flag).
def initMsg = s"${BackendReporting.methodSignature(calleeDeclClass.internalName, callee)} is annotated @inline but cannot be inlined"
@@ -69,7 +69,7 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) {
}
}
- case Callsite(ins, _, _, Left(warning), _, _, _, pos) =>
+ case Callsite(ins, _, _, Left(warning), _, _, _, pos, _, _) =>
if (warning.emitWarning(compilerSettings))
backendReporting.inlinerWarning(pos, s"failed to determine if ${ins.name} should be inlined:\n$warning")
}
@@ -108,12 +108,11 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) {
else None
case "default" =>
- if (callee.safeToInline && !callee.annotatedNoInline) {
- val shouldInlineHO = callee.samParamTypes.nonEmpty && (callee.samParamTypes exists {
+ if (callee.safeToInline && !callee.annotatedNoInline && !callsite.annotatedNoInline) {
+ def shouldInlineHO = callee.samParamTypes.nonEmpty && (callee.samParamTypes exists {
case (index, _) => callsite.argInfos.contains(index)
})
-
- if (shouldInlineHO || callee.annotatedInline) Some(requestIfCanInline(callsite))
+ if (callee.annotatedInline || callsite.annotatedInline || shouldInlineHO) Some(requestIfCanInline(callsite))
else None
} else None
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 26e04edcca..45ebbd532d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4130,6 +4130,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
ann setType arg1.tpe.withAnnotation(annotInfo)
}
val atype = ann.tpe
+ // For `f(): @inline/noinline` callsites, add the InlineAnnotatedAttachment. TypeApplys
+ // are eliminated by erasure, so add it to the underlying function in this case.
+ def setInlineAttachment(t: Tree, att: InlineAnnotatedAttachment): Unit = t match {
+ case TypeApply(fun, _) => setInlineAttachment(fun, att)
+ case _ => t.updateAttachment(att)
+ }
+ if (atype.hasAnnotation(definitions.ScalaNoInlineClass)) setInlineAttachment(arg1, NoInlineCallsiteAttachment)
+ else if (atype.hasAnnotation(definitions.ScalaInlineClass)) setInlineAttachment(arg1, InlineCallsiteAttachment)
Typed(arg1, resultingTypeTree(atype)) setPos tree.pos setType atype
}
}
diff --git a/src/library/scala/inline.scala b/src/library/scala/inline.scala
index a21cced928..dc55af301c 100644
--- a/src/library/scala/inline.scala
+++ b/src/library/scala/inline.scala
@@ -11,8 +11,30 @@
package scala
/**
- * An annotation on methods that requests that the compiler should
- * try especially hard to inline the annotated method.
+ * An annotation on methods that requests that the compiler should try especially hard to inline the
+ * annotated method. The annotation can be used at definition site or at callsite.
+ *
+ * {{{
+ * @inline final def f1(x: Int) = x
+ * @noinline final def f2(x: Int) = x
+ * final def f3(x: Int) = x
+ *
+ * def t1 = f1(1) // inlined if possible
+ * def t2 = f2(1) // not inlined
+ * def t3 = f3(1) // may be inlined (heuristics)
+ * def t4 = f1(1): @noinline // not inlined (override at callsite)
+ * def t5 = f2(1): @inline // not inlined (cannot override the @noinline at f2's definition)
+ * def t6 = f3(1): @inline // inlined if possible
+ * def t7 = f3(1): @noinline // not inlined
+ * }
+ * }}}
+ *
+ * Note: parentheses are required when annotating a callsite withing a larger expression.
+ *
+ * {{{
+ * def t1 = f1(1) + f1(1): @noinline // equivalent to (f1(1) + f1(1)): @noinline
+ * def t2 = f1(1) + (f1(1): @noinline) // the second call to f1 is not inlined
+ * }}}
*
* @author Lex Spoon
* @version 1.0, 2007-5-21
diff --git a/src/library/scala/noinline.scala b/src/library/scala/noinline.scala
index 38fd4c39d6..a427e170f4 100644
--- a/src/library/scala/noinline.scala
+++ b/src/library/scala/noinline.scala
@@ -11,8 +11,30 @@
package scala
/**
- * An annotation on methods that forbids the compiler to inline the
- * method, no matter how safe the inlining appears to be.
+ * An annotation on methods that forbids the compiler to inline the method, no matter how safe the
+ * inlining appears to be. The annotation can be used at definition site or at callsite.
+ *
+ * {{{
+ * @inline final def f1(x: Int) = x
+ * @noinline final def f2(x: Int) = x
+ * final def f3(x: Int) = x
+ *
+ * def t1 = f1(1) // inlined if possible
+ * def t2 = f2(1) // not inlined
+ * def t3 = f3(1) // may be inlined (heuristics)
+ * def t4 = f1(1): @noinline // not inlined (override at callsite)
+ * def t5 = f2(1): @inline // not inlined (cannot override the @noinline at f2's definition)
+ * def t6 = f3(1): @inline // inlined if possible
+ * def t7 = f3(1): @noinline // not inlined
+ * }
+ * }}}
+ *
+ * Note: parentheses are required when annotating a callsite withing a larger expression.
+ *
+ * {{{
+ * def t1 = f1(1) + f1(1): @noinline // equivalent to (f1(1) + f1(1)): @noinline
+ * def t2 = f1(1) + (f1(1): @noinline) // the second call to f1 is not inlined
+ * }}}
*
* @author Lex Spoon
* @version 1.0, 2007-5-21
diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala
index cca33253be..8358c1295c 100644
--- a/src/reflect/scala/reflect/internal/StdAttachments.scala
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -52,4 +52,8 @@ trait StdAttachments {
/** Untyped list of subpatterns attached to selector dummy. */
case class SubpatternsAttachment(patterns: List[Tree])
+
+ abstract class InlineAnnotatedAttachment
+ case object NoInlineCallsiteAttachment extends InlineAnnotatedAttachment
+ case object InlineCallsiteAttachment extends InlineAnnotatedAttachment
}
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index 1e9a4fe8a5..0132fff17c 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -41,6 +41,8 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.ForAttachment
this.SyntheticUnitAttachment
this.SubpatternsAttachment
+ this.NoInlineCallsiteAttachment
+ this.InlineCallsiteAttachment
this.noPrint
this.typeDebug
this.Range
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
index f329a43b30..3857d3e8ce 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
@@ -165,12 +165,6 @@ class CallGraphTest extends ClearAfterClass {
checkCallsite(fn, m, forNameMeth, classTp, safeToInline = false, atInline = false, atNoInline = false)
}
- /**
- * NOTE: if this test fails for you when running within the IDE, it's probably because you're
- * using 2.12.0-M2 for compilining within the IDE, which doesn't add SAM information to the
- * InlineInfo attribute. So the InlineInfo in the classfile for Function1 doesn't say that
- * it's a SAM type. The test passes when running with ant (which does a full bootstrap).
- */
@Test
def checkArgInfos(): Unit = {
val code =
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 37cd9431dc..1e01627969 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -1056,12 +1056,75 @@ class InlinerTest extends ClearAfterClass {
assertNoInvoke(convertMethod(d))
}
- /**
- * NOTE: if this test fails for you when running within the IDE, it's probably because you're
- * using 2.12.0-M2 for compilining within the IDE, which doesn't add SAM information to the
- * InlineInfo attribute. So the InlineInfo in the classfile for Function1 doesn't say that
- * it's a SAM type. The test passes when running with ant (which does a full bootstrap).
- */
+ @Test
+ def inlineAnnotatedCallsite(): Unit = {
+ val code =
+ """class C {
+ | final def a(x: Int, f: Int => Int): Int = f(x)
+ | final def b(x: Int) = x
+ | final def c = 1
+ | final def d[T] = 2
+ | final def e[T](x: T) = c
+ | final def f[T](x: T) = println(x)
+ | final def g(x: Int)(y: Int) = x
+ |
+ | def t1 = a(10, _ + 1)
+ | def t2 = a(10, _ + 1): @noinline
+ | def t3 = b(3)
+ | def t4 = b(3): @inline
+ | def t5 = c: @inline
+ | def t6 = d[Int]: @inline
+ | def t7 = e[Int](2): @inline
+ | def t8 = f[Int](2): @inline
+ | def t9 = g(1)(2): @inline
+ |}
+ """.stripMargin
+
+ val List(c) = compile(code)
+ assertInvoke(getSingleMethod(c, "t1"), "C", "C$$$anonfun$1")
+ assertInvoke(getSingleMethod(c, "t2"), "C", "a")
+ assertInvoke(getSingleMethod(c, "t3"), "C", "b")
+ assertNoInvoke(getSingleMethod(c, "t4"))
+ assertNoInvoke(getSingleMethod(c, "t5"))
+ assertNoInvoke(getSingleMethod(c, "t6"))
+ assertInvoke(getSingleMethod(c, "t7"), "C", "c")
+ assertInvoke(getSingleMethod(c, "t8"), "scala/Predef$", "println")
+ assertNoInvoke(getSingleMethod(c, "t9"))
+ }
+
+ @Test
+ def inlineNoInlineOverride(): Unit = {
+ val code =
+ """class C {
+ | @inline final def f1(x: Int) = x
+ | @noinline final def f2(x: Int) = x
+ | final def f3(x: Int) = x
+ |
+ | def t1 = f1(1) // inlined
+ | def t2 = f2(1) // not inlined
+ | def t3 = f1(1): @noinline // not inlined
+ | def t4 = f2(1): @inline // not inlined (cannot override the def-site @noinline)
+ | def t5 = f3(1): @inline // inlined
+ | def t6 = f3(1): @noinline // not inlined
+ |
+ | def t7 = f1(1) + (f3(1): @inline) // without parenthesis, the ascription encloses the entire expression..
+ | def t8 = f1(1) + (f1(1): @noinline)
+ | def t9 = f1(1) + f1(1) : @noinline // the ascription goes on the entire expression, so on the + invocation.. both f1 are inlined
+ |}
+ """.stripMargin
+
+ val List(c) = compile(code)
+ assertNoInvoke(getSingleMethod(c, "t1"))
+ assertInvoke(getSingleMethod(c, "t2"), "C", "f2")
+ assertInvoke(getSingleMethod(c, "t3"), "C", "f1")
+ assertInvoke(getSingleMethod(c, "t4"), "C", "f2")
+ assertNoInvoke(getSingleMethod(c, "t5"))
+ assertInvoke(getSingleMethod(c, "t6"), "C", "f3")
+ assertNoInvoke(getSingleMethod(c, "t7"))
+ assertInvoke(getSingleMethod(c, "t8"), "C", "f1")
+ assertNoInvoke(getSingleMethod(c, "t9"))
+ }
+
@Test
def inlineHigherOrder(): Unit = {
val code =