summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala15
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala24
-rw-r--r--test/files/run/lazy-locals.check5
-rw-r--r--test/files/run/lazy-locals.scala24
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
}