diff options
author | Iulian Dragos <jaguarul@gmail.com> | 2012-07-02 12:02:33 +0200 |
---|---|---|
committer | Iulian Dragos <jaguarul@gmail.com> | 2012-07-02 12:02:33 +0200 |
commit | 59300ee6e3fc2c34482c7fb10ee4f7b298a6fbce (patch) | |
tree | d0d963940c5bb8c185fe9aa6f9a03f2b31a09a11 | |
parent | bad1e8e6d7f513f37353c9f7f23dbde5f59cb038 (diff) | |
download | scala-59300ee6e3fc2c34482c7fb10ee4f7b298a6fbce.tar.gz scala-59300ee6e3fc2c34482c7fb10ee4f7b298a6fbce.tar.bz2 scala-59300ee6e3fc2c34482c7fb10ee4f7b298a6fbce.zip |
Fix SI-5929 - Verify error with finally and pattern match
Don't enter all labels in a method when emitting a forward jump, since some
labels will be duplicated (if defined inside finally blocks). For each forward
jump, enter only the label that is needed for that jump.
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 18 | ||||
-rw-r--r-- | test/files/run/patmat-finally.scala | 25 |
2 files changed, 32 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index f7541a4739..b638745327 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -860,7 +860,7 @@ abstract class GenICode extends SubComponent { if (sym.isLabel) { // jump to a label val label = ctx.labels.getOrElse(sym, { // it is a forward jump, scan for labels - scanForLabels(ctx.defdef, ctx) + resolveForwardLabel(ctx.defdef, ctx, sym) ctx.labels.get(sym) match { case Some(l) => log("Forward jump for " + sym.fullLocationString + ": scan found label " + l) @@ -1406,21 +1406,17 @@ abstract class GenICode extends SubComponent { def ifOneIsNull(l: Tree, r: Tree) = if (isNull(l)) r else if (isNull(r)) l else null /** - * Traverse the tree and store label stubs in the context. This is - * necessary to handle forward jumps, because at a label application - * with arguments, the symbols of the corresponding LabelDef parameters - * are not yet known. + * Find the label denoted by `lsym` and enter it in context `ctx`. * - * Since it is expensive to traverse each method twice, this method is called - * only when forward jumps really happen, and then it re-traverses the whole - * method, scanning for LabelDefs. + * We only enter one symbol at a time, even though we might traverse the same + * tree more than once per method. That's because we cannot enter labels that + * might be duplicated (for instance, inside finally blocks). * * TODO: restrict the scanning to smaller subtrees than the whole method. * It is sufficient to scan the trees of the innermost enclosing block. */ - // - private def scanForLabels(tree: Tree, ctx: Context): Unit = tree foreachPartial { - case t @ LabelDef(_, params, rhs) => + private def resolveForwardLabel(tree: Tree, ctx: Context, lsym: Symbol): Unit = tree foreachPartial { + case t @ LabelDef(_, params, rhs) if t.symbol == lsym => ctx.labels.getOrElseUpdate(t.symbol, { val locals = params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false)) ctx.method addLocals locals diff --git a/test/files/run/patmat-finally.scala b/test/files/run/patmat-finally.scala new file mode 100644 index 0000000000..6f769b30a0 --- /dev/null +++ b/test/files/run/patmat-finally.scala @@ -0,0 +1,25 @@ +/** Test pattern matching and finally, see SI-5929. */ +object Test extends App { + def bar(s1: Object, s2: Object) { + s1 match { + case _ => + } + + try { + () + } finally { + s2 match { + case _ => + } + } + } + + def x = { + null match { case _ => } + + try { 1 } finally { while(false) { } } + } + + bar(null, null) + x +} |