-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Post typer transformer #64
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
Changes from all commits
912b4bc
29d2d29
0089217
3eabe4a
b6cb517
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to reduce variety of types of trees which can be seen during transformations. |
||
* (3) All trees designating types are instances of TypeTree | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are the alternatives? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OrTypeTree, AndTypeTree, SingletonTypeTree, RefinedTypeTree, TypeBoundsTree, AppliedTypeTree |
||
*/ | ||
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) | ||
} | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's a module class definition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation class of companion object.