scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

Avoid needless anonfun() methods for lambdas and SAMs with trivial bodies #11356

Open retronym opened 8 years ago

retronym commented 8 years ago

When the body of a lambda or a SAM is just a "method reference", we could use that as the implementation method of the LambdaMetaFactory bootstrap, rather than emitting a wrapper method.

Current:

scala> class LMF { def test = (_: C).toString }
defined class LMF

scala> :javap -c -private LMF
Compiled from "<console>"
public class $line4.$read$$iw$$iw$LMF {
  public scala.Function1<$line3.$read$$iw$$iw$C, java.lang.String> test();
    Code:
       0: invokedynamic #53,  0             // InvokeDynamic #0:apply:()Lscala/runtime/java8/JFunction1;
       5: areturn

  public static final java.lang.String $line4$$read$$iw$$iw$LMF$$$anonfun$1($line3.$read$$iw$$iw$C);
    Code:
       0: aload_0
       1: invokevirtual #60                 // Method java/lang/Object.toString:()Ljava/lang/String;
       4: areturn

  public $line4.$read$$iw$$iw$LMF();
    Code:
       0: aload_0
       1: invokespecial #65                 // Method java/lang/Object."<init>":()V
       4: return

  private static java.lang.Object $deserializeLambda$(java.lang.invoke.SerializedLambda);
    Code:
       0: aload_0
       1: invokedynamic #77,  0             // InvokeDynamic #1:lambdaDeserialize:(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;
       6: areturn
}
retronym commented 8 years ago

Thinking about this some more, this change might need to be nuanced a little. The user might expect that the following works:

class C { def foo = { (x: Any) => "YO!" + x.toString) }
class Test1 extends App { save(serialize(new C().foo) })
% scalac test.scala && scala Test1
class C { def foo = { (x: Any) => x.toString) }
class Test2 extends App { deserialize(load() })
% scalac test.scala && scala Test2

However, if we to elide the anonFun lambda implementation method on the second compilation of C, we would be unable to deserialize.

A similar argument applies to the ability to reflect on the parameter names of lambdas, which is now supported with Java 8 lambdas (by looking at the parameter names of the non-capture arguments to the impl method).

As such, javac only seems to directly refer to the method called in the lambda when the method reference syntax is used.