aboutsummaryrefslogtreecommitdiff
path: root/compiler/src
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2017-03-22 09:21:45 +0100
committerGitHub <noreply@github.com>2017-03-22 09:21:45 +0100
commit3af0ebbde81ff6429175ff1661f4ba927dc0d295 (patch)
treef585e60bdf9d5b37414859df2907ebeb93d10cfe /compiler/src
parente54b7e337e5e69e8ef6cc866a641c1e3f0c3b148 (diff)
parent16ce4f7f5b36ef1a182155574fcc7945da4c5653 (diff)
downloaddotty-3af0ebbde81ff6429175ff1661f4ba927dc0d295.tar.gz
dotty-3af0ebbde81ff6429175ff1661f4ba927dc0d295.tar.bz2
dotty-3af0ebbde81ff6429175ff1661f4ba927dc0d295.zip
Merge pull request #2134 from dotty-staging/fix/incremental-compilation-restart
Fix incremental compilation not working after restarting sbt
Diffstat (limited to 'compiler/src')
-rw-r--r--compiler/src/dotty/tools/dotc/sbt/ThunkHolder.scala68
1 files changed, 64 insertions, 4 deletions
diff --git a/compiler/src/dotty/tools/dotc/sbt/ThunkHolder.scala b/compiler/src/dotty/tools/dotc/sbt/ThunkHolder.scala
index e377de6da..abdd5cfdd 100644
--- a/compiler/src/dotty/tools/dotc/sbt/ThunkHolder.scala
+++ b/compiler/src/dotty/tools/dotc/sbt/ThunkHolder.scala
@@ -1,4 +1,5 @@
-package dotty.tools.dotc
+package dotty.tools
+package dotc
package sbt
import scala.annotation.tailrec
@@ -24,7 +25,7 @@ private[sbt] trait ThunkHolder {
* It will be forced by the next call to `forceThunks()`
*/
def lzy[T <: AnyRef](t: => T): api.Lazy[T] = {
- val l = SafeLazy(() => t)
+ val l = SafeLazyWrapper(() => t)
thunks += l
l
}
@@ -37,10 +38,69 @@ private[sbt] trait ThunkHolder {
* see https://github.com/sbt/zinc/issues/114
*/
def strict2lzy[T <: AnyRef](t: T): api.Lazy[T] =
- SafeLazy.strict(t)
+ SafeLazyWrapper.strict(t)
}
-// TODO: Use xsbti.SafeLazy once https://github.com/sbt/zinc/issues/113 is fixed
+/** Wrapper around SafeLazy implementations.
+ *
+ * `xsbti.SafeLazy` is part of sbt but it is not part of the `interface` jar
+ * that dotty depends on, therefore we can only access it by reflection,
+ * and this will only succeed when dotty is run by sbt (otherwise
+ * `xsbti.SafeLazy` won't be on the classpath at all).
+ *
+ * For testing purposes, we still want to be able to run the sbt phases outside
+ * of sbt, using `-Yforce-sbt-phases` and `-Ydump-sbt-inc`, therefore we
+ * provide a copy of SafeLazy in `dotty.tools.dotc.sbt.SafeLazy` that we use
+ * when `xsbti.SafeLazy` is unavailable.
+ *
+ * This raises a question: why bother with `xsbti.SafeLazy` if we have our own
+ * version anyway? Because sbt uses Java serialization to persist the output of
+ * the incremental compilation analysis when sbt is stopped and restarted. If
+ * we used `dotty.tools.dotc.sbt.SafeLazy` with sbt, deserialization would fail
+ * and every restart of sbt would require a full recompilation.
+ *
+ * Note: this won't be needed once we switch to zinc 1.0 where `SafeLazy` becomes
+ * part of the `interface` jar, see https://github.com/sbt/zinc/issues/113
+ */
+private object SafeLazyWrapper {
+
+ @sharable private[this] val safeLazy =
+ try {
+ Class.forName("xsbti.SafeLazy")
+ } catch {
+ case e: ClassNotFoundException =>
+ null
+ }
+
+ @sharable private[this] val safeLazyApply =
+ if (safeLazy != null)
+ safeLazy.getMethod("apply", classOf[xsbti.F0[_]])
+ else
+ null
+ @sharable private[this] val safeLazyStrict =
+ if (safeLazy != null)
+ safeLazy.getMethod("strict", classOf[Object])
+ else
+ null
+
+ def apply[T <: AnyRef](eval: () => T): xsbti.api.Lazy[T] =
+ if (safeLazyApply != null)
+ safeLazyApply
+ .invoke(null, new xsbti.F0[T] { def apply() = eval() })
+ .asInstanceOf[xsbti.api.Lazy[T]]
+ else
+ SafeLazy(eval)
+
+ def strict[T <: AnyRef](value: T): xsbti.api.Lazy[T] =
+ if (safeLazyStrict != null)
+ safeLazyStrict
+ .invoke(null, value)
+ .asInstanceOf[xsbti.api.Lazy[T]]
+ else
+ SafeLazy.strict(value)
+}
+
+// Adapted from https://github.com/sbt/sbt/blob/0.13/compile/api/src/main/scala/xsbti/SafeLazy.scala
private object SafeLazy {
def apply[T <: AnyRef](eval: () => T): xsbti.api.Lazy[T] =
new Impl(eval)