Add missing bridges for default methods.

In Java 8 bridges due to default methods are also implemented
as default methods in interfaces.

Bug: #9406
Bug-Link: https://github.com/gwtproject/gwt/issues/9406
Change-Id: I2d2b7d2b5ce9501385394587b0d5fa049c9faae5
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 ba7e267..55c5968 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
@@ -1269,7 +1269,6 @@
         JClassType functionalExpressionImplementationClass,
         FunctionalExpression functionalExpression,
         JMethod functionalInterfaceAbstractMethod) {
-      // TODO(rluble): create bridges that might be needed for default methods.
       if (functionalExpression.getRequiredBridges() != null) {
         for (MethodBinding methodBinding : functionalExpression.getRequiredBridges()) {
           // Create bridges.
@@ -2556,12 +2555,10 @@
         processEnumType((JEnumType) type);
       }
 
-      if (type instanceof JClassType) {
-        if (type.isJsNative()) {
-          maybeImplementJavaLangObjectMethodsOnNativeClass(type);
-        }
-        addBridgeMethods(x.binding);
+      if (type instanceof JClassType && type.isJsNative()) {
+        maybeImplementJavaLangObjectMethodsOnNativeClass(type);
       }
+      addBridgeMethods(x.binding);
 
       curClass = classStack.pop();
     }
@@ -2776,54 +2773,38 @@
       createBridgeMethod(curClass.type, jdtBridgeMethod, targetMethod);
     }
 
-    private void createBridgeMethod(
+    /**
+     * Create a bridge method. It calls a same-named method with the same
+     * arguments, but with a different type signature.
+     */
+    private JMethod createBridgeMethod(
         JDeclaredType enclosingType, MethodBinding sourceMethodBinding, JMethod targetMethod) {
+
       JType returnType = typeMap.get(sourceMethodBinding.returnType);
-      Iterable<JType> parameterTypes =
-          FluentIterable.from(Arrays.asList(sourceMethodBinding.parameters)).transform(
-              new Function<TypeBinding, JType>() {
-                @Override
-                public JType apply(TypeBinding typeBinding) {
-                  return typeMap.get(typeBinding.erasure());
-                }
-              });
+      Iterable<JType> parameterTypes = mapTypes(sourceMethodBinding.parameters);
+      Iterable<JClassType> thrownExceptionTypes = mapTypes(sourceMethodBinding.thrownExceptions);
 
-      Iterable<JClassType> thrownExceptionTypes =
-          FluentIterable.from(Arrays.asList(sourceMethodBinding.thrownExceptions)).transform(
-          new Function<ReferenceBinding, JClassType>() {
-            @Override
-            public JClassType apply(ReferenceBinding exceptionReferenceBinding) {
-              return (JClassType) typeMap.get(exceptionReferenceBinding.erasure());
-            }
-          });
-
-      JMethod bridgeMethod = createBridgeMethod(
-          enclosingType, targetMethod, parameterTypes, returnType, thrownExceptionTypes);
-      typeMap.setMethod(sourceMethodBinding, bridgeMethod);
-    }
-
-      /**
-       * Create a bridge method. It calls a same-named method with the same
-       * arguments, but with a different type signature.
-       */
-    private JMethod createBridgeMethod(JDeclaredType enclosingType,
-        JMethod targetMethod, Iterable<JType> parameterTypes, JType returnType,
-        Iterable<JClassType> thrownExceptions) {
       SourceInfo info = targetMethod.getSourceInfo();
       JMethod bridgeMethod =
           new JMethod(info, targetMethod.getName(), enclosingType, returnType, false, false,
               targetMethod.isFinal(), targetMethod.getAccess());
       bridgeMethod.setBody(new JMethodBody(info));
-      enclosingType.addMethod(bridgeMethod);
+      if (enclosingType instanceof JInterfaceType) {
+        // Mark bridges created in interfaces as default methods so they are processed correctly
+        // by the rest of the pipeline.
+        bridgeMethod.setDefaultMethod();
+      }
       bridgeMethod.setSynthetic();
-      int paramIdx = 0;
+
+      enclosingType.addMethod(bridgeMethod);
+      int paramIndex = 0;
       List<JParameter> implParams = targetMethod.getParams();
       for (JType parameterType : parameterTypes) {
-        JParameter parameter = implParams.get(paramIdx++);
+        JParameter parameter = implParams.get(paramIndex++);
         bridgeMethod.createFinalParameter(
             parameter.getSourceInfo(), parameter.getName(), parameterType);
       }
-      for (JClassType thrownException : thrownExceptions) {
+      for (JClassType thrownException : thrownExceptionTypes) {
         bridgeMethod.addThrownException(thrownException);
       }
       bridgeMethod.freezeParamTypes();
@@ -2841,6 +2822,7 @@
       } else {
         body.getBlock().addStmt(call.makeReturnStatement());
       }
+      typeMap.setMethod(sourceMethodBinding, bridgeMethod);
       return bridgeMethod;
     }
 
@@ -3664,6 +3646,16 @@
     }
   }
 
+  private <T extends JType> Iterable<T> mapTypes(TypeBinding[] types) {
+    return FluentIterable.from(Arrays.asList(types)).transform(
+        new Function<TypeBinding, T>() {
+          @Override
+          public T apply(TypeBinding typeBinding) {
+            return (T) typeMap.get(typeBinding.erasure());
+          }
+        });
+  }
+
   static class ClassInfo {
     public final JClassType classType;
     public final ClassScope scope;
@@ -4185,17 +4177,11 @@
     TypeBinding[] params =
         JdtUtil.getAnnotationParameterTypeBindingArray(specializeAnnotation, "params");
     assert params != null : "params is a mandatory field";
-    List<JType> paramTypes = new ArrayList<JType>();
-    for (TypeBinding pType : params) {
-      paramTypes.add(typeMap.get(pType));
-    }
+    List<JType> paramTypes = Lists.newArrayList(mapTypes(params));
 
     TypeBinding returns =
         JdtUtil.getAnnotationParameterTypeBinding(specializeAnnotation, "returns");
-    JType returnsType = null;
-    if (returns != null) {
-      returnsType = typeMap.get(returns);
-    }
+    JType returnsType = returns == null ? null : typeMap.get(returns);
 
     String targetMethod = JdtUtil.getAnnotationParameterString(specializeAnnotation, "target");
     assert targetMethod != null : "target is a mandatory parameter";
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 e4ae64d..a50dbf8 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
@@ -1628,7 +1628,7 @@
     T apply(T t);
     // TODO(rluble): uncomment the line below to when bridges for default methods are created
     // in functional expressions
-    // FunctionalExpressionBridges_I<T> m(T t);
+    FunctionalExpressionBridges_I<T> m(T t);
   }
 
   @FunctionalInterface