Skip to content

Commit 0089217

Browse files
committed
PostTyper transformers
1) reorders companion objects so that they allways follow matching classes 2) removes imports and named arguments 3) rewrites all trees holding types are to TypeTrees
1 parent 29d2d29 commit 0089217

File tree

3 files changed

+181
-1
lines changed

3 files changed

+181
-1
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
278278
*/
279279
def ModuleDef(sym: TermSymbol, body: List[Tree])(implicit ctx: Context): tpd.Thicket = {
280280
val modcls = sym.moduleClass.asClass
281-
val constr = DefDef(modcls.primaryConstructor.asTerm, EmptyTree)
281+
val constrSym = modcls.primaryConstructor orElse ctx.newDefaultConstructor(modcls).entered
282+
val constr = DefDef(constrSym.asTerm, EmptyTree)
282283
val clsdef = ClassDef(modcls, constr, body)
283284
val valdef = ValDef(sym, New(modcls.typeRef))
284285
Thicket(valdef, clsdef)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package dotty.tools.dotc.transform
2+
3+
import dotty.tools.dotc.core._
4+
import Symbols._
5+
import scala.Some
6+
import dotty.tools.dotc.transform.TreeTransforms.{NXTransformations, TransformerInfo, TreeTransform, TreeTransformer}
7+
import dotty.tools.dotc.ast.tpd
8+
import dotty.tools.dotc.core.Contexts.Context
9+
import scala.collection.mutable
10+
import dotty.tools.dotc.core.Names.Name
11+
import NameOps._
12+
13+
object PostTyperTransformers {
14+
15+
import tpd.{TreeTransformer => _, _}
16+
17+
18+
/** A trait that's assumed by the transformers that run right after typer.
19+
* Ensures that trees are normalized when seen by other transforms. This means:
20+
* (1) All module class definitions appear after their companion class definitions
21+
* (2) There are no import clauses or named arguments
22+
* (3) All trees designating types are instances of TypeTree
23+
*/
24+
abstract class PostTyperTransformer extends TreeTransformer {
25+
26+
/** Reorder statements so that module classes always come after their companion classes, add missing companion classes */
27+
def reorder(stats: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] = {
28+
val moduleClassDefs = mutable.Map[Name, Tree]()
29+
def reorder0(stats: List[Tree]): List[Tree] = {
30+
stats match {
31+
case (stat: TypeDef) :: stats1 if stat.symbol.isClass =>
32+
if (stat.symbol is Flags.Module) {
33+
moduleClassDefs += (stat.name -> stat)
34+
val stats1r = reorder0(stats1)
35+
if (moduleClassDefs contains stat.name) stat :: stats1r else stats1r
36+
}
37+
else {
38+
val mclsName = stat.name.moduleClassName
39+
moduleClassDefs remove mclsName match {
40+
case Some(mcdef) => stat :: mcdef :: reorder0(stats1)
41+
case None => stat :: reorder0(stats1)
42+
}
43+
}
44+
case stat :: stats1 => stat :: reorder0(stats1)
45+
case Nil => Nil
46+
}
47+
}
48+
reorder0(stats)
49+
}
50+
51+
override def transformStats(trees: List[tpd.Tree], info: TransformerInfo, current: Int)(implicit ctx: Context): List[tpd.Tree] =
52+
super.transformStats(reorder(trees)(ctx, info), info, current)
53+
54+
override def transform(tree: tpd.Tree, info: TransformerInfo, cur: Int)(implicit ctx: Context): tpd.Tree = tree match {
55+
case tree: Import => EmptyTree
56+
case tree: NamedArg => super.transform(tree.arg, info, cur)
57+
case tree: TypeTree => super.transform(tree, info, cur)
58+
case tree => super.transform(if (tree.isType) TypeTree(tree.tpe) else tree, info, cur)
59+
}
60+
}
61+
62+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package test.transform
2+
3+
4+
import org.junit.{Assert, Test}
5+
import test.DottyTest
6+
import dotty.tools.dotc.core._
7+
import dotty.tools.dotc.ast.Trees
8+
import Contexts._
9+
import Flags._
10+
import Denotations._
11+
import NameOps._
12+
import Symbols._
13+
import Types._
14+
import Decorators._
15+
import Trees._
16+
import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer}
17+
import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer
18+
19+
class PostTyperTransformerTest extends DottyTest {
20+
21+
@Test
22+
def shouldStripImports = checkCompile("frontend", "class A{ import scala.collection.mutable._; val d = 1}") {
23+
(tree, context) =>
24+
implicit val ctx = context
25+
class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
26+
val transformer = new PostTyperTransformer {
27+
override def transformations = Array(new EmptyTransform(_, _))
28+
29+
override def name: String = "test"
30+
}
31+
val transformed = transformer.transform(tree)
32+
33+
Assert.assertTrue("should strip imports",
34+
!transformed.toString.toLowerCase.contains("import")
35+
)
36+
}
37+
38+
@Test
39+
def shouldStripNamedArgs = checkCompile("frontend", "class A{ def p(x:Int, y:Int= 2) = 1; p(1, y = 2)}") {
40+
(tree, context) =>
41+
implicit val ctx = context
42+
class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
43+
val transformer = new PostTyperTransformer {
44+
override def transformations = Array(new EmptyTransform(_, _))
45+
46+
override def name: String = "test"
47+
}
48+
val transformed = transformer.transform(tree)
49+
50+
Assert.assertTrue("should string named arguments",
51+
!transformed.toString.contains("NamedArg")
52+
)
53+
}
54+
55+
@Test
56+
def shouldReorderExistingObjectsInPackage = checkCompile("frontend", "object A{}; class A{} ") {
57+
(tree, context) =>
58+
implicit val ctx = context
59+
class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
60+
val transformer = new PostTyperTransformer {
61+
override def transformations = Array(new EmptyTransform(_, _))
62+
63+
override def name: String = "test"
64+
}
65+
val transformed = transformer.transform(tree).toString
66+
val classPattern = "TypeDef(Modifiers(,,List()),A,"
67+
val classPos = transformed.indexOf(classPattern)
68+
val moduleClassPattern = "TypeDef(Modifiers(final module,,List()),A$,"
69+
val modulePos = transformed.indexOf(moduleClassPattern)
70+
71+
Assert.assertTrue("should reorder existing objects in package",
72+
classPos < modulePos
73+
)
74+
}
75+
76+
@Test
77+
def shouldReorderExistingObjectsInBlock = checkCompile("frontend", "class D {def p = {object A{}; class A{}; 1}} ") {
78+
(tree, context) =>
79+
implicit val ctx = context
80+
class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
81+
val transformer = new PostTyperTransformer {
82+
override def transformations = Array(new EmptyTransform(_, _))
83+
84+
override def name: String = "test"
85+
}
86+
val transformed = transformer.transform(tree).toString
87+
val classPattern = "TypeDef(Modifiers(,,List()),A,"
88+
val classPos = transformed.indexOf(classPattern)
89+
val moduleClassPattern = "TypeDef(Modifiers(final module,,List()),A$,"
90+
val modulePos = transformed.indexOf(moduleClassPattern)
91+
92+
Assert.assertTrue("should reorder existing objects in block",
93+
classPos < modulePos
94+
)
95+
}
96+
97+
@Test
98+
def shouldReorderExistingObjectsInTemplate = checkCompile("frontend", "class D {object A{}; class A{}; } ") {
99+
(tree, context) =>
100+
implicit val ctx = context
101+
class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
102+
val transformer = new PostTyperTransformer {
103+
override def transformations = Array(new EmptyTransform(_, _))
104+
105+
override def name: String = "test"
106+
}
107+
val transformed = transformer.transform(tree).toString
108+
val classPattern = "TypeDef(Modifiers(,,List()),A,"
109+
val classPos = transformed.indexOf(classPattern)
110+
val moduleClassPattern = "TypeDef(Modifiers(final module,,List()),A$,"
111+
val modulePos = transformed.indexOf(moduleClassPattern)
112+
113+
Assert.assertTrue("should reorder existing objects in template",
114+
classPos < modulePos
115+
)
116+
}
117+
}

0 commit comments

Comments
 (0)