Skip to content

Transform/private to static #207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Nov 9, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ class Compiler {
List(new Erasure),
List(new CapturedVars,
new Constructors),
List(new LambdaLift)
List(new LambdaLift,
new Flatten,
new RestoreScopes),
List(new PrivateToStatic)
)

var runId = 1
Expand Down
15 changes: 0 additions & 15 deletions src/dotty/tools/dotc/Flatten.scala

This file was deleted.

7 changes: 7 additions & 0 deletions src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,11 @@ object Trees {
s
}

/** If this is a thicket, gerform `op` on each of its trees
* otherwise, perform `op` ion tree itself.
*/
def foreachInThicket(op: Tree[T] => Unit): Unit = op(this)

override def toText(printer: Printer) = printer.toText(this)

override def hashCode(): Int = System.identityHashCode(this)
Expand Down Expand Up @@ -809,6 +814,8 @@ object Trees {
val newTrees = trees.map(_.withPos(pos))
new Thicket[T](newTrees).asInstanceOf[this.type]
}
override def foreachInThicket(op: Tree[T] => Unit): Unit =
trees foreach (_.foreachInThicket(op))
}

class EmptyValDef[T >: Untyped] extends ValDef[T](
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case _ =>
false
}
try test
try test || tp.symbol.is(JavaStatic)
catch { // See remark in SymDenotations#accessWithin
case ex: NotDefinedHere => test(ctx.addMode(Mode.FutureDefsOK))
}
Expand Down
3 changes: 3 additions & 0 deletions src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,9 @@ object Flags {
/** Labeled `private` or `final` */
final val PrivateOrFinal = Private | Final

/** A private method */
final val PrivateMethod = allOf(Private, Method)

/** A type parameter with synthesized name */
final val ExpandedTypeParam = allOf(ExpandedName, TypeParam)

Expand Down
6 changes: 4 additions & 2 deletions src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
override def nameString(name: Name): String = name.decode.toString

override protected def simpleNameString(sym: Symbol): String =
sym.originalName.decode.toString
sym.name.decode.toString

override protected def fullNameOwner(sym: Symbol) = {
val owner = super.fullNameOwner(sym)
Expand Down Expand Up @@ -222,7 +222,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
"`" ~ toText(id.name) ~ "`"
case Ident(name) =>
tree.typeOpt match {
case tp: NamedType if name != nme.WILDCARD => toTextPrefix(tp.prefix) ~ selectionString(tp)
case tp: NamedType if name != nme.WILDCARD =>
val pre = if (tp.symbol is JavaStatic) tp.prefix.widen else tp.prefix
toTextPrefix(pre) ~ selectionString(tp)
case _ => toText(name)
}
case tree @ Select(qual, name) =>
Expand Down
49 changes: 49 additions & 0 deletions src/dotty/tools/dotc/transform/Flatten.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package dotty.tools.dotc
package transform

import core._
import DenotTransformers.SymTransformer
import Phases.Phase
import Contexts.Context
import Flags._
import SymUtils._
import SymDenotations.SymDenotation
import collection.mutable
import TreeTransforms.MiniPhaseTransform
import dotty.tools.dotc.transform.TreeTransforms.TransformerInfo

class Flatten extends MiniPhaseTransform with SymTransformer { thisTransform =>
import ast.tpd._
override def phaseName = "flatten"

def transformSym(ref: SymDenotation)(implicit ctx: Context) = {
if (ref.isClass && !ref.is(Package) && !ref.owner.is(Package)) {
ref.copySymDenotation(
name = ref.flatName,
owner = ref.enclosingPackageClass)
}
else ref
}

override def treeTransformPhase = thisTransform.next

private val liftedDefs = new mutable.ListBuffer[Tree]

private def liftIfNested(tree: Tree)(implicit ctx: Context, info: TransformerInfo) =
if (ctx.owner is Package) tree
else {
transformFollowing(tree).foreachInThicket(liftedDefs += _)
EmptyTree
}

override def transformStats(stats: List[Tree])(implicit ctx: Context, info: TransformerInfo) =
if (ctx.owner is Package) {
val liftedStats = stats ++ liftedDefs
liftedDefs.clear
liftedStats
}
else stats

override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) =
liftIfNested(tree)
}
33 changes: 17 additions & 16 deletions src/dotty/tools/dotc/transform/LambdaLift.scala
Original file line number Diff line number Diff line change
Expand Up @@ -278,20 +278,20 @@ class LambdaLift extends MiniPhaseTransform with IdentityDenotTransformer { this
}
}

override def init(implicit ctx: Context, info: TransformerInfo) = {
free.clear()
proxyMap.clear()
called.clear()
calledFromInner.clear()
liftedOwner.clear()
liftedDefs.clear()
assert(ctx.phase == thisTransform)
(new CollectDependencies).traverse(NoSymbol, ctx.compilationUnit.tpdTree)
computeFreeVars()
computeLiftedOwners()
generateProxies()(ctx.withPhase(thisTransform.next))
liftLocals()(ctx.withPhase(thisTransform.next))
}
override def init(implicit ctx: Context, info: TransformerInfo) =
ctx.atPhase(thisTransform) { implicit ctx =>
free.clear()
proxyMap.clear()
called.clear()
calledFromInner.clear()
liftedOwner.clear()
liftedDefs.clear()
(new CollectDependencies).traverse(NoSymbol, ctx.compilationUnit.tpdTree)
computeFreeVars()
computeLiftedOwners()
generateProxies()(ctx.withPhase(thisTransform.next))
liftLocals()(ctx.withPhase(thisTransform.next))
}

