Skip to content

Commit 4180bc3

Browse files
committed
Merge pull request #207 from dotty-staging/transform/privateToStatic
Transform/private to static
2 parents 5eaa143 + 3da5448 commit 4180bc3

19 files changed

+325
-40
lines changed

src/dotty/tools/dotc/Compiler.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ class Compiler {
5555
List(new Erasure),
5656
List(new CapturedVars,
5757
new Constructors),
58-
List(new LambdaLift)
58+
List(new LambdaLift,
59+
new Flatten,
60+
new RestoreScopes),
61+
List(new PrivateToStatic)
5962
)
6063

6164
var runId = 1

src/dotty/tools/dotc/Flatten.scala

-15
This file was deleted.

src/dotty/tools/dotc/ast/Trees.scala

+7
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,11 @@ object Trees {
347347
s
348348
}
349349

350+
/** If this is a thicket, gerform `op` on each of its trees
351+
* otherwise, perform `op` ion tree itself.
352+
*/
353+
def foreachInThicket(op: Tree[T] => Unit): Unit = op(this)
354+
350355
override def toText(printer: Printer) = printer.toText(this)
351356

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

814821
class EmptyValDef[T >: Untyped] extends ValDef[T](

src/dotty/tools/dotc/ast/tpd.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
263263
case _ =>
264264
false
265265
}
266-
try test
266+
try test || tp.symbol.is(JavaStatic)
267267
catch { // See remark in SymDenotations#accessWithin
268268
case ex: NotDefinedHere => test(ctx.addMode(Mode.FutureDefsOK))
269269
}

src/dotty/tools/dotc/core/Flags.scala

+3
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ object Flags {
512512
/** Labeled `private` or `final` */
513513
final val PrivateOrFinal = Private | Final
514514

515+
/** A private method */
516+
final val PrivateMethod = allOf(Private, Method)
517+
515518
/** A type parameter with synthesized name */
516519
final val ExpandedTypeParam = allOf(ExpandedName, TypeParam)
517520

src/dotty/tools/dotc/printing/RefinedPrinter.scala

+4-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
3636
override def nameString(name: Name): String = name.decode.toString
3737

3838
override protected def simpleNameString(sym: Symbol): String =
39-
sym.originalName.decode.toString
39+
sym.name.decode.toString
4040

4141
override protected def fullNameOwner(sym: Symbol) = {
4242
val owner = super.fullNameOwner(sym)
@@ -222,7 +222,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
222222
"`" ~ toText(id.name) ~ "`"
223223
case Ident(name) =>
224224
tree.typeOpt match {
225-
case tp: NamedType if name != nme.WILDCARD => toTextPrefix(tp.prefix) ~ selectionString(tp)
225+
case tp: NamedType if name != nme.WILDCARD =>
226+
val pre = if (tp.symbol is JavaStatic) tp.prefix.widen else tp.prefix
227+
toTextPrefix(pre) ~ selectionString(tp)
226228
case _ => toText(name)
227229
}
228230
case tree @ Select(qual, name) =>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import DenotTransformers.SymTransformer
6+
import Phases.Phase
7+
import Contexts.Context
8+
import Flags._
9+
import SymUtils._
10+
import SymDenotations.SymDenotation
11+
import collection.mutable
12+
import TreeTransforms.MiniPhaseTransform
13+
import dotty.tools.dotc.transform.TreeTransforms.TransformerInfo
14+
15+
class Flatten extends MiniPhaseTransform with SymTransformer { thisTransform =>
16+
import ast.tpd._
17+
override def phaseName = "flatten"
18+
19+
def transformSym(ref: SymDenotation)(implicit ctx: Context) = {
20+
if (ref.isClass && !ref.is(Package) && !ref.owner.is(Package)) {
21+
ref.copySymDenotation(
22+
name = ref.flatName,
23+
owner = ref.enclosingPackageClass)
24+
}
25+
else ref
26+
}
27+
28+
override def treeTransformPhase = thisTransform.next
29+
30+
private val liftedDefs = new mutable.ListBuffer[Tree]
31+
32+
private def liftIfNested(tree: Tree)(implicit ctx: Context, info: TransformerInfo) =
33+
if (ctx.owner is Package) tree
34+
else {
35+
transformFollowing(tree).foreachInThicket(liftedDefs += _)
36+
EmptyTree
37+
}
38+
39+
override def transformStats(stats: List[Tree])(implicit ctx: Context, info: TransformerInfo) =
40+
if (ctx.owner is Package) {
41+
val liftedStats = stats ++ liftedDefs
42+
liftedDefs.clear
43+
liftedStats
44+
}
45+
else stats
46+
47+
override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) =
48+
liftIfNested(tree)
49+
}

src/dotty/tools/dotc/transform/LambdaLift.scala

+17-16
Original file line numberDiff line numberDiff line change
@@ -278,20 +278,20 @@ class LambdaLift extends MiniPhaseTransform with IdentityDenotTransformer { this
278278
}
279279
}
280280

