Fix bad boxing in (instance) method references.
Bug: #9340
Bug-Link: http://github.com/gwtproject/gwt/issues/9340
Change-Id: I4305181d680044bf8892d6acd0482df1f2e2eccb
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index cb066da..4044774 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -1867,17 +1867,22 @@
JExpression paramExpr = param.makeRef(info);
// params may need to be boxed or unboxed
TypeBinding destParam = null;
+ // The method declared in the functional interface might have more parameters than the
+ // method referred by the method reference. In the case of an instance method without
+ // an explicit qualifier (A::m vs instance::m) the method in the functional interface will
+ // have an additional parameter for the instance preceding all the method parameters.
+ TypeBinding samParameterBinding =
+ samBinding.parameters[paramNumber
+ + (samBinding.parameters.length - referredMethodBinding.parameters.length)];
// if it is not the trailing param or varargs, or interface method is already varargs
if (varArgInitializers == null || !referredMethodBinding.isVarargs() || (paramNumber < varArg)) {
destParam = referredMethodBinding.parameters[paramNumber];
- paramExpr = boxOrUnboxExpression(paramExpr, samBinding.parameters[paramNumber],
- destParam);
+ paramExpr = boxOrUnboxExpression(paramExpr, samParameterBinding, destParam);
samCall.addArg(paramExpr);
- } else if (!samBinding.parameters[paramNumber].isArrayType()) {
+ } else if (!samParameterBinding.isArrayType()) {
// else add trailing parameters to var-args initializer list for an array
destParam = referredMethodBinding.parameters[varArg].leafComponentType();
- paramExpr = boxOrUnboxExpression(paramExpr, samBinding.parameters[paramNumber],
- destParam);
+ paramExpr = boxOrUnboxExpression(paramExpr, samParameterBinding, destParam);
varArgInitializers.add(paramExpr);
}
paramNumber++;
diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java
index aaf4248..45f38de 100644
--- a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -1441,19 +1441,19 @@
V apply(T t, U u);
}
- public void testMethodReferenceImplementedInSuperclass() {
+ public void testMethodReference_implementedInSuperclass() {
MyFunction1<StringBuilder, String> toString = StringBuilder::toString;
assertEquals("Hello", toString.apply(new StringBuilder("Hello")));
}
static MyFunction2<String, String, String> concat = (s,t) -> s + t;
- public void testMethodReferenceWithGenericTypeParameters() {
- testMethodReferencesWithGenericTypeParameters(
+ public void testMethodReference_genericTypeParameters() {
+ testMethodReference_genericTypeParameters(
new Some<String>("Hell", concat), "Hell", "o", concat);
}
- private static <T> void testMethodReferencesWithGenericTypeParameters(
+ private static <T> void testMethodReference_genericTypeParameters(
Some<T> some, T t1, T t2, MyFunction2<T, T, T> combine) {
T t1t2 = combine.apply(t1, t2);
@@ -1471,4 +1471,87 @@
assertEquals(t1t2,
((MyFunction2<T, MyFunction2<T, T, T>, Some<T>>) Some<T>::new).apply(t1t2, combine).m1());
}
+
+ static MyFunction2<Integer, Integer, Integer> addInteger = (s,t) -> s + t;
+
+ @FunctionalInterface
+ interface MyIntFunction1 {
+ int apply(int t);
+ }
+
+ @FunctionalInterface
+ interface MyIntFunction2 {
+ int apply(int t, int u);
+ }
+
+ @FunctionalInterface
+ interface MyIntFuncToSomeIntegeFunction2 {
+ SomeInteger apply(int t, MyFunction2<Integer, Integer, Integer> u);
+ }
+
+ @FunctionalInterface
+ interface MySomeIntegerFunction1 {
+ int apply(SomeInteger t);
+ }
+
+ @FunctionalInterface
+ interface MySomeIntegerIntFunction2 {
+ int apply(SomeInteger t, int u);
+ }
+
+ static MyIntFunction2 addint = (s,t) -> s + t;
+
+ static class SomeInteger {
+ int s;
+ MyFunction2<Integer, Integer ,Integer> combine;
+ SomeInteger(int s, MyFunction2<Integer, Integer, Integer> combine) {
+ this.s = s;
+ this.combine = combine;
+ }
+ public int m(int s2) {
+ return combine.apply(s, s2);
+ }
+ public int m1() {
+ return s;
+ }
+ }
+
+ public void testMethodReference_autoboxing() {
+ SomeInteger some = new SomeInteger(3, addInteger);
+
+ // Test all 4 flavours of methodReference autoboxing parameters.
+ // 1. Static method
+ assertEquals((Integer) 5, ((MyFunction1<Integer, Integer>) Java8Test::m).apply(5));
+ // 2. Qualified instance method
+ assertEquals((Integer) 5, ((MyFunction1<Integer, Integer>) some::m).apply(2));
+ // 3. Unqualified instance method
+ assertEquals((Integer) 3, ((MyFunction1<SomeInteger, Integer>) SomeInteger::m1).apply(some));
+ assertEquals((Integer) 5, ((MyFunction2<SomeInteger, Integer, Integer>)
+ SomeInteger::m).apply(some, 2));
+ assertEquals((Integer) 5,
+ ((MyFunction1<SomeInteger, Integer>)
+ SomeInteger::m1).apply(new SomeInteger(5, addInteger)));
+ // 4. Constructor reference.
+ assertEquals(5,
+ ((MyFunction2<Integer, MyFunction2<Integer, Integer, Integer>, SomeInteger>)
+ SomeInteger::new).apply(5, addInteger).m1());
+
+ // Test all 4 flavours of methodReference (interface unboxed)
+ // 1. Static method
+ assertEquals(5, ((MyIntFunction1) Java8Test::m).apply(5));
+ // 2. Qualified instance method
+ assertEquals(5, ((MyIntFunction1) some::m).apply(2));
+ // 3. Unqualified instance method
+ assertEquals(3, ((MySomeIntegerFunction1) SomeInteger::m1).apply(some));
+ // The next expression was the one that triggered bug #9346 where decisions on whether to
+ // box/unbox were decided incorrectly due to differring number of parameters in the method
+ // reference and the functional interface method.
+ assertEquals(5, ((MySomeIntegerIntFunction2) SomeInteger::m).apply(some, 2));
+ assertEquals(5,
+ ((MySomeIntegerFunction1)
+ SomeInteger::m1).apply(new SomeInteger(5, addInteger)));
+ // 4. Constructor reference.
+ assertEquals(5,
+ ((MyIntFuncToSomeIntegeFunction2) SomeInteger::new).apply(5, addInteger).m1());
+ }
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
index 6525b0a..3c360f1 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -276,11 +276,15 @@
assertFalse(isGwtSourceLevel8());
}
- public void testMethodReferenceImplementedInSuperclass() {
+ public void testMethodReference_implementedInSuperclass() {
assertFalse(isGwtSourceLevel8());
}
- public void testMethodReferenceWithGenericTypeParameters() {
+ public void testMethodReference_genericTypeParameters() {
+ assertFalse(isGwtSourceLevel8());
+ }
+
+ public void testMethodReference_autoboxing() {
assertFalse(isGwtSourceLevel8());
}