1
- package dotty .tools .dotc
1
+ package dotty .tools
2
+ package dotc
2
3
package sbt
3
4
4
5
import scala .annotation .tailrec
@@ -24,7 +25,7 @@ private[sbt] trait ThunkHolder {
24
25
* It will be forced by the next call to `forceThunks()`
25
26
*/
26
27
def lzy [T <: AnyRef ](t : => T ): api.Lazy [T ] = {
27
- val l = SafeLazy (() => t)
28
+ val l = SafeLazyWrapper (() => t)
28
29
thunks += l
29
30
l
30
31
}
@@ -37,10 +38,69 @@ private[sbt] trait ThunkHolder {
37
38
* see https://github.com/sbt/zinc/issues/114
38
39
*/
39
40
def strict2lzy [T <: AnyRef ](t : T ): api.Lazy [T ] =
40
- SafeLazy .strict(t)
41
+ SafeLazyWrapper .strict(t)
41
42
}
42
43
43
- // TODO: Use xsbti.SafeLazy once https://github.com/sbt/zinc/issues/113 is fixed
44
+ /** Wrapper around SafeLazy implementations.
45
+ *
46
+ * `xsbti.SafeLazy` is part of sbt but it is not part of the `interface` jar
47
+ * that dotty depends on, therefore we can only access it by reflection,
48
+ * and this will only succeed when dotty is run by sbt (otherwise
49
+ * `xsbti.SafeLazy` won't be on the classpath at all).
50
+ *
51
+ * For testing purposes, we still want to be able to run the sbt phases outside
52
+ * of sbt, using `-Yforce-sbt-phases` and `-Ydump-sbt-inc`, therefore we
53
+ * provide a copy of SafeLazy in `dotty.tools.dotc.sbt.SafeLazy` that we use
54
+ * when `xsbti.SafeLazy` is unavailable.
55
+ *
56
+ * This raises a question: why bother with `xsbti.SafeLazy` if we have our own
57
+ * version anyway? Because sbt uses Java serialization to persist the output of
58
+ * the incremental compilation analysis when sbt is stopped and restarted. If
59
+ * we used `dotty.tools.dotc.sbt.SafeLazy` with sbt, deserialization would fail
60
+ * and every restart of sbt would require a full recompilation.
61
+ *
62
+ * Note: this won't be needed once we switch to zinc 1.0 where `SafeLazy` becomes
63
+ * part of the `interface` jar, see https://github.com/sbt/zinc/issues/113
64
+ */
65
+ private object SafeLazyWrapper {
66
+
67
+ @ sharable private [this ] val safeLazy =
68
+ try {
69
+ Class .forName(" xsbti.SafeLazy" )
70
+ } catch {
71
+ case e : ClassNotFoundException =>
72
+ null
73
+ }
74
+
75
+ @ sharable private [this ] val safeLazyApply =
76
+ if (safeLazy != null )
77
+ safeLazy.getMethod(" apply" , classOf [xsbti.F0 [_]])
78
+ else
79
+ null
80
+ @ sharable private [this ] val safeLazyStrict =
81
+ if (safeLazy != null )
82
+ safeLazy.getMethod(" strict" , classOf [Object ])
83
+ else
84
+ null
85
+
86
+ def apply [T <: AnyRef ](eval : () => T ): xsbti.api.Lazy [T ] =
87
+ if (safeLazyApply != null )
88
+ safeLazyApply
89
+ .invoke(null , new xsbti.F0 [T ] { def apply () = eval() })
90
+ .asInstanceOf [xsbti.api.Lazy [T ]]
91
+ else
92
+ SafeLazy (eval)
93
+
94
+ def strict [T <: AnyRef ](value : T ): xsbti.api.Lazy [T ] =
95
+ if (safeLazyStrict != null )
96
+ safeLazyStrict
97
+ .invoke(null , value)
98
+ .asInstanceOf [xsbti.api.Lazy [T ]]
99
+ else
100
+ SafeLazy .strict(value)
101
+ }
102
+
103
+ // Adapted from https://github.com/sbt/sbt/blob/0.13/compile/api/src/main/scala/xsbti/SafeLazy.scala
44
104
private object SafeLazy {
45
105
def apply [T <: AnyRef ](eval : () => T ): xsbti.api.Lazy [T ] =
46
106
new Impl (eval)
0 commit comments