@@ -129,50 +129,56 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
129129 Thicket (field, getter)
130130 }
131131
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+ * // TODO: Implement Unit-typed lazy val optimization described below
141+ * // for a Unit-typed lazy val, this becomes `{ rhs ; x$lzy.initialize() }`
142+ * // to avoid passing around BoxedUnit
143+ * }
144+ *
145+ * def x(): Int = if (x$lzy.initialized()) x$lzy.value() else x$lzycompute()
146+ * ```
147+ */
136148 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)
149+ val xname = x.name.asTermName
150+ val tpe = x.tpe.widen.resultType.widen
151+
152+ // val x$lzy = new scala.runtime.LazyInt()
153+ val holderName = LazyLocalName .fresh(xname)
154+ val holderImpl = defn.LazyHolder ()(ctx)(tpe.typeSymbol)
155+ val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.pos)
156+ val holderTree = ValDef (holderSymbol, New (holderImpl.typeRef, Nil ))
157+
158+ val holderRef = ref(holderSymbol)
159+ val getValue = holderRef.select(lazyNme.value).ensureApplied.withPos(x.pos)
160+ val initialized = holderRef.select(lazyNme.initialized).ensureApplied
161+
162+ // def x$lzycompute(): Int = x$lzy.synchronized {
163+ // if (x$lzy.initialized()) x$lzy.value()
164+ // else x$lzy.initialize(<RHS>)
165+ // }
166+ val initName = LazyLocalInitName .fresh(xname)
167+ val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType (Nil , tpe), coord = x.pos)
168+ val rhs = x.rhs.changeOwnerAfter(x.symbol, initSymbol, this )
169+ val initialize = holderRef.select(lazyNme.initialize).appliedTo(rhs)
170+ val initBody = holderRef
171+ .select(defn.Object_synchronized )
172+ .appliedToType(tpe)
173+ .appliedTo(If (initialized, getValue, initialize).ensureConforms(tpe))
174+ val initTree = DefDef (initSymbol, initBody)
175+
176+ // def x(): Int = if (x$lzy.initialized()) x$lzy.value() else x$lzycompute()
177+ val accessorBody = If (initialized, getValue, ref(initSymbol).ensureApplied).ensureConforms(tpe)
178+ val accessor = DefDef (x.symbol.asTerm, accessorBody)
179+
180+ ctx.debuglog(s " found a lazy val ${x.show}, \n rewrote with ${holderTree.show}" )
181+ Thicket (holderTree, initTree, accessor)
176182 }
177183
178184
@@ -458,6 +464,7 @@ object LazyVals {
458464 val result : TermName = " result" .toTermName
459465 val value : TermName = " value" .toTermName
460466 val initialized : TermName = " initialized" .toTermName
467+ val initialize : TermName = " initialize" .toTermName
461468 val retry : TermName = " retry" .toTermName
462469 }
463470}
0 commit comments