Skip to content

Commit 8aae56b

Browse files
committed
Make CapturedVars a functional transform.
No global side effect on capturedVars anymore.
1 parent c3b11ce commit 8aae56b

File tree

1 file changed

+72
-69
lines changed

1 file changed

+72
-69
lines changed

src/dotty/tools/dotc/transform/CapturedVars.scala

Lines changed: 72 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -17,91 +17,94 @@ import SymUtils._
1717
import collection.{ mutable, immutable }
1818
import collection.mutable.{ LinkedHashMap, LinkedHashSet, TreeSet }
1919

20-
class CapturedVars extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
20+
class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisTransform =>
2121
import ast.tpd._
2222

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

26-
override def treeTransformPhase = thisTransform.next
27+
class Transform(captured: collection.Set[Symbol]) extends TreeTransform {
28+
def phase = thisTransform
29+
override def treeTransformPhase = thisTransform.next
2730

28-
private var captured: mutable.HashSet[Symbol] = _
29-
30-
private class CollectCaptured(implicit ctx: Context) extends EnclosingMethodTraverser {
31-
def traverse(enclMeth: Symbol, tree: Tree) = tree match {
32-
case id: Ident =>
33-
val sym = id.symbol
34-
if (sym.is(Mutable, butNot = Method) && sym.owner.isTerm && sym.enclosingMethod != enclMeth) {
35-
ctx.log(i"capturing $sym in ${sym.enclosingMethod}, referenced from $enclMeth")
36-
captured += sym
37-
}
38-
case _ =>
39-
foldOver(enclMeth, tree)
40-
}
41-
def runOver(tree: Tree) = {
42-
captured = mutable.HashSet()
43-
apply(NoSymbol, tree)
31+
private class CollectCaptured(implicit ctx: Context) extends EnclosingMethodTraverser {
32+
private val captured = mutable.HashSet[Symbol]()
33+
def traverse(enclMeth: Symbol, tree: Tree) = tree match {
34+
case id: Ident =>
35+
val sym = id.symbol
36+
if (sym.is(Mutable, butNot = Method) && sym.owner.isTerm && sym.enclosingMethod != enclMeth) {
37+
ctx.log(i"capturing $sym in ${sym.enclosingMethod}, referenced from $enclMeth")
38+
captured += sym
39+
}
40+
case _ =>
41+
foldOver(enclMeth, tree)
42+
}
43+
def runOver(tree: Tree): collection.Set[Symbol] = {
44+
apply(NoSymbol, tree)
45+
captured
46+
}
4447
}
45-
}
4648

47-
override def prepareForUnit(tree: Tree)(implicit ctx: Context) = {
48-
(new CollectCaptured)(ctx.withPhase(thisTransform)).runOver(ctx.compilationUnit.tpdTree)
49-
this
50-
}
49+
override def prepareForUnit(tree: Tree)(implicit ctx: Context) = {
50+
val captured = (new CollectCaptured)(ctx.withPhase(thisTransform))
51+
.runOver(ctx.compilationUnit.tpdTree)
52+
new Transform(captured)
53+
}
5154

52-
/** The {Volatile|}{Int|Double|...|Object}Ref class corresponding to the class `cls`,
53-
* depending on whether the reference should be @volatile
54-
*/
55-
def refCls(cls: Symbol, isVolatile: Boolean)(implicit ctx: Context): Symbol = {
56-
val refMap = if (isVolatile) defn.volatileRefClass else defn.refClass
57-
refMap.getOrElse(cls, refMap(defn.ObjectClass))
58-
}
55+
/** The {Volatile|}{Int|Double|...|Object}Ref class corresponding to the class `cls`,
56+
* depending on whether the reference should be @volatile
57+
*/
58+
def refCls(cls: Symbol, isVolatile: Boolean)(implicit ctx: Context): Symbol = {
59+
val refMap = if (isVolatile) defn.volatileRefClass else defn.refClass
60+
refMap.getOrElse(cls, refMap(defn.ObjectClass))
61+
}
5962

60-
def capturedType(vble: Symbol)(implicit ctx: Context): Type = {
61-
val oldInfo = vble.denot(ctx.withPhase(thisTransform)).info
62-
refCls(oldInfo.classSymbol, vble.isVolatile).typeRef
63-
}
63+
def capturedType(vble: Symbol)(implicit ctx: Context): Type = {
64+
val oldInfo = vble.denot(ctx.withPhase(thisTransform)).info
65+
refCls(oldInfo.classSymbol, vble.isVolatile).typeRef
66+
}
6467

65-
override def prepareForValDef(vdef: ValDef)(implicit ctx: Context) = {
66-
val sym = vdef.symbol
67-
if (captured contains sym) {
68-
val newd = sym.denot(ctx.withPhase(thisTransform)).copySymDenotation(
69-
info = refCls(sym.info.classSymbol, sym.hasAnnotation(defn.VolatileAnnot)).typeRef)
70-
newd.removeAnnotation(defn.VolatileAnnot)
71-
newd.installAfter(thisTransform)
68+
override def prepareForValDef(vdef: ValDef)(implicit ctx: Context) = {
69+
val sym = vdef.symbol
70+
if (captured contains sym) {
71+
val newd = sym.denot(ctx.withPhase(thisTransform)).copySymDenotation(
72+
info = refCls(sym.info.classSymbol, sym.hasAnnotation(defn.VolatileAnnot)).typeRef)
73+
newd.removeAnnotation(defn.VolatileAnnot)
74+
newd.installAfter(thisTransform)
75+
}
76+
this
7277
}
73-
this
74-
}
7578

76-
override def transformValDef(vdef: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
77-
val vble = vdef.symbol
78-
if (captured contains vble) {
79-
def boxMethod(name: TermName): Tree =
80-
ref(vble.info.classSymbol.companionModule.info.member(name).symbol)
81-
cpy.ValDef(vdef)(
82-
rhs = vdef.rhs match {
83-
case EmptyTree => boxMethod(nme.zero).appliedToNone.withPos(vdef.pos)
84-
case arg => boxMethod(nme.create).appliedTo(arg)
85-
},
86-
tpt = TypeTree(vble.info).withPos(vdef.tpt.pos))
79+
override def transformValDef(vdef: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
80+
val vble = vdef.symbol
81+
if (captured contains vble) {
82+
def boxMethod(name: TermName): Tree =
83+
ref(vble.info.classSymbol.companionModule.info.member(name).symbol)
84+
cpy.ValDef(vdef)(
85+
rhs = vdef.rhs match {
86+
case EmptyTree => boxMethod(nme.zero).appliedToNone.withPos(vdef.pos)
87+
case arg => boxMethod(nme.create).appliedTo(arg)
88+
},
89+
tpt = TypeTree(vble.info).withPos(vdef.tpt.pos))
90+
} else vdef
8791
}
88-
else vdef
89-
}
9092

91-
override def transformIdent(id: Ident)(implicit ctx: Context, info: TransformerInfo): Tree = {
92-
val vble = id.symbol
93-
if (captured(vble))
94-
(id select nme.elem).ensureConforms(vble.denot(ctx.withPhase(thisTransform)).info)
95-
else id
96-
}
93+
override def transformIdent(id: Ident)(implicit ctx: Context, info: TransformerInfo): Tree = {
94+
val vble = id.symbol
95+
if (captured(vble))
96+
(id select nme.elem).ensureConforms(vble.denot(ctx.withPhase(thisTransform)).info)
97+
else id
98+
}
9799

98-
override def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree = {
99-
val lhs1 = tree.lhs match {
100-
case TypeApply(Select(qual @ Select(qual2, nme.elem), nme.asInstanceOf_), _) =>
101-
assert(captured(qual2.symbol))
102-
qual
103-
case _ => tree.lhs
100+
override def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree = {
101+
val lhs1 = tree.lhs match {
102+
case TypeApply(Select(qual @ Select(qual2, nme.elem), nme.asInstanceOf_), _) =>
103+
assert(captured(qual2.symbol))
104+
qual
105+
case _ => tree.lhs
106+
}
107+
cpy.Assign(tree)(lhs1, tree.rhs)
104108
}
105-
cpy.Assign(tree)(lhs1, tree.rhs)
106109
}
107110
}

0 commit comments

Comments
 (0)