Fix for bad method resolution in GwtAstBuilder.

Bug: #9598
Bug-Link: https://github.com/gwtproject/gwt/issues/9598
Change-Id: Ie6a5b485eb524436d9f5fe4f7dc758d35fcc4d60
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 fce0237..471c7c2 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
@@ -2917,7 +2917,6 @@
       } else {
         body.getBlock().addStmt(call.makeReturnStatement());
       }
-      typeMap.setMethod(sourceMethodBinding, bridgeMethod);
       return bridgeMethod;
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
index 1a9c4a3..77b5363 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
@@ -33,6 +33,7 @@
 import com.google.gwt.dev.jjs.ast.JReferenceType;
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.util.StringInterner;
+import com.google.gwt.thirdparty.guava.common.base.Preconditions;
 import com.google.gwt.thirdparty.guava.common.collect.Interner;
 
 import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
@@ -184,13 +185,26 @@
   }
 
   public void setField(FieldBinding binding, JField field) {
+    // Make sure that the enclosing type of the field binding corresponds to the enclosing type of
+    // field to avoid associating a field binding with the wrong JField.
+    Preconditions.checkArgument(get(binding.declaringClass.erasure()) == field.getEnclosingType());
+
     String key = JdtUtil.signature(binding);
-    sourceFields.put(key, field);
+    JField oldField = sourceFields.put(key, field);
+
+    // Make sure this is called at most once per field binding.
+    Preconditions.checkState(oldField == null);
   }
 
   public void setMethod(MethodBinding binding, JMethod method) {
+    // Make sure that the enclosing type of the method binding corresponds to the enclosing type of
+    // method to avoid associating a method binding with the wrong JMethod.
+    Preconditions.checkArgument(get(binding.declaringClass.erasure()) == method.getEnclosingType());
     String key = JdtUtil.signature(binding);
-    sourceMethods.put(key, method);
+    JMethod oldMethod = sourceMethods.put(key, method);
+
+    // Make sure this is called at most once per method binding.
+    Preconditions.checkState(oldMethod == null);
   }
 
   public void setSourceType(SourceTypeBinding binding, JDeclaredType type) {
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java
index c4837a2..d332443 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java
@@ -46,6 +46,7 @@
 import com.google.gwt.thirdparty.guava.common.collect.Sets;
 
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -276,6 +277,40 @@
     }
   }
 
+  public void testBridgeMethodResolution() throws UnableToCompleteException {
+    sourceLevel = SourceLevel.JAVA9;
+
+    sources.add(JavaResourceBase.createMockJavaResource("test.SuperInterface",
+        "package test;",
+        "public interface SuperInterface<T> {",
+        "  void m(T t);",
+        "}",
+        "interface SubInterface extends  SuperInterface<String> {",
+        "  void m(String t);",
+        "  default SubInterface get() { ",
+        "    // A lambda that will have a bridge m(Object) -> m(String)",
+        "    return o -> {};",
+        "  } ",
+        "  static <T> void applyM(SuperInterface<T> s) { s.m(null); } ",
+        "}"
+    ));
+
+    JProgram program = compileProgram("test.SuperInterface");
+    JMethod applyM = findQualifiedMethod(program, "test.SubInterface.applyM");
+
+    final Set<String> calledMethods = new HashSet<>();
+
+    new JVisitor() {
+      @Override
+      public void endVisit(JMethodCall x, Context ctx) {
+        calledMethods.add(x.getTarget().getQualifiedName());
+      }
+    }.accept(applyM);
+    assertEquals(
+        Sets.newHashSet(Arrays.asList("test.SuperInterface.m(Ljava/lang/Object;)V")),
+        calledMethods);
+  }
+
   public void testUniqueArrayTypeInstance() throws UnableToCompleteException {
     JProgram program = compileProgram("test.DalGrid");
     Set<String> arrayTypeNames = Sets.newHashSet();
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 d46bbdb..63b6e6c 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
@@ -27,6 +27,7 @@
 import java.util.List;
 import java.util.function.BiFunction;
 import java.util.function.IntFunction;
+import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
@@ -2038,4 +2039,24 @@
     };
     assertEquals("hello", helloSupplier.get());
   }
+
+  interface Selector extends Predicate<String> {
+    @Override
+    boolean test(String object);
+
+    default Selector trueSelector() {
+      // Unused variable that creates a lambda with a bridge for the method test. The bug #9598
+      // was caused by GwtAstBuilder associating the bridge method Lambda.test(Object) on the
+      // lambda below to the method Predicate.test(Object), causing the method resolution in the
+      // code that refers to the Predicate.test(Object) in the test below to refer to
+      // Lambda.test(Object) which is the wrong method.
+      return receiver -> true;
+    }
+  }
+
+  // Regression tests for #9598
+  public void testImproperMethodResolution() {
+    Predicate p = o -> true;
+    assertTrue(p.test(null));
+  }
 }
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 e706f45..1c20945 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -352,6 +352,10 @@
     assertFalse(isGwtSourceLevel9());
   }
 
+  public void testImproperMethodResolution() {
+    assertFalse(isGwtSourceLevel9());
+  }
+
   private boolean isGwtSourceLevel9() {
     return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA9) >= 0;
   }