From 8aae56b4f08806eda9745b0a980da151c0a7dc8c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 12 Nov 2014 18:10:47 +0100 Subject: Make CapturedVars a functional transform. No global side effect on capturedVars anymore. --- src/dotty/tools/dotc/transform/CapturedVars.scala | 141 +++++++++++----------- 1 file changed, 72 insertions(+), 69 deletions(-) (limited to 'src/dotty/tools/dotc/transform/CapturedVars.scala') diff --git a/src/dotty/tools/dotc/transform/CapturedVars.scala b/src/dotty/tools/dotc/transform/CapturedVars.scala index b2118d3ec..14bb4a738 100644 --- a/src/dotty/tools/dotc/transform/CapturedVars.scala +++ b/src/dotty/tools/dotc/transform/CapturedVars.scala @@ -17,91 +17,94 @@ import SymUtils._ import collection.{ mutable, immutable } import collection.mutable.{ LinkedHashMap, LinkedHashSet, TreeSet } -class CapturedVars extends MiniPhaseTransform with IdentityDenotTransformer { 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 prepareForUnit(tree: Tree)(implicit ctx: Context) = { - (new CollectCaptured)(ctx.withPhase(thisTransform)).runOver(ctx.compilationUnit.tpdTree) - this - } + override def prepareForUnit(tree: Tree)(implicit ctx: Context) = { + val captured = (new CollectCaptured)(ctx.withPhase(thisTransform)) + .runOver(ctx.compilationUnit.tpdTree) + new Transform(captured) + } - /** 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) + 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 } - 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) } } \ No newline at end of file -- cgit v1.2.3