Skip to content

Commit 9eeafdf

Browse files
committed
simplify monitor, add tracking/cancellation to semanticdb
1 parent 7fc4341 commit 9eeafdf

File tree

6 files changed

+104
-90
lines changed

6 files changed

+104
-90
lines changed

Diff for: compiler/src/dotty/tools/dotc/Run.scala

+26-20
Original file line numberDiff line numberDiff line change
@@ -172,30 +172,30 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
172172
private var _progress: Progress | Null = null // Set if progress reporting is enabled
173173

174174
/** Only safe to call if progress is being tracked. */
175-
private inline def trackProgress(using Context)(inline op: Context ?=> Progress => Unit): Unit =
175+
private inline def trackProgress(inline op: Progress => Unit): Unit =
176176
val local = _progress
177177
if local != null then
178-
op(using ctx)(local)
178+
op(local)
179179

180-
private inline def foldProgress[T](using Context)(inline default: T)(inline op: Context ?=> Progress => T): T =
180+
private inline def foldProgress[T](inline default: T)(inline op: Progress => T): T =
181181
val local = _progress
182182
if local != null then
183-
op(using ctx)(local)
183+
op(local)
184184
else
185185
default
186186

187-
def didEnterUnit()(using Context): Boolean =
188-
foldProgress(true /* should progress by default */)(_.tryEnterUnit(ctx.compilationUnit))
187+
def didEnterUnit(unit: CompilationUnit): Boolean =
188+
foldProgress(true /* should progress by default */)(_.tryEnterUnit(unit))
189189

190-
def didEnterFinal()(using Context): Boolean =
191-
foldProgress(true /* should progress by default */)(p => !p.checkCancellation())
190+
def progressCancelled(): Boolean =
191+
foldProgress(false /* should progress by default */)(_.checkCancellation())
192192

193-
def doAdvanceUnit()(using Context): Unit =
193+
def doAdvanceUnit(): Unit =
194194
trackProgress: progress =>
195195
progress.unitc += 1 // trace that we completed a unit in the current (sub)phase
196196
progress.refreshProgress()
197197

198-
def doAdvanceLate()(using Context): Unit =
198+
def doAdvanceLate(): Unit =
199199
trackProgress: progress =>
200200
progress.latec += 1 // trace that we completed a late compilation
201201
progress.refreshProgress()
@@ -211,7 +211,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
211211
finally
212212
Thread.currentThread().nn.interrupt()
213213

214-
private def doAdvancePhase(currentPhase: Phase, wasRan: Boolean)(using Context): Unit =
214+
private def doAdvancePhase(currentPhase: Phase, wasRan: Boolean): Unit =
215215
trackProgress: progress =>
216216
progress.unitc = 0 // reset unit count in current (sub)phase
217217
progress.subtraversalc = 0 // reset subphase index to initial
@@ -223,7 +223,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
223223
// no subphases were ran, remove traversals from expected total
224224
progress.totalTraversals -= currentPhase.traversals
225225

