Skip to content

Commit

Permalink
Make incremental compilation aware of synthesized mirrors (#18310)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bishabosha committed Jul 31, 2023
2 parents face377 + ec59c31 commit 082dc6f
Show file tree
Hide file tree
Showing 22 changed files with 413 additions and 195 deletions.
9 changes: 9 additions & 0 deletions compiler/src/dotty/tools/dotc/CompilationUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,20 @@ class CompilationUnit protected (val source: SourceFile) {
/** List of all comments present in this compilation unit */
var comments: List[Comment] = Nil

/** This is used to record dependencies to invalidate during incremental
* compilation, but only if `ctx.runZincPhases` is true.
*/
val depRecorder: sbt.DependencyRecorder = sbt.DependencyRecorder()

/** Suspends the compilation unit by thowing a SuspendException
* and recording the suspended compilation unit
*/
def suspend()(using Context): Nothing =
assert(isSuspendable)
// Clear references to symbols that may become stale. No need to call
// `depRecorder.sendToZinc()` since all compilation phases will be rerun
// when this unit is unsuspended.
depRecorder.clear()
if !suspended then
if (ctx.settings.XprintSuspension.value)
report.echo(i"suspended: $this")
Expand Down
11 changes: 8 additions & 3 deletions compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -676,11 +676,16 @@ private class ExtractAPICollector(using Context) extends ThunkHolder {

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

Expand Down
Loading

0 comments on commit 082dc6f

Please sign in to comment.