Fix bad varargs conversion in method reference.

The functional method in a functional interfaces and the method
reference implementing it do not need to be exact matches
parameterwise.

The compiler should insert conversion code to bridge that gap.

In particular take the code

  String first(Strings... strings) { return strings[0]; }

  Function<String, String> f = this::first;

  f("Hello");

The class to f in this case needs some conversion as the implementation
expectss a String...  (which is exacty a String[]).

The code that performed the conversion in GwtAstBuilder had a bug when
the functional type was generic.

Bug: #9497
Bug-Link: https://github.com/gwtproject/gwt/issues/9497
Change-Id: I3ea724a9586dd53e1e94591b5685475bb8000e40
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 b6c10c3..ba927d8 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
@@ -1762,10 +1762,11 @@
       x.resolve(blockScope);
       // Calculate what type this reference is going to bind to, and what single abstract method
       TypeBinding binding = x.expectedType();
-      MethodBinding samBinding = binding.getSingleAbstractMethod(blockScope, false).original();
-
+      MethodBinding samBinding = binding.getSingleAbstractMethod(blockScope, false);
+      MethodBinding declarationSamBinding =
+          binding.getSingleAbstractMethod(blockScope, false).original();
       // Get the interface method is binds to
-      JMethod interfaceMethod = typeMap.get(samBinding);
+      JMethod interfaceMethod = typeMap.get(declarationSamBinding);
       JInterfaceType funcType = (JInterfaceType) typeMap.get(binding);
       SourceInfo info = makeSourceInfo(x);
 
@@ -1889,7 +1890,8 @@
       // interface Foo { m(int x, int y); } bound to reference foo(int... args)
       // if varargs and incoming param is not already a var-arg, we'll need to convert
       // trailing args of the target interface into an array
-      if (referredMethodBinding.isVarargs() && !samBinding.parameters[varArg].isArrayType()) {
+      if (referredMethodBinding.isVarargs()
+          && !samBinding.parameters[varArg].isArrayType()) {
         varArgInitializers = Lists.newArrayList();
       }
 
@@ -1903,8 +1905,9 @@
         // 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)];
+            declarationSamBinding.parameters[paramNumber
+                + (declarationSamBinding.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()
@@ -1935,7 +1938,7 @@
       // is handled there.
       if (samMethod.getType() != JPrimitiveType.VOID) {
         JExpression samExpression = boxOrUnboxExpression(samCall, referredMethodBinding.returnType,
-            samBinding.returnType);
+            declarationSamBinding.returnType);
         samMethodBody.getBlock().addStmt(simplify(samExpression, x).makeReturnStatement());
       } else {
         samMethodBody.getBlock().addStmt(samCall.makeStatement());
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 503475c..6a4ee29 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
@@ -1746,5 +1746,15 @@
     assertEquals("Hi", new SubSub_SuperDefaultMethodDevirtualizationOrder() {
     }.m());
   }
+
+  private static String first(String... strings) {
+    return strings[0];
+  }
+
+  // Regresion test for https://github.com/gwtproject/gwt/issues/9497
+  public void testVarargsFunctionalConversion() {
+    Function<String[], String> function = CompilerMiscRegressionTest::first;
+    assertEquals("Hello", function.apply(new String[] {"Hello", "GoodBye"}));
+  }
 }
 
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 a87b1a3..cafda4c 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -320,6 +320,10 @@
     assertFalse(isGwtSourceLevel8());
   }
 
+  public void testVarargsFunctionalConversion() {
+    assertFalse(isGwtSourceLevel8());
+  }
+
   private boolean isGwtSourceLevel8() {
     return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA8) >= 0;
   }