226-
private def doAdvanceSubPhase()(using Context): Unit =
226+
private def doEnterSubPhase()(using Context): Unit =
227227
trackProgress: progress =>
228228
progress.unitc = 0 // reset unit count in current (sub)phase
229229
progress.seen += 1 // trace that we've seen a (sub)phase
@@ -351,7 +351,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
351351
if (!ctx.reporter.hasErrors)
352352
Rewrites.writeBack()
353353
suppressions.runFinished(hasErrors = ctx.reporter.hasErrors)
354-
while (finalizeActions.nonEmpty && didEnterFinal()) {
354+
while (finalizeActions.nonEmpty && !progressCancelled()) {
355355
val action = finalizeActions.remove(0)
356356
action()
357357
}
@@ -563,7 +563,7 @@ object Run {
563563
true
564564

565565
/** trace the current progress out of the total, in the current (sub)phase, reporting the next (sub)phase */
566-
private[Run] def refreshProgress()(using Context): Unit =
566+
private[Run] def refreshProgress(): Unit =
567567
requireInitialized()
568568
val total = totalProgress()
569569
if total > 0 && !cb.progress(currentProgress(), total, currPhaseName, nextPhaseName) then
@@ -572,19 +572,25 @@ object Run {
572572
extension (run: Run | Null)
573573

574574
/** record that the current phase has begun for the compilation unit of the current Context */
575-
def enterUnit()(using Context): Boolean =
576-
if run != null then run.didEnterUnit()
575+
def enterUnit(unit: CompilationUnit): Boolean =
576+
if run != null then run.didEnterUnit(unit)
577+
else true // don't check cancellation if we're not tracking progress
578+
579+
/** check progress cancellation, true if not cancelled */
580+
def enterBlock(): Boolean =
581+
if run != null then !run.progressCancelled()
577582
else true // don't check cancellation if we're not tracking progress
578583

579584
/** advance the unit count and record progress in the current phase */
580-
def advanceUnit()(using Context): Unit =
585+
def advanceUnit(): Unit =
581586
if run != null then run.doAdvanceUnit()
582587

583-
def advanceSubPhase()(using Context): Unit =
584-
if run != null then run.doAdvanceSubPhase()
588+
/** advance the current/next sub-phase and record progress */
589+
def enterSubPhase()(using Context): Unit =
590+
if run != null then run.doEnterSubPhase()
585591

586592
/** advance the late count and record progress in the current phase */
587-
def advanceLate()(using Context): Unit =
593+
def advanceLate(): Unit =
588594
if run != null then run.doAdvanceLate()
589595

590596
def enrichedErrorMessage: Boolean = if run == null then false else run.myEnrichedErrorMessage

Diff for: compiler/src/dotty/tools/dotc/core/Phases.scala

+14-17
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ object Phases {
340340
val buf = List.newBuilder[CompilationUnit]
341341
for unit <- units do
342342
given unitCtx: Context = runCtx.fresh.setPhase(this.start).setCompilationUnit(unit).withRootImports
343-
if ctx.run.enterUnit() then
343+
if ctx.run.enterUnit(unit) then
344344
try run
345345
catch case ex: Throwable if !ctx.run.enrichedErrorMessage =>
346346
println(ctx.run.enrichErrorMessage(s"unhandled exception while running $phaseName on $unit"))
@@ -458,29 +458,26 @@ object Phases {
458458
final def iterator: Iterator[Phase] =
459459
Iterator.iterate(this)(_.next) takeWhile (_.hasNext)
460460

461-
/** run the body as one iteration of a (sub)phase (see Run.Progress), Enrich crash messages */
461+
/** Cancellable region, if not cancelled, run the body in the context of the current compilation unit.
462+
* Enrich crash messages.
463+
*/
462464
final def monitor(doing: String)(body: Context ?=> Unit)(using Context): Boolean =
463-
if ctx.run.enterUnit() then
465+
val unit = ctx.compilationUnit
466+
if ctx.run.enterUnit(unit) then
464467
try {body; true}
465-
catch
466-
case NonFatal(ex) if !ctx.run.enrichedErrorMessage =>
467-
report.echo(ctx.run.enrichErrorMessage(s"exception occurred while $doing ${ctx.compilationUnit}"))
468-
throw ex
468+
catch case NonFatal(ex) if !ctx.run.enrichedErrorMessage =>
469+
report.echo(ctx.run.enrichErrorMessage(s"exception occurred while $doing $unit"))
470+
throw ex
469471
finally ctx.run.advanceUnit()
470472
else
471473
false
472474

473-
/** run the body as one iteration of a (sub)phase (see Run.Progress), Enrich crash messages */
474-
final def monitorOpt[T](doing: String)(body: Context ?=> Option[T])(using Context): Option[T] =
475-
if ctx.run.enterUnit() then
476-
try body
477-
catch
478-
case NonFatal(ex) if !ctx.run.enrichedErrorMessage =>
479-
report.echo(ctx.run.enrichErrorMessage(s"exception occurred while $doing ${ctx.compilationUnit}"))
480-
throw ex
481-
finally ctx.run.advanceUnit()
475+
/** Do not run if compile progress has been cancelled */
476+
final def cancellable(body: Context ?=> Unit)(using Context): Boolean =
477+
if ctx.run.enterBlock() then
478+
{body; true}
482479
else
483-
None
480+
false
484481

485482
override def toString: String = phaseName
486483
}

Diff for: compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala

+6-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import NameOps._
1212
import ast.Trees.Tree
1313
import Phases.Phase
1414

15-
1615
/** Load trees from TASTY files */
1716
class ReadTasty extends Phase {
1817

@@ -23,13 +22,14 @@ class ReadTasty extends Phase {
2322

2423
override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
2524
withMode(Mode.ReadPositions) {
26-
val unitContexts = units.map(unit => ctx.fresh.setCompilationUnit(unit))
27-
unitContexts.flatMap(applyPhase()(using _))
25+
val nextUnits = collection.mutable.ListBuffer.empty[CompilationUnit]
26+
val unitContexts = units.view.map(ctx.fresh.setCompilationUnit)
27+
for given Context <- unitContexts if addTasty(nextUnits += _) do ()
28+
nextUnits.toList
2829
}
2930

30-
private def applyPhase()(using Context): Option[CompilationUnit] = monitorOpt(phaseName):
31-
val unit = ctx.compilationUnit
32-
readTASTY(unit)
31+
def addTasty(fn: CompilationUnit => Unit)(using Context): Boolean = monitor(phaseName):
32+
readTASTY(ctx.compilationUnit).foreach(fn)
3333

3434
def readTASTY(unit: CompilationUnit)(using Context): Option[CompilationUnit] = unit match {
3535
case unit: TASTYCompilationUnit =>

Diff for: compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala

+45-34
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import dotty.tools.dotc.{semanticdb => s}
2929
import dotty.tools.io.{AbstractFile, JarArchive}
3030
import dotty.tools.dotc.semanticdb.DiagnosticOps.*
3131
import scala.util.{Using, Failure, Success}
32+
import java.nio.file.Path
33+
import dotty.tools.dotc.reporting.Diagnostic.Warning
3234

3335

3436
/** Extract symbol references and uses to semanticdb files.
@@ -60,48 +62,57 @@ class ExtractSemanticDB private (phaseMode: ExtractSemanticDB.PhaseMode) extends
6062
// Check not needed since it does not transform trees
6163
override def isCheckable: Boolean = false
6264

65+
private def semanticdbOfUnit(unit: CompilationUnit, sourceRoot: String)(using Context) =
66+
ExtractSemanticDB.semanticdbPath(unit.source, ExtractSemanticDB.semanticdbOutDir, sourceRoot)
67+
68+
private def extractSemanticDB(sourceRoot: String, writeSemanticdbText: Boolean)(using Context): Boolean =
69+
monitor(phaseName) {
70+
val unit = ctx.compilationUnit
71+
val extractor = ExtractSemanticDB.Extractor()
72+
extractor.extract(unit.tpdTree)
73+
ExtractSemanticDB.write(
74+
unit.source,
75+
extractor.occurrences.toList,
76+
extractor.symbolInfos.toList,
77+
extractor.synthetics.toList,
78+
semanticdbOfUnit(unit, sourceRoot),
79+
sourceRoot,
80+
writeSemanticdbText
81+
)
82+
}
83+
84+
def computeDiagnostics(
85+
warnings: WarningsMap, sourceRoot: String, accept: SourceDiagnostics => Unit)(using Context): Boolean =
86+
monitor(phaseName) {
87+
val unit = ctx.compilationUnit
88+
for ws <- warnings.get(unit.source) do
89+
val outputPath = semanticdbOfUnit(unit, sourceRoot)
90+
accept(SourceDiagnostics(outputPath, ws.map(_.toSemanticDiagnostic)))
91+
}
92+
93+
type WarningsMap = Map[SourceFile, List[Warning]]
94+
case class SourceDiagnostics(outputDir: Path, diagnostics: List[Diagnostic])
95+
6396
override def runOn(units: List[CompilationUnit])(using ctx: Context): List[CompilationUnit] = {
6497
val sourceRoot = ctx.settings.sourceroot.value
6598
val appendDiagnostics = phaseMode == ExtractSemanticDB.PhaseMode.AppendDiagnostics
99+
val unitContexts = units.map(unit => ctx.fresh.setCompilationUnit(unit).withRootImports)
66100
if (appendDiagnostics)
67101
val warnings = ctx.reporter.allWarnings.groupBy(w => w.pos.source)
68-
units.flatMap { unit =>
69-
warnings.get(unit.source).map { ws =>
70-
val unitCtx = ctx.fresh.setCompilationUnit(unit).withRootImports
71-
val outputDir =
72-
ExtractSemanticDB.semanticdbPath(
73-
unit.source,
74-
ExtractSemanticDB.semanticdbOutDir(using unitCtx),
75-
sourceRoot
76-
)
77-
(outputDir, ws.map(_.toSemanticDiagnostic))
102+
val reportBuf = mutable.ListBuffer.empty[SourceDiagnostics]
103+
val units0 =
104+
for given Context <- unitContexts if computeDiagnostics(warnings, sourceRoot, reportBuf += _)
105+
yield ctx.compilationUnit
106+
cancellable {
107+
reportBuf.toList.asJava.parallelStream().forEach { case SourceDiagnostics(out, warnings) =>
108+
ExtractSemanticDB.appendDiagnostics(warnings, out)
78109
}
79-
}.asJava.parallelStream().forEach { case (out, warnings) =>
80-
ExtractSemanticDB.appendDiagnostics(warnings, out)
81110
}
111+
units0
82112
else
83113
val writeSemanticdbText = ctx.settings.semanticdbText.value
84-
units.foreach { unit =>
85-
val unitCtx = ctx.fresh.setCompilationUnit(unit).withRootImports
86-
val outputDir =
87-
ExtractSemanticDB.semanticdbPath(
88-
unit.source,
89-
ExtractSemanticDB.semanticdbOutDir(using unitCtx),
90-
sourceRoot
91-
)
92-
val extractor = ExtractSemanticDB.Extractor()
93-
extractor.extract(unit.tpdTree)(using unitCtx)
94-
ExtractSemanticDB.write(
95-
unit.source,
96-
extractor.occurrences.toList,
97-
extractor.symbolInfos.toList,
98-
extractor.synthetics.toList,
99-
outputDir,
100-
sourceRoot,
101-
writeSemanticdbText
102-
)
103-
}
104-
units
114+
for given Context <- unitContexts if extractSemanticDB(sourceRoot, writeSemanticdbText)
115+
yield ctx.compilationUnit
105116
}
106117

107118
def run(using Context): Unit = unsupported("run")
@@ -611,4 +622,4 @@ object ExtractSemanticDB:
611622
traverse(vparam.tpt)
612623
tparams.foreach(tp => traverse(tp.rhs))
613624
end Extractor
614-
end ExtractSemanticDB
625+
end ExtractSemanticDB

Diff for: compiler/src/dotty/tools/dotc/transform/init/Checker.scala

+11-11
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,21 @@ class Checker extends Phase:
4040
val traverser = new InitTreeTraverser()
4141
val unitContexts = units.map(unit => checkCtx.fresh.setCompilationUnit(unit))
4242

43-
val unitContexts0 =
44-
for
45-
given Context <- unitContexts
46-
if traverse(traverser)
47-
yield ctx
43+
val units0 =
44+
for given Context <- unitContexts if traverse(traverser) yield ctx.compilationUnit
4845

49-
val classes = traverser.getClasses()
46+
cancellable {
47+
val classes = traverser.getClasses()
5048

51-
if ctx.settings.YcheckInit.value then
52-
Semantic.checkClasses(classes)(using checkCtx)
49+
if ctx.settings.YcheckInit.value then
50+
Semantic.checkClasses(classes)(using checkCtx)
5351

54-
if ctx.settings.YcheckInitGlobal.value then
55-
Objects.checkClasses(classes)(using checkCtx)
52+
if ctx.settings.YcheckInitGlobal.value then
53+
Objects.checkClasses(classes)(using checkCtx)
54+
}
5655

57-
unitContexts0.map(_.compilationUnit)
56+
units0
57+
end runOn
5858

5959
def run(using Context): Unit = unsupported("run")
6060

Diff for: compiler/src/dotty/tools/dotc/typer/TyperPhase.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase {
7979
if enterSyms
8080
yield ctx
8181
finally
82-
ctx.run.advanceSubPhase() // tick from "typer (indexing)" to "typer (typechecking)"
82+
ctx.run.enterSubPhase() // tick from "typer (indexing)" to "typer (typechecking)"
8383

8484
ctx.base.parserPhase match {
8585
case p: ParserPhase =>
@@ -98,7 +98,7 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase {
9898
if typeCheck
9999
yield ctx
100100
finally
101-
ctx.run.advanceSubPhase() // tick from "typer (typechecking)" to "typer (java checking)"
101+
ctx.run.enterSubPhase() // tick from "typer (typechecking)" to "typer (java checking)"
102102

103103
record("total trees after typer", ast.Trees.ntrees)
104104

0 commit comments

Comments
 (0)