Skip to content

Commit 508268d

Browse files
committed
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 scala#34 // Field $outer:Lp1/DelambdafyInline; 4: invokevirtual scala#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 scala#34 // Field $outer:Lp1/DelambdafyInline; 11: aload_0 12: invokespecial scala#42 // Method java/lang/Object."<init>":()V 15: aload_0 16: invokespecial scala#45 // Method p1/T.$init$:()V 19: return } scala> :quit ```
1 parent 3904c32 commit 508268d

File tree

1 file changed

+11
-5
lines changed

1 file changed

+11
-5
lines changed

src/compiler/scala/tools/nsc/transform/UnCurry.scala

+11-5
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ abstract class UnCurry extends InfoTransform
7575

7676
// Expand `Function`s in constructors to class instance creation (SI-6666, SI-8363)
7777
// We use Java's LambdaMetaFactory (LMF), which requires an interface for the sam's owner
78-
private def mustExpandFunction(fun: Function) = forceExpandFunction || {
78+
private def mustExpandFunction(fun: Function) = {
7979
// (TODO: Can't use isInterface, yet, as it hasn't been updated for the new trait encoding)
80-
val canUseLambdaMetaFactory = inConstructorFlag == 0 && (fun.attachments.get[SAMFunction] match {
80+
val canUseLambdaMetaFactory = (fun.attachments.get[SAMFunction] match {
8181
case Some(SAMFunction(userDefinedSamTp, sam)) =>
8282
// LambdaMetaFactory cannot mix in trait members for us, or instantiate classes -- only pure interfaces need apply
8383
erasure.compilesToPureInterface(erasure.javaErasure(userDefinedSamTp).typeSymbol) &&
@@ -207,8 +207,10 @@ abstract class UnCurry extends InfoTransform
207207
def transformFunction(fun: Function): Tree =
208208
// Undo eta expansion for parameterless and nullary methods
209209
if (fun.vparams.isEmpty && isByNameRef(fun.body)) { noApply += fun.body ; fun.body }
210-
else if (mustExpandFunction(fun)) gen.expandFunction(localTyper)(fun, inConstructorFlag)
211-
else {
210+
else if (forceExpandFunction || inConstructorFlag != 0) {
211+
// Expand the function body into an anonymous class
212+
gen.expandFunction(localTyper)(fun, inConstructorFlag)
213+
} else {
212214
// method definition with the same arguments, return type, and body as the original lambda
213215
val liftedMethod = gen.mkLiftedFunctionBodyMethod(localTyper)(fun.symbol.owner, fun)
214216

@@ -217,7 +219,11 @@ abstract class UnCurry extends InfoTransform
217219
gen.mkForwarder(gen.mkAttributedRef(liftedMethod.symbol), (fun.vparams map (_.symbol)) :: Nil)
218220
))
219221

220-
localTyper.typedPos(fun.pos)(Block(liftedMethod, super.transform(newFun)))
222+
val typedNewFun = localTyper.typedPos(fun.pos)(Block(liftedMethod, super.transform(newFun)))
223+
if (mustExpandFunction(fun)) {
224+
val Block(stats, expr : Function) = typedNewFun
225+
treeCopy.Block(typedNewFun, stats, gen.expandFunction(localTyper)(expr, inConstructorFlag))
226+
} else typedNewFun
221227
}
222228

223229
def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = {

0 commit comments

Comments
 (0)