Skip to content

Commit 21d5b07

Browse files
authored
Merge pull request #7846 from dotty-staging/fix-#7843
Fix #7843: Move LiftTry back to before CapturedVars
2 parents d13efef + 9a9855a commit 21d5b07

File tree

5 files changed

+55
-9
lines changed

5 files changed

+55
-9
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class Compiler {
8383
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods
8484
new Getters, // Replace non-private vals and vars with getter defs (fields are added later)
8585
new ElimByName, // Expand by-name parameter references
86+
new LiftTry, // Put try expressions that might execute on non-empty stacks into their own methods
8687
new CollectNullableFields, // Collect fields that can be nulled out after use in lazy initialization
8788
new ElimOuterSelect, // Expand outer selections
8889
new AugmentScala2Traits, // Augments Scala2 traits with additional members needed for mixin composition.
@@ -105,8 +106,7 @@ class Compiler {
105106
// Note: constructors changes decls in transformTemplate, no InfoTransformers should be added after it
106107
new FunctionalInterfaces, // Rewrites closures to implement @specialized types of Functions.
107108
new Instrumentation, // Count closure allocations under -Yinstrument-closures
108-
new GetClass, // Rewrites getClass calls on primitive types.
109-
new LiftTry) :: // Put try expressions that might execute on non-empty stacks into their own methods their implementations
109+
new GetClass) :: // Rewrites getClass calls on primitive types.
110110
List(new LinkScala2Impls, // Redirect calls to trait methods defined by Scala 2.x, so that they now go to
111111
new LambdaLift, // Lifts out nested functions to class scope, storing free variables in environments
112112
// Note: in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here

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

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisPhase =
2323
/** the following two members override abstract members in Transform */
2424
val phaseName: String = "capturedVars"
2525

26+
override def runsAfterGroupsOf: Set[String] = Set(LiftTry.name)
27+
// lifting tries changes what variables are considered to be captured
28+
2629
private[this] var Captured: Store.Location[collection.Set[Symbol]] = _
2730
private def captured(implicit ctx: Context) = ctx.store(Captured)
2831

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

+12-7
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@ import util.Store
3030
class LiftTry extends MiniPhase with IdentityDenotTransformer { thisPhase =>
3131
import ast.tpd._
3232

33-
val phaseName: String = "liftTry"
34-
35-
// See tests/run/t2333.scala for an example where running after the group of LazyVals matters
36-
override def runsAfterGroupsOf: Set[String] = Set(LazyVals.name)
33+
val phaseName: String = LiftTry.name
3734

3835
private var NeedLift: Store.Location[Boolean] = _
3936
private def needLift(implicit ctx: Context): Boolean = ctx.store(NeedLift)
@@ -48,9 +45,15 @@ class LiftTry extends MiniPhase with IdentityDenotTransformer { thisPhase =>
4845
liftingCtx(true)
4946

5047
override def prepareForValDef(tree: ValDef)(implicit ctx: Context): Context =
51-
if (!tree.symbol.exists ||
52-
tree.symbol.isSelfSym ||
53-
tree.symbol.owner == ctx.owner.enclosingMethod) ctx
48+
if !tree.symbol.exists
49+
|| tree.symbol.isSelfSym
50+
|| tree.symbol.owner == ctx.owner.enclosingMethod
51+
&& !tree.symbol.is(Lazy)
52+
// The current implementation wraps initializers of lazy vals in
53+
// calls to an initialize method, which means that a `try` in the
54+
// initializer needs to be lifted. Note that the new scheme proposed
55+
// in #6979 would avoid this.
56+
then ctx
5457
else liftingCtx(true)
5558

5659
override def prepareForAssign(tree: Assign)(implicit ctx: Context): Context =
@@ -75,3 +78,5 @@ class LiftTry extends MiniPhase with IdentityDenotTransformer { thisPhase =>
7578
}
7679
else tree
7780
}
81+
object LiftTry with
82+
val name = "liftTry"

tests/run/i7843.check

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
done outside try: false
2+
setting done to true
3+
done in catch clause: true
4+
done

tests/run/i7843.scala

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import scala.concurrent._, duration._
2+
3+
object Test {
4+
implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global
5+
val thunkFuture: Future[() => String] = Future.successful(() => throw new RuntimeException("Whoops"))
6+
7+
final def shouldTerminate: Future[Unit] =
8+
thunkFuture.flatMap { thunk =>
9+
def fold() = {
10+
var done = false
11+
while (!done) {
12+
println(s"done outside try: $done")
13+
try {
14+
thunk()
15+
} catch {
16+
case _: Throwable =>
17+
println("setting done to true")
18+
done = true
19+
println(s"done in catch clause: $done")
20+
}
21+
}
22+
}
23+
24+
Future {
25+
fold()
26+
}
27+
}
28+
29+
30+
def main(args: Array[String]): Unit = {
31+
Await.result(shouldTerminate, Duration.Inf)
32+
println("done")
33+
}
34+
}

0 commit comments

Comments
 (0)