Skip to content

Commit 097cae6

Browse files
committed
Use aggregation instead of inheritance for dependency collection
1 parent f70157f commit 097cae6

File tree

2 files changed

+41
-37
lines changed

2 files changed

+41
-37
lines changed

compiler/src/dotty/tools/dotc/transform/DependencyCollector.scala

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,24 @@ import ExplicitOuter.outer
1919
import util.Store
2020
import collection.mutable
2121
import collection.mutable.{ HashMap, HashSet, LinkedHashMap, TreeSet }
22+
import annotation.constructorOnly
2223

23-
abstract class DependencyCollector:
24+
/** Exposes the dependencies of the typed tree in the current compilation unit
25+
* in sets `freeVars`, `liftedOwner`.
26+
*/
27+
abstract class Dependencies(@constructorOnly rootContext: Context):
2428
import ast.tpd._
2529

2630
def enclosure(using Context): Symbol
2731
def isExpr(sym: Symbol)(using Context): Boolean
2832

29-
protected type SymSet = TreeSet[Symbol]
33+
type SymSet = TreeSet[Symbol]
3034

3135
/** A map storing free variables of functions and classes */
3236
val free: mutable.LinkedHashMap[Symbol, SymSet] = new LinkedHashMap
3337

3438
/** A hashtable storing calls between functions */
35-
val called = new LinkedHashMap[Symbol, SymSet]
39+
private val called = new LinkedHashMap[Symbol, SymSet]
3640

3741
/** A map from local methods and classes to the owners to which they will be lifted as members.
3842
* For methods and classes that do not have any dependencies this will be the enclosing package.
@@ -55,17 +59,15 @@ abstract class DependencyCollector:
5559
private def symSet(f: LinkedHashMap[Symbol, SymSet], sym: Symbol): SymSet =
5660
f.getOrElseUpdate(sym, newSymSet)
5761

58-
def freeVars(sym: Symbol): List[Symbol] = free.get(sym) match
59-
case Some(set) => set.toList
60-
case None => Nil
62+
def freeVars(sym: Symbol): collection.Set[Symbol] = free.getOrElse(sym, Set.empty)
6163

6264
/** A symbol is local if it is owned by a term or a local trait,
6365
* or if it is a constructor of a local symbol.
6466
* Note: we count members of local traits as local since their free variables
6567
* have to be passed on from their callers. By contrast, class members get their
6668
* free variable proxies from their enclosing class.
6769
*/
68-
def isLocal(sym: Symbol)(using Context): Boolean =
70+
private def isLocal(sym: Symbol)(using Context): Boolean =
6971
val owner = sym.maybeOwner
7072
owner.isTerm
7173
|| owner.is(Trait) && isLocal(owner)
@@ -74,7 +76,7 @@ abstract class DependencyCollector:
7476
/** Set `liftedOwner(sym)` to `owner` if `owner` is more deeply nested
7577
* than the previous value of `liftedowner(sym)`.
7678
*/
77-
def narrowLiftedOwner(sym: Symbol, owner: Symbol)(using Context): Unit =
79+
private def narrowLiftedOwner(sym: Symbol, owner: Symbol)(using Context): Unit =
7880
if sym.maybeOwner.isTerm
7981
&& owner.isProperlyContainedIn(liftedOwner(sym))
8082
&& owner != sym
@@ -172,7 +174,7 @@ abstract class DependencyCollector:
172174
symSet(called, caller) += callee
173175
}
174176

175-
def process(tree: Tree)(using Context) =
177+
protected def process(tree: Tree)(using Context) =
176178
val sym = tree.symbol
177179

178180
def narrowTo(thisClass: ClassSymbol) =
@@ -259,8 +261,9 @@ abstract class DependencyCollector:
259261
changedLiftedOwner
260262
do ()
261263

262-
def collectDependencies()(using Context): Unit =
263-
CollectDependencies().traverse(ctx.compilationUnit.tpdTree)
264+
inContext(rootContext) {
265+
CollectDependencies().traverse(rootContext.compilationUnit.tpdTree)
264266
computeFreeVars()
265267
computeLiftedOwners()
266-
end DependencyCollector
268+
}
269+
end Dependencies

