summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2005-06-29 09:33:36 +0000
committerIulian Dragos <jaguarul@gmail.com>2005-06-29 09:33:36 +0000
commita4e5d4a1d7209f290973d981897eff94b479b1f3 (patch)
tree561ebcfe7beff4d860743fa96513f8d3ec17494f
parent239380408564518fe11f7f3b9d5abb5bb29f15da (diff)
downloadscala-a4e5d4a1d7209f290973d981897eff94b479b1f3.tar.gz
scala-a4e5d4a1d7209f290973d981897eff94b479b1f3.tar.bz2
scala-a4e5d4a1d7209f290973d981897eff94b479b1f3.zip
Head of empty list fixed and moved tailcalls be...
Head of empty list fixed and moved tailcalls before transmatch
-rwxr-xr-xsources/scala/tools/nsc/Global.scala14
-rw-r--r--sources/scala/tools/nsc/transform/TailCalls.scala62
2 files changed, 46 insertions, 30 deletions
diff --git a/sources/scala/tools/nsc/Global.scala b/sources/scala/tools/nsc/Global.scala
index 1507be774f..154a1ab84b 100755
--- a/sources/scala/tools/nsc/Global.scala
+++ b/sources/scala/tools/nsc/Global.scala
@@ -171,12 +171,18 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
}
val uncurryPhase = new uncurry.Phase(refchecksPhase);
+ object tailCalls extends TailCalls {
+ val global: Global.this.type = Global.this;
+ }
+ val tailCallPhase = new tailCalls.Phase(uncurryPhase);
+
+
object transmatcher extends TransMatcher {
val global: Global.this.type = Global.this;
}
- val transMatchPhase = new transmatcher.Phase(uncurryPhase);
+ val transMatchPhase = new transmatcher.Phase(tailCallPhase);
//object typesAsValues extends TypesAsValues {
// val global: Global.this.type = Global.this;
//}
@@ -186,10 +192,6 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
}
val samplePhase = new sampleTransform.Phase(transMatchPhase);
- object tailCalls extends TailCalls {
- val global: Global.this.type = Global.this;
- }
- val tailCallPhase = new tailCalls.Phase(samplePhase);
//val transMatchPhase = new transmatcher.TransMatchPhase(picklePhase);
/*
@@ -204,7 +206,7 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
}
*/
- val terminalPhase = new Phase(tailCallPhase) {
+ val terminalPhase = new Phase(samplePhase) {
def name = "terminal";
def run: unit = {}
}
diff --git a/sources/scala/tools/nsc/transform/TailCalls.scala b/sources/scala/tools/nsc/transform/TailCalls.scala
index eb42966312..f28ef94f97 100644
--- a/sources/scala/tools/nsc/transform/TailCalls.scala
+++ b/sources/scala/tools/nsc/transform/TailCalls.scala
@@ -124,7 +124,6 @@ abstract class TailCalls extends Transform {
newCtx.makeLabel();
newCtx.label.setInfo(tree.symbol.info);
newCtx.tailPos = true;
- log("Label type is: " + newCtx.label.info);
if (newCtx.currentMethod.isFinal) {
newCtx.types = Nil;
@@ -138,10 +137,12 @@ abstract class TailCalls extends Transform {
var newRHS = transform(rhs, newCtx);
if (newCtx.accessed) {
log("Rewrote def " + newCtx.currentMethod);
- vparams.head map ((v) => log(v.symbol));
+
newRHS =
typed(atPos(tree.pos)(
- LabelDef(newCtx.label, vparams.head map (.symbol), newRHS)));
+ LabelDef(newCtx.label,
+ List.flatten(vparams) map (.symbol),
+ newRHS)));
copy.DefDef(tree, mods, name, tparams, vparams, tpt, newRHS);
} else
copy.DefDef(tree, mods, name, tparams, vparams, tpt, newRHS);
@@ -190,13 +191,21 @@ abstract class TailCalls extends Transform {
case New(tpt) => super.transform(tree);
case Typed(expr, tpt) => super.transform(tree);
+ case Apply(tapply @ TypeApply(fun, targs), vargs) =>
+ if ( ctx.tailPos &&
+ isSameTypes(ctx.types, targs map (.tpe)) &&
+ isRecursiveCall(fun))
+ rewriteTailCall(fun, transformTrees(vargs, mkContext(ctx, false)));
+ else
+ copy.Apply(tree, tapply, transformTrees(vargs, mkContext(ctx, false)));
+
case TypeApply(fun, args) =>
- throw new RuntimeException("Lonely TypeApply found -- we can only handle them inside Apply(TypeApply())");
+ super.transform(tree);
+// throw new RuntimeException("Lonely TypeApply found -- we can only handle them inside Apply(TypeApply()): " + tree + " at: " + unit);
case Apply(fun, args) =>
- log("entering Apply: " + ctx);
- if ((fun.symbol eq ctx.currentMethod) && ctx.tailPos)
- rewriteTailCall(tree, transformTrees(args, mkContext(ctx, false)));
+ if (ctx.tailPos && isRecursiveCall(fun))
+ rewriteTailCall(fun, transformTrees(args, mkContext(ctx, false)));
else
copy.Apply(tree, fun, transformTrees(args, mkContext(ctx, false)));
@@ -212,19 +221,6 @@ abstract class TailCalls extends Transform {
tree;
case TypeTree() => tree;
-// case Block(List(), expr) => // a simple optimization
-// expr
-// case Block(defs, sup @ Super(qual, mix)) => // A hypthothetic transformation, which replaces
-// // {super} by {super.sample}
-// copy.Block( // `copy' is the usual lazy tree copier
-// tree, defs,
-// typed( // `typed' assigns types to its tree argument
-// atPos(tree.pos)( // `atPos' fills in position of its tree argument
-// Select( // The `Select' factory method is defined in class `Trees'
-// sup,
-// currentOwner.newValue( // creates a new term symbol owned by `currentowner'
-// tree.pos,
-// newTermName("sample")))))) // The standard term name creator
case _ =>
tree
}
@@ -233,11 +229,29 @@ abstract class TailCalls extends Transform {
def transformTrees(trees: List[Tree], nctx: Context): List[Tree] =
trees map ((tree) => transform(tree, nctx));
- private def rewriteTailCall(tree: Tree, args: List[Tree]): Tree = {
- log("Rewriting..");
+ private def rewriteTailCall(fun: Tree, args: List[Tree]): Tree = {
+ log("Rewriting tail recursive method call.");
ctx.accessed = true;
- typed(atPos(tree.pos)(
- Apply(Ident(ctx.label), args)));
+ typed(atPos(fun.pos)(
+ Apply(Ident(ctx.label), args)));
}
+
+ /** Return true if the fun tree refers to the same method as the one
+ * saved in ctx. If it is a method call, we check that it is applied to
+ * "this"
+ */
+ private def isRecursiveCall(fun: Tree): Boolean =
+ if (fun.symbol eq ctx.currentMethod)
+ fun match {
+ case Select(t @ This(_), _) =>
+ assert(t.symbol == ctx.currentMethod.owner, "This refers to other class: " +
+ t.symbol + ": " + ctx.currentMethod.owner);
+ true;
+
+ case Ident(_) => true;
+ case _ => false;
+ }
+ else
+ false;
}
}