Skip to content

Commit b510772

Browse files
committed
simplify subphase traversal
1 parent b072662 commit b510772

File tree

5 files changed

+56
-41
lines changed

5 files changed

+56
-41
lines changed

compiler/src/dotty/tools/dotc/Run.scala

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,15 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
220220
// no subphases were ran, remove traversals from expected total
221221
progress.totalTraversals -= currentPhase.traversals
222222

223-
private def doAdvanceSubPhase()(using Context): Unit =
223+
private def tryAdvanceSubPhase()(using Context): Unit =
224224
trackProgress: progress =>
225-
progress.currentUnitCount = 0 // reset unit count in current (sub)phase
226-
progress.seenPhaseCount += 1 // trace that we've seen a (sub)phase
227-
progress.completedTraversalCount += 1 // add an extra traversal now that we completed a (sub)phase
228-
progress.currentCompletedSubtraversalCount += 1 // record that we've seen a subphase
229-
if !progress.isCancelled() then
230-
progress.tickSubphase()
225+
if progress.canAdvanceSubPhase then
226+
progress.currentUnitCount = 0 // reset unit count in current (sub)phase
227+
progress.seenPhaseCount += 1 // trace that we've seen a (sub)phase
228+
progress.completedTraversalCount += 1 // add an extra traversal now that we completed a (sub)phase
229+
progress.currentCompletedSubtraversalCount += 1 // record that we've seen a subphase
230+
if !progress.isCancelled() then
231+
progress.tickSubphase()
231232

232233
/** Will be set to true if any of the compiled compilation units contains
233234
* a pureFunctions language import.
@@ -476,20 +477,25 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
476477

477478
object Run {
478479

480+
case class SubPhase(val name: String):
481+
override def toString: String = name
482+
479483
class SubPhases(val phase: Phase):
480484
require(phase.exists)
481485

482486
private def baseName: String = phase match
483487
case phase: MegaPhase => phase.shortPhaseName
484488
case phase => phase.phaseName
485489

486-
val all = IArray.from(phase.subPhases.map(sub => s"$baseName ($sub)"))
490+
val all = IArray.from(phase.subPhases.map(sub => s"$baseName[$sub]"))
487491

488492
def next(using Context): Option[SubPhases] =
489493
val next0 = phase.megaPhase.next.megaPhase
490494
if next0.exists then Some(SubPhases(next0))
491495
else None
492496

497+
def size: Int = all.size
498+
493499
def subPhase(index: Int) =
494500
if index < all.size then all(index)
495501
else baseName
@@ -511,14 +517,17 @@ object Run {
511517
private var nextPhaseName: String = uninitialized // initialized by enterPhase
512518

513519
/** Enter into a new real phase, setting the current and next (sub)phases */
514-
private[Run] def enterPhase(newPhase: Phase)(using Context): Unit =
520+
def enterPhase(newPhase: Phase)(using Context): Unit =
515521
if newPhase ne currPhase then
516522
currPhase = newPhase
517523
subPhases = SubPhases(newPhase)
518524
tickSubphase()
519525

