summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala60
-rw-r--r--test/files/pos/t3670.scala43
-rw-r--r--test/files/run/t3670.check5
-rw-r--r--test/files/run/t3670.scala31
-rw-r--r--test/files/run/t3877.check104
-rw-r--r--test/files/run/t3877.scala81
6 files changed, 319 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index 98b98b06ac..02da067619 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -16,6 +16,28 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
def newTransformer(unit: CompilationUnit): Transformer =
new LazyValues(unit)
+ object LocalLazyValFinder extends Traverser {
+ var result: Boolean = _
+
+ def find(t: Tree) = {result = false; traverse(t); result}
+ def find(ts: List[Tree]) = {result = false; traverseTrees(ts); result}
+
+ override def traverse(t: Tree) {
+ if (!result)
+ t match {
+ case v@ValDef(_, _, _, _) if v.symbol.isLazy =>
+ result = true
+
+ case ClassDef(_, _, _, _) | DefDef(_, _, _, _, _, _) | ModuleDef(_, _, _) =>
+
+ case LabelDef(name, _, _) if nme.isLoopHeaderLabel(name) =>
+
+ case _ =>
+ super.traverse(t)
+ }
+ }
+ }
+
/**
* Transform local lazy accessors to check for the initialized bit.
*/
@@ -46,14 +68,15 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
val enclosingDummyOrMethod =
if (sym.enclMethod == NoSymbol) sym.owner else sym.enclMethod
val idx = lazyVals(enclosingDummyOrMethod)
+ lazyVals(enclosingDummyOrMethod) = idx + 1
val rhs1 = mkLazyDef(enclosingDummyOrMethod, super.transform(rhs), idx)
- lazyVals(sym.owner) = idx + 1
sym.resetFlag(LAZY | ACCESSOR)
rhs1
} else
super.transform(rhs)
+
treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt,
- typed(addBitmapDefs(sym, res)))
+ if (LocalLazyValFinder.find(res)) typed(addBitmapDefs(sym, res)) else res)
}
case Template(parents, self, body) => atOwner(currentOwner) {
@@ -61,9 +84,13 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
var added = false
val stats =
for (stat <- body1) yield stat match {
- case Block(_, _) if !added =>
- added = true
- typed(addBitmapDefs(sym, stat))
+ case Block(_, _) | Apply(_, _) | If(_, _, _) if !added =>
+ // Avoid adding bitmaps when they are fully overshadowed by those
+ // that are added inside loops
+ if (LocalLazyValFinder.find(stat)) {
+ added = true
+ typed(addBitmapDefs(sym, stat))
+ } else stat
case ValDef(mods, name, tpt, rhs) =>
typed(treeCopy.ValDef(stat, mods, name, tpt, addBitmapDefs(stat.symbol, rhs)))
case _ =>
@@ -72,6 +99,29 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
treeCopy.Template(tree, parents, self, stats)
}
+ case ValDef(mods, name, tpt, rhs0) if (!sym.owner.isModule && !sym.owner.isClass) =>
+ val rhs = super.transform(rhs0)
+ treeCopy.ValDef(tree, mods, name, tpt,
+ if (LocalLazyValFinder.find(rhs)) typed(addBitmapDefs(sym, rhs)) else rhs)
+
+ case l@LabelDef(name0, params0, ifp0@If(_, _, _)) if name0.startsWith(nme.WHILE_PREFIX) =>
+ val ifp1 = super.transform(ifp0)
+ val If(cond0, thenp0, elsep0) = ifp1
+ if (LocalLazyValFinder.find(thenp0))
+ treeCopy.LabelDef(l, name0, params0,
+ treeCopy.If(ifp1, cond0, typed(addBitmapDefs(sym.owner, thenp0)), elsep0))
+ else
+ l
+
+ case l@LabelDef(name0, params0, block@Block(stats0, _))
+ if name0.startsWith(nme.WHILE_PREFIX) || name0.startsWith(nme.DO_WHILE_PREFIX) =>
+ val stats1 = super.transformTrees(stats0)
+ if (LocalLazyValFinder.find(stats1))
+ treeCopy.LabelDef(l, name0, params0,
+ treeCopy.Block(block, typed(addBitmapDefs(sym.owner, stats1.head))::stats1.tail, block.expr))
+ else
+ l
+
case _ => super.transform(tree)
}
}
diff --git a/test/files/pos/t3670.scala b/test/files/pos/t3670.scala
new file mode 100644
index 0000000000..ec4fbe5b4f
--- /dev/null
+++ b/test/files/pos/t3670.scala
@@ -0,0 +1,43 @@
+class A {
+ val n = {
+ val z = {
+ lazy val bb = 1
+ bb
+ }
+ val a = {
+ lazy val cc = 2
+ cc
+ }
+ lazy val b = {
+ lazy val dd = 3
+ dd
+ }
+ z
+ }
+}
+
+class B {
+ locally {
+ lazy val ms = "as"
+ ms
+ }
+}
+
+class C {
+ val things = List("things")
+ if(things.size < 100) {
+ lazy val msg = "foo"
+ msg
+ }
+}
+
+class D {
+ val things = List("things")
+ if(things.size < 100) {
+ if (things.size > 10) {
+ lazy val msg = "foo"
+ msg
+ }
+ }
+}
+
diff --git a/test/files/run/t3670.check b/test/files/run/t3670.check
new file mode 100644
index 0000000000..bc49bb6437
--- /dev/null
+++ b/test/files/run/t3670.check
@@ -0,0 +1,5 @@
+a
+b
+1
+2
+42
diff --git a/test/files/run/t3670.scala b/test/files/run/t3670.scala
new file mode 100644
index 0000000000..a37c3a242c
--- /dev/null
+++ b/test/files/run/t3670.scala
@@ -0,0 +1,31 @@
+class C {
+ val things = List("abcs")
+
+ if (things.length < 30) {
+ lazy val a = "a"
+ println(a)
+ }
+ if (things.length < 30) {
+ lazy val b = "b"
+ println(b)
+ }
+}
+
+class M extends Application {
+ def foo {
+ lazy val a = {
+ lazy val b = 1
+ lazy val c = 2
+ println(b)
+ println(c)
+ }
+ a
+ lazy val d = 42
+ println(d)
+ }
+}
+
+object Test extends Application {
+ new C()
+ new M().foo
+} \ No newline at end of file
diff --git a/test/files/run/t3877.check b/test/files/run/t3877.check
new file mode 100644
index 0000000000..72aa5577f6
--- /dev/null
+++ b/test/files/run/t3877.check
@@ -0,0 +1,104 @@
+test1: 3
+test1: 4
+test1: 5
+test1: 6
+test1: 7
+test1: 8
+test1: 9
+test1: 10
+test2: 3
+test2: 4
+test2: 5
+test2: 6
+test2: 7
+test2: 8
+test2: 9
+test2: 10
+test3: 3
+test3: 4
+test3: 5
+test3: 6
+test3: 7
+test3: 8
+test3: 9
+test3: 10
+test4: 3
+test4: 4
+test4: 5
+test4: 6
+test4: 7
+test4: 8
+test4: 9
+test4: 10
+test5.1: 3
+test5.2: 3
+test5.2: 4
+test5.2: 5
+test5.2: 6
+test5.2: 7
+test5.2: 8
+test5.2: 9
+test5.2: 10
+test5.1: 4
+test5.2: 3
+test5.2: 4
+test5.2: 5
+test5.2: 6
+test5.2: 7
+test5.2: 8
+test5.2: 9
+test5.2: 10
+test5.1: 5
+test5.2: 3
+test5.2: 4
+test5.2: 5
+test5.2: 6
+test5.2: 7
+test5.2: 8
+test5.2: 9
+test5.2: 10
+test5.1: 6
+test5.2: 3
+test5.2: 4
+test5.2: 5
+test5.2: 6
+test5.2: 7
+test5.2: 8
+test5.2: 9
+test5.2: 10
+test5.1: 7
+test5.2: 3
+test5.2: 4
+test5.2: 5
+test5.2: 6
+test5.2: 7
+test5.2: 8
+test5.2: 9
+test5.2: 10
+test5.1: 8
+test5.2: 3
+test5.2: 4
+test5.2: 5
+test5.2: 6
+test5.2: 7
+test5.2: 8
+test5.2: 9
+test5.2: 10
+test5.1: 9
+test5.2: 3
+test5.2: 4
+test5.2: 5
+test5.2: 6
+test5.2: 7
+test5.2: 8
+test5.2: 9
+test5.2: 10
+test5.1: 10
+test5.2: 3
+test5.2: 4
+test5.2: 5
+test5.2: 6
+test5.2: 7
+test5.2: 8
+test5.2: 9
+test5.2: 10
diff --git a/test/files/run/t3877.scala b/test/files/run/t3877.scala
new file mode 100644
index 0000000000..5710e982a0
--- /dev/null
+++ b/test/files/run/t3877.scala
@@ -0,0 +1,81 @@
+object Test {
+ val LIMIT = 10
+
+ def test1 {
+ var d = 2
+ var i = 0 // avoid infinite loops
+ while (d < LIMIT && i < LIMIT) {
+ lazy val b = d + 1
+ d = b
+ i += 1
+ println("test1: " + d)
+ }
+ }
+
+ def test2 {
+ var d = 2
+ var i = 0
+ while (true) {
+ lazy val b = d + 1
+ d = b
+ i += 1
+ println("test2: " + d)
+
+ if (d >= LIMIT || i >= LIMIT)
+ return
+ }
+ }
+
+ def test3 {
+ var d = 2
+ var i = 0
+ do {
+ lazy val b = d + 1
+ d = b
+ i += 1
+ println("test3: " + d)
+ } while (d < LIMIT && i < LIMIT)
+ }
+
+ def test4 {
+ var d = 2
+ var i = 0
+ do {
+ lazy val b = d + 1
+ d = b
+ i += 1
+ println("test4: " + d)
+ if (d >= LIMIT || i >= LIMIT)
+ return
+ } while (true)
+ }
+
+ def test5 {
+ var d = 2
+ var i = 0
+ while (d < LIMIT && i < LIMIT) {
+ lazy val b = d + 1
+ d = b
+ i += 1
+ println("test5.1: " + d)
+
+ var e = 2
+ var j = 0
+ while (e < LIMIT && j < LIMIT) {
+ lazy val f = e + 1
+ e = f
+ j += 1
+ println("test5.2: " + e)
+ }
+ }
+ }
+
+
+ def main(args: Array[String]) {
+ test1
+ test2
+ test3
+ test4
+ test5
+ }
+}