Skip to content
This repository was archived by the owner on Jul 12, 2024. It is now read-only.

Commit 3c489e8

Browse files
committed
Fix #101: Interaction between TryFinally and Labeled/Return.
See the big "HERE BE DRAGONS" comment for details.
1 parent bfc35ac commit 3c489e8

File tree

5 files changed

+604
-88
lines changed

5 files changed

+604
-88
lines changed

Diff for: build.sbt

-2
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,6 @@ lazy val IgnoredTestNames: Set[String] = {
236236
"org.scalajs.testsuite.javalib.lang.ThrowableJSTest",
237237
// jsError/jsObject failed: AssertionError because Wasm objects are not instanceof Error/Object
238238
"org.scalajs.testsuite.compiler.RuntimeTypeTestsJSTest",
239-
// keepBreakToLabelWithinFinallyBlock_Issue2689 failed: java.lang.AssertionError: expected:<2> but was:<1>
240-
"org.scalajs.testsuite.compiler.OptimizerTest",
241239
// No support for stack traces
242240
"org.scalajs.testsuite.library.StackTraceTest",
243241
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package testsuite.core
2+
3+
import testsuite.Assert.assertSame
4+
5+
/** Imported from the Scala test case `test/files/run/finally.scala`. */
6+
object TryFinallyReturnTest {
7+
// Simulate a `println` API that we can check afterwards
8+
var printlnOutput: String = ""
9+
10+
def println(x: Any): Unit =
11+
printlnOutput = printlnOutput + x + "\n"
12+
13+
val expectedOutput = raw"""Running throwCatchFinally
14+
hi
15+
In Finally
16+
java.lang.RuntimeException: ouch
17+
----------------------------------------
18+
Running retCatch
19+
java.lang.Exception
20+
in finally
21+
----------------------------------------
22+
Running throwCatch
23+
java.lang.Exception
24+
in finally
25+
CAUGHT: java.lang.Exception
26+
----------------------------------------
27+
Running retBody
28+
in finally
29+
----------------------------------------
30+
Running throwBody
31+
java.lang.Exception
32+
in finally
33+
----------------------------------------
34+
Running retFinally
35+
body
36+
in finally 1
37+
in finally 2
38+
----------------------------------------
39+
Running throwFinally
40+
body
41+
in finally
42+
java.lang.Exception
43+
----------------------------------------
44+
Running nestedFinallyBlocks
45+
in finally 1
46+
in finally 2
47+
----------------------------------------
48+
"""
49+
50+
def main(): Unit = {
51+
test(throwCatchFinally(), "throwCatchFinally")
52+
test(retCatch(), "retCatch")
53+
test(throwCatch(), "throwCatch")
54+
test(retBody(), "retBody")
55+
test(throwBody(), "throwBody")
56+
test(retFinally(), "retFinally")
57+
test(throwFinally(), "throwFinally")
58+
test(nestedFinallyBlocks(), "nestedFinallyBlocks")
59+
60+
assertSame(expectedOutput, printlnOutput)
61+
}
62+
63+
// test that finally is not covered by any exception handlers.
64+
def throwCatchFinally(): Unit = {
65+
try {
66+
bar()
67+
} catch {
68+
case e: Throwable => println(e)
69+
}
70+
}
71+
72+
// test that finally is not covered by any exception handlers.
73+
def bar(): Unit = {
74+
try {
75+
println("hi")
76+
} catch {
77+
case e: Throwable => println("SHOULD NOT GET HERE")
78+
} finally {
79+
println("In Finally")
80+
throw new RuntimeException("ouch")
81+
}
82+
}
83+
84+
// return in catch (finally is executed)
85+
def retCatch(): Unit = {
86+
try {
87+
throw new Exception
88+
} catch {
89+
case e: Throwable =>
90+
println(e);
91+
return
92+
} finally println("in finally")
93+
}
94+
95+
// throw in catch (finally is executed, exception propagated)
96+
def throwCatch(): Unit = {
97+
try {
98+
throw new Exception
99+
} catch {
100+
case e: Throwable =>
101+
println(e);
102+
throw e
103+
} finally println("in finally")
104+
}
105+
106+
// return inside body (finally is executed)
107+
def retBody(): Unit = {
108+
try {
109+
return
110+
} catch {
111+
case e: Throwable =>
112+
println(e);
113+
throw e
114+
} finally println("in finally")
115+
}
116+
117+
// throw inside body (finally and catch are executed)
118+
def throwBody(): Unit = {
119+
try {
120+
throw new Exception
121+
} catch {
122+
case e: Throwable =>
123+
println(e);
124+
} finally println("in finally")
125+
}
126+
127+
// return inside finally (each finally is executed once)
128+
def retFinally(): Unit = {
129+
try {
130+
try println("body")
131+
finally {
132+
println("in finally 1")
133+
return
134+
}
135+
} finally println("in finally 2")
136+
}
137+
138+
// throw inside finally (finally is executed once, exception is propagated)
139+
def throwFinally(): Unit = {
140+
try {
141+
try println("body")
142+
finally {
143+
println("in finally")
144+
throw new Exception
145+
}
146+
} catch {
147+
case e: Throwable => println(e)
148+
}
149+
}
150+
151+
// nested finally blocks with return value
152+
def nestedFinallyBlocks(): Int =
153+
try {
154+
try {
155+
return 10
156+
} finally {
157+
try { () }
158+
catch { case _: Throwable => () }
159+
println("in finally 1")
160+
}
161+
} finally {
162+
println("in finally 2")
163+
}
164+
165+
def test[A](m: => A, name: String): Unit = {
166+
println("Running %s".format(name))
167+
try {
168+
m
169+
} catch {
170+
case e: Throwable => println("CAUGHT: " + e)
171+
}
172+
println("-" * 40)
173+
}
174+
}

Diff for: tests/src/test/scala/tests/TestSuites.scala

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ object TestSuites {
4040
TestSuite("testsuite.core.StaticMethodTest"),
4141
TestSuite("testsuite.core.ThrowAndTryTest"),
4242
TestSuite("testsuite.core.ThrowablesTest"),
43+
TestSuite("testsuite.core.TryFinallyReturnTest"),
4344
TestSuite("testsuite.core.ToStringTest"),
4445
TestSuite("testsuite.core.UnitPatMatTest"),
4546
TestSuite("testsuite.core.MatchTest"),

0 commit comments

Comments
 (0)