526+
def canAdvanceSubPhase: Boolean =
527+
currentCompletedSubtraversalCount + 1 < subPhases.size
528+
520529
/** Compute the current (sub)phase name and next (sub)phase name */
521-
private[Run] def tickSubphase()(using Context): Unit =
530+
def tickSubphase()(using Context): Unit =
522531
val index = currentCompletedSubtraversalCount
523532
val s = subPhases
524533
currPhaseName = s.subPhase(index)
@@ -547,20 +556,20 @@ object Run {
547556
private def requireInitialized(): Unit =
548557
require((currPhase: Phase | Null) != null, "enterPhase was not called")
549558

550-
private[Run] def checkCancellation(): Boolean =
559+
def checkCancellation(): Boolean =
551560
if Thread.interrupted() then cancel()
552561
isCancelled()
553562

554563
/** trace that we are beginning a unit in the current (sub)phase, unless cancelled */
555-
private[Run] def tryEnterUnit(unit: CompilationUnit): Boolean =
564+
def tryEnterUnit(unit: CompilationUnit): Boolean =
556565
if checkCancellation() then false
557566
else
558567
requireInitialized()
559568
cb.informUnitStarting(currPhaseName, unit)
560569
true
561570

562571
/** trace the current progress out of the total, in the current (sub)phase, reporting the next (sub)phase */
563-
private[Run] def refreshProgress()(using Context): Unit =
572+
def refreshProgress()(using Context): Unit =
564573
requireInitialized()
565574
val total = totalProgress()
566575
if total > 0 && !cb.progress(currentProgress(), total, currPhaseName, nextPhaseName) then
@@ -582,8 +591,9 @@ object Run {
582591
def advanceUnit()(using Context): Unit =
583592
if run != null then run.doAdvanceUnit()
584593

585-
def advanceSubPhase()(using Context): Unit =
586-
if run != null then run.doAdvanceSubPhase()
594+
/** if there exists another subphase, switch to it and record progress */
595+
def enterNextSubphase()(using Context): Unit =
596+
if run != null then run.tryAdvanceSubPhase()
587597

588598
/** advance the late count and record progress in the current phase */
589599
def advanceLate()(using Context): Unit =

compiler/src/dotty/tools/dotc/core/Phases.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ object Phases {
329329
def runsAfter: Set[String] = Set.empty
330330

331331
/** for purposes of progress tracking, overridden in TyperPhase */
332-
def subPhases: List[String] = Nil
332+
def subPhases: List[Run.SubPhase] = Nil
333333
final def traversals: Int = if subPhases.isEmpty then 1 else subPhases.length
334334

335335
/** @pre `isRunnable` returns true */
@@ -472,6 +472,13 @@ object Phases {
472472
else
473473
false
474474

475+
inline def runSubPhase[T](id: Run.SubPhase)(inline body: (Run.SubPhase, Context) ?=> T)(using Context): T =
476+
given Run.SubPhase = id
477+
try
478+
body
479+
finally
480+
ctx.run.enterNextSubphase()
481+
475482
/** Do not run if compile progress has been cancelled */
476483
final def cancellable(body: Context ?=> Unit)(using Context): Boolean =
477484
if ctx.run.enterRegion() then

compiler/src/dotty/tools/dotc/typer/TyperPhase.scala

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dotc
33
package typer
44

55
import core._
6+
import Run.SubPhase
67
import Phases._
78
import Contexts._
89
import Symbols._
@@ -31,13 +32,13 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase {
3132
// Run regardless of parsing errors
3233
override def isRunnable(implicit ctx: Context): Boolean = true
3334

34-
def enterSyms(using Context): Boolean = monitor("indexing") {
35+
def enterSyms(using Context)(using subphase: SubPhase): Boolean = monitor(subphase.name) {
3536
val unit = ctx.compilationUnit
3637
ctx.typer.index(unit.untpdTree)
3738
typr.println("entered: " + unit.source)
3839
}
3940

40-
def typeCheck(using Context): Boolean = monitor("typechecking") {
41+
def typeCheck(using Context)(using subphase: SubPhase): Boolean = monitor(subphase.name) {
4142
val unit = ctx.compilationUnit
4243
try
4344
if !unit.suspended then
@@ -49,7 +50,7 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase {
4950
catch case _: CompilationUnit.SuspendException => ()
5051
}
5152

52-
def javaCheck(using Context): Boolean = monitor("checking java") {
53+
def javaCheck(using Context)(using subphase: SubPhase): Boolean = monitor(subphase.name) {
5354
val unit = ctx.compilationUnit
5455
if unit.isJava then
5556
JavaChecks.check(unit.tpdTree)
@@ -58,10 +59,11 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase {
5859
protected def discardAfterTyper(unit: CompilationUnit)(using Context): Boolean =
5960
unit.isJava || unit.suspended
6061

61-
/** Keep synchronised with `monitor` subcalls */
62-
override def subPhases: List[String] = List("indexing", "typechecking", "checking java")
62+
override val subPhases: List[SubPhase] = List(
63+
SubPhase("indexing"), SubPhase("typechecking"), SubPhase("checkingJava"))
6364

6465
override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
66+
val List(Indexing @ _, Typechecking @ _, CheckingJava @ _) = subPhases: @unchecked
6567
val unitContexts =
6668
for unit <- units yield
6769
val newCtx0 = ctx.fresh.setPhase(this.start).setCompilationUnit(unit)
@@ -72,14 +74,12 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase {
7274
else
7375
newCtx
7476

75-
val unitContexts0 =
76-
try
77-
for
78-
unitContext <- unitContexts
79-
if enterSyms(using unitContext)
80-
yield unitContext
81-
finally
82-
ctx.run.advanceSubPhase() // tick from "typer (indexing)" to "typer (typechecking)"
77+
val unitContexts0 = runSubPhase(Indexing) {
78+
for
79+
unitContext <- unitContexts
80+
if enterSyms(using unitContext)
81+
yield unitContext
82+
}
8383

8484
ctx.base.parserPhase match {
8585
case p: ParserPhase =>
@@ -91,23 +91,21 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase {
9191
case _ =>
9292
}
9393

94-
val unitContexts1 =
95-
try
96-
for
97-
unitContext <- unitContexts0
98-
if typeCheck(using unitContext)
99-
yield unitContext
100-
finally
101-
ctx.run.advanceSubPhase() // tick from "typer (typechecking)" to "typer (java checking)"
94+
val unitContexts1 = runSubPhase(Typechecking) {
95+
for
96+
unitContext <- unitContexts0
97+
if typeCheck(using unitContext)
98+
yield unitContext
99+
}
102100

103101
record("total trees after typer", ast.Trees.ntrees)
104102

105-
val unitContexts2 =
103+
val unitContexts2 = runSubPhase(CheckingJava) {
106104
for
107105
unitContext <- unitContexts1
108106
if javaCheck(using unitContext) // after typechecking to avoid cycles
109107
yield unitContext
110-
108+
}
111109
val newUnits = unitContexts2.map(_.compilationUnit).filterNot(discardAfterTyper)
112110
ctx.run.nn.checkSuspendedUnits(newUnits)
113111
newUnits

compiler/test/dotty/tools/dotc/sbt/ProgressCallbackTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ final class ProgressCallbackTest extends DottyTest:
5757

5858
@Test
5959
def cancelMidTyper: Unit =
60-
inspectCancellationAtPhase("typer (typechecking)")
60+
inspectCancellationAtPhase("typer[typechecking]")
6161

6262
@Test
6363
def cancelErasure: Unit =

sbt-bridge/test/xsbt/CompileProgressSpecification.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class CompileProgressSpecification {
5252
val someExpectedPhases = // just check some "fundamental" phases, don't put all phases to avoid brittleness
5353
Set(
5454
"parser",
55-
"typer (indexing)", "typer (typechecking)", "typer (checking java)",
55+
"typer[indexing]", "typer[typechecking]", "typer[checkingJava]",
5656
"sbt-deps",
5757
"posttyper",
5858
"sbt-api",

0 commit comments

Comments
 (0)