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());
+ }
}