You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adjust parameter order of static accessor method in Delambdafy
Under `-Ydelambdafy:method`, a public, static accessor method is
created to expose the private method containing the body of the
lambda.
Currently this accessor method has its parameters in the same order
structure as those of the lambda body method.
What is this order? There are three categories of parameters:
1. lambda parameters
2. captured parameters (added by lambdalift)
3. self parameters (added to lambda bodies that end up in trait
impl classes by mixin, and added unconditionally to the static
accessor method.)
These are currently emitted in order #3, #1, #2.
Here are examples of the current behaviour:
BEFORE (trait):
```
% cat sandbox/test.scala
trait Test {
def member: A
def foo {
val local = new B
(arg: C) => "" + arg + member + local
}
}
% qscalac -Ydelambdafy:method sandbox/test.scala && echo ':javap -private Test$class' | qscala
scala> :javap -private Test$class
Compiled from "test.scala"
public abstract class Test$class {
public static void foo(Test);
private static final java.lang.String $anonfun$1(Test, C, B);
public static void $init$(Test);
public static final java.lang.String accessor$1(Test, C, B);
}
```
BEFORE (class):
```
% cat sandbox/test.scala
abstract class Test {
def member: A
def foo {
val local = new B
(arg: C) => "" + arg + member + local
}
}
% qscalac -Ydelambdafy:method sandbox/test.scala && echo ':javap -private Test' | qscala
scala> :javap -private Test
Compiled from "test.scala"
public abstract class Test {
public abstract A member();
public void foo();
private final java.lang.String $anonfun$1(C, B);
public Test();
public static final java.lang.String accessor$1(Test, C, B);
}
```
Contrasting the class case with Java:
```
% cat sandbox/Test.java
public abstract class Test {
public static class A {};
public static class B {};
public static class C {};
public static interface I {
public abstract Object c(C arg);
}
public abstract A member();
public void test() {
B local = new B();
I i1 = (C arg) -> "" + member() + local;
}
}
% javac -d . sandbox/Test.java && javap -private Test
Compiled from "Test.java"
public abstract class Test {
public Test();
public abstract Test$A member();
public void test();
private java.lang.Object lambda$test$0(Test$B, Test$C);
}
```
We can see that in Java 8 lambda parameters come first. If we
want to use Java's LambdaMetafactory to spin up our anoymous FunctionN
subclasses on the fly, a signature must change.
I can see three options for change:
1. Adjust `Mixin` to always append the `$this` parameter, rather
than prepending it.
2. More conservatively, do this just for lambda bodies
3. Adjust the parameters of the accessor method only. The body
of this method can permute params before calling the lambda
body method.
This commit implements option #3. This is the lowest risk / impact
to pave the way for experimentation with indy lambdas. But it isn't
ideal as a long term solution, as indy lambdas actually don't need
the accessor method at all, private methods can be used directly
by LambdaMetaFactory, saving a little indirection.
Option #1 might be worth a shot on the 2.12.x branch. Option #2 might
even be feasible on 2.11.x.
I've included a test that shows this in all in action. However, that
is currently disabled, as we don't have a partest category for tests
that require Java 8.
0 commit comments