Skip to content

Commit 7279f73

Browse files
committed
Refactor: make state explicit
1 parent 5d1fe86 commit 7279f73

File tree

2 files changed

+52
-31
lines changed

2 files changed

+52
-31
lines changed

compiler/src/dotty/tools/dotc/transform/init/Checker.scala

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package init
55

66
import dotty.tools.dotc._
77
import ast.tpd
8+
import tpd._
89

910
import dotty.tools.dotc.core._
1011
import Contexts._
@@ -15,32 +16,32 @@ import StdNames._
1516
import dotty.tools.dotc.transform._
1617
import Phases._
1718

18-
1919
import scala.collection.mutable
2020

21+
import Semantic._
2122

2223
class Checker extends Phase {
23-
import tpd._
2424

2525
val phaseName = "initChecker"
2626

27-
private val semantic = new Semantic
28-
2927
override val runsAfter = Set(Pickler.name)
3028

3129
override def isEnabled(using Context): Boolean =
3230
super.isEnabled && ctx.settings.YcheckInit.value
3331

3432
override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
35-
units.foreach { unit => traverser.traverse(unit.tpdTree) }
36-
semantic.check()
37-
super.runOn(units)
33+
Semantic.withInitialState {
34+
val traverser = new InitTreeTraverser()
35+
units.foreach { unit => traverser.traverse(unit.tpdTree) }
36+
Semantic.check()
37+
super.runOn(units)
38+
}
3839

3940
def run(using Context): Unit = {
40-
// ignore, we already called `semantic.check()` in `runOn`
41+
// ignore, we already called `Semantic.check()` in `runOn`
4142
}
4243

43-
val traverser = new TreeTraverser {
44+
class InitTreeTraverser(using State) extends TreeTraverser {
4445
override def traverse(tree: Tree)(using Context): Unit =
4546
traverseChildren(tree)
4647
tree match {
@@ -51,13 +52,13 @@ class Checker extends Phase {
5152

5253
mdef match
5354
case tdef: TypeDef if tdef.isClassDef =>
54-
import semantic._
5555
val cls = tdef.symbol.asClass
5656
val ctor = cls.primaryConstructor
5757
val args = ctor.defTree.asInstanceOf[DefDef].termParamss.flatten.map(_ => Hot)
5858
val outer = Hot
5959
val thisRef = ThisRef(cls, outer, ctor, args)
60-
if shouldCheckClass(cls) then semantic.addTask(thisRef)(using Trace.empty)
60+
given Trace = Trace.empty
61+
if shouldCheckClass(cls) then Semantic.addTask(thisRef)
6162
case _ =>
6263

6364
case _ =>

compiler/src/dotty/tools/dotc/transform/init/Semantic.scala

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ import Errors._
1919
import scala.collection.mutable
2020
import scala.annotation.tailrec
2121

22-
class Semantic {
23-
import Semantic._
22+
object Semantic {
2423

2524
// ----- Domain definitions --------------------------------
2625

@@ -93,10 +92,10 @@ class Semantic {
9392
*
9493
* We need to restrict nesting levels of `outer` to finitize the domain.
9594
*/
96-
case class Warm(klass: ClassSymbol, outer: Value, args: List[Value]) extends Ref {
95+
case class Warm(klass: ClassSymbol, outer: Value, args: List[Value])(using Heap) extends Ref {
9796
val objekt = getCachedObject()
9897

99-
private def getCachedObject() =
98+
private def getCachedObject()(using Heap) =
10099
if heap.contains(this) then heap(this)
101100
else {
102101
val obj = Objekt(this.klass, fields = mutable.Map.empty, outers = mutable.Map(this.klass -> this.outer))
@@ -149,7 +148,7 @@ class Semantic {
149148
opaque type Heap = mutable.Map[Warm, Objekt]
150149

151150
/** Note: don't use `val` to avoid incorrect sharing */
152-
def empty: Heap = mutable.Map.empty
151+
private[Semantic] def empty: Heap = mutable.Map.empty
153152

154153
extension (heap: Heap)
155154
def contains(ref: Warm): Boolean = heap.contains(ref)
@@ -160,8 +159,9 @@ class Semantic {
160159
}
161160
type Heap = Heap.Heap
162161

162+
inline def heap(using h: Heap): Heap = h
163+
163164
import Heap._
164-
private val heap: Heap = Heap.empty
165165

166166
/** The environment for method parameters
167167
*
@@ -205,7 +205,7 @@ class Semantic {
205205
}
206206

207207
type Env = Env.Env
208-
def env(using env: Env) = env
208+
inline def env(using env: Env) = env
209209
inline def withEnv[T](env: Env)(op: Env ?=> T): T = op(using env)
210210

211211
import Env._
@@ -233,7 +233,7 @@ class Semantic {
233233
type Promoted = Promoted.Promoted
234234

235235
import Promoted._
236-
def promoted(using p: Promoted): Promoted = p
236+
inline def promoted(using p: Promoted): Promoted = p
237237

238238
/** Interpreter configuration
239239
*
@@ -290,8 +290,15 @@ class Semantic {
290290
value.instantiate(klass, ctor, args, source) ++ errors
291291
}
292292

293+
// ----- State --------------------------------------------
294+
/** Global state of the checker */
295+
class State(val heap: Heap, val workList: WorkList)
296+
297+
given (using s: State): Heap = s.heap
298+
given (using s: State): WorkList = s.workList
299+
293300
/** The state that threads through the interpreter */
294-
type Contextual[T] = (Env, Context, Trace, Promoted) ?=> T
301+
type Contextual[T] = (Env, Context, Trace, Promoted, State) ?=> T
295302

296303
// ----- Error Handling -----------------------------------
297304

@@ -704,7 +711,7 @@ class Semantic {
704711
// ----- Work list ---------------------------------------------------
705712
case class Task(value: ThisRef)(val trace: Trace)
706713

707-
private class WorkList {
714+
class WorkList private[Semantic]() {
708715
private var checkedTasks: Set[Task] = Set.empty
709716
private var pendingTasks: List[Task] = Nil
710717

@@ -713,7 +720,7 @@ class Semantic {
713720

714721
/** Process the worklist until done */
715722
@tailrec
716-
final def work()(using Context): Unit =
723+
final def work()(using State, Context): Unit =
717724
pendingTasks match
718725
case task :: rest =>
719726
pendingTasks = rest
@@ -726,7 +733,7 @@ class Semantic {
726733
*
727734
* This method should only be called from the work list scheduler.
728735
*/
729-
private def doTask(task: Task)(using Context): Unit = {
736+
private def doTask(task: Task)(using State, Context): Unit = {
730737
val thisRef = task.value
731738
val tpl = thisRef.klass.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
732739

@@ -738,14 +745,31 @@ class Semantic {
738745
res.errors.foreach(_.issue)
739746
}
740747
}
748+
inline def workList(using wl: WorkList): WorkList = wl
741749

742-
private val workList = new WorkList
750+
// ----- API --------------------------------
743751

744752
/** Add a checking task to the work list */
745-
def addTask(task: ThisRef)(using Trace) = workList.addTask(Task(task)(trace))
753+
def addTask(task: ThisRef)(using WorkList, Trace) = workList.addTask(Task(task)(trace))
754+
755+
/** Perform check on the work list until it becomes empty
756+
*
757+
* Should only be called once from the checker.
758+
*/
759+
def check()(using State, Context) = workList.work()
746760

747-
/** Perform check on the work list until it becomes empty */
748-
def check()(using Context) = workList.work()
761+
/** Perform actions with initial checking state.
762+
*
763+
* Semantic.withInitialState {
764+
* Semantic.addTask(...)
765+
* ...
766+
* Semantic.check()
767+
* }
768+
*/
769+
def withInitialState[T](work: State ?=> T): T = {
770+
val initialState = State(Heap.empty, new WorkList)
771+
work(using initialState)
772+
}
749773

750774
// ----- Semantic definition --------------------------------
751775

@@ -1210,10 +1234,6 @@ class Semantic {
12101234
traverser.traverse(tpt.tpe)
12111235
buf.toList
12121236

1213-
}
1214-
1215-
object Semantic {
1216-
12171237
// ----- Utility methods and extractors --------------------------------
12181238

12191239
def typeRefOf(tp: Type)(using Context): TypeRef = tp.dealias.typeConstructor match {

0 commit comments

Comments
 (0)