From aad6deae7204a7fc95b59ede61b188bb62f51188 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 3 May 2012 23:41:10 -0700 Subject: Fix for broken non-local returns. Don't change the owner of a return if the new owner is nested inside the old owner. Closes SI-5612. --- src/compiler/scala/reflect/internal/Trees.scala | 14 ++++++++++--- test/files/run/nonlocalreturn.check | 1 + test/files/run/nonlocalreturn.scala | 15 +++++++++++++ test/files/run/t5612.check | 4 ++++ test/files/run/t5612.scala | 28 +++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 test/files/run/nonlocalreturn.check create mode 100644 test/files/run/nonlocalreturn.scala create mode 100644 test/files/run/t5612.check create mode 100644 test/files/run/t5612.scala diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 5f1a8f3fbe..c43528b8e9 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -315,11 +315,19 @@ trait Trees extends api.Trees { self: SymbolTable => class ChangeOwnerTraverser(val oldowner: Symbol, val newowner: Symbol) extends Traverser { def changeOwner(tree: Tree) = tree match { case Return(expr) => - if (tree.symbol == oldowner) - tree.symbol = newowner + if (tree.symbol == oldowner) { + // SI-5612 + if (newowner hasTransOwner oldowner) + log("NOT changing owner of %s because %s is nested in %s".format(tree, newowner, oldowner)) + else { + log("changing owner of %s: %s => %s".format(tree, oldowner, newowner)) + tree.symbol = newowner + } + } case _: DefTree | _: Function => - if (tree.symbol != NoSymbol && tree.symbol.owner == oldowner) + if (tree.symbol != NoSymbol && tree.symbol.owner == oldowner) { tree.symbol.owner = newowner + } case _ => } override def traverse(tree: Tree) { diff --git a/test/files/run/nonlocalreturn.check b/test/files/run/nonlocalreturn.check new file mode 100644 index 0000000000..aeb2d5e239 --- /dev/null +++ b/test/files/run/nonlocalreturn.check @@ -0,0 +1 @@ +Some(1) diff --git a/test/files/run/nonlocalreturn.scala b/test/files/run/nonlocalreturn.scala new file mode 100644 index 0000000000..3c1e7420ed --- /dev/null +++ b/test/files/run/nonlocalreturn.scala @@ -0,0 +1,15 @@ +object Test { + def wrap[K](body: => K): K = body + + def f(): Option[Int] = { + wrap({ return Some(1) ; None }) + } + + def main(args: Array[String]) { + println(f()) + } +} +// java.lang.ClassCastException: scala.Some cannot be cast to scala.None$ +// at Test$$anonfun$f$1.apply(nonlocalreturn.scala:5) +// at Test$$anonfun$f$1.apply(nonlocalreturn.scala:5) +// at Test$.wrap(nonlocalreturn.scala:2) diff --git a/test/files/run/t5612.check b/test/files/run/t5612.check new file mode 100644 index 0000000000..9d19cca292 --- /dev/null +++ b/test/files/run/t5612.check @@ -0,0 +1,4 @@ +START for List(Two, Two, One, Three) +TWO +TWO +ONE diff --git a/test/files/run/t5612.scala b/test/files/run/t5612.scala new file mode 100644 index 0000000000..48b3093548 --- /dev/null +++ b/test/files/run/t5612.scala @@ -0,0 +1,28 @@ +object L extends Enumeration { + val One, Two, Three = Value +} + +class Foo { + def foo(xs: List[L.Value]) { + import scala.util.control.Breaks.{break, breakable} + println("START for " + xs) + breakable { + for (x <- xs) { + x match { + case L.One => println("ONE"); return + case L.Two => println("TWO") + case L.Three => println("THREE"); break + } + } + } + println("FINISH") + } +} + +object Test { + def main(args: Array[String]) { + val f = new Foo() + val l = List(L.Two, L.Two, L.One, L.Three) + f.foo(l) + } +} -- cgit v1.2.3