1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
package dotty.tools
package dotc
package sbt
import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer
import xsbti.api
/** Create and hold thunks. A thunk is a (potentially) unevaluated value
* that may be evaluated once.
*/
private[sbt] trait ThunkHolder {
private[this] val thunks = new ListBuffer[api.Lazy[_]]
/** Force all unevaluated thunks to prevent space leaks. */
@tailrec protected final def forceThunks(): Unit = if (!thunks.isEmpty) {
val toForce = thunks.toList
thunks.clear()
toForce.foreach(_.get())
// Forcing thunks may create new thunks
forceThunks()
}
/** Store the by-name parameter `s` in a `Lazy` container without evaluating it.
* It will be forced by the next call to `forceThunks()`
*/
def lzy[T <: AnyRef](t: => T): api.Lazy[T] = {
val l = SafeLazyWrapper(() => t)
thunks += l
l
}
/** Store the parameter `s` in a `Lazy` container, since `s` is not by-name, there
* is nothing to force.
*
* TODO: Get rid of this method. It is only needed because some xsbti.api classes
* take lazy arguments when they could be strict, but this can be fixed in sbt,
* see https://github.com/sbt/zinc/issues/114
*/
def strict2lzy[T <: AnyRef](t: T): api.Lazy[T] =
SafeLazyWrapper.strict(t)
}
/** 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)
def strict[T <: AnyRef](value: T): xsbti.api.Lazy[T] =
new Strict(value)
private[this] final class Impl[T <: AnyRef](private[this] var eval: () => T) extends xsbti.api.AbstractLazy[T] {
private[this] lazy val _t = {
val t = eval()
eval = null // clear the reference, ensuring the only memory we hold onto is the result
t
}
def get: T = _t
}
private[this] final class Strict[T <: AnyRef](val get: T) extends xsbti.api.Lazy[T] with java.io.Serializable
}
|