Fix semantics of try-with-resources.

Exceptions in constructors were not handled correctly.

Change-Id: Iac9a1b89e384630576cb62f284672b898a6f40d7
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 41edfa4..cc95e09 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
@@ -2151,9 +2151,10 @@
        *  to
        *
        * try {
-       *   A1 a1 = new A1();... ; An an = new An();
+       *   A1 a1 = null; ...; An an = null;
        *   Throwable $exception = null;
        *   try {
+       *     a1 = new A1();... ; an = new An();
        *     ... tryBlock...
        *   } catch (Throwable t) {
        *     $exception = t;
@@ -2169,7 +2170,7 @@
        *
        */
 
-      JBlock innerBlock = new JBlock(info);
+      JBlock outerTryBlock = new JBlock(info);
       // add resource variables
       List<JLocal> resourceVariables = Lists.newArrayList();
       for (int i = x.resources.length - 1; i >= 0; i--) {
@@ -2179,13 +2180,13 @@
 
         JLocal resourceVar = (JLocal) curMethod.locals.get(x.resources[i].binding);
         resourceVariables.add(0, resourceVar);
-        innerBlock.addStmt(0, resourceDecl);
+        tryBlock.addStmt(0, resourceDecl);
       }
 
       // add exception variable
       JLocal exceptionVar = createLocalThrowable(info, "$primary_ex");
 
-      innerBlock.addStmt(makeDeclaration(info, exceptionVar, JNullLiteral.INSTANCE));
+      outerTryBlock.addStmt(makeDeclaration(info, exceptionVar, JNullLiteral.INSTANCE));
 
       // create catch block
       List<JTryStatement.CatchClause> catchClauses = Lists.newArrayListWithCapacity(1);
@@ -2217,9 +2218,9 @@
           new JThrowStatement(info, new JLocalRef(info, exceptionVar)), null));
 
       // Stitch all together into a inner try block
