Skip to content

Commit b570776

Browse files
authored
Merge pull request #4872 from abeln/lift-try
Fix #4866: do not lift try with no catch block
2 parents cc3bec1 + a0a1c8f commit b570776

File tree

4 files changed

+41
-1
lines changed

4 files changed

+41
-1
lines changed

compiler/src/dotty/tools/dotc/transform/LiftTry.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ import util.Store
2020
* is lifted to
2121
*
2222
* { def liftedTree$n() = try body catch handler; liftedTree$n() }
23+
*
24+
* However, don't lift try's without catch expressions (try-finally).
25+
* Lifting is needed only for try-catch expressions that are evaluated in a context
26+
* where the stack might not be empty. `finally` does not attempt to continue evaluation
27+
* after an exception, so the fact that values on the stack are 'lost' does not matter
28+
* (copied from https://github.com/scala/scala/pull/922).
2329
*/
2430
class LiftTry extends MiniPhase with IdentityDenotTransformer { thisPhase =>
2531
import ast.tpd._
@@ -58,7 +64,7 @@ class LiftTry extends MiniPhase with IdentityDenotTransformer { thisPhase =>
5864
liftingCtx(false)
5965

6066
override def transformTry(tree: Try)(implicit ctx: Context): Tree =
61-
if (needLift) {
67+
if (needLift && tree.cases.nonEmpty) {
6268
ctx.debuglog(i"lifting tree at ${tree.pos}, current owner = ${ctx.owner}")
6369
val fn = ctx.newSymbol(
6470
ctx.owner, LiftedTreeName.fresh(), Synthetic | Method,

tests/run/i1692.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ class LazyNullable(a: => Int) {
1212

1313
private[this] val d = "D"
1414
lazy val l3 = d + d // null out d (Scalac require single use?)
15+
16+
private [this] val e = "E"
17+
lazy val l4 = try e finally () // null out e
1518
}
1619

1720
object LazyNullable2 {
@@ -47,6 +50,10 @@ class LazyNotNullable {
4750
class Inner {
4851
lazy val l8 = h
4952
}
53+
54+
private[this] val i = "I"
55+
// not nullable because try is lifted, so i is used outside lazy val initializer
56+
lazy val l9 = try i catch { case e: Exception => () }
5057
}
5158

5259
trait LazyTrait {
@@ -87,6 +94,9 @@ object Test {
8794
assert(lz.l3 == "DD")
8895
assertNull("d")
8996

97+
assert(lz.l4 == "E")
98+
assertNull("e")
99+
90100
assert(LazyNullable2.l0 == "A")
91101
assert(readField("a", LazyNullable2) == null)
92102
}
@@ -124,6 +134,9 @@ object Test {
124134
assert(inner.l8 == "H")
125135
assertNotNull("LazyNotNullable$$h") // fragile: test will break if compiler generated names change
126136

137+
assert(lz.l9 == "I")
138+
assertNotNull("i")
139+
127140
val fromTrait = new LazyTrait {}
128141
assert(fromTrait.l0 == "A")
129142
assert(readField("LazyTrait$$a", fromTrait) != null) // fragile: test will break if compiler generated names change

tests/run/i4866.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Foo #lifted: 0
2+
FooLifted #lifted: 1

tests/run/i4866.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Test that try-finally aren't lifted, but try-catch are.
2+
3+
class Foo {
4+
val field = try 1 finally ()
5+
}
6+
7+
class FooLifted {
8+
val field = try 1 catch { case e: Exception => () } finally ()
9+
}
10+
11+
object Test extends App {
12+
def numLifted(o: Object) = {
13+
def isLifted(m: java.lang.reflect.Method) = m.getName.startsWith("lifted")
14+
o.getClass.getDeclaredMethods.count(isLifted)
15+
}
16+
17+
println("Foo #lifted: " + numLifted(new Foo))
18+
println("FooLifted #lifted: " + numLifted(new FooLifted))
19+
}

0 commit comments

Comments
 (0)