summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-03-30 22:44:34 +1000
committerAdriaan Moors <adriaan.moors@typesafe.com>2016-03-30 12:11:02 -0700
commitaec2b940cfa04843efe2eab00272557823fd8dd2 (patch)
treef4b278e7fae6317f4f1da857c423a472e382a59f /src/compiler
parent3904c3216c741b387d81754e55aa079ce4218d06 (diff)
downloadscala-aec2b940cfa04843efe2eab00272557823fd8dd2.tar.gz
scala-aec2b940cfa04843efe2eab00272557823fd8dd2.tar.bz2
scala-aec2b940cfa04843efe2eab00272557823fd8dd2.zip
Keep SAM body in anonfun method in enclosing class
Rather than in implementation of the abstract method in the expanded anonymous class. This leads to more more efficient use of the constant pool, code shapes more amenable to SAM inlining, and is compatible with the old behaviour of `-Xexperimental` in Scala 2.11, which ScalaJS now relies upon. Manual test: ``` scala> :paste -raw // Entering paste mode (ctrl-D to finish) package p1; trait T { val x = 0; def apply(): Any }; class DelambdafyInline { def t: T = (() => "") } // Exiting paste mode, now interpreting. scala> :javap -c p1.DelambdafyInline Compiled from "<pastie>" public class p1.DelambdafyInline { public p1.T t(); Code: 0: new #10 // class p1/DelambdafyInline$$anonfun$t$1 3: dup 4: aload_0 5: invokespecial #16 // Method p1/DelambdafyInline$$anonfun$t$1."<init>":(Lp1/DelambdafyInline;)V 8: areturn public final java.lang.Object p1$DelambdafyInline$$$anonfun$1(); Code: 0: ldc #22 // String 2: areturn public p1.DelambdafyInline(); Code: 0: aload_0 1: invokespecial #25 // Method java/lang/Object."<init>":()V 4: return } scala> :javap -c p1.DelambdafyInline$$anonfun$t$1 Compiled from "<pastie>" public final class p1.DelambdafyInline$$anonfun$t$1 implements p1.T,scala.Serializable { public static final long serialVersionUID; public int x(); Code: 0: aload_0 1: getfield #25 // Field x:I 4: ireturn public void p1$T$_setter_$x_$eq(int); Code: 0: aload_0 1: iload_1 2: putfield #25 // Field x:I 5: return public final java.lang.Object apply(); Code: 0: aload_0 1: getfield #34 // Field $outer:Lp1/DelambdafyInline; 4: invokevirtual #37 // Method p1/DelambdafyInline.p1$DelambdafyInline$$$anonfun$1:()Ljava/lang/Object; 7: areturn public p1.DelambdafyInline$$anonfun$t$1(p1.DelambdafyInline); Code: 0: aload_1 1: ifnonnull 6 4: aconst_null 5: athrow 6: aload_0 7: aload_1 8: putfield #34 // Field $outer:Lp1/DelambdafyInline; 11: aload_0 12: invokespecial #42 // Method java/lang/Object."<init>":()V 15: aload_0 16: invokespecial #45 // Method p1/T.$init$:()V 19: return } scala> :quit ``` Adriaan is to `git blame` for `reflection-mem-typecheck.scala`.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala16
1 files changed, 11 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 50e413fba2..44d2469621 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -75,9 +75,9 @@ abstract class UnCurry extends InfoTransform
// Expand `Function`s in constructors to class instance creation (SI-6666, SI-8363)
// We use Java's LambdaMetaFactory (LMF), which requires an interface for the sam's owner
- private def mustExpandFunction(fun: Function) = forceExpandFunction || {
+ private def mustExpandFunction(fun: Function) = {
// (TODO: Can't use isInterface, yet, as it hasn't been updated for the new trait encoding)
- val canUseLambdaMetaFactory = inConstructorFlag == 0 && (fun.attachments.get[SAMFunction] match {
+ val canUseLambdaMetaFactory = (fun.attachments.get[SAMFunction] match {
case Some(SAMFunction(userDefinedSamTp, sam)) =>
// LambdaMetaFactory cannot mix in trait members for us, or instantiate classes -- only pure interfaces need apply
erasure.compilesToPureInterface(erasure.javaErasure(userDefinedSamTp).typeSymbol) &&
@@ -207,8 +207,10 @@ abstract class UnCurry extends InfoTransform
def transformFunction(fun: Function): Tree =
// Undo eta expansion for parameterless and nullary methods
if (fun.vparams.isEmpty && isByNameRef(fun.body)) { noApply += fun.body ; fun.body }
- else if (mustExpandFunction(fun)) gen.expandFunction(localTyper)(fun, inConstructorFlag)
- else {
+ else if (forceExpandFunction || inConstructorFlag != 0) {
+ // Expand the function body into an anonymous class
+ gen.expandFunction(localTyper)(fun, inConstructorFlag)
+ } else {
// method definition with the same arguments, return type, and body as the original lambda
val liftedMethod = gen.mkLiftedFunctionBodyMethod(localTyper)(fun.symbol.owner, fun)
@@ -217,7 +219,11 @@ abstract class UnCurry extends InfoTransform
gen.mkForwarder(gen.mkAttributedRef(liftedMethod.symbol), (fun.vparams map (_.symbol)) :: Nil)
))
- localTyper.typedPos(fun.pos)(Block(liftedMethod, super.transform(newFun)))
+ val typedNewFun = localTyper.typedPos(fun.pos)(Block(liftedMethod, super.transform(newFun)))
+ if (mustExpandFunction(fun)) {
+ val Block(stats, expr : Function) = typedNewFun
+ treeCopy.Block(typedNewFun, stats, gen.expandFunction(localTyper)(expr, inConstructorFlag))
+ } else typedNewFun
}
def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = {