diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2017-03-21 22:39:20 +0100 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2017-03-21 23:56:10 +0100 |
commit | 16ce4f7f5b36ef1a182155574fcc7945da4c5653 (patch) | |
tree | f585e60bdf9d5b37414859df2907ebeb93d10cfe /compiler/src/dotty/tools/dotc/sbt/ThunkHolder.scala | |
parent | e54b7e337e5e69e8ef6cc866a641c1e3f0c3b148 (diff) | |
download | dotty-16ce4f7f5b36ef1a182155574fcc7945da4c5653.tar.gz dotty-16ce4f7f5b36ef1a182155574fcc7945da4c5653.tar.bz2 dotty-16ce4f7f5b36ef1a182155574fcc7945da4c5653.zip |
Fix incremental compilation not working after restarting sbt
Previously, every time sbt was restarted, `compile` would do a full
recompilation. This happened because sbt uses Java serialization to
persist the incremental compilation analysis, deserialization was always
silently failing because we used to serialize a class from the
dotty-compiler jar which is not on the classpath at deserialization
time. See the added comments for more details.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/sbt/ThunkHolder.scala')
-rw-r--r-- | compiler/src/dotty/tools/dotc/sbt/ThunkHolder.scala | 68 |
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) |