Fix a small bug in java8 method reference.

If some method references refer to exactly the same function and
create the same inner class, the same inner class was added into
AST multiple times.

For example,
foo(instance1::m); foo(instance2::m);
instance1::m and instance2::m refer to the same function,
the same inner class Lambda$m__I$Type will be added twice.

Fix another bug in UnifyAst:
Unify the enclosing type of a declared type.

Change-Id: I7d40bbde119c039a39ce462ab27d2b726a59fcc9
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 273ec92..d063742 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
@@ -1713,6 +1713,7 @@
       if (innerLambdaClass == null) {
         innerLambdaClass = createInnerClass(lambdaName, x, funcType, info);
         lambdaNameToInnerLambdaType.put(lambdaName, innerLambdaClass);
+        newTypes.add(innerLambdaClass);
 
         JConstructor ctor = new JConstructor(info, innerLambdaClass);
 
@@ -1876,7 +1877,6 @@
       }
 
       push(allocLambda);
-      newTypes.add(innerLambdaClass);
     }
 
     private JExpression boxOrUnboxExpression(JExpression expr, TypeBinding fromType,
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
index 15dbe22..ce2cab3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -1462,6 +1462,9 @@
 
   private void resolveType(JDeclaredType type) {
     assert !type.isExternal();
+    if (type.getEnclosingType() != null) {
+      type.setEnclosingType(translate(type.getEnclosingType()));
+    }
     if (type instanceof JClassType && type.getSuperClass() != null) {
       ((JClassType) type).setSuperClass(translate(type.getSuperClass()));
     }
@@ -1498,7 +1501,6 @@
 
   private JDeclaredType internalFindType(String typeName,
       NameBasedTypeLocator nameBasedTypeLocator, boolean reportErrors) {
-
     if (nameBasedTypeLocator.resolvedTypeIsAvailable(typeName)) {
       // The type was already resolved.
       return nameBasedTypeLocator.getResolvedType(typeName);
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java
index 099085f..1ba51ce 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java
@@ -24,6 +24,8 @@
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.util.arg.SourceLevel;
 
+import java.util.Collections;
+
 /**
  * Tests that {@link com.google.gwt.dev.jjs.impl.GwtAstBuilder} correctly builds the AST for
  * features introduced in Java 8.
@@ -70,6 +72,9 @@
         "public class Pojo {",
         "  public Pojo(int x, int y) {",
         "  }",
+        "  public Integer fooInstance(int a, int b) {",
+        "    return a + b;",
+        "  }",
         "}"
     ));
   }
@@ -304,6 +309,46 @@
         formatSource(samMethod.toSource()));
   }
 
+  public void testCompileInstanceReferenceBindingMultiple() throws Exception {
+    addSnippetClassDecl("Pojo instance1 = new Pojo(1, 2);");
+    addSnippetClassDecl("Pojo instance2 = new Pojo(3, 4);");
+    String reference =
+        "new AcceptsLambda<Integer>().accept(instance1::fooInstance);\n" +
+        "new AcceptsLambda<Integer>().accept(instance2::fooInstance);";
+    assertEqualBlock(
+        "(new AcceptsLambda()).accept(new Lambda$fooInstance__IILjava_lang_Integer_2$Type(this.instance1));\n"
+        + "(new AcceptsLambda()).accept(new Lambda$fooInstance__IILjava_lang_Integer_2$Type(this.instance2));",
+        reference);
+    JProgram program = compileSnippet("void", reference, false);
+
+    // created by GwtAstBuilder
+    JClassType lambdaInnerClass = (JClassType) getType(program,
+        "test.Lambda$fooInstance__IILjava_lang_Integer_2$Type");
+    assertNotNull(lambdaInnerClass);
+    assertEquals(1, Collections.frequency(program.getDeclaredTypes(), lambdaInnerClass));
+
+    // should have constructor taking the instance
+    JMethod ctor = findMethod(lambdaInnerClass, "Lambda$fooInstance__IILjava_lang_Integer_2$Type");
+    assertTrue(ctor instanceof JConstructor);
+    // instance capture
+    assertEquals(1, ctor.getParams().size());
+    assertEquals(lambdaInnerClass.getEnclosingType(), ctor.getOriginalParamTypes().get(0));
+
+    // should have 1 field to store the captured instance
+    assertEquals(1, lambdaInnerClass.getFields().size());
+    assertEquals(lambdaInnerClass.getEnclosingType(),
+        lambdaInnerClass.getFields().get(0).getType());
+
+    // should extends test.Lambda
+    assertTrue(lambdaInnerClass.getImplements().contains(program.getFromTypeMap("test.Lambda")));
+
+    // should implement run method and invoke lambda via captured instance
+    JMethod samMethod = findMethod(lambdaInnerClass, "run");
+    assertEquals(
+        "public final Object run(int arg0,int arg1){return this.$$outer_0.fooInstance(arg0,arg1);}",
+        formatSource(samMethod.toSource()));
+  }
+
   public void testCompileImplicitQualifierReferenceBinding() throws Exception {
     String lambda = "new AcceptsLambda<String>().accept2(String::equalsIgnoreCase);";
     assertEqualBlock(