aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/transform/PrivateToStatic.scala
blob: 17f17685568f8ef203cefbc26dfaff4d4430f58c (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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package dotty.tools.dotc
package transform

import core._
import DenotTransformers.SymTransformer
import Contexts.Context
import Symbols._
import Scopes._
import Flags._
import StdNames._
import SymDenotations._
import Types._
import collection.mutable
import TreeTransforms._
import Decorators._
import ast.Trees._
import TreeTransforms.TransformerInfo

/** The preceding lambda lift and flatten phases move symbols to different scopes
 *  and rename them. This miniphase cleans up afterwards and makes sure that all
 *  class scopes contain the symbols defined in them.
 */
class PrivateToStatic extends MiniPhase with SymTransformer { thisTransform =>
  import ast.tpd._
  override def phaseName = "privateToStatic"
  override def relaxedTyping = true

  private val Immovable = Deferred | Accessor | JavaStatic

  def shouldBeStatic(sd: SymDenotation)(implicit ctx: Context) =
    sd.current(ctx.withPhase(thisTransform)).asInstanceOf[SymDenotation]
      .is(PrivateMethod, butNot = Immovable) &&
    (sd.owner.is(Trait) || sd.is(NotJavaPrivate))

  override def transformSym(sd: SymDenotation)(implicit ctx: Context): SymDenotation =
    if (shouldBeStatic(sd)) {
      val mt @ MethodType(pnames, ptypes) = sd.info
      sd.copySymDenotation(
        initFlags = sd.flags | JavaStatic,
        info = MethodType(nme.SELF :: pnames, sd.owner.thisType :: ptypes, mt.resultType))
    }
    else sd

  val treeTransform = new Transform(NoSymbol)

  class Transform(thisParam: Symbol) extends TreeTransform {
    def phase = thisTransform
    override def treeTransformPhase = thisTransform.next

    override def prepareForDefDef(tree: DefDef)(implicit ctx: Context) =
      if (shouldBeStatic(tree.symbol)) {
        val selfParam = ctx.newSymbol(tree.symbol, nme.SELF, Param, tree.symbol.owner.thisType, coord = tree.pos)
        new Transform(selfParam)
      }
      else this

    override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo) =
      if (shouldBeStatic(tree.symbol)) {
        val thisParamDef = ValDef(thisParam.asTerm)
        val vparams :: Nil = tree.vparamss
        cpy.DefDef(tree)(
          mods = tree.mods | JavaStatic,
          vparamss = (thisParamDef :: vparams) :: Nil)
      }
      else tree

    override def transformThis(tree: This)(implicit ctx: Context, info: TransformerInfo) =
      if (shouldBeStatic(ctx.owner.enclosingMethod)) ref(thisParam).withPos(tree.pos)
      else tree

    override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) =
      tree.fun match {
        case fun @ Select(qual, name) if shouldBeStatic(fun.symbol) =>
          println(i"mapping $tree to ${cpy.Ident(fun)(name)} (${qual :: tree.args}%, %)")
          cpy.Apply(tree)(ref(fun.symbol).withPos(fun.pos), qual :: tree.args)
        case _ =>
          tree
      }

    override def transformClosure(tree: Closure)(implicit ctx: Context, info: TransformerInfo) =
      tree.meth match {
        case meth @ Select(qual, name) if shouldBeStatic(meth.symbol) =>
          cpy.Closure(tree)(
            env = qual :: tree.env,
            meth = ref(meth.symbol).withPos(meth.pos))
        case _ =>
          tree
    }
  }
}