aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/LiftTry.scala
blob: d011956146e886e272cf372a7b8ce04a6ca11f55 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package dotty.tools.dotc
package transform

import TreeTransforms._
import core.DenotTransformers._
import core.Symbols._
import core.Contexts._
import core.Types._
import core.Flags._
import core.Decorators._
import NonLocalReturns._

/** Lifts try's that might be executed on non-empty expression stacks
 *  to their own methods. I.e.
 *
 *      try body catch handler
 *
 *  is lifted to
 *
 *      { def liftedTree$n() = try body catch handler; liftedTree$n() }
 */
class LiftTry extends MiniPhase with IdentityDenotTransformer { thisTransform =>
  import ast.tpd._

  /** the following two members override abstract members in Transform */
  val phaseName: String = "liftTry"

  val treeTransform = new Transform(needLift = false)
  val liftingTransform = new Transform(needLift = true)

  class Transform(needLift: Boolean) extends TreeTransform {
    def phase = thisTransform

    override def prepareForApply(tree: Apply)(implicit ctx: Context) =
      if (tree.fun.symbol.is(Label)) this
      else liftingTransform

    override def prepareForValDef(tree: ValDef)(implicit ctx: Context) =
      if (!tree.symbol.exists  ||
          tree.symbol.isSelfSym ||
          tree.symbol.owner == ctx.owner.enclosingMethod) this
      else liftingTransform

    override def prepareForAssign(tree: Assign)(implicit ctx: Context) =
      if (tree.lhs.symbol.maybeOwner == ctx.owner.enclosingMethod) this
      else liftingTransform

    override def prepareForReturn(tree: Return)(implicit ctx: Context) =
      if (!isNonLocalReturn(tree)) this
      else liftingTransform

    override def prepareForTemplate(tree: Template)(implicit ctx: Context) =
      treeTransform

    override def transformTry(tree: Try)(implicit ctx: Context, info: TransformerInfo): Tree =
      if (needLift) {
        ctx.debuglog(i"lifting tree at ${tree.pos}, current owner = ${ctx.owner}")
        val fn = ctx.newSymbol(
          ctx.owner, ctx.freshName("liftedTree").toTermName, Synthetic | Method,
          MethodType(Nil, tree.tpe.widenIfUnstable), coord = tree.pos)
        tree.changeOwnerAfter(ctx.owner, fn, thisTransform)
        Block(DefDef(fn, tree) :: Nil, ref(fn).appliedToNone)
      }
      else tree
  }
}