Skip to content

Commit 082dc6f

Browse files
authored
Make incremental compilation aware of synthesized mirrors (#18310)
A product mirror needs to be resynthesized if any class parameter changes, and a sum mirror needs to be resynthesized if any child of the sealed type changes, but previously this did not reliably work because the dependency recording in ExtractDependencies was unaware of mirrors. Instead of making ExtractDependencies aware of mirrors, we solve this by directly recording the dependencies when the mirror is synthesized, this way we can be sure to always correctly invalidate users of mirrors, even if the synthesized mirror type is not present in the AST at phase ExtractDependencies. This is the first time that we record dependencies outside of the ExtractDependencies phase, in the future we should see if we can extend this mechanism to record more dependencies during typechecking to make incremental compilation more robust (e.g. by keeping track of symbols looked up by macros). Eventually, we might even want to completely get rid of the ExtractDependencies phase and record all dependencies on the fly if it turns out to be faster.
2 parents face377 + ec59c31 commit 082dc6f

File tree

22 files changed

+413
-195
lines changed

22 files changed

+413
-195
lines changed

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

+9
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,20 @@ class CompilationUnit protected (val source: SourceFile) {
7373
/** List of all comments present in this compilation unit */
7474
var comments: List[Comment] = Nil
7575

76+
/** This is used to record dependencies to invalidate during incremental
77+
* compilation, but only if `ctx.runZincPhases` is true.
78+
*/
79+
val depRecorder: sbt.DependencyRecorder = sbt.DependencyRecorder()
80+
7681
/** Suspends the compilation unit by thowing a SuspendException
7782
* and recording the suspended compilation unit
7883
*/
7984
def suspend()(using Context): Nothing =
8085
assert(isSuspendable)
86+
// Clear references to symbols that may become stale. No need to call
87+
// `depRecorder.sendToZinc()` since all compilation phases will be rerun
88+
// when this unit is unsuspended.
89+
depRecorder.clear()
8190
if !suspended then
8291
if (ctx.settings.XprintSuspension.value)
8392
report.echo(i"suspended: $this")

Diff for: compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala

+8-3
Original file line numberDiff line numberDiff line change
@@ -676,11 +676,16 @@ private class ExtractAPICollector(using Context) extends ThunkHolder {
676676

677677
// In the Scala2 ExtractAPI phase we only extract annotations that extend
678678
// StaticAnnotation, but in Dotty we currently pickle all annotations so we
679-
// extract everything (except annotations missing from the classpath which
680-
// we simply skip over, and inline body annotations which are handled above).
679+
// extract everything, except:
680+
// - annotations missing from the classpath which we simply skip over
681+
// - inline body annotations which are handled above
682+
// - the Child annotation since we already extract children via
683+
// `api.ClassLike#childrenOfSealedClass` and adding this annotation would
684+
// lead to overcompilation when using zinc's
685+
// `IncOptions#useOptimizedSealed`.
681686
s.annotations.foreach { annot =>
682687
val sym = annot.symbol
683-
if sym.exists && sym != defn.BodyAnnot then
688+
if sym.exists && sym != defn.BodyAnnot && sym != defn.ChildAnnot then
684689
annots += apiAnnotation(annot)
685690
}
686691

0 commit comments

Comments
 (0)