@@ -12,23 +12,34 @@ import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform
12
12
import dotty .tools .dotc .ast .Trees ._
13
13
import dotty .tools .dotc .ast .{untpd , tpd }
14
14
import dotty .tools .dotc .core .Constants .Constant
15
- import dotty .tools .dotc .core .Types .MethodType
15
+ import dotty .tools .dotc .core .Types .{ ExprType , NoType , MethodType }
16
16
import dotty .tools .dotc .core .Names .Name
17
- import dotty .runtime .LazyVals
17
+ import dotty .runtime .{ LazyVals => RLazyVals } // dotty deviation
18
18
import SymUtils ._
19
19
import scala .collection .mutable .ListBuffer
20
20
import dotty .tools .dotc .core .Denotations .SingleDenotation
21
21
import dotty .tools .dotc .core .SymDenotations .SymDenotation
22
- import dotty .tools .dotc .core .DenotTransformers .{IdentityDenotTransformer , DenotTransformer }
22
+ import dotty .tools .dotc .core .DenotTransformers .{SymTransformer , IdentityDenotTransformer , DenotTransformer }
23
23
24
- class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer {
24
+ class LazyVals extends MiniPhaseTransform with SymTransformer {
25
25
26
26
import tpd ._
27
27
28
28
29
- def transformer = new LazyValsTransform
29
+ def transformSym (d : SymDenotation )(implicit ctx : Context ): SymDenotation = {
30
+ if (d is(Flags .Lazy , butNot = Flags .ModuleVal | Flags .Method )) {
31
+ // Method flag is set on lazy vals coming from Unpickler. They are already methods and shouldn't be transformed twice
32
+ d.copySymDenotation(
33
+ initFlags = d.flags | Flags .Method ,
34
+ info = ExprType (d.info))
35
+ }
36
+ else d
37
+ }
38
+
39
+ def transformer = new LazyVals
30
40
31
- val containerFlags = Flags .Synthetic | Flags .Mutable
41
+ val containerFlags = Flags .Synthetic | Flags .Mutable | Flags .Lazy
42
+ val initFlags = Flags .Synthetic | Flags .Method
32
43
33
44
/** this map contains mutable state of transformation: OffsetDefs to be appended to companion object definitions,
34
45
* and number of bits currently used */
@@ -72,9 +83,9 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
72
83
* dotty.runtime(eg dotty.runtime.LazyInt)
73
84
*/
74
85
def transformLocalValDef (x : ValDef )(implicit ctx : Context ) = x match {
75
- case x@ ValDef (name, tpt, rhs) =>
76
- val valueInitter = rhs
86
+ case x@ ValDef (name, tpt, valueInitter) =>
77
87
val holderName = ctx.freshName(name.toString + StdNames .nme.LAZY_LOCAL ).toTermName
88
+ val initName = ctx.freshName(name.toString + StdNames .nme.LAZY_LOCAL_INIT ).toTermName
78
89
val tpe = x.tpe.widen
79
90
80
91
val holderType =
@@ -88,21 +99,35 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
88
99
else if (tpe isRef defn.ShortClass ) " LazyShort"
89
100
else " LazyRef"
90
101
102
+
91
103
val holderImpl = ctx.requiredClass(" dotty.runtime." + holderType)
92
104
93
- val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.symbol.coord)
94
- val holderTree = ValDef (holderSymbol, New (holderImpl.typeRef, List (valueInitter.changeOwner(x.symbol, holderSymbol))))
105
+ val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.pos)
106
+ val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType (Nil , tpe), coord = x.pos)
107
+ val result = ref(holderSymbol).select(" value" .toTermName)
108
+ val flag = ref(holderSymbol).select(" initialized" .toTermName)
109
+ val initer = valueInitter.changeOwner(x.symbol, initSymbol)
110
+ val initBody =
111
+ ref(holderSymbol).select(defn.Object_synchronized ).appliedToType(tpe).appliedTo(
112
+ mkNonThreadSafeDef(result, flag, initer).ensureConforms(tpe))
113
+ val initTree = DefDef (initSymbol, initBody)
114
+ val holderTree = ValDef (holderSymbol, New (holderImpl.typeRef, List ()))
95
115
val methodBody = {
96
- val prefix = ref(holderSymbol).select(" value" .toTermName)
97
- if (holderType != " LazyRef" ) prefix
98
- else prefix.select(defn.Any_asInstanceOf ).appliedToType(tpe)
116
+ tpd.If (flag, EmptyTree , ref(initSymbol))
117
+ result.ensureConforms(tpe)
99
118
}
100
119
val methodTree = DefDef (x.symbol.asTerm, methodBody)
101
120
ctx.debuglog(s " found a lazy val ${x.show}, \n rewrote with ${holderTree.show}" )
102
- Thicket (holderTree, methodTree)
121
+ Thicket (holderTree, initTree, methodTree)
103
122
}
104
123
105
- /** Create non-threadsafe lazy accessor equivalent to such code
124
+
125
+ override def transformStats (trees : List [tpd.Tree ])(implicit ctx : Context , info : TransformerInfo ): List [tpd.Tree ] = {
126
+ val (holders, stats) = trees.partition { _.symbol.flags == containerFlags}
127
+ holders::: stats
128
+ }
129
+
130
+ /** Create non-threadsafe lazy accessor equivalent to such code
106
131
* def methodSymbol() = {
107
132
* if (flag) target
108
133
* else {
@@ -113,13 +138,11 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
113
138
* }
114
139
*/
115
140
116
- def mkNonThreadSafeDef (target : Symbol , flag : Symbol , rhs : Tree )(implicit ctx : Context ) = {
117
- val cond = ref(flag)
118
- val exp = ref(target)
119
- val setFlag = Assign (cond, Literal (Constants .Constant (true )))
120
- val setTarget = Assign (exp, rhs)
121
- val init = Block (List (setFlag, setTarget), exp)
122
- If (cond, exp, init)
141
+ def mkNonThreadSafeDef (target : Tree , flag : Tree , rhs : Tree )(implicit ctx : Context ) = {
142
+ val setFlag = Assign (flag, Literal (Constants .Constant (true )))
143
+ val setTarget = Assign (target, rhs)
144
+ val init = Block (List (setFlag, setTarget), target)
145
+ If (flag, target, init)
123
146
}
124
147
125
148
/** Create non-threadsafe lazy accessor for not-nullable types equivalent to such code
@@ -155,7 +178,7 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
155
178
val flagName = ctx.freshName(name.toString + StdNames .nme.BITMAP_PREFIX ).toTermName
156
179
val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags, defn.BooleanType )
157
180
val flag = ValDef (flagSymbol, Literal (Constants .Constant (false )))
158
- val slowPath = DefDef (x.symbol.asTerm, mkNonThreadSafeDef(containerSymbol, flagSymbol, rhs))
181
+ val slowPath = DefDef (x.symbol.asTerm, mkNonThreadSafeDef(ref( containerSymbol), ref( flagSymbol) , rhs))
159
182
Thicket (List (containerTree, flag, slowPath))
160
183
}
161
184
@@ -266,15 +289,15 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
266
289
val thiz = This (claz)(ctx.fresh.setOwner(claz))
267
290
val companion = claz.companionModule
268
291
val helperModule = ctx.requiredModule(" dotty.runtime.LazyVals" )
269
- val getOffset = Select (ref(helperModule), LazyVals .Names .getOffset.toTermName)
292
+ val getOffset = Select (ref(helperModule), RLazyVals .Names .getOffset.toTermName)
270
293
var offsetSymbol : TermSymbol = null
271
294
var flag : Tree = EmptyTree
272
295
var ord = 0
273
296
274
297
// compute or create appropriate offsetSymol, bitmap and bits used by current ValDef
275
298
appendOffsetDefs.get(companion.name.moduleClassName) match {
276
299
case Some (info) =>
277
- val flagsPerLong = 64 / LazyVals .BITS_PER_LAZY_VAL
300
+ val flagsPerLong = 64 / RLazyVals .BITS_PER_LAZY_VAL
278
301
info.ord += 1
279
302
ord = info.ord % flagsPerLong
280
303
val id = info.ord / flagsPerLong
@@ -305,11 +328,11 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer
305
328
val containerTree = ValDef (containerSymbol, initValue(tpe))
306
329
307
330
val offset = Select (ref(companion), offsetSymbol.name)
308
- val getFlag = Select (ref(helperModule), LazyVals .Names .get.toTermName)
309
- val setFlag = Select (ref(helperModule), LazyVals .Names .setFlag.toTermName)
310
- val wait = Select (ref(helperModule), LazyVals .Names .wait4Notification.toTermName)
311
- val state = Select (ref(helperModule), LazyVals .Names .state.toTermName)
312
- val cas = Select (ref(helperModule), LazyVals .Names .cas.toTermName)
331
+ val getFlag = Select (ref(helperModule), RLazyVals .Names .get.toTermName)
332
+ val setFlag = Select (ref(helperModule), RLazyVals .Names .setFlag.toTermName)
333
+ val wait = Select (ref(helperModule), RLazyVals .Names .wait4Notification.toTermName)
334
+ val state = Select (ref(helperModule), RLazyVals .Names .state.toTermName)
335
+ val cas = Select (ref(helperModule), RLazyVals .Names .cas.toTermName)
313
336
314
337
val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, rhs, tpe, offset, getFlag, state, cas, setFlag, wait)
315
338
if (flag eq EmptyTree )
0 commit comments