aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Doeraene <sjrdoeraene@gmail.com>2014-03-13 15:50:52 +0100
committerSébastien Doeraene <sjrdoeraene@gmail.com>2014-03-13 15:50:52 +0100
commit9cd9d972c5b92e9c3cbb9f8bd6d591812174a74e (patch)
treee32c15a8d3d2b43f0ffaa030f4f157f3fe728f29
parent194be919664447631ba55446eb4874979c908d27 (diff)
parentb6cb517570e77c2acf4bc6c8b1e83f922e1fd25f (diff)
downloaddotty-9cd9d972c5b92e9c3cbb9f8bd6d591812174a74e.tar.gz
dotty-9cd9d972c5b92e9c3cbb9f8bd6d591812174a74e.tar.bz2
dotty-9cd9d972c5b92e9c3cbb9f8bd6d591812174a74e.zip
Merge pull request #64 from DarkDimius/PostTyperTransformer
Post typer transformer
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala3
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala6
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala4
-rw-r--r--src/dotty/tools/dotc/core/Types.scala12
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/transform/CreateCompanionObjects.scala53
-rw-r--r--src/dotty/tools/dotc/transform/PostTyperTransformers.scala62
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala91
-rw-r--r--test/test/transform/CreateCompanionObjectsTest.scala117
-rw-r--r--test/test/transform/PostTyperTransformerTest.scala117
10 files changed, 421 insertions, 46 deletions
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index bda90b9e6..0dce4c324 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -278,7 +278,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
*/
def ModuleDef(sym: TermSymbol, body: List[Tree])(implicit ctx: Context): tpd.Thicket = {
val modcls = sym.moduleClass.asClass
- val constr = DefDef(modcls.primaryConstructor.asTerm, EmptyTree)
+ val constrSym = modcls.primaryConstructor orElse ctx.newDefaultConstructor(modcls).entered
+ val constr = DefDef(constrSym.asTerm, EmptyTree)
val clsdef = ClassDef(modcls, constr, body)
val valdef = ValDef(sym, New(modcls.typeRef))
Thicket(valdef, clsdef)
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 8e17fb01d..b9e901735 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -395,10 +395,14 @@ object Flags {
// --------- Combined Flag Sets and Conjunctions ----------------------
/** Flags representing source modifiers */
- final val ModifierFlags =
+ final val SourceModifierFlags =
commonFlags(Private, Protected, Abstract, Final,
Sealed, Case, Implicit, Override, AbsOverride, Lazy)
+ /** Flags representing modifiers that can appear in trees */
+ final val ModifierFlags =
+ SourceModifierFlags | Trait | Module | Param | Synthetic | Package
+
/** Flags representing access rights */
final val AccessFlags = Private | Protected | Local
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index ea96b3023..aa0cbb5a9 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -132,7 +132,7 @@ trait Symbols { this: Context =>
infoFn(module, modcls), privateWithin)
val mdenot = SymDenotation(
module, owner, name, modFlags | ModuleCreationFlags,
- if (cdenot.isCompleted) TypeRef(owner.thisType, modclsName) withSym modcls
+ if (cdenot.isCompleted) TypeRef.withSymAndName(owner.thisType, modcls, modclsName)
else new ModuleCompleter(modcls))
module.denot = mdenot
modcls.denot = cdenot
@@ -157,7 +157,7 @@ trait Symbols { this: Context =>
newModuleSymbol(
owner, name, modFlags, clsFlags,
(module, modcls) => ClassInfo(
- owner.thisType, modcls, parents, decls, TermRef(owner.thisType, name) withSym module),
+ owner.thisType, modcls, parents, decls, TermRef.withSymAndName(owner.thisType, module, name)),
privateWithin, coord, assocFile)
/** Create a package symbol with associated package class
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 67dc13775..9714f7eae 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1167,8 +1167,10 @@ object Types {
def apply(prefix: Type, name: TermName)(implicit ctx: Context): TermRef =
ctx.uniqueNamedTypes.enterIfNew(prefix, name).asInstanceOf[TermRef]
def apply(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef =
- if (prefix eq NoPrefix) unique(new NoPrefixTermRef(sym.name, sym))
- else apply(prefix, sym.name) withSym sym
+ withSymAndName(prefix, sym, sym.name)
+ def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef =
+ if (prefix eq NoPrefix) unique(new NoPrefixTermRef(name, sym))
+ else apply(prefix, name) withSym sym
def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef =
(if (prefix eq NoPrefix) apply(prefix, denot.symbol.asTerm) else apply(prefix, name)) withDenot denot
def withSig(prefix: Type, name: TermName, sig: Signature)(implicit ctx: Context): TermRef =
@@ -1182,8 +1184,10 @@ object Types {
def apply(prefix: Type, name: TypeName)(implicit ctx: Context): TypeRef =
ctx.uniqueNamedTypes.enterIfNew(prefix, name).asInstanceOf[TypeRef]
def apply(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef =
- if (prefix eq NoPrefix) unique(new NoPrefixTypeRef(sym.name, sym))
- else apply(prefix, sym.name) withSym sym
+ withSymAndName(prefix, sym, sym.name)
+ def withSymAndName(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef =
+ if (prefix eq NoPrefix) unique(new NoPrefixTypeRef(name, sym))
+ else apply(prefix, name) withSym sym
def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef =
(if (prefix eq NoPrefix) apply(prefix, denot.symbol.asType) else apply(prefix, name)) withDenot denot
}
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 5231ccd93..0d84a9e61 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -15,7 +15,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
override protected def recursionLimitExceeded() = {}
- protected val PrintableFlags = (ModifierFlags | Label | Module).toCommonFlags
+ protected val PrintableFlags = (SourceModifierFlags | Label | Module).toCommonFlags
/** The closest enclosing DefDef, TypeDef, or ClassDef node */
private var currentOwner: untpd.Tree = untpd.EmptyTree
diff --git a/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala b/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala
new file mode 100644
index 000000000..dcbcc3b54
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala
@@ -0,0 +1,53 @@
+package dotty.tools.dotc.transform
+
+import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Contexts.Context
+import scala.collection.mutable.ListBuffer
+import dotty.tools.dotc.core.{Scopes, Flags}
+import dotty.tools.dotc.core.Symbols.NoSymbol
+import scala.annotation.tailrec
+import dotty.tools.dotc.core._
+import Symbols._
+import scala.Some
+import dotty.tools.dotc.transform.TreeTransforms.{NXTransformations, TransformerInfo, TreeTransform, TreeTransformer}
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Contexts.Context
+import scala.collection.mutable
+import dotty.tools.dotc.core.Names.Name
+import NameOps._
+
+/** A transformer that provides a convenient way to create companion objects
+ */
+abstract class CreateCompanionObjects(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {
+
+ import tpd._
+
+ /** Given class definition should return true if companion object creation should be enforced
+ */
+ def predicate(cls: TypeDef): Boolean
+
+ override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[tpd.Tree] = {
+ @tailrec
+ def transformStats0(trees: List[Tree], acc: ListBuffer[Tree]): List[Tree] = {
+ trees match {
+ case Nil => acc.toList
+ case (claz: TypeDef) :: stats if claz.symbol.isClass && !(claz.symbol is Flags.Module) => {
+ val moduleExists = !(claz.symbol.companionModule eq NoSymbol)
+ if (moduleExists || !predicate(claz)) transformStats0(stats, acc += claz)
+ else {
+ val moduleSymbol = ctx.newCompleteModuleSymbol(claz.symbol.owner, claz.name.toTermName, Flags.Synthetic, Flags.Synthetic, List(defn.ObjectClass.typeRef), Scopes.newScope)
+ if (moduleSymbol.owner.isClass) moduleSymbol.entered
+ val companion = tpd.ModuleDef(moduleSymbol, List(EmptyTree))
+ acc += claz
+ acc += companion
+ transformStats0(stats, acc)
+ }
+ }
+ case stat :: stats => transformStats0(stats, acc += stat)
+ }
+ }
+
+ transformStats0(trees, ListBuffer())
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/PostTyperTransformers.scala b/src/dotty/tools/dotc/transform/PostTyperTransformers.scala
new file mode 100644
index 000000000..066a733f9
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/PostTyperTransformers.scala
@@ -0,0 +1,62 @@
+package dotty.tools.dotc.transform
+
+import dotty.tools.dotc.core._
+import Symbols._
+import scala.Some
+import dotty.tools.dotc.transform.TreeTransforms.{NXTransformations, TransformerInfo, TreeTransform, TreeTransformer}
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Contexts.Context
+import scala.collection.mutable
+import dotty.tools.dotc.core.Names.Name
+import NameOps._
+
+object PostTyperTransformers {
+
+ import tpd.{TreeTransformer => _, _}
+
+
+ /** A trait that's assumed by the transformers that run right after typer.
+ * Ensures that trees are normalized when seen by other transforms. This means:
+ * (1) All module class definitions appear after their companion class definitions
+ * (2) There are no import clauses or named arguments
+ * (3) All trees designating types are instances of TypeTree
+ */
+ abstract class PostTyperTransformer extends TreeTransformer {
+
+ /** Reorder statements so that module classes always come after their companion classes, add missing companion classes */
+ def reorder(stats: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] = {
+ val moduleClassDefs = mutable.Map[Name, Tree]()
+ def reorder0(stats: List[Tree]): List[Tree] = {
+ stats match {
+ case (stat: TypeDef) :: stats1 if stat.symbol.isClass =>
+ if (stat.symbol is Flags.Module) {
+ moduleClassDefs += (stat.name -> stat)
+ val stats1r = reorder0(stats1)
+ if (moduleClassDefs contains stat.name) stat :: stats1r else stats1r
+ }
+ else {
+ val mclsName = stat.name.moduleClassName
+ moduleClassDefs remove mclsName match {
+ case Some(mcdef) => stat :: mcdef :: reorder0(stats1)
+ case None => stat :: reorder0(stats1)
+ }
+ }
+ case stat :: stats1 => stat :: reorder0(stats1)
+ case Nil => Nil
+ }
+ }
+ reorder0(stats)
+ }
+
+ override def transformStats(trees: List[tpd.Tree], info: TransformerInfo, current: Int)(implicit ctx: Context): List[tpd.Tree] =
+ super.transformStats(reorder(trees)(ctx, info), info, current)
+
+ override def transform(tree: tpd.Tree, info: TransformerInfo, cur: Int)(implicit ctx: Context): tpd.Tree = tree match {
+ case tree: Import => EmptyTree
+ case tree: NamedArg => super.transform(tree.arg, info, cur)
+ case tree: TypeTree => super.transform(tree, info, cur)
+ case tree => super.transform(if (tree.isType) TypeTree(tree.tpe) else tree, info, cur)
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index 853544df5..6cee17589 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -4,7 +4,6 @@ import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.ast.Trees._
-import java.util
import scala.annotation.tailrec
object TreeTransforms {
@@ -49,7 +48,6 @@ object TreeTransforms {
class TreeTransform(group: TreeTransformer, idx: Int) {
import tpd._
- import group._
def prepareForIdent(tree: Ident) = this
def prepareForSelect(tree: Select) = this
@@ -81,6 +79,7 @@ object TreeTransforms {
def prepareForDefDef(tree: DefDef) = this
def prepareForTemplate(tree: Template) = this
def prepareForPackageDef(tree: PackageDef) = this
+ def prepareForStats(trees: List[Tree]) = this
def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree = tree
def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree = tree
@@ -112,6 +111,7 @@ object TreeTransforms {
def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo): Tree = tree
def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo): Tree = tree
def transformPackageDef(tree: PackageDef)(implicit ctx: Context, info: TransformerInfo): Tree = tree
+ def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] = trees
/** Transform tree using all transforms of current group (including this one) */
def transform(tree: Tree)(implicit ctx: Context): Tree = group.transform(tree)
@@ -125,7 +125,7 @@ object TreeTransforms {
val NoTransform = new TreeTransform(null, -1)
- type Mutator = (TreeTransform, tpd.Tree) => TreeTransform
+ type Mutator[T] = (TreeTransform, T) => TreeTransform
class TransformerInfo(val transformers: Array[TreeTransform], val nx: NXTransformations) {}
@@ -219,6 +219,7 @@ object TreeTransforms {
nxPrepTypeDef = index(transformations, "prepareForTypeDef")
nxPrepTemplate = index(transformations, "prepareForTemplate")
nxPrepPackageDef = index(transformations, "prepareForPackageDef")
+ nxPrepStats = index(transformations, "prepareForStats")
nxTransIdent = index(transformations, "transformIdent")
nxTransSelect = index(transformations, "transformSelect")
@@ -250,6 +251,7 @@ object TreeTransforms {
nxTransTypeDef = index(transformations, "transformTypeDef")
nxTransTemplate = index(transformations, "transformTemplate")
nxTransPackageDef = index(transformations, "transformPackageDef")
+ nxTransStats = index(transformations, "transformStats")
}
def this(prev: NXTransformations, changedTansformation: TreeTransform, transformationIndex: Int, reuse: Boolean = false) = {
@@ -285,6 +287,7 @@ object TreeTransforms {
nxPrepTypeDef = indexUpdate(prev.nxPrepTypeDef, changedTansformation, transformationIndex, "prepareForTypeDef", copy)
nxPrepTemplate = indexUpdate(prev.nxPrepTemplate, changedTansformation, transformationIndex, "prepareForTemplate", copy)
nxPrepPackageDef = indexUpdate(prev.nxPrepPackageDef, changedTansformation, transformationIndex, "prepareForPackageDef", copy)
+ nxPrepStats = indexUpdate(prev.nxPrepStats, changedTansformation, transformationIndex, "prepareForStats", copy)
nxTransIdent = indexUpdate(prev.nxTransIdent, changedTansformation, transformationIndex, "transformIdent", copy)
nxTransSelect = indexUpdate(prev.nxTransSelect, changedTansformation, transformationIndex, "transformSelect", copy)
@@ -316,6 +319,7 @@ object TreeTransforms {
nxTransTypeDef = indexUpdate(prev.nxTransTypeDef, changedTansformation, transformationIndex, "transformTypeDef", copy)
nxTransTemplate = indexUpdate(prev.nxTransTemplate, changedTansformation, transformationIndex, "transformTemplate", copy)
nxTransPackageDef = indexUpdate(prev.nxTransPackageDef, changedTansformation, transformationIndex, "transformPackageDef", copy)
+ nxTransStats = indexUpdate(prev.nxTransStats, changedTansformation, transformationIndex, "transformStats", copy)
}
var nxPrepIdent: Array[Int] = _
@@ -348,6 +352,7 @@ object TreeTransforms {
var nxPrepTypeDef: Array[Int] = _
var nxPrepTemplate: Array[Int] = _
var nxPrepPackageDef: Array[Int] = _
+ var nxPrepStats: Array[Int] = _
var nxTransIdent: Array[Int] = _
var nxTransSelect: Array[Int] = _
@@ -379,6 +384,7 @@ object TreeTransforms {
var nxTransTypeDef: Array[Int] = _
var nxTransTemplate: Array[Int] = _
var nxTransPackageDef: Array[Int] = _
+ var nxTransStats: Array[Int] = _
}
/** A group of tree transforms that are applied in sequence during the same phase */
@@ -388,7 +394,6 @@ object TreeTransforms {
protected def transformations: Array[(TreeTransformer, Int) => TreeTransform]
- private val processedTrees = new util.IdentityHashMap[Tree, Tree]()
override def run(implicit ctx: Context): Unit = {
val curTree = ctx.compilationUnit.tpdTree
@@ -396,7 +401,7 @@ object TreeTransforms {
ctx.compilationUnit.tpdTree = newTree
}
- def mutateTransformers(info: TransformerInfo, mutator: Mutator, mutationPlan: Array[Int], tree: Tree, cur: Int) = {
+ def mutateTransformers[T](info: TransformerInfo, mutator: Mutator[T], mutationPlan: Array[Int], tree: T, cur: Int) = {
var transformersCopied = false
var nxCopied = false
var result = info.transformers
@@ -424,36 +429,37 @@ object TreeTransforms {
else new TransformerInfo(result, resultNX)
}
- val prepForIdent: Mutator = (trans, tree) => trans.prepareForIdent(tree.asInstanceOf[Ident])
- val prepForSelect: Mutator = (trans, tree) => trans.prepareForSelect(tree.asInstanceOf[Select])
- val prepForThis: Mutator = (trans, tree) => trans.prepareForThis(tree.asInstanceOf[This])
- val prepForSuper: Mutator = (trans, tree) => trans.prepareForSuper(tree.asInstanceOf[Super])
- val prepForApply: Mutator = (trans, tree) => trans.prepareForApply(tree.asInstanceOf[Apply])
- val prepForTypeApply: Mutator = (trans, tree) => trans.prepareForTypeApply(tree.asInstanceOf[TypeApply])
- val prepForNew: Mutator = (trans, tree) => trans.prepareForNew(tree.asInstanceOf[New])
- val prepForPair: Mutator = (trans, tree) => trans.prepareForPair(tree.asInstanceOf[Pair])
- val prepForTyped: Mutator = (trans, tree) => trans.prepareForTyped(tree.asInstanceOf[Typed])
- val prepForAssign: Mutator = (trans, tree) => trans.prepareForAssign(tree.asInstanceOf[Assign])
- val prepForLiteral: Mutator = (trans, tree) => trans.prepareForLiteral(tree.asInstanceOf[Literal])
- val prepForBlock: Mutator = (trans, tree) => trans.prepareForBlock(tree.asInstanceOf[Block])
- val prepForIf: Mutator = (trans, tree) => trans.prepareForIf(tree.asInstanceOf[If])
- val prepForClosure: Mutator = (trans, tree) => trans.prepareForClosure(tree.asInstanceOf[Closure])
- val prepForMatch: Mutator = (trans, tree) => trans.prepareForMatch(tree.asInstanceOf[Match])
- val prepForCaseDef: Mutator = (trans, tree) => trans.prepareForCaseDef(tree.asInstanceOf[CaseDef])
- val prepForReturn: Mutator = (trans, tree) => trans.prepareForReturn(tree.asInstanceOf[Return])
- val prepForTry: Mutator = (trans, tree) => trans.prepareForTry(tree.asInstanceOf[Try])
- val prepForThrow: Mutator = (trans, tree) => trans.prepareForThrow(tree.asInstanceOf[Throw])
- val prepForSeqLiteral: Mutator = (trans, tree) => trans.prepareForSeqLiteral(tree.asInstanceOf[SeqLiteral])
- val prepForTypeTree: Mutator = (trans, tree) => trans.prepareForTypeTree(tree.asInstanceOf[TypeTree])
- val prepForSelectFromTypeTree: Mutator = (trans, tree) => trans.prepareForSelectFromTypeTree(tree.asInstanceOf[SelectFromTypeTree])
- val prepForBind: Mutator = (trans, tree) => trans.prepareForBind(tree.asInstanceOf[Bind])
- val prepForAlternative: Mutator = (trans, tree) => trans.prepareForAlternative(tree.asInstanceOf[Alternative])
- val prepForUnApply: Mutator = (trans, tree) => trans.prepareForUnApply(tree.asInstanceOf[UnApply])
- val prepForValDef: Mutator = (trans, tree) => trans.prepareForValDef(tree.asInstanceOf[ValDef])
- val prepForDefDef: Mutator = (trans, tree) => trans.prepareForDefDef(tree.asInstanceOf[DefDef])
- val prepForTypeDef: Mutator = (trans, tree) => trans.prepareForTypeDef(tree.asInstanceOf[TypeDef])
- val prepForTemplate: Mutator = (trans, tree) => trans.prepareForTemplate(tree.asInstanceOf[Template])
- val prepForPackageDef: Mutator = (trans, tree) => trans.prepareForPackageDef(tree.asInstanceOf[PackageDef])
+ val prepForIdent: Mutator[Ident] = (trans, tree) => trans.prepareForIdent(tree)
+ val prepForSelect: Mutator[Select] = (trans, tree) => trans.prepareForSelect(tree)
+ val prepForThis: Mutator[This] = (trans, tree) => trans.prepareForThis(tree)
+ val prepForSuper: Mutator[Super] = (trans, tree) => trans.prepareForSuper(tree)
+ val prepForApply: Mutator[Apply] = (trans, tree) => trans.prepareForApply(tree)
+ val prepForTypeApply: Mutator[TypeApply] = (trans, tree) => trans.prepareForTypeApply(tree)
+ val prepForNew: Mutator[New] = (trans, tree) => trans.prepareForNew(tree)
+ val prepForPair: Mutator[Pair] = (trans, tree) => trans.prepareForPair(tree)
+ val prepForTyped: Mutator[Typed] = (trans, tree) => trans.prepareForTyped(tree)
+ val prepForAssign: Mutator[Assign] = (trans, tree) => trans.prepareForAssign(tree)
+ val prepForLiteral: Mutator[Literal] = (trans, tree) => trans.prepareForLiteral(tree)
+ val prepForBlock: Mutator[Block] = (trans, tree) => trans.prepareForBlock(tree)
+ val prepForIf: Mutator[If] = (trans, tree) => trans.prepareForIf(tree)
+ val prepForClosure: Mutator[Closure] = (trans, tree) => trans.prepareForClosure(tree)
+ val prepForMatch: Mutator[Match] = (trans, tree) => trans.prepareForMatch(tree)
+ val prepForCaseDef: Mutator[CaseDef] = (trans, tree) => trans.prepareForCaseDef(tree)
+ val prepForReturn: Mutator[Return] = (trans, tree) => trans.prepareForReturn(tree)
+ val prepForTry: Mutator[Try] = (trans, tree) => trans.prepareForTry(tree)
+ val prepForThrow: Mutator[Throw] = (trans, tree) => trans.prepareForThrow(tree)
+ val prepForSeqLiteral: Mutator[SeqLiteral] = (trans, tree) => trans.prepareForSeqLiteral(tree)
+ val prepForTypeTree: Mutator[TypeTree] = (trans, tree) => trans.prepareForTypeTree(tree)
+ val prepForSelectFromTypeTree: Mutator[SelectFromTypeTree] = (trans, tree) => trans.prepareForSelectFromTypeTree(tree)
+ val prepForBind: Mutator[Bind] = (trans, tree) => trans.prepareForBind(tree)
+ val prepForAlternative: Mutator[Alternative] = (trans, tree) => trans.prepareForAlternative(tree)
+ val prepForUnApply: Mutator[UnApply] = (trans, tree) => trans.prepareForUnApply(tree)
+ val prepForValDef: Mutator[ValDef] = (trans, tree) => trans.prepareForValDef(tree)
+ val prepForDefDef: Mutator[DefDef] = (trans, tree) => trans.prepareForDefDef(tree)
+ val prepForTypeDef: Mutator[TypeDef] = (trans, tree) => trans.prepareForTypeDef(tree)
+ val prepForTemplate: Mutator[Template] = (trans, tree) => trans.prepareForTemplate(tree)
+ val prepForPackageDef: Mutator[PackageDef] = (trans, tree) => trans.prepareForPackageDef(tree)
+ val prepForStats: Mutator[List[Tree]]= (trans, trees) => trans.prepareForStats(trees)
def transform(t: Tree)(implicit ctx: Context): Tree = {
val initialTransformations = transformations.zipWithIndex.map(x => x._1(this, x._2))
@@ -1060,8 +1066,19 @@ object TreeTransforms {
}
}
- def transformStats(trees: List[Tree], info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tree] =
- transformL(trees, info, current)(ctx)
+ @tailrec
+ final private[TreeTransforms] def goStats(trees: List[Tree], cur: Int)(implicit ctx: Context, info: TransformerInfo): List[Tree] = {
+ if (cur < info.transformers.length) {
+ val stats = info.transformers(cur).transformStats(trees)
+ goStats(stats, info.nx.nxTransStats(cur + 1))
+ } else trees
+ }
+
+ def transformStats(trees: List[Tree], info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tree] = {
+ val newInfo = mutateTransformers(info, prepForStats, info.nx.nxPrepStats, trees, current)
+ val newTrees = transformL(trees, newInfo, current)(ctx)
+ flatten(goStats(newTrees, newInfo.nx.nxTransStats(current))(ctx, newInfo))
+ }
def transformL(trees: List[Tree], info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tree] =
flatten(trees mapConserve (x => transform(x, info, current)))
diff --git a/test/test/transform/CreateCompanionObjectsTest.scala b/test/test/transform/CreateCompanionObjectsTest.scala
new file mode 100644
index 000000000..95a84f4e0
--- /dev/null
+++ b/test/test/transform/CreateCompanionObjectsTest.scala
@@ -0,0 +1,117 @@
+package test.transform
+
+
+import org.junit.{Assert, Test}
+import test.DottyTest
+import dotty.tools.dotc.core._
+import dotty.tools.dotc.ast.{tpd, Trees}
+import Contexts._
+import Flags._
+import Denotations._
+import NameOps._
+import Symbols._
+import Types._
+import Decorators._
+import Trees._
+import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer}
+import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer
+import dotty.tools.dotc.transform.CreateCompanionObjects
+
+
+class CreateCompanionObjectsTest extends DottyTest {
+
+ import tpd._
+
+ @Test
+ def shouldCreateNonExistingObjectsInPackage = checkCompile("frontend", "class A{} ") {
+ (tree, context) =>
+ implicit val ctx = context
+
+ val transformer = new PostTyperTransformer {
+ override def transformations = Array(new CreateCompanionObjects(_, _) {
+ override def predicate(cts: TypeDef): Boolean = true
+ })
+
+ override def name: String = "test"
+ }
+ val transformed = transformer.transform(tree).toString
+ println(transformed)
+ val classPattern = "TypeDef(Modifiers(,,List()),A,"
+ val classPos = transformed.indexOf(classPattern)
+ val moduleClassPattern = "TypeDef(Modifiers(final module <synthetic>,,List()),A$"
+ val modulePos = transformed.indexOf(moduleClassPattern)
+
+ Assert.assertTrue("should create non-existing objects in package",
+ classPos < modulePos
+ )
+ }
+
+ @Test
+ def shouldCreateNonExistingObjectsInBlock = checkCompile("frontend", "class D {def p = {class A{}; 1}} ") {
+ (tree, context) =>
+ implicit val ctx = context
+ val transformer = new PostTyperTransformer {
+ override def transformations = Array(new CreateCompanionObjects(_, _) {
+ override def predicate(cts: TypeDef): Boolean = true
+ })
+
+ override def name: String = "test"
+ }
+ val transformed = transformer.transform(tree).toString
+ val classPattern = "TypeDef(Modifiers(,,List()),A,"
+ val classPos = transformed.indexOf(classPattern)
+ val moduleClassPattern = "TypeDef(Modifiers(final module <synthetic>,,List()),A$"
+ val modulePos = transformed.indexOf(moduleClassPattern)
+
+ Assert.assertTrue("should create non-existing objects in block",
+ classPos < modulePos
+ )
+ }
+
+ @Test
+ def shouldCreateNonExistingObjectsInTemplate = checkCompile("frontend", "class D {class A{}; } ") {
+ (tree, context) =>
+ implicit val ctx = context
+ val transformer = new PostTyperTransformer {
+ override def transformations = Array(new CreateCompanionObjects(_, _) {
+ override def predicate(cts: TypeDef): Boolean = true
+ })
+
+ override def name: String = "test"
+ }
+ val transformed = transformer.transform(tree).toString
+ val classPattern = "TypeDef(Modifiers(,,List()),A,"
+ val classPos = transformed.indexOf(classPattern)
+ val moduleClassPattern = "TypeDef(Modifiers(final module <synthetic>,,List()),A$"
+ val modulePos = transformed.indexOf(moduleClassPattern)
+
+ Assert.assertTrue("should create non-existing objects in template",
+ classPos < modulePos
+ )
+ }
+
+ @Test
+ def shouldCreateOnlyIfAskedFor = checkCompile("frontend", "class DONT {class CREATE{}; } ") {
+ (tree, context) =>
+ implicit val ctx = context
+ val transformer = new PostTyperTransformer {
+ override def transformations = Array(new CreateCompanionObjects(_, _) {
+ override def predicate(cts: TypeDef): Boolean = cts.name.toString.contains("CREATE")
+ })
+
+ override def name: String = "test"
+ }
+ val transformed = transformer.transform(tree).toString
+ val classPattern = "TypeDef(Modifiers(,,List()),A,"
+ val classPos = transformed.indexOf(classPattern)
+ val moduleClassPattern = "TypeDef(Modifiers(final module <synthetic>,,List()),CREATE$"
+ val modulePos = transformed.indexOf(moduleClassPattern)
+
+ val notCreatedModulePattern = "TypeDef(Modifiers(final module <synthetic>,,List()),DONT"
+ val notCreatedPos = transformed.indexOf(notCreatedModulePattern)
+
+ Assert.assertTrue("should create non-existing objects in template",
+ classPos < modulePos && (notCreatedPos < 0)
+ )
+ }
+}
diff --git a/test/test/transform/PostTyperTransformerTest.scala b/test/test/transform/PostTyperTransformerTest.scala
new file mode 100644
index 000000000..50696728e
--- /dev/null
+++ b/test/test/transform/PostTyperTransformerTest.scala
@@ -0,0 +1,117 @@
+package test.transform
+
+
+import org.junit.{Assert, Test}
+import test.DottyTest
+import dotty.tools.dotc.core._
+import dotty.tools.dotc.ast.Trees
+import Contexts._
+import Flags._
+import Denotations._
+import NameOps._
+import Symbols._
+import Types._
+import Decorators._
+import Trees._
+import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer}
+import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer
+
+class PostTyperTransformerTest extends DottyTest {
+
+ @Test
+ def shouldStripImports = checkCompile("frontend", "class A{ import scala.collection.mutable._; val d = 1}") {
+ (tree, context) =>
+ implicit val ctx = context
+ class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
+ val transformer = new PostTyperTransformer {
+ override def transformations = Array(new EmptyTransform(_, _))
+
+ override def name: String = "test"
+ }
+ val transformed = transformer.transform(tree)
+
+ Assert.assertTrue("should strip imports",
+ !transformed.toString.toLowerCase.contains("import")
+ )
+ }
+
+ @Test
+ def shouldStripNamedArgs = checkCompile("frontend", "class A{ def p(x:Int, y:Int= 2) = 1; p(1, y = 2)}") {
+ (tree, context) =>
+ implicit val ctx = context
+ class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
+ val transformer = new PostTyperTransformer {
+ override def transformations = Array(new EmptyTransform(_, _))
+
+ override def name: String = "test"
+ }
+ val transformed = transformer.transform(tree)
+
+ Assert.assertTrue("should string named arguments",
+ !transformed.toString.contains("NamedArg")
+ )
+ }
+
+ @Test
+ def shouldReorderExistingObjectsInPackage = checkCompile("frontend", "object A{}; class A{} ") {
+ (tree, context) =>
+ implicit val ctx = context
+ class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
+ val transformer = new PostTyperTransformer {
+ override def transformations = Array(new EmptyTransform(_, _))
+
+ override def name: String = "test"
+ }
+ val transformed = transformer.transform(tree).toString
+ val classPattern = "TypeDef(Modifiers(,,List()),A,"
+ val classPos = transformed.indexOf(classPattern)
+ val moduleClassPattern = "TypeDef(Modifiers(final module,,List()),A$,"
+ val modulePos = transformed.indexOf(moduleClassPattern)
+
+ Assert.assertTrue("should reorder existing objects in package",
+ classPos < modulePos
+ )
+ }
+
+ @Test
+ def shouldReorderExistingObjectsInBlock = checkCompile("frontend", "class D {def p = {object A{}; class A{}; 1}} ") {
+ (tree, context) =>
+ implicit val ctx = context
+ class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
+ val transformer = new PostTyperTransformer {
+ override def transformations = Array(new EmptyTransform(_, _))
+
+ override def name: String = "test"
+ }
+ val transformed = transformer.transform(tree).toString
+ val classPattern = "TypeDef(Modifiers(,,List()),A,"
+ val classPos = transformed.indexOf(classPattern)
+ val moduleClassPattern = "TypeDef(Modifiers(final module,,List()),A$,"
+ val modulePos = transformed.indexOf(moduleClassPattern)
+
+ Assert.assertTrue("should reorder existing objects in block",
+ classPos < modulePos
+ )
+ }
+
+ @Test
+ def shouldReorderExistingObjectsInTemplate = checkCompile("frontend", "class D {object A{}; class A{}; } ") {
+ (tree, context) =>
+ implicit val ctx = context
+ class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {}
+ val transformer = new PostTyperTransformer {
+ override def transformations = Array(new EmptyTransform(_, _))
+
+ override def name: String = "test"
+ }
+ val transformed = transformer.transform(tree).toString
+ val classPattern = "TypeDef(Modifiers(,,List()),A,"
+ val classPos = transformed.indexOf(classPattern)
+ val moduleClassPattern = "TypeDef(Modifiers(final module,,List()),A$,"
+ val modulePos = transformed.indexOf(moduleClassPattern)
+
+ Assert.assertTrue("should reorder existing objects in template",
+ classPos < modulePos
+ )
+ }
+}