-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add sbt incremental compilation support #1244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
To run the scripted tests in dotty-bridge: $ sbt
> scripted source-dependencies/* |
@@ -25,4 +27,12 @@ | |||
* Example: ./src/library/scala/collection/Seq.scala | |||
*/ | |||
default void onSourceCompiled(SourceFile source) {}; | |||
|
|||
default void sourceDependency(File dependsOn, File source, xsbti.DependencyContext context) {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont see what a method does given its name. Should it be addSourceDependency
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove these extra callbacks, they're not needed now that I added Context#sbtCallback
instead.
94c6809
to
5c5bdec
Compare
@@ -160,6 +160,8 @@ class ScalaSettings extends Settings.SettingGroup { | |||
val YtestPickler = BooleanSetting("-Ytest-pickler", "self-test for pickling functionality; should be used with -Ystop-after:pickler") | |||
val YcheckReentrant = BooleanSetting("-Ycheck-reentrant", "check that compiled program does not contain vars that can be accessed from a global root.") | |||
val YkeepComments = BooleanSetting("-Ykeep-comments", "Keep comments when scanning source files.") | |||
val YforceSbtPhase = BooleanSetting("-Yforce-sbt-phase", "Run the sbt incremental compiler phase even if the compiler is ran outside of sbt, for debugging.") | |||
val YdumpSbtApi = BooleanSetting("-Ydump-sbt-api", "For every compiled foo.scala, output the sbt API representation in foo.api, implies -Yforce-sbt-phase.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dependsOn(YforceSbtPhase)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this would force the user to write -Yforce-sbt-phase -Ydump-sbt-api
, I can do the change if you want but I don't think it's very useful
fd79ba0
to
341e76c
Compare
I didn't realize this before but there's a single test that does not pass now: |
401ca9e
to
fffa04e
Compare
55340fe
to
5dae0a7
Compare
This involved some mad ClassLoader hacks, see `CompilerClassLoader`. Starting from this commit, dotty-bridge will only work with a dotty where scala/scala3#1244 has been merged.
OK I just fixed
I've also cleaned up the changes needed to |
/cc @gkossakowski and @adriaanm who might be interested to know that this exist (also thanks to both of you for the discussions we had on incremental compilation!) |
quick hack to experiment with stability/perf of api extraction I tried to stay as close to the way it's done in sbt, EXCEPT for fusing all traversals into one tree walk (there's still some local redundant tree.foreach'ing, but should be ok) i do believe integrating sbt's compiler interface into the compiler is the way forward
This involved some mad ClassLoader hacks, see `CompilerClassLoader`. Starting from this commit, dotty-bridge will only work with a dotty where scala/scala3#1244 has been merged.
d318f9f
to
64d2b47
Compare
This involved some mad ClassLoader hacks, see `CompilerClassLoader`. Starting from this commit, dotty-bridge will only work with a dotty where scala/scala3#1244 has been merged.
This involved some mad ClassLoader hacks, see `CompilerClassLoader`. Starting from this commit, dotty-bridge will only work with a dotty where scala/scala3#1244 has been merged.
Needs rebasing. |
@@ -41,56 +41,58 @@ class Compiler { | |||
*/ | |||
def phases: List[List[Phase]] = | |||
List( | |||
List(new FrontEnd), // Compiler frontend: scanner, parser, namer, typer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer not to loose git history here.
Indentation is not that important.
Additionally, it will introduce a lot of merge conflicts with linker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, will revert formatting change (though note that git blame -w
and git diff -w
make this less important)
I've done a quick review, as I'm not into details of I'd be curious to see how much does introduction of this phase affect compilation time of dotty&stdlib. Otherwise LGTM |
I spent a bunch of time optimizing it and currently it adds a few seconds to compilation, most of that time is just because of the full AST traversal done by |
SymDenotations#topLevelClass: don't throw an exception Symbols#associateFile: avoid infinite loop
This works similarly to `Trees#TreeTraverser`.
To test this with sbt, see https://github.com/lampepfl/dotty/wiki/Using-Dotty-with-sbt The following flags are added: - -Yforce-sbt-phases: Run the phases used by sbt for incremental compilation (ExtractDependencies and ExtractAPI) even if the compiler is ran outside of sbt, for debugging. - -Ydump-sbt-inc: For every compiled foo.scala, output the API representation and dependencies used for sbt incremental compilation in foo.inc, implies -Yforce-sbt-phases. This commit introduces two new phases which do not transform trees: - `ExtractDependencies` which extracts the dependency information of the current compilation unit and sends it to sbt via callbacks - `ExtractAPI` which creates a representation of the API of the current compilation unit and sends it to sbt via callbacks Briefly, when a file changes sbt will recompile it, if its API has changed (determined by what `ExtractAPI` sent) then sbt will determine which reverse-dependencies (determined by what `ExtractDependencies` sent) of the API have to be recompiled depending on what changed. See http://www.scala-sbt.org/0.13/docs/Understanding-Recompilation.html for more information on how sbt incremental compilation works. This phase was originally based on https://github.com/adriaanm/scala/tree/sbt-api-consolidate/src/compiler/scala/tools/sbt which attempts to integrate the sbt phases into scalac (and is itself based on https://github.com/sbt/sbt/tree/0.13/compile/interface/src/main/scala/xsbt), but it has been heavily refactored and adapted to Dotty. The main functional differences are: - ExtractDependencies runs right after Frontend (so that we don't lose dependency informations because of the simplifications done by PostTyper), but ExtractAPI runs right after PostTyper (so that SuperAccessors are part of the API). - `ExtractAPI` only extract types as they are defined and never "as seen from" some some specific prefix, see its documentation for more details. - `ExtractDependenciesTraverser` and `ExtractUsedNames` have been fused into one tree traversal in `ExtractDependenciesCollector`. TODO: Try to run these phases in parallel with the rest of the compiler pipeline since they're independent (except for the sbt callbacks in `GenBCode`) ?
We have a big improvement in performance, I guess it's due to incremental compilation: |
That's very weird, the incremental compilation cannot possibily be used by these tests, they're not set up to be run through sbt and the dotty-bridge |
This involved some mad ClassLoader hacks, see `CompilerClassLoader`. Starting from this commit, dotty-bridge will only work with a dotty where scala/scala3#1244 has been merged.
@smarter Can you confirm this prevents issues like sbt/sbt#466, as I'm thinking? To summarize: nowadays adding super calls to a |
Review by @DarkDimius
To test this with sbt, see
https://github.com/lampepfl/dotty/wiki/Using-Dotty-with-sbt
The following flags are added:
-Yforce-sbt-phases
: Run the phases used by sbt for incremental compilation(ExtractDependencies and ExtractAPI) even if the compiler is ran outside of
sbt, for debugging.
-Ydump-sbt-inc
: For every compiled foo.scala, output the sbt APIrepresentation and dependencies in foo.inc, implies -Yforce-sbt-phases.
This commit introduces two new phases which do not transform trees:
ExtractDependencies
which extracts the dependency information of the currentcompilation unit and sends it to sbt via callbacks
ExtractAPI
which creates a representation of the API of the current compilationunit and sends it to sbt via callbacks
Briefly, when a file changes sbt will recompile it, if its API has
changed (determined by what
ExtractAPI
sent) then sbt will determinewhich reverse-dependencies (determined by what
ExtractDependencies
sent) of the API have to be recompiled depending on what changed.
See http://www.scala-sbt.org/0.13/docs/Understanding-Recompilation.html for
more information on how sbt incremental compilation works.
This phase was originally based on
https://github.com/adriaanm/scala/tree/sbt-api-consolidate/src/compiler/scala/tools/sbt
which attempts to integrate the sbt phases into scalac (and is itself based
on https://github.com/sbt/sbt/tree/0.13/compile/interface/src/main/scala/xsbt),
but it has been heavily refactored and adapted to Dotty. The main
functional differences are:
dependency informations because of the simplifications done by PostTyper),
but ExtractAPI runs right after PostTyper (so that SuperAccessors are
part of the API).
ExtractAPI
only extract types as they are defined and never "as seenfrom" some some specific prefix, see its documentation for more details.
ExtractDependenciesTraverser
andExtractUsedNames
have been fused intoone tree traversal in
ExtractDependenciesCollector
.TODO: Try to run these phases in parallel with the rest of the compiler
pipeline since they're independent (except for the sbt callbacks in
GenBCode
) ?