private def currentEnclosure(implicit ctx: Context) =
ctx.owner.enclosingMethod.skipConstructor
Expand Down Expand Up @@ -355,8 +355,9 @@ class LambdaLift extends MiniPhaseTransform with IdentityDenotTransformer { this
}
}

private def liftDef(tree: MemberDef)(implicit ctx: Context): Tree = {
liftedDefs(tree.symbol.owner) += rename(tree, tree.symbol.name)
private def liftDef(tree: MemberDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
val buf = liftedDefs(tree.symbol.owner)
transformFollowing(rename(tree, tree.symbol.name)).foreachInThicket(buf += _)
EmptyTree
}

Expand Down
97 changes: 97 additions & 0 deletions src/dotty/tools/dotc/transform/PrivateToStatic.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
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) || 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)(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't rhs be also transformed to use new argument instead of this in the similar way how tailrec and extensionMethods does it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've got it. You are doing it already and you don't need handling of complicated types as you are after erasure.

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

/** 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) =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get what's happening here. Could you please include documentation for this method?

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
}
}
}
36 changes: 36 additions & 0 deletions src/dotty/tools/dotc/transform/RestoreScopes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package dotty.tools.dotc
package transform

import core._
import DenotTransformers.IdentityDenotTransformer
import Contexts.Context
import Symbols._
import Scopes._
import collection.mutable
import TreeTransforms.MiniPhaseTransform
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 RestoreScopes extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
import ast.tpd._
override def phaseName = "restoreScopes"

override def treeTransformPhase = thisTransform.next

override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) = {
val TypeDef(_, _, Template(constr, _, _, body)) = tree
val restoredDecls = newScope
for (stat <- constr :: body)
if (stat.isInstanceOf[MemberDef] && stat.symbol.exists)
restoredDecls.enter(stat.symbol)
val cinfo = tree.symbol.asClass.classInfo
tree.symbol.copySymDenotation(
info = cinfo.derivedClassInfo( // Dotty deviation: Cannot expand cinfo inline without a type error
decls = restoredDecls: Scope)).installAfter(thisTransform)
tree
}
}
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/SuperAccessors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this
val body1 = forwardParamAccessors(transformStats(impl.body, tree.symbol))
accDefs -= currentClass
ownStats ++= body1
cpy.Template(impl)(body = body1)
cpy.Template(impl)(body = ownStats.toList)
}
transformTemplate

Expand Down
7 changes: 6 additions & 1 deletion src/dotty/tools/dotc/transform/SymUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import core._
import Types._
import Contexts._
import Symbols._
import SymDenotations._
import Decorators._
import Names._
import StdNames._
Expand All @@ -13,7 +14,8 @@ import Flags._
import language.implicitConversions

object SymUtils {
implicit def decorateSymUtils(sym: Symbol): SymUtils = new SymUtils(sym)
implicit def decorateSymbol(sym: Symbol): SymUtils = new SymUtils(sym)
implicit def decorateSymDenot(d: SymDenotation): SymUtils = new SymUtils(d.symbol)
}

/** A decorator that provides methods on symbols
Expand Down Expand Up @@ -64,4 +66,7 @@ class SymUtils(val self: Symbol) extends AnyVal {

def field(implicit ctx: Context): Symbol =
self.owner.info.decl(self.asTerm.name.fieldName).suchThat(!_.is(Method)).symbol

/** `fullName` where `$' is the separator character */
def flatName(implicit ctx: Context): Name = self.fullNameSeparated('$')
}
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ class TreeChecker {
override def typedStats(trees: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {
for (tree <- trees) tree match {
case tree: untpd.DefTree => checkOwner(tree)
case _: untpd.Thicket => assert(false, "unexpanded thicket in statement sequence")
case _: untpd.Thicket => assert(false, i"unexpanded thicket $tree in statement sequence $trees%\n%")
case _ =>
}
super.typedStats(trees, exprOwner)
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ trait Applications extends Compatibility { self: Typer =>

val result = {
var typedArgs = typedArgBuf.toList
val app0 = cpy.Apply(app)(normalizedFun, typedArgs)
def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later
val app1 =
if (!success) app0.withType(ErrorType)
else {
Expand Down
2 changes: 1 addition & 1 deletion test/dotc/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class tests extends CompilerTest {

implicit val defaultOptions = noCheckOptions ++ List(
"-Yno-deep-subtypes",
"-Ycheck:patternMatcher,gettersSetters,lambdaLift"
"-Ycheck:patternMatcher,gettersSetters,restoreScopes"
)

val twice = List("#runs", "2", "-YnoDoubleBindings")
Expand Down
Loading