Skip to content

Commit

Permalink
Support Scala 3's Best Effort compilation
Browse files Browse the repository at this point in the history
This commit allows bloop to support best effort compilation for Metals,
with it being enabled with the other Metals options.

Best Effort is meant to be a set of Scala 3 compiler options that allow
the errored, but typed programs, to be able to be serialized into a
TASTy aligned format (Best Effort TASTy), and later to reuse those
typed program trees in both the dependent projects, and in the
presentation compiler.

Those best effort tasty files are serialized to a
META-INF/best-effort in classesDir. Best effort compilation
may fail, similarly to the regular compilation. In that case we
stop compiling the downstream dependencies.

Currently best-effort compilation is unable t assist in producing the
zinc analysis files, which lead to the projects being recompiled every
time. This is solved with a custom hashing solution.
  • Loading branch information
jchyb committed May 29, 2024
1 parent 335d37e commit 8e006f6
Show file tree
Hide file tree
Showing 22 changed files with 735 additions and 158 deletions.
41 changes: 29 additions & 12 deletions backend/src/main/scala/bloop/BloopClassFileManager.scala
Original file line number Diff line number Diff line change
Expand Up @@ -216,19 +216,36 @@ final class BloopClassFileManager(
) => {
clientTracer.traceTaskVerbose("copy new products to external classes dir") { _ =>
val config = ParallelOps.CopyConfiguration(5, CopyMode.ReplaceExisting, Set.empty)
ParallelOps
.copyDirectories(config)(
newClassesDir,
clientExternalClassesDir.underlying,
inputs.ioScheduler,
enableCancellation = false,
inputs.logger
)
.map { walked =>
readOnlyCopyDenylist.++=(walked.target)
val clientExternalBestEffortDir =
clientExternalClassesDir.underlying.resolve("META-INF/best-effort")

// Deletes all previous best-effort artifacts to get rid of all of the outdated ones.
// Since best effort compilation is not affected by incremental compilation,
// all relevant files are always produced by the compiler. Because of this,
// we can always delete all previous files and copy newly created ones
// without losing anything in the process.
val deleteClientExternalBestEffortDir =
Task {
if (Files.exists(clientExternalBestEffortDir)) {
BloopPaths.delete(AbsolutePath(clientExternalBestEffortDir))
}
()
}
.flatMap(_ => deleteAfterCompilation)
}.memoize

deleteClientExternalBestEffortDir *>
ParallelOps
.copyDirectories(config)(
newClassesDir,
clientExternalClassesDir.underlying,
inputs.ioScheduler,
enableCancellation = false,
inputs.logger
)
.map { walked =>
readOnlyCopyDenylist.++=(walked.target)
()
}
.flatMap(_ => deleteAfterCompilation)
}
}
)
Expand Down
Loading

0 comments on commit 8e006f6

Please sign in to comment.