Skip to content
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

Prevent overcompilation in mixed projects without pipelining #868

Merged
merged 6 commits into from
Aug 3, 2020
Merged

Prevent overcompilation in mixed projects without pipelining #868

merged 6 commits into from
Aug 3, 2020

Conversation

eatkins
Copy link
Contributor

@eatkins eatkins commented Aug 1, 2020

The latest zinc will overcompile mixed projects when scala sources have changed but no java sources have. Fixes #867.

It is possible to invoke the java compiiler in  astate where the output
directory doens't exist. When this happens, the compiler throws an
IllegalStateException:

[error] sbt.internal.inc.BatchScriptRunner$PreciseScriptedError: {line 8} Command failed: 'run'
[error] Caused by: java.lang.IllegalStateException: directory not found: /var/folders/zv/2wskcxc14cn6kyj4yb53whc40000gn/T/sbt_4bd7559c/target/classes
[error]         at com.sun.tools.javac.main.Main.error(Main.java:186)
[error]         at
com.sun.tools.javac.main.Main.checkDirectory(Main.java:345)
[error]         at
com.sun.tools.javac.main.Main.processArgs(Main.java:274)
[error]         at com.sun.tools.javac.main.Main.compile(Main.java:414)
[error]         at
com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
[error]         at
com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
[error]         at
sbt.internal.inc.javac.LocalJavaCompiler.run(LocalJava.scala:327)
[error]         at
sbt.internal.inc.javac.AnalyzingJavaCompiler.$anonfun$compile$12(AnalyzingJavaCompiler.scala:167)
...
@@ -340,18 +340,21 @@ object Incremental {
incremental.invalidateInitial(previous.relations, initialChanges)

// If there's any compilation at all, invalidate all java sources too, so we have access to their type information.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about this part? Does this change lead to a loss of type information?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That comment was added in 0504f70 (port of https://github.com/mspnf/zinc/blob/9ef2eba6f829c2afa783987f64ea4e785b678265/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala). The type information that this makes it available is to the downstream subproject compilation, which is only relevant in pipelining.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, cool, thanks.

We should always call Files.createDirectories to ensure the output
directory exists. If the directory already exists and is a directory,
Files.createDirectories is a no-op and is the same amount of io as the
Files.exists check. If the directory exists but is actually a file, then
that is a bug and compilcation is likely to fail so we should throw an
exception.
When any java source is invalidated, we want to recompile the entire
subproject to generate the java class signatures. For this reason, it is
necessary to invalidate _all_ of the java sources when any change is
detected. We don't however want to recompile all of the java sources if
_none_ of them have changed.

Prior to this change, in the sbt build with pipelining off, changing any
scala source in a mixed project would rebuild all of the java sources
which could trigger a cascade of invalidations that could potentially
invalidate the entire project even when none of the java sources had
actually changed. Due to this behavioral change, in
0504f70 it was necessary to change the
iteration count in less-inter-inv-java test from 3 to 2 because the
overcompiling behavior made it only do one cycle when a single source
file was changed because all of the sources were automatically
invalidated. This commit restores the old behavior so the test can be
restored as well. It also adds a test for mixed projects to ensure that
changing a scala file does not automatically trigger recompilation of
java files.
Copy link
Member

@eed3si9n eed3si9n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines -352 to +353
if (initialInvSources0.nonEmpty) initialInvSources0 ++ javaSources
else Set.empty[VirtualFileRef]
if (isPickleJava && initialInvSources0.nonEmpty) initialInvSources0 ++ javaSources
else initialInvSources0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 There's no point in invalidating Java sources unless isPickleJava is on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. I was about to submit a comment justifying this choice but I don't need to since you've confirmed my intuition.

Copy link
Contributor Author

@eatkins eatkins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@eed3si9n eed3si9n merged commit c32628a into sbt:develop Aug 3, 2020
@eatkins eatkins deleted the java-invalidations branch August 3, 2020 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Zinc invalidates all java sources in mixed projects with any scala source change
3 participants