Skip to content

Commit 0de90f3

Browse files
bishaboshaWojciechMazur
authored andcommitted
simplify subphase traversal
[Cherry-picked b510772]
1 parent 0404c00 commit 0de90f3

File tree

5 files changed

+56
-41
lines changed

5 files changed

+56
-41
lines changed

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

+25-15
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.
@@ -475,20 +476,25 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
475476

476477
object Run {
477478

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

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

485-
val all = IArray.from(phase.subPhases.map(sub => s"$baseName ($sub)"))
489+
val all = IArray.from(phase.subPhases.map(sub => s"$baseName[$sub]"))
486490

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

496+
def size: Int = all.size
497+
492498
def subPhase(index: Int) =
493499
if index < all.size then all(index)
494500
else baseName
@@ -510,14 +516,17 @@ object Run {
510516
private var nextPhaseName: String = uninitialized // initialized by enterPhase
511517

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

525+
def canAdvanceSubPhase: Boolean =
526+
currentCompletedSubtraversalCount + 1 < subPhases.size
527+
519528
/** Compute the current (sub)phase name and next (sub)phase name */
520-
private[Run] def tickSubphase()(using Context): Unit =
529+
def tickSubphase()(using Context): Unit =
521530
val index = currentCompletedSubtraversalCount
522531
val s = subPhases
523532
currPhaseName = s.subPhase(index)
@@ -546,20 +555,20 @@ object Run {
546555
private def requireInitialized(): Unit =
547556
require((currPhase: Phase | Null) != null, "enterPhase was not called")
548557

549-
private[Run] def checkCancellation(): Boolean =
558+
def checkCancellation(): Boolean =
550559
if Thread.interrupted() then cancel()
551560
isCancelled()
552561

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

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

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

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

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ object Phases {
318318
def runsAfter: Set[String] = Set.empty
319319

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

324324
/** @pre `isRunnable` returns true */
@@ -460,6 +460,13 @@ object Phases {
460460
else
461461
false
462462

463+
inline def runSubPhase[T](id: Run.SubPhase)(inline body: (Run.SubPhase, Context) ?=> T)(using Context): T =
464+
given Run.SubPhase = id
465+
try
466+
body
467+
finally
468+
ctx.run.enterNextSubphase()
469+
463470
/** Do not run if compile progress has been cancelled */
464471
final def cancellable(body: Context ?=> Unit)(using Context): Boolean =
465472
if ctx.run.enterRegion() then

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

+21-23
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

+1-1
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

+1-1
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)