-      innerBlock.addStmt(new JTryStatement(info, tryBlock, catchClauses,
+      outerTryBlock.addStmt(new JTryStatement(info, tryBlock, catchClauses,
             finallyBlock));
-      return innerBlock;
+      return outerTryBlock;
     }
 
     private JLocal createLocalThrowable(SourceInfo info, String prefix) {
diff --git a/user/test/com/google/gwt/dev/jjs/test/Java7Test.java b/user/test/com/google/gwt/dev/jjs/test/Java7Test.java
index 10a71b0..2880b2a 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java7Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java7Test.java
@@ -19,7 +19,7 @@
 
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -60,12 +60,26 @@
 
   final List<String> log = new ArrayList<String>();
 
+  enum ThrowsWhen {
+    NEVER, ONCONSTRUCTOR, ONCLOSE;
+  }
+
   class Resource implements AutoCloseable {
 
-    String name;
-    public Resource(String name) {
+    final String name;
+    final ThrowsWhen throwsWhen;
+
+    public Resource(String name) throws E1 {
+      this(name, ThrowsWhen.NEVER);
+    }
+
+    public Resource(String name, ThrowsWhen throwsWhen) throws E1 {
       this.name = name;
+      this.throwsWhen = throwsWhen;
       log.add("Open " + name);
+      if (throwsWhen == ThrowsWhen.ONCONSTRUCTOR) {
+        throwException("ExceptionOnConstructor");
+      }
     }
 
     public void doSomething() {
@@ -78,36 +92,23 @@
 
     public void close() throws Exception {
       log.add("Close " + name);
+      if (throwsWhen == ThrowsWhen.ONCLOSE) {
+        throwException("ExceptionOnClose");
+      }
     }
   }
 
-  class ResourceWithExceptionOnClose extends Resource {
-
-    public ResourceWithExceptionOnClose(String name) {
-      super(name);
-    }
-
-    public void close() throws Exception {
-      throw new E1("Exception in close " + name);
+  private void logException(Exception e) {
+    log.add(e.getMessage());
+    for (Throwable t : e.getSuppressed()) {
+      log.add("Suppressed: " + t.getMessage());
     }
   }
 
-  public void testResource() throws Exception {
+  public void testTryWithResources_noExceptions() throws Exception {
     log.clear();
-    try (Resource c = new Resource("A")) {
-
-      c.doSomething();
-    }
-
-    assertContentsInOrder(log,
-        "Open A",
-        "doSomething A",
-        "Close A");
-  }
-
-  public void test3Resources() throws Exception {
-    log.clear();
-    try (Resource rA = new Resource("A");
+    try (
+        Resource rA = new Resource("A");
         Resource rB = new Resource("B");
         Resource rC = new Resource("C")) {
 
@@ -129,10 +130,11 @@
     );
   }
 
-  public void testResourcesWithExceptions() throws Exception {
+  public void testTryWithResources_exceptions() throws Exception {
     log.clear();
-    try (Resource rA = new Resource("A");
-        Resource rB = new ResourceWithExceptionOnClose("B");
+    try (
+        Resource rA = new Resource("A");
+        Resource rB = new Resource("B", ThrowsWhen.ONCLOSE);
         Resource rC = new Resource("C")) {
 
       rA.doSomething();
@@ -152,26 +154,25 @@
         "doSomething B",
         "doSomething C",
         "Close C",
+        "Close B",
         "Close A",
-        "Exception in close B",
+        "ExceptionOnClose in B",
         "finally"
     );
   }
 
-  public void testResourcesWithSuppressedExceptions() throws Exception {
+  public void testTryWithResources_suppressedExceptions() throws Exception {
     log.clear();
-    try (Resource rA = new ResourceWithExceptionOnClose("A");
+    try (
+        Resource rA = new Resource("A", ThrowsWhen.ONCLOSE);
         Resource rB = new Resource("B");
-        Resource rC = new ResourceWithExceptionOnClose("C")) {
+        Resource rC = new Resource("C", ThrowsWhen.ONCLOSE)) {
 
       rA.doSomething();
       rB.doSomething();
       rC.doSomething();
     } catch (Exception e) {
-      log.add(e.getMessage());
-      for (Throwable t : e.getSuppressed()) {
-        log.add("Suppressed: " + t.getMessage());
-      }
+      logException(e);
     }
 
     assertContentsInOrder(log,
@@ -181,24 +182,24 @@
         "doSomething A",
         "doSomething B",
         "doSomething C",
+        "Close C",
         "Close B",
-        "Exception in close C",
-        "Suppressed: Exception in close A"
+        "Close A",
+        "ExceptionOnClose in C",
+        "Suppressed: ExceptionOnClose in A"
     );
 
     log.clear();
-    try (Resource rA = new Resource("A");
-        Resource rB = new ResourceWithExceptionOnClose("B");
+    try (
+        Resource rA = new Resource("A");
+        Resource rB = new Resource("B", ThrowsWhen.ONCLOSE);
         Resource rC = new Resource("C")) {
 
       rA.doSomething();
       rB.throwException("E1 here");
       rC.doSomething();
     } catch (Exception e) {
-      log.add(e.getMessage());
-      for (Throwable t : e.getSuppressed()) {
-        log.add("Suppressed: " + t.getMessage());
-      }
+      logException(e);
     } finally {
       log.add("finally");
     }
@@ -209,13 +210,37 @@
         "Open C",
         "doSomething A",
         "Close C",
+        "Close B",
         "Close A",
         "E1 here in B",
-        "Suppressed: Exception in close B",
+        "Suppressed: ExceptionOnClose in B",
         "finally"
     );
   }
 
+  public void testTryWithResources_exceptionInAcquisition() {
+    log.clear();
+    try (
+        Resource rA = new Resource("A", ThrowsWhen.ONCLOSE);
+        Resource rB = new Resource("B", ThrowsWhen.ONCONSTRUCTOR);
+        Resource rC = new Resource("C", ThrowsWhen.ONCLOSE)) {
+
+      rA.doSomething();
+      rB.doSomething();
+      rC.doSomething();
+    } catch (Exception e) {
+      logException(e);
+    }
+
+    assertContentsInOrder(log,
+        "Open A",
+        "Open B",
+        "Close A",
+        "ExceptionOnConstructor in B",
+        "Suppressed: ExceptionOnClose in A"
+    );
+  }
+
   public void testAddSuppressedExceptions() {
     Throwable throwable = new Throwable("primary");
     assertNotNull(throwable.getSuppressed());
@@ -231,17 +256,6 @@
     assertEquals(suppressed2, throwable.getSuppressed()[1]);
   }
 
-  private void assertContentsInOrder(Iterable<String> contents, String... elements) {
-    int sz = elements.length;
-    Iterator<String> it = contents.iterator();
-    for (int i = 0; i < sz; i++) {
-      assertTrue(it.hasNext());
-      String expected = it.next();
-      assertEquals(elements[i], expected);
-    }
-    assertFalse(it.hasNext());
-  }
-
   static class E1 extends Exception {
     String name;
     public E1(String name) {
@@ -347,4 +361,8 @@
       // Expected.
     }
   }
+
+  private void assertContentsInOrder(Iterable<String> contents, String... elements) {
+    assertEquals(Arrays.asList(elements).toString(), contents.toString());
+  }
 }