281-
override def init(implicit ctx: Context, info: TransformerInfo) = {
282-
free.clear()
283-
proxyMap.clear()
284-
called.clear()
285-
calledFromInner.clear()
286-
liftedOwner.clear()
287-
liftedDefs.clear()
288-
assert(ctx.phase == thisTransform)
289-
(new CollectDependencies).traverse(NoSymbol, ctx.compilationUnit.tpdTree)
290-
computeFreeVars()
291-
computeLiftedOwners()
292-
generateProxies()(ctx.withPhase(thisTransform.next))
293-
liftLocals()(ctx.withPhase(thisTransform.next))
294-
}
281+
override def init(implicit ctx: Context, info: TransformerInfo) =
282+
ctx.atPhase(thisTransform) { implicit ctx =>
283+
free.clear()
284+
proxyMap.clear()
285+
called.clear()
286+
calledFromInner.clear()
287+
liftedOwner.clear()
288+
liftedDefs.clear()
289+
(new CollectDependencies).traverse(NoSymbol, ctx.compilationUnit.tpdTree)
290+
computeFreeVars()
291+
computeLiftedOwners()
292+
generateProxies()(ctx.withPhase(thisTransform.next))
293+
liftLocals()(ctx.withPhase(thisTransform.next))
294+
}
295295

296296
private def currentEnclosure(implicit ctx: Context) =
297297
ctx.owner.enclosingMethod.skipConstructor
@@ -355,8 +355,9 @@ class LambdaLift extends MiniPhaseTransform with IdentityDenotTransformer { this
355355
}
356356
}
357357

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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import DenotTransformers.SymTransformer
6+
import Contexts.Context
7+
import Symbols._
8+
import Scopes._
9+
import Flags._
10+
import StdNames._
11+
import SymDenotations._
12+
import Types._
13+
import collection.mutable
14+
import TreeTransforms._
15+
import Decorators._
16+
import ast.Trees._
17+
import TreeTransforms.TransformerInfo
18+
19+
/** Makes private methods static, provided they not deferred, accessors, or static,
20+
* by rewriting a method `m` in class `C` as follows:
21+
*
22+
* private def m(ps) = e
23+
*
24+
* --> private static def($this: C, ps) = [this -> $this] e
25+
*/
26+
class PrivateToStatic extends MiniPhase with SymTransformer { thisTransform =>
27+
import ast.tpd._
28+
override def phaseName = "privateToStatic"
29+
override def relaxedTyping = true
30+
31+
private val Immovable = Deferred | Accessor | JavaStatic
32+
33+
def shouldBeStatic(sd: SymDenotation)(implicit ctx: Context) =
34+
sd.current(ctx.withPhase(thisTransform)).asSymDenotation
35+
.is(PrivateMethod, butNot = Immovable) &&
36+
(sd.owner.is(Trait) || sd.is(NotJavaPrivate))
37+
38+
override def transformSym(sd: SymDenotation)(implicit ctx: Context): SymDenotation =
39+
if (shouldBeStatic(sd)) {
40+
val mt @ MethodType(pnames, ptypes) = sd.info
41+
sd.copySymDenotation(
42+
initFlags = sd.flags | JavaStatic,
43+
info = MethodType(nme.SELF :: pnames, sd.owner.thisType :: ptypes, mt.resultType))
44+
}
45+
else sd
46+
47+
val treeTransform = new Transform(NoSymbol)
48+
49+
class Transform(thisParam: Symbol) extends TreeTransform {
50+
def phase = thisTransform
51+
override def treeTransformPhase = thisTransform.next
52+
53+
override def prepareForDefDef(tree: DefDef)(implicit ctx: Context) =
54+
if (shouldBeStatic(tree.symbol)) {
55+
val selfParam = ctx.newSymbol(tree.symbol, nme.SELF, Param, tree.symbol.owner.thisType, coord = tree.pos)
56+
new Transform(selfParam)
57+
}
58+
else this
59+
60+
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo) =
61+
if (shouldBeStatic(tree.symbol)) {
62+
val thisParamDef = ValDef(thisParam.asTerm)
63+
val vparams :: Nil = tree.vparamss
64+
cpy.DefDef(tree)(
65+
mods = tree.mods | JavaStatic,
66+
vparamss = (thisParamDef :: vparams) :: Nil)
67+
}
68+
else tree
69+
70+
override def transformThis(tree: This)(implicit ctx: Context, info: TransformerInfo) =
71+
if (shouldBeStatic(ctx.owner.enclosingMethod)) ref(thisParam).withPos(tree.pos)
72+
else tree
73+
74+
/** Rwrites a call to a method `m` which is made static as folows:
75+
*
76+
* qual.m(args) --> m(qual, args)
77+
*/
78+
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) =
79+
tree.fun match {
80+
case fun @ Select(qual, name) if shouldBeStatic(fun.symbol) =>
81+
ctx.debuglog(i"mapping $tree to ${cpy.Ident(fun)(name)} (${qual :: tree.args}%, %)")
82+
cpy.Apply(tree)(ref(fun.symbol).withPos(fun.pos), qual :: tree.args)
83+
case _ =>
84+
tree
85+
}
86+
87+
override def transformClosure(tree: Closure)(implicit ctx: Context, info: TransformerInfo) =
88+
tree.meth match {
89+
case meth @ Select(qual, name) if shouldBeStatic(meth.symbol) =>
90+
cpy.Closure(tree)(
91+
env = qual :: tree.env,
92+
meth = ref(meth.symbol).withPos(meth.pos))
93+
case _ =>
94+
tree
95+
}
96+
}
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import DenotTransformers.IdentityDenotTransformer
6+
import Contexts.Context
7+
import Symbols._
8+
import Scopes._
9+
import collection.mutable
10+
import TreeTransforms.MiniPhaseTransform
11+
import ast.Trees._
12+
import TreeTransforms.TransformerInfo
13+
14+
/** The preceding lambda lift and flatten phases move symbols to different scopes
15+
* and rename them. This miniphase cleans up afterwards and makes sure that all
16+
* class scopes contain the symbols defined in them.
17+
*/
18+
class RestoreScopes extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
19+
import ast.tpd._
20+
override def phaseName = "restoreScopes"
21+
22+
override def treeTransformPhase = thisTransform.next
23+
24+
override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) = {
25+
val TypeDef(_, _, Template(constr, _, _, body)) = tree
26+
val restoredDecls = newScope
27+
for (stat <- constr :: body)
28+
if (stat.isInstanceOf[MemberDef] && stat.symbol.exists)
29+
restoredDecls.enter(stat.symbol)
30+
val cinfo = tree.symbol.asClass.classInfo
31+
tree.symbol.copySymDenotation(
32+
info = cinfo.derivedClassInfo( // Dotty deviation: Cannot expand cinfo inline without a type error
33+
decls = restoredDecls: Scope)).installAfter(thisTransform)
34+
tree
35+
}
36+
}

