@@ -129,50 +129,58 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
129
129
Thicket (field, getter)
130
130
}
131
131
132
- /** Replace a local lazy val inside a method,
133
- * with a LazyHolder from
134
- * dotty.runtime(eg dotty.runtime.LazyInt)
135
- */
132
+ /** Desugar a local `lazy val x: Int = <RHS>` into:
133
+ *
134
+ * ```
135
+ * val x$lzy = new scala.runtime.LazyInt()
136
+ *
137
+ * def x$lzycompute(): Int = x$lzy.synchronized {
138
+ * if (x$lzy.initialized()) x$lzy.value()
139
+ * else x$lzy.initialize(<RHS>)
140
+ * // for a Unit-typed lazy val, this becomes `{ rhs ; x$lzy.initialize() }`
141
+ * // to avoid passing around BoxedUnit
142
+ * }
143
+ *
144
+ * def x(): Int = if (x$lzy.initialized()) x$lzy.value() else x$lzycompute()
145
+ * ```
146
+ *
147
+ * TODO: Implement Unit-typed lazy val optimization described above
148
+ */
136
149
def transformLocalDef (x : ValOrDefDef )(implicit ctx : Context ): Thicket = {
137
- val valueInitter = x.rhs
138
- val xname = x.name.asTermName
139
- val holderName = LazyLocalName .fresh(xname)
140
- val initName = LazyLocalInitName .fresh(xname)
141
- val tpe = x.tpe.widen.resultType.widen
142
-
143
- val holderType =
144
- if (tpe isRef defn.IntClass ) " LazyInt"
145
- else if (tpe isRef defn.LongClass ) " LazyLong"
146
- else if (tpe isRef defn.BooleanClass ) " LazyBoolean"
147
- else if (tpe isRef defn.FloatClass ) " LazyFloat"
148
- else if (tpe isRef defn.DoubleClass ) " LazyDouble"
149
- else if (tpe isRef defn.ByteClass ) " LazyByte"
150
- else if (tpe isRef defn.CharClass ) " LazyChar"
151
- else if (tpe isRef defn.ShortClass ) " LazyShort"
152
- else " LazyRef"
153
-
154
-
155
- val holderImpl = ctx.requiredClass(" dotty.runtime." + holderType)
156
-
157
- val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.pos)
158
- val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType (Nil , tpe), coord = x.pos)
159
- val result = ref(holderSymbol).select(lazyNme.value).withPos(x.pos)
160
- val flag = ref(holderSymbol).select(lazyNme.initialized)
161
- val initer = valueInitter.changeOwnerAfter(x.symbol, initSymbol, this )
162
- val initBody =
163
- adaptToType(
164
- ref(holderSymbol).select(defn.Object_synchronized ).appliedTo(
165
- adaptToType(mkNonThreadSafeDef(result, flag, initer, nullables = Nil ), defn.ObjectType )),
166
- tpe)
167
- val initTree = DefDef (initSymbol, initBody)
168
- val holderTree = ValDef (holderSymbol, New (holderImpl.typeRef, List ()))
169
- val methodBody = tpd.If (flag.ensureApplied,
170
- result.ensureApplied,
171
- ref(initSymbol).ensureApplied).ensureConforms(tpe)
172
-
173
- val methodTree = DefDef (x.symbol.asTerm, methodBody)
174
- ctx.debuglog(s " found a lazy val ${x.show}, \n rewrote with ${holderTree.show}" )
175
- Thicket (holderTree, initTree, methodTree)
150
+ val xname = x.name.asTermName
151
+ val holderName = LazyLocalName .fresh(xname)
152
+ val initName = LazyLocalInitName .fresh(xname)
153
+ val tpe = x.tpe.widen.resultType.widen
154
+
155
+ // val x$lzy = new scala.runtime.LazyInt()
156
+ val holderImpl = defn.LazyHolder ()(ctx)(tpe.typeSymbol)
157
+ val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.pos)
158
+ val holderTree = ValDef (holderSymbol, New (holderImpl.typeRef, List ()))
159
+
160
+ val holderRef = ref(holderSymbol)
161
+ val getValue = holderRef.select(lazyNme.value).ensureApplied.withPos(x.pos)
162
+ val initialized = holderRef.select(lazyNme.initialized).ensureApplied
163
+
164
+ // def x$lzycompute(): Int = x$lzy.synchronized {
165
+ // if (x$lzy.initialized()) x$lzy.value()
166
+ // else x$lzy.initialize(<RHS>)
167
+ // }
168
+ val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType (Nil , tpe), coord = x.pos)
169
+ val rhs = x.rhs.changeOwnerAfter(x.symbol, initSymbol, this )
170
+ val initialize = holderRef.select(lazyNme.initialize).appliedTo(rhs)
171
+ val initBody =
172
+ adaptToType(
173
+ holderRef.select(defn.Object_synchronized ).appliedTo(
174
+ adaptToType(If (initialized, getValue, initialize), defn.ObjectType )),
175
+ tpe)
176
+ val initTree = DefDef (initSymbol, initBody)
177
+
178
+ // def x(): Int = if (x$lzy.initialized()) x$lzy.value() else x$lzycompute()
179
+ val accessorBody = If (initialized, getValue, ref(initSymbol).ensureApplied).ensureConforms(tpe)
180
+ val accessor = DefDef (x.symbol.asTerm, accessorBody)
181
+
182
+ ctx.debuglog(s " found a lazy val ${x.show}, \n rewrote with ${holderTree.show}" )
183
+ Thicket (holderTree, initTree, accessor)
176
184
}
177
185
178
186
@@ -458,6 +466,7 @@ object LazyVals {
458
466
val result : TermName = " result" .toTermName
459
467
val value : TermName = " value" .toTermName
460
468
val initialized : TermName = " initialized" .toTermName
469
+ val initialize : TermName = " initialize" .toTermName
461
470
val retry : TermName = " retry" .toTermName
462
471
}
463
472
}
0 commit comments