From 845c4fcd316ea0ec0b9ad38cad80d77a93607342 Mon Sep 17 00:00:00 2001 From: Iulian Dragos Date: Mon, 30 Mar 2009 14:50:49 +0000 Subject: Fixed nested lazy values (#1589). --- .../scala/tools/nsc/transform/LazyVals.scala | 15 +++++++++----- src/compiler/scala/tools/nsc/transform/Mixin.scala | 24 ++++++++++++++-------- test/files/run/lazy-locals.check | 5 +++++ test/files/run/lazy-locals.scala | 24 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index f3d74e3ed4..ce960068e2 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -72,8 +72,8 @@ abstract class LazyVals extends Transform { case Block(_, _) if !added => added = true typed(addBitmapDefs(sym, stat)) - case ValDef(mods, name, tpt, b @ Block(_, _)) => - typed(copy.ValDef(stat, mods, name, tpt, addBitmapDefs(stat.symbol, b))) + case ValDef(mods, name, tpt, rhs) => + typed(copy.ValDef(stat, mods, name, tpt, addBitmapDefs(stat.symbol, rhs))) case _ => stat } @@ -84,21 +84,26 @@ abstract class LazyVals extends Transform { } /** Add the bitmap definitions to the rhs of a method definition. - * If the rhs has been tail-call trasnformed, insert the bitmap + * If the rhs has been tail-call transformed, insert the bitmap * definitions inside the top-level label definition, so that each * iteration has the lazy values un-initialized. Otherwise add them * at the very beginning of the method. */ private def addBitmapDefs(methSym: Symbol, rhs: Tree): Tree = { + def prependStats(stats: List[Tree], tree: Tree): Block = tree match { + case Block(stats1, res) => Block(stats ::: stats1, res) + case _ => Block(stats, tree) + } + val bmps = bitmaps(methSym) map { b => ValDef(b, Literal(Constant(0))) } if (bmps.isEmpty) rhs else rhs match { case Block(assign, l @ LabelDef(name, params, rhs1)) if (name.toString.equals("_" + methSym.name) && List.forall2(params.tail, methSym.tpe.paramTypes) { (ident, tpe) => ident.tpe == tpe }) => val sym = l.symbol - Block(assign, copy.LabelDef(l, name, params, typed(Block(bmps, rhs1)))) + Block(assign, copy.LabelDef(l, name, params, typed(prependStats(bmps, rhs1)))) - case _ => Block(bmps, rhs) + case _ => prependStats(bmps, rhs) } } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 16f710a481..c41ade3ea7 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -611,7 +611,7 @@ abstract class Mixin extends InfoTransform { * where bitmap$n is an int value acting as a bitmap of initialized values. It is * the 'n' is (offset / 32), the MASK is (1 << (offset % 32)). */ - def mkLazyDef(clazz: Symbol, init: Tree, retVal: Tree, offset: Int): Tree = { + def mkLazyDef(clazz: Symbol, init: List[Tree], retVal: Tree, offset: Int): Tree = { val bitmapSym = bitmapFor(clazz, offset) @@ -620,12 +620,12 @@ abstract class Mixin extends InfoTransform { If(mkTest(clazz, mask, bitmapSym, true), gen.mkSynchronized(gen.mkAttributedThis(clazz), If(mkTest(clazz, mask, bitmapSym, true), - Block(List(init, - mkSetFlag(clazz, offset)), + Block(init ::: + List(mkSetFlag(clazz, offset)), Literal(Constant(()))), EmptyTree)), EmptyTree) - localTyper.typed(atPos(init.pos)(Block(List(result), retVal))) + localTyper.typed(atPos(init.head.pos)(Block(List(result), retVal))) } def mkCheckedAccessor(clazz: Symbol, retVal: Tree, offset: Int, pos: Position): Tree = { @@ -644,15 +644,21 @@ abstract class Mixin extends InfoTransform { * the class constructor is changed to set the initialized bits. */ def addCheckedGetters(clazz: Symbol, stats: List[Tree]): List[Tree] = { + def findLazyAssignment(stats: List[Tree]): Tree = + (stats find { + case Assign(lhs, _) if lhs.symbol.hasFlag(LAZY) => true + case _ => false + }).get // if there's no assignment then it's a bug and we crash + val stats1 = for (stat <- stats; sym = stat.symbol) yield stat match { case DefDef(mods, name, tp, vp, tpt, rhs) if sym.hasFlag(LAZY) && rhs != EmptyTree && !clazz.isImplClass => assert(fieldOffset.isDefinedAt(sym)) val rhs1 = if (sym.tpe.resultType.typeSymbol == definitions.UnitClass) - mkLazyDef(clazz, rhs, Literal(()), fieldOffset(sym)) + mkLazyDef(clazz, List(rhs), Literal(()), fieldOffset(sym)) else { - val Block(List(assignment), res) = rhs - mkLazyDef(clazz, assignment, Select(This(clazz), res.symbol), fieldOffset(sym)) + val Block(stats, res) = rhs + mkLazyDef(clazz, stats, Select(This(clazz), res.symbol), fieldOffset(sym)) } copy.DefDef(stat, mods, name, tp, vp, tpt, rhs1) @@ -788,13 +794,13 @@ abstract class Mixin extends InfoTransform { if (sym.hasFlag(LAZY) && sym.isGetter) { val rhs1 = if (sym.tpe.resultType.typeSymbol == definitions.UnitClass) - mkLazyDef(clazz, Apply(staticRef(initializer(sym)), List(gen.mkAttributedThis(clazz))), Literal(()), fieldOffset(sym)) + mkLazyDef(clazz, List(Apply(staticRef(initializer(sym)), List(gen.mkAttributedThis(clazz)))), Literal(()), fieldOffset(sym)) else { val assign = atPos(sym.pos) { Assign(Select(This(sym.accessed.owner), sym.accessed) /*gen.mkAttributedRef(sym.accessed)*/ , Apply(staticRef(initializer(sym)), gen.mkAttributedThis(clazz) :: Nil)) } - mkLazyDef(clazz, assign, Select(This(clazz), sym.accessed), fieldOffset(sym)) + mkLazyDef(clazz, List(assign), Select(This(clazz), sym.accessed), fieldOffset(sym)) } rhs1 } else if (sym.getter(sym.owner).tpe.resultType.typeSymbol == definitions.UnitClass) { diff --git a/test/files/run/lazy-locals.check b/test/files/run/lazy-locals.check index 63beca0717..7d14da243b 100644 --- a/test/files/run/lazy-locals.check +++ b/test/files/run/lazy-locals.check @@ -82,3 +82,8 @@ forced lazy val t at n = 5 First 5 elements of ones: List(1, 1, 1, 1, 1) I am initialized when the constructor is run false +forcing x +forcing y +42 +15 +42 diff --git a/test/files/run/lazy-locals.scala b/test/files/run/lazy-locals.scala index 5279901795..be738a0f70 100644 --- a/test/files/run/lazy-locals.scala +++ b/test/files/run/lazy-locals.scala @@ -161,6 +161,28 @@ object Test extends Application { } } + // see #1589 + object NestedLazyVals extends Application { + lazy val x = { + lazy val y = { println("forcing y"); 42; } + println("forcing x") + y + } + + val x1 = 5 + { lazy val y = 10 ; y } + + println(x) + println(x1) + } + + trait TNestedLazyVals { + lazy val x = { lazy val y = 42; y } + } + + object ONestedLazyVals extends Application with TNestedLazyVals { + println(x) + } + println(testLazy) testLazy32 testLazy33 @@ -169,4 +191,6 @@ object Test extends Application { testRecVal new CtorBlock println(testReturnInLazyVal) + NestedLazyVals + ONestedLazyVals } -- cgit v1.2.3