src/dotty/tools/dotc/transform/SuperAccessors.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this
295295
val body1 = forwardParamAccessors(transformStats(impl.body, tree.symbol))
296296
accDefs -= currentClass
297297
ownStats ++= body1
298-
cpy.Template(impl)(body = body1)
298+
cpy.Template(impl)(body = ownStats.toList)
299299
}
300300
transformTemplate
301301

src/dotty/tools/dotc/transform/SymUtils.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import core._
55
import Types._
66
import Contexts._
77
import Symbols._
8+
import SymDenotations._
89
import Decorators._
910
import Names._
1011
import StdNames._
@@ -13,7 +14,8 @@ import Flags._
1314
import language.implicitConversions
1415

1516
object SymUtils {
16-
implicit def decorateSymUtils(sym: Symbol): SymUtils = new SymUtils(sym)
17+
implicit def decorateSymbol(sym: Symbol): SymUtils = new SymUtils(sym)
18+
implicit def decorateSymDenot(d: SymDenotation): SymUtils = new SymUtils(d.symbol)
1719
}
1820

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

6567
def field(implicit ctx: Context): Symbol =
6668
self.owner.info.decl(self.asTerm.name.fieldName).suchThat(!_.is(Method)).symbol
69+
70+
/** `fullName` where `$' is the separator character */
71+
def flatName(implicit ctx: Context): Name = self.fullNameSeparated('$')
6772
}

src/dotty/tools/dotc/transform/TreeChecker.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ class TreeChecker {
180180
override def typedStats(trees: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {
181181
for (tree <- trees) tree match {
182182
case tree: untpd.DefTree => checkOwner(tree)
183-
case _: untpd.Thicket => assert(false, "unexpanded thicket in statement sequence")
183+
case _: untpd.Thicket => assert(false, i"unexpanded thicket $tree in statement sequence $trees%\n%")
184184
case _ =>
185185
}
186186
super.typedStats(trees, exprOwner)

src/dotty/tools/dotc/typer/Applications.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ trait Applications extends Compatibility { self: Typer =>
461461

462462
val result = {
463463
var typedArgs = typedArgBuf.toList
464-
val app0 = cpy.Apply(app)(normalizedFun, typedArgs)
464+
def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later
465465
val app1 =
466466
if (!success) app0.withType(ErrorType)
467467
else {

test/dotc/tests.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class tests extends CompilerTest {
1515

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

2121
val twice = List("#runs", "2", "-YnoDoubleBindings")

0 commit comments

Comments
 (0)