diff options
author | Sébastien Doeraene <sjrdoeraene@gmail.com> | 2014-03-13 15:50:52 +0100 |
---|---|---|
committer | Sébastien Doeraene <sjrdoeraene@gmail.com> | 2014-03-13 15:50:52 +0100 |
commit | 9cd9d972c5b92e9c3cbb9f8bd6d591812174a74e (patch) | |
tree | e32c15a8d3d2b43f0ffaa030f4f157f3fe728f29 | |
parent | 194be919664447631ba55446eb4874979c908d27 (diff) | |
parent | b6cb517570e77c2acf4bc6c8b1e83f922e1fd25f (diff) | |
download | dotty-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.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Symbols.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/CreateCompanionObjects.scala | 53 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/PostTyperTransformers.scala | 62 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TreeTransform.scala | 91 | ||||
-rw-r--r-- | test/test/transform/CreateCompanionObjectsTest.scala | 117 | ||||
-rw-r--r-- | test/test/transform/PostTyperTransformerTest.scala | 117 |
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 + ) + } +} |