Skip to content

Commit

Permalink
Simplify CapturedVars phase
Browse files Browse the repository at this point in the history
No need for a separate entry in the context's store; we can keep everything in the phase
itself, which is more efficient and modular.
  • Loading branch information
odersky committed Nov 4, 2023
1 parent a18ff54 commit 7beff3a
Showing 1 changed file with 20 additions and 35 deletions.
55 changes: 20 additions & 35 deletions compiler/src/dotty/tools/dotc/transform/CapturedVars.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,20 @@ import core.NameKinds.TempResultName
import core.Constants._
import util.Store
import dotty.tools.uncheckedNN

import scala.compiletime.uninitialized
import ast.tpd.*
import compiletime.uninitialized

/** This phase translates variables that are captured in closures to
* heap-allocated refs.
*/
class CapturedVars extends MiniPhase with IdentityDenotTransformer:
thisPhase =>
import ast.tpd._

override def phaseName: String = CapturedVars.name

override def description: String = CapturedVars.description

private[this] var Captured: Store.Location[util.ReadOnlySet[Symbol]] = uninitialized
private def captured(using Context) = ctx.store(Captured)

override def initContext(ctx: FreshContext): Unit =
Captured = ctx.addLocation(util.ReadOnlySet.empty)
private var captured = util.HashSet[Symbol]()

private class RefInfo(using Context) {
/** The classes for which a Ref type exists. */
Expand All @@ -57,33 +52,10 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer:
myRefInfo.uncheckedNN
}

private class CollectCaptured extends TreeTraverser {
private val captured = util.HashSet[Symbol]()
def traverse(tree: Tree)(using Context) = tree match {
case id: Ident =>
val sym = id.symbol
if (sym.is(Mutable, butNot = Method) && sym.owner.isTerm) {
val enclMeth = ctx.owner.enclosingMethod
if (sym.enclosingMethod != enclMeth) {
report.log(i"capturing $sym in ${sym.enclosingMethod}, referenced from $enclMeth")
captured += sym
}
}
case _ =>
traverseChildren(tree)
}
def runOver(tree: Tree)(using Context): util.ReadOnlySet[Symbol] = {
traverse(tree)
captured
}
}

override def prepareForUnit(tree: Tree)(using Context): Context = {
val captured = atPhase(thisPhase) {
CollectCaptured().runOver(ctx.compilationUnit.tpdTree)
}
ctx.fresh.updateStore(Captured, captured)
}
override def prepareForUnit(tree: Tree)(using Context): Context =
captured.clear()
atPhase(thisPhase)(CapturedVars.collect(captured)).traverse(tree)
ctx

/** The {Volatile|}{Int|Double|...|Object}Ref class corresponding to the class `cls`,
* depending on whether the reference should be @volatile
Expand Down Expand Up @@ -143,3 +115,16 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer:
object CapturedVars:
val name: String = "capturedVars"
val description: String = "represent vars captured by closures as heap objects"

def collect(captured: util.HashSet[Symbol]): TreeTraverser = new:
def traverse(tree: Tree)(using Context) = tree match
case id: Ident =>
val sym = id.symbol
if sym.is(Mutable, butNot = Method) && sym.owner.isTerm then
val enclMeth = ctx.owner.enclosingMethod
if sym.enclosingMethod != enclMeth then
report.log(i"capturing $sym in ${sym.enclosingMethod}, referenced from $enclMeth")
captured += sym
case _ =>
traverseChildren(tree)
end CapturedVars

0 comments on commit 7beff3a

Please sign in to comment.