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