Make sure synthetic bridge methods are properly rewritten.

Synthetic bridges and the methods they dispatch to have different
signatures and hence different names in regular Java classes.

In the context of js interop we allow to name both the bridge and
the regular method with the same name because it is natural to do
so, e.g.:

  @JsType
  abstract class SomeSuper {
    public abstract SomeSuper m();
  }

  @JsType
  class SubClass extends SomeSuper {
    public SubClass m() { return this; }
  }

In this case SomeSuper.m() has signature m()LSomeSuper; and
SubClass.m() has signature m()LSubClass;. Hence an bridge method
m()LSomeSuper; is created that calls this.m()LSubClass; in SubClass.

In this context both method will be named "m" in JavaScript and it
is OK not to emit the bridge in this case; for simplicity the
generated code will emit the bridge and immediately rewrite it with
the actual concrete method.

Change-Id: I0248b171807d274c23f329b531ccaa71046dbfb7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index 9cbda78..bf2d791 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -2309,11 +2309,24 @@
      */
     private void generatePrototypeDefinitions(JDeclaredType type) {
         assert !program.isRepresentedAsNativeJsPrimitive(type);
-      for (JMethod method : type.getMethods()) {
-        if (!method.needsDynamicDispatch()) {
-          continue;
-        }
 
+      // Emit synthetic methods first. In JsInterop we allow a more user written method to be named
+      // with the same name as a synthetic bridge (required due to generics) relying that the
+      // synthetic method is output first into the prototype slot and rewritten in this situation.
+      // TODO(rluble): this is a band aid. The user written method (and its overrides) should be
+      // automatically JsIgnored. Otherwise some semantics become looser. E.g. the synthetic bridge
+      // method may be casting some of the parameters. Such casts are lost in this scheme.
+      Iterable<JMethod> orderedInstanceMethods = Iterables.concat(
+          Iterables.filter(type.getMethods(),
+              Predicates.and(
+                  JjsPredicates.IS_SYNTHETIC,
+                  JjsPredicates.NEEDS_DYNAMIC_DISPATCH)),
+          Iterables.filter(type.getMethods(),
+              Predicates.and(
+                  Predicates.not(JjsPredicates.IS_SYNTHETIC),
+                  JjsPredicates.NEEDS_DYNAMIC_DISPATCH)));
+
+      for (JMethod method : orderedInstanceMethods) {
         generatePrototypeDefinition(method, (JsExpression) transformMethod(method));
       }
     }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsPredicates.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsPredicates.java
new file mode 100644
index 0000000..e0ff7dc
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsPredicates.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.impl;
+
+import com.google.gwt.dev.jjs.ast.JMember;
+import com.google.gwt.thirdparty.guava.common.base.Predicate;
+
+/**
+ * General predicates for Java AST nodes.
+ */
+public class JjsPredicates {
+  public static Predicate<JMember> IS_SYNTHETIC =
+      new Predicate<JMember>() {
+        @Override
+        public boolean apply(JMember method) {
+          return method.isSynthetic();
+        }
+      };
+
+  public static Predicate<JMember> NEEDS_DYNAMIC_DISPATCH =
+      new Predicate<JMember>() {
+        @Override
+        public boolean apply(JMember method) {
+          return method.needsDynamicDispatch();
+        }
+      };
+
+  private JjsPredicates() {
+  }
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
index ad9a5f2..242c9a3 100644
--- a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
+++ b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
@@ -513,4 +513,30 @@
     assertTrue(NativeJsTypeWithOverlay.hasM(object));
     assertEquals(2, NativeJsTypeWithOverlay.x);
   }
+
+  @JsType
+  static abstract class SomeAbstractClass {
+    public abstract SomeAbstractClass m();
+  }
+
+  // Do not rename this class.
+  @JsType
+  static abstract class SomeZAbstractSubclass extends SomeAbstractClass {
+    public abstract SomeZAbstractSubclass m();
+  }
+
+  @JsType
+  static class SomeConcreteSubclass extends SomeZAbstractSubclass {
+    public SomeConcreteSubclass m() {
+      return this;
+    }
+  }
+
+  public void testNamedBridge() {
+    // Bridges are sorted by signature in the JDT. Make sure that the bridge method appears second.
+    assertTrue(
+        SomeConcreteSubclass.class.getName().compareTo(SomeZAbstractSubclass.class.getName()) < 0);
+    SomeConcreteSubclass o = new SomeConcreteSubclass();
+    assertEquals(o, o.m());
+  }
 }