Skip to content

Refactor/tree transform inits #224

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 6 commits into from
Nov 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
138 changes: 73 additions & 65 deletions src/dotty/tools/dotc/transform/CapturedVars.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,86 +17,94 @@ import SymUtils._
import collection.{ mutable, immutable }
import collection.mutable.{ LinkedHashMap, LinkedHashSet, TreeSet }

class CapturedVars extends MiniPhaseTransform with SymTransformer { thisTransform =>
class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisTransform =>
import ast.tpd._

/** the following two members override abstract members in Transform */
val phaseName: String = "capturedVars"
val treeTransform = new Transform(Set())

override def treeTransformPhase = thisTransform.next
class Transform(captured: collection.Set[Symbol]) extends TreeTransform {
def phase = thisTransform
override def treeTransformPhase = thisTransform.next

private var captured: mutable.HashSet[Symbol] = _

private class CollectCaptured(implicit ctx: Context) extends EnclosingMethodTraverser {
def traverse(enclMeth: Symbol, tree: Tree) = tree match {
case id: Ident =>
val sym = id.symbol
if (sym.is(Mutable, butNot = Method) && sym.owner.isTerm && sym.enclosingMethod != enclMeth) {
ctx.log(i"capturing $sym in ${sym.enclosingMethod}, referenced from $enclMeth")
captured += sym
}
case _ =>
foldOver(enclMeth, tree)
}
def runOver(tree: Tree) = {
captured = mutable.HashSet()
apply(NoSymbol, tree)
private class CollectCaptured(implicit ctx: Context) extends EnclosingMethodTraverser {
private val captured = mutable.HashSet[Symbol]()
def traverse(enclMeth: Symbol, tree: Tree) = tree match {
case id: Ident =>
val sym = id.symbol
if (sym.is(Mutable, butNot = Method) && sym.owner.isTerm && sym.enclosingMethod != enclMeth) {
ctx.log(i"capturing $sym in ${sym.enclosingMethod}, referenced from $enclMeth")
captured += sym
}
case _ =>
foldOver(enclMeth, tree)
}
def runOver(tree: Tree): collection.Set[Symbol] = {
apply(NoSymbol, tree)
captured
}
}
}

override def init(implicit ctx: Context, info: TransformerInfo): Unit =
(new CollectCaptured)(ctx.withPhase(thisTransform)).runOver(ctx.compilationUnit.tpdTree)
override def prepareForUnit(tree: Tree)(implicit ctx: Context) = {
val captured = (new CollectCaptured)(ctx.withPhase(thisTransform))
.runOver(ctx.compilationUnit.tpdTree)
new Transform(captured)
}

override def transformSym(sd: SymDenotation)(implicit ctx: Context): SymDenotation =
if (captured(sd.symbol)) {
val newd = sd.copySymDenotation(
info = refCls(sd.info.classSymbol, sd.hasAnnotation(defn.VolatileAnnot)).typeRef)
newd.removeAnnotation(defn.VolatileAnnot)
newd
} else sd
/** The {Volatile|}{Int|Double|...|Object}Ref class corresponding to the class `cls`,
* depending on whether the reference should be @volatile
*/
def refCls(cls: Symbol, isVolatile: Boolean)(implicit ctx: Context): Symbol = {
val refMap = if (isVolatile) defn.volatileRefClass else defn.refClass
refMap.getOrElse(cls, refMap(defn.ObjectClass))
}

/** The {Volatile|}{Int|Double|...|Object}Ref class corresponding to the class `cls`,
* depending on whether the reference should be @volatile
*/
def refCls(cls: Symbol, isVolatile: Boolean)(implicit ctx: Context): Symbol = {
val refMap = if (isVolatile) defn.volatileRefClass else defn.refClass
refMap.getOrElse(cls, refMap(defn.ObjectClass))
}
def capturedType(vble: Symbol)(implicit ctx: Context): Type = {
val oldInfo = vble.denot(ctx.withPhase(thisTransform)).info
refCls(oldInfo.classSymbol, vble.isVolatile).typeRef
}

def capturedType(vble: Symbol)(implicit ctx: Context): Type = {
val oldInfo = vble.denot(ctx.withPhase(thisTransform)).info
refCls(oldInfo.classSymbol, vble.isVolatile).typeRef
}
override def prepareForValDef(vdef: ValDef)(implicit ctx: Context) = {
val sym = vdef.symbol
if (captured contains sym) {
val newd = sym.denot(ctx.withPhase(thisTransform)).copySymDenotation(
info = refCls(sym.info.classSymbol, sym.hasAnnotation(defn.VolatileAnnot)).typeRef)
newd.removeAnnotation(defn.VolatileAnnot)
newd.installAfter(thisTransform)
}
this
}

override def transformValDef(vdef: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
val vble = vdef.symbol
if (captured contains vble) {
def boxMethod(name: TermName): Tree =
ref(vble.info.classSymbol.companionModule.info.member(name).symbol)
cpy.ValDef(vdef)(
rhs = vdef.rhs match {
case EmptyTree => boxMethod(nme.zero).appliedToNone.withPos(vdef.pos)
case arg => boxMethod(nme.create).appliedTo(arg)
},
tpt = TypeTree(vble.info).withPos(vdef.tpt.pos))
override def transformValDef(vdef: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
val vble = vdef.symbol
if (captured contains vble) {
def boxMethod(name: TermName): Tree =
ref(vble.info.classSymbol.companionModule.info.member(name).symbol)
cpy.ValDef(vdef)(
rhs = vdef.rhs match {
case EmptyTree => boxMethod(nme.zero).appliedToNone.withPos(vdef.pos)
case arg => boxMethod(nme.create).appliedTo(arg)
},
tpt = TypeTree(vble.info).withPos(vdef.tpt.pos))
} else vdef
}
else vdef
}

override def transformIdent(id: Ident)(implicit ctx: Context, info: TransformerInfo): Tree = {
val vble = id.symbol
if (captured(vble))
(id select nme.elem).ensureConforms(vble.denot(ctx.withPhase(thisTransform)).info)
else id
}
override def transformIdent(id: Ident)(implicit ctx: Context, info: TransformerInfo): Tree = {
val vble = id.symbol
if (captured(vble))
(id select nme.elem).ensureConforms(vble.denot(ctx.withPhase(thisTransform)).info)
else id
}

override def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree = {
val lhs1 = tree.lhs match {
case TypeApply(Select(qual @ Select(qual2, nme.elem), nme.asInstanceOf_), _) =>
assert(captured(qual2.symbol))
qual
case _ => tree.lhs
override def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree = {
val lhs1 = tree.lhs match {
case TypeApply(Select(qual @ Select(qual2, nme.elem), nme.asInstanceOf_), _) =>
assert(captured(qual2.symbol))
qual
case _ => tree.lhs
}
cpy.Assign(tree)(lhs1, tree.rhs)
}
cpy.Assign(tree)(lhs1, tree.rhs)
}
}
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/transform/CollectEntryPoints.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ import dotty.tools.dotc.config.JavaPlatform
class CollectEntryPoints extends MiniPhaseTransform {

/** perform context-dependant initialization */
override def init(implicit ctx: Context, info: TransformerInfo): Unit = {
override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context) = {
entryPoints = collection.immutable.TreeSet.empty[Symbol](new SymbolOrdering())
assert(ctx.platform.isInstanceOf[JavaPlatform], "Java platform specific phase")
this
}

private var entryPoints: Set[Symbol] = _
Expand Down
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/transform/InterceptedMethods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ class InterceptedMethods extends MiniPhaseTransform {
private var primitiveGetClassMethods: Set[Symbol] = _

/** perform context-dependant initialization */
override def init(implicit ctx: Context, info: TransformerInfo): Unit = {
override def prepareForUnit(tree: Tree)(implicit ctx: Context) = {
poundPoundMethods = Set(defn.Any_##)
Any_comparisons = Set(defn.Any_==, defn.Any_!=)
interceptedMethods = poundPoundMethods ++ Any_comparisons
primitiveGetClassMethods = Set[Symbol]() ++ defn.ScalaValueClasses.map(x => x.requiredMethod(nme.getClass_))
this
}

// this should be removed if we have guarantee that ## will get Apply node
Expand Down
Loading