summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2007-07-12 15:01:25 +0000
committerIulian Dragos <jaguarul@gmail.com>2007-07-12 15:01:25 +0000
commit6d2449f066e1146f4dd6305dc96a096d98830d53 (patch)
treec24bfabdbb013590be0d96e975daf608680babf1
parent8b78ce001230be826d9cda61f4d5973ffe007f0b (diff)
downloadscala-6d2449f066e1146f4dd6305dc96a096d98830d53.tar.gz
scala-6d2449f066e1146f4dd6305dc96a096d98830d53.tar.bz2
scala-6d2449f066e1146f4dd6305dc96a096d98830d53.zip
Fixed bug #1205 to optimize even more tail calls.
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala9
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala8
-rw-r--r--test/files/run/tailcalls.check2
-rw-r--r--test/files/run/tailcalls.scala25
4 files changed, 36 insertions, 8 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 33d8739333..d79310ec93 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -47,9 +47,6 @@ abstract class GenICode extends SubComponent {
val Comparator_equals = definitions.getMember(definitions.getModule("scala.runtime.Comparator"),
nme.equals_)
- /** Tree transformer that makes fresh label defs. */
- val duplicator = new DuplicateLabels
-
///////////////////////////////////////////////////////////
override def run: Unit = {
@@ -558,7 +555,7 @@ abstract class GenICode extends SubComponent {
ctx1
}) :: handlers;
- val duppedFinalizer = duplicator(ctx, finalizer)
+ val duppedFinalizer = (new DuplicateLabels(ctx.labels.keySet))(ctx, finalizer)
if (settings.debug.value)
log("Duplicated finalizer: " + duppedFinalizer)
ctx.Try(
@@ -1666,7 +1663,7 @@ abstract class GenICode extends SubComponent {
* All LabelDefs are entered into the context label map, since it makes no sense
* to delay it any more: they will be used at some point.
*/
- class DuplicateLabels extends Transformer {
+ class DuplicateLabels(boundLabels: collection.Set[Symbol]) extends Transformer {
val labels: Map[Symbol, Symbol] = new HashMap
var method: Symbol = _
var ctx: Context = _
@@ -1679,7 +1676,7 @@ abstract class GenICode extends SubComponent {
override def transform(t: Tree): Tree = {
t match {
- case t @ Apply(fun, args) if t.symbol.isLabel =>
+ case t @ Apply(fun, args) if (t.symbol.isLabel && !boundLabels(t.symbol)) =>
if (!labels.isDefinedAt(t.symbol)) {
val oldLabel = t.symbol
val sym = method.newLabel(oldLabel.pos, unit.fresh.newName(oldLabel.name.toString))
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index 605cf3f3fc..142ae140fd 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -227,8 +227,12 @@ abstract class TailCalls extends Transform
case Return(expr) => super.transform(tree)
case Try(block, catches, finalizer) =>
- if (finalizer == EmptyTree) super.transform(tree)
- else tree
+ if (finalizer == EmptyTree)
+ super.transform(tree)
+ else
+ copy.Try(tree, transform(block, mkContext(ctx, false)), // recursive calls are not in tail position if there is non-empty finally clause
+ transformTrees(catches, ctx).asInstanceOf[List[CaseDef]],
+ transform(finalizer, ctx))
case Throw(expr) => super.transform(tree)
case New(tpt) => super.transform(tree)
diff --git a/test/files/run/tailcalls.check b/test/files/run/tailcalls.check
index e1e23c4ae1..2bf399ec54 100644
--- a/test/files/run/tailcalls.check
+++ b/test/files/run/tailcalls.check
@@ -50,3 +50,5 @@ test NonTailCall.f2 was successful
test TailCall.b1 was successful
test TailCall.b2 was successful
+test FancyTailCalls.tcTryLocal was successful
+test FancyTailCalls.tcTryCatch was successful
diff --git a/test/files/run/tailcalls.scala b/test/files/run/tailcalls.scala
index 8b198b53a0..9e714b979b 100644
--- a/test/files/run/tailcalls.scala
+++ b/test/files/run/tailcalls.scala
@@ -194,6 +194,27 @@ class TailCall[S](s: S) {
}
+class FancyTailCalls {
+
+ def tcTryLocal(x: Int, v: Int): Int = {
+ try {
+ def loop(n: Int): Int = {
+ if (n == 0) v else loop(n - 1)
+ }
+ loop(x)
+ } finally {}
+ }
+
+ final def tcTryCatch(x: Int, v: Int): Int =
+ try {
+ if (x == 0) v
+ else throw new RuntimeException("")
+ } catch {
+ case _: RuntimeException =>
+ tcTryCatch(x - 1, v)
+ }
+
+}
class NonTailCall {
final def f1(n: Int): Int = try {
@@ -348,6 +369,10 @@ object Test {
check_success_b("TailCall.b1", TailCall.b1(max), true);
check_success_b("TailCall.b2", TailCall.b2(max), true);
+
+ val FancyTailCalls = new FancyTailCalls;
+ check_success("FancyTailCalls.tcTryLocal", FancyTailCalls.tcTryLocal(max, max), max)
+ check_success("FancyTailCalls.tcTryCatch", FancyTailCalls.tcTryCatch(max, max), max)
}
}