Skip to content

Commit 527a9ec

Browse files
committed
Remove mutable state from StagingLevel
1 parent 67a6475 commit 527a9ec

File tree

6 files changed

+33
-68
lines changed

6 files changed

+33
-68
lines changed

compiler/src/dotty/tools/dotc/inlines/PrepareInlineable.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import transform.{AccessProxies, PCPCheckAndHeal, Splicer}
2121
import transform.SymUtils.*
2222
import config.Printers.inlining
2323
import util.Property
24-
import dotty.tools.dotc.staging.StagingLevel.freshStagingLevelContext
2524

2625
object PrepareInlineable {
2726
import tpd._
@@ -293,7 +292,7 @@ object PrepareInlineable {
293292
if (code.symbol.flags.is(Inline))
294293
report.error("Macro cannot be implemented with an `inline` method", code.srcPos)
295294
Splicer.checkValidMacroBody(code)
296-
(new PCPCheckAndHeal).transform(body)(using freshStagingLevelContext) // Ignore output, only check PCP
295+
(new PCPCheckAndHeal).transform(body) // Ignore output, only check PCP
297296
case Block(List(stat), Literal(Constants.Constant(()))) => checkMacro(stat)
298297
case Block(Nil, expr) => checkMacro(expr)
299298
case Typed(expr, _) => checkMacro(expr)

compiler/src/dotty/tools/dotc/staging/StagingLevel.scala

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,20 @@ import scala.collection.mutable
1313
object StagingLevel {
1414

1515
/** A key to be used in a context property that caches the `levelOf` mapping */
16-
private val LevelOfKey = new Property.Key[mutable.HashMap[Symbol, Int]]
17-
18-
/** Initial context for a StagingTransformer transformation. */
19-
def freshStagingLevelContext(using Context): Context =
20-
ctx.fresh.setProperty(LevelOfKey, new mutable.HashMap[Symbol, Int])
16+
private val LevelOfKey = new Property.Key[Map[Symbol, Int]]
2117

2218
/** The quotation level of the definition of the locally defined symbol */
2319
def levelOf(sym: Symbol)(using Context): Int =
24-
ctx.property(LevelOfKey).get.getOrElse(sym, 0)
25-
26-
def removeLevelOf(sym: Symbol)(using Context): Unit =
27-
val levelOfMap = ctx.property(LevelOfKey).get
28-
levelOfMap -= sym
20+
ctx.property(LevelOfKey) match
21+
case Some(map) => map.getOrElse(sym, 0)
22+
case None => 0
2923

30-
/** Enter staging level of symbol defined by `tree` */
31-
def markSymbol(sym: Symbol)(using Context): Boolean =
32-
val levelOfMap = ctx.property(LevelOfKey).get
33-
if level != 0 && !levelOfMap.contains(sym) then
34-
levelOfMap(sym) = level
35-
true
24+
/** Context with the current staging level set for the symbols */
25+
def symbolsInCurrentLevel(syms: List[Symbol])(using Context): Context =
26+
if level == 0 then ctx
3627
else
37-
false
28+
val levelOfMap = ctx.property(LevelOfKey).getOrElse(Map.empty)
29+
val syms1 = syms//.filter(sym => !levelOfMap.contains(sym))
30+
val newMap = syms1.foldLeft(levelOfMap)((acc, sym) => acc.updated(sym, level))
31+
ctx.fresh.setProperty(LevelOfKey, newMap)
3832
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import scala.collection.mutable
1919
import dotty.tools.dotc.core.Annotations._
2020
import dotty.tools.dotc.core.StdNames._
2121
import dotty.tools.dotc.quoted._
22-
import dotty.tools.dotc.staging.StagingLevel.freshStagingLevelContext
2322
import dotty.tools.dotc.inlines.Inlines
2423

2524
import scala.annotation.constructorOnly
@@ -93,7 +92,7 @@ class PickleQuotes extends MacroTransform {
9392
case _ =>
9493

9594
override def run(using Context): Unit =
96-
if (ctx.compilationUnit.needsStaging) super.run(using freshStagingLevelContext)
95+
if (ctx.compilationUnit.needsStaging) super.run
9796

9897
protected def newTransformer(using Context): Transformer = new Transformer {
9998
override def transform(tree: tpd.Tree)(using Context): tpd.Tree =

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import dotty.tools.dotc.core.Annotations._
2121
import dotty.tools.dotc.core.Names._
2222
import dotty.tools.dotc.core.StdNames._
2323
import dotty.tools.dotc.quoted._
24-
import dotty.tools.dotc.staging.StagingLevel.freshStagingLevelContext
2524
import dotty.tools.dotc.config.ScalaRelease.*
2625

2726
import scala.annotation.constructorOnly
@@ -77,7 +76,7 @@ class Splicing extends MacroTransform:
7776

7877
override def run(using Context): Unit =
7978
if ctx.compilationUnit.needsStaging then
80-
super.run(using freshStagingLevelContext)
79+
super.run
8180

8281
protected def newTransformer(using Context): Transformer = Level0QuoteTransformer
8382

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class Staging extends MacroTransform {
5151
tp
5252
}
5353
}
54-
checker.transform(tree)(using freshStagingLevelContext)
54+
checker.transform(tree)
5555
case _ =>
5656
}
5757

@@ -66,7 +66,7 @@ class Staging extends MacroTransform {
6666
}
6767

6868
override def run(using Context): Unit =
69-
if (ctx.compilationUnit.needsStaging) super.run(using freshStagingLevelContext)
69+
if (ctx.compilationUnit.needsStaging) super.run
7070

7171
protected def newTransformer(using Context): Transformer = new Transformer {
7272
override def transform(tree: tpd.Tree)(using Context): tpd.Tree =

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

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,20 @@ import dotty.tools.dotc.core.Contexts._
88
import dotty.tools.dotc.core.StagingContext._
99
import dotty.tools.dotc.core.Symbols._
1010
import dotty.tools.dotc.util.Property
11-
import dotty.tools.dotc.staging.StagingLevel
11+
import dotty.tools.dotc.staging.StagingLevel.*
1212

1313
import scala.collection.mutable
1414

15-
/** The main transformer class
16-
* @param level the current level, where quotes add one and splices subtract one level.
17-
* The initial level is 0, a level `l` where `l > 0` implies code has been quoted `l` times
18-
* and `l == -1` is code inside a top level splice (in an inline method).
19-
* @param levels a stacked map from symbols to the levels in which they were defined
20-
*/
15+
/** TreeMap that keeps track of staging levels using StagingLevel. */
2116
abstract class TreeMapWithStages extends TreeMapWithImplicits {
2217
import tpd._
2318

24-
/** A stack of entered symbols, to be unwound after scope exit */
25-
private[this] var enteredSyms: List[Symbol] = Nil
26-
2719
/** If we are inside a quote or a splice */
2820
private[this] var inQuoteOrSplice = false
2921

30-
/** Locally defined symbols seen so far by `StagingTransformer.transform` */
31-
protected def localSymbols: List[Symbol] = enteredSyms
32-
3322
/** If we are inside a quote or a splice */
3423
protected def isInQuoteOrSplice: Boolean = inQuoteOrSplice
3524

36-
/** Enter staging level of symbol defined by `tree` */
37-
private def markSymbol(sym: Symbol)(using Context): Unit =
38-
if StagingLevel.markSymbol(sym) then
39-
enteredSyms = sym :: enteredSyms
40-
41-
/** Enter staging level of symbol defined by `tree`, if applicable. */
42-
private def markDef(tree: Tree)(using Context): Unit = tree match {
43-
case tree: DefTree => markSymbol(tree.symbol)
44-
case _ =>
45-
}
46-
4725
/** Transform the quote `quote` which contains the quoted `body`.
4826
*
4927
* - `quoted.runtime.Expr.quote[T](<body0>)` --> `quoted.runtime.Expr.quote[T](<body>)`
@@ -66,14 +44,6 @@ abstract class TreeMapWithStages extends TreeMapWithImplicits {
6644
if (tree.source != ctx.source && tree.source.exists)
6745
transform(tree)(using ctx.withSource(tree.source))
6846
else reporting.trace(i"StagingTransformer.transform $tree at $level", staging, show = true) {
69-
def mapOverTree(lastEntered: List[Symbol]) =
70-
try super.transform(tree)
71-
finally
72-
while (enteredSyms ne lastEntered) {
73-
StagingLevel.removeLevelOf(enteredSyms.head)
74-
enteredSyms = enteredSyms.tail
75-
}
76-
7747
def dropEmptyBlocks(tree: Tree): Tree = tree match {
7848
case Block(Nil, expr) => dropEmptyBlocks(expr)
7949
case _ => tree
@@ -118,26 +88,30 @@ abstract class TreeMapWithStages extends TreeMapWithImplicits {
11888
finally inQuoteOrSplice = old
11989

12090
case Block(stats, _) =>
121-
val last = enteredSyms
122-
stats.foreach(markDef)
123-
mapOverTree(last)
91+
val defSyms = stats.collect { case defTree: DefTree => defTree.symbol }
92+
super.transform(tree)(using symbolsInCurrentLevel(defSyms))
12493

12594
case CaseDef(pat, guard, body) =>
126-
val last = enteredSyms
127-
tpd.patVars(pat).foreach(markSymbol)
128-
mapOverTree(last)
95+
super.transform(tree)(using symbolsInCurrentLevel(tpd.patVars(pat)))
12996

13097
case (_:Import | _:Export) =>
13198
tree
13299

133100
case _: Template =>
134-
val last = enteredSyms
135-
tree.symbol.owner.info.decls.foreach(markSymbol)
136-
mapOverTree(last)
101+
val decls = tree.symbol.owner.info.decls.toList
102+
super.transform(tree)(using symbolsInCurrentLevel(decls))
103+
104+
case LambdaTypeTree(tparams, body) =>
105+
super.transform(tree)(using symbolsInCurrentLevel(tparams.map(_.symbol)))
106+
107+
case tree: DefTree =>
108+
val paramSyms = tree match
109+
case tree: DefDef => tree.paramss.flatten.map(_.symbol)
110+
case _ => Nil
111+
super.transform(tree)(using symbolsInCurrentLevel(tree.symbol :: paramSyms))
137112

138113
case _ =>
139-
markDef(tree)
140-
mapOverTree(enteredSyms)
114+
super.transform(tree)
141115
}
142116
}
143117
}

0 commit comments

Comments
 (0)