compiler/src/dotty/tools/dotc/transform/LambdaLift.scala

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,37 +27,41 @@ object LambdaLift {
2727
val name: String = "lambdaLift"
2828

2929
/** The core lambda lift functionality. */
30-
class Lifter(thisPhase: MiniPhase & DenotTransformer)(using Context) extends DependencyCollector:
31-
32-
/** A map storing the free variable proxies of functions and classes.
33-
* For every function and class, this is a map from the free variables
34-
* of that function or class to the proxy symbols accessing them.
35-
*/
36-
private val proxyMap = new LinkedHashMap[Symbol, Map[Symbol, Symbol]]
30+
class Lifter(thisPhase: MiniPhase & DenotTransformer)(using Context):
3731

3832
/** The outer parameter of a constructor */
3933
private val outerParam = new HashMap[Symbol, Symbol]
4034

4135
/** Buffers for lifted out classes and methods, indexed by owner */
4236
val liftedDefs: mutable.HashMap[Symbol, mutable.ListBuffer[Tree]] = new HashMap
4337

44-
def proxyOf(sym: Symbol, fv: Symbol): Symbol = proxyMap.getOrElse(sym, Map.empty)(fv)
38+
val deps = new Dependencies(ctx.withPhase(thisPhase)):
39+
def enclosure(using Context) = ctx.owner.enclosingMethod
40+
def isExpr(sym: Symbol)(using Context): Boolean = sym.is(Method)
41+
42+
override def process(tree: Tree)(using Context): Unit =
43+
super.process(tree)
44+
tree match
45+
case tree: DefDef if tree.symbol.isConstructor =>
46+
tree.termParamss.head.find(_.name == nme.OUTER) match
47+
case Some(vdef) => outerParam(tree.symbol) = vdef.symbol
48+
case _ =>
49+
case tree: Template =>
50+
liftedDefs(tree.symbol.owner) = new mutable.ListBuffer
51+
case _ =>
52+
end deps
53+
export deps.{liftedOwner, free}
4554

46-
def proxies(sym: Symbol): List[Symbol] = freeVars(sym).map(proxyOf(sym, _))
55+
/** A map storing the free variable proxies of functions and classes.
56+
* For every function and class, this is a map from the free variables
57+
* of that function or class to the proxy symbols accessing them.
58+
*/
59+
private val proxyMap = new LinkedHashMap[Symbol, Map[Symbol, Symbol]]
4760

48-
def enclosure(using Context) = ctx.owner.enclosingMethod
49-
def isExpr(sym: Symbol)(using Context): Boolean = sym.is(Method)
61+
def proxyOf(sym: Symbol, fv: Symbol): Symbol = proxyMap.getOrElse(sym, Map.empty)(fv)
5062

51-
override def process(tree: Tree)(using Context): Unit =
52-
super.process(tree)
53-
tree match
54-
case tree: DefDef if tree.symbol.isConstructor =>
55-
tree.termParamss.head.find(_.name == nme.OUTER) match
56-
case Some(vdef) => outerParam(tree.symbol) = vdef.symbol
57-
case _ =>
58-
case tree: Template =>
59-
liftedDefs(tree.symbol.owner) = new mutable.ListBuffer
60-
case _ =>
63+
def proxies(sym: Symbol): List[Symbol] =
64+
deps.freeVars(sym).toList.map(proxyOf(sym, _))
6165

6266
private def newName(sym: Symbol)(using Context): Name =
6367
if (sym.isAnonymousFunction && sym.owner.is(Method))
@@ -133,9 +137,6 @@ object LambdaLift {
133137
}
134138

135139
// initialization
136-
atPhase(thisPhase) {
137-
collectDependencies()
138-
}
139140
atPhase(thisPhase.next) {
140141
generateProxies()
141142
liftLocals()
@@ -205,7 +206,7 @@ object LambdaLift {
205206

206207
/** Initialize proxy fields from proxy parameters and map `rhs` from fields to parameters */
207208
def copyParams(rhs: Tree) = {
208-
val fvs = freeVars(sym.owner)
209+
val fvs = deps.freeVars(sym.owner).toList
209210
val classProxies = fvs.map(proxyOf(sym.owner, _))
210211
val constrProxies = fvs.map(proxyOf(sym, _))
211212
report.debuglog(i"copy params ${constrProxies.map(_.showLocated)}%, % to ${classProxies.map(_.showLocated)}%, %}")

0 commit comments

Comments
 (0)