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
/** Makes private methods static, provided they not deferred, accessors, or static,
* by rewriting a method `m` in class `C` as follows:
*
* private def m(ps) = e
*
* --> private static def($this: C, ps) = [this -> $this] e
*/
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)).asSymDenotation
.is(PrivateMethod, butNot = Immovable) &&
sd.owner.is(Trait)
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 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)(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
/** Rwrites a call to a method `m` which is made static as folows:
*
* qual.m(args) --> m(qual, args)
*/
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) =
tree.fun match {
case fun @ Select(qual, name) if shouldBeStatic(fun.symbol) =>
ctx.debuglog(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
}
}
}