Skip to content

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

Merged
merged 5 commits into from
Mar 13, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 5 additions & 1 deletion src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
12 changes: 8 additions & 4 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions src/dotty/tools/dotc/transform/CreateCompanionObjects.scala
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())
}
}
62 changes: 62 additions & 0 deletions src/dotty/tools/dotc/transform/PostTyperTransformers.scala
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
Copy link

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?

Copy link
Contributor Author

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.

* (2) There are no import clauses or named arguments
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.
This is performed after the "Frontend" phase, so IDEs and, possibly, quasiquotes, should be able to see NamedArgs and Imports.

* (3) All trees designating types are instances of TypeTree
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the alternatives?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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)
}
}

}
Loading