summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-02-02 10:03:40 -0800
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-02-02 10:03:40 -0800
commitfc15cfc2399661f1de7d91b2ca0f5d12f32bc708 (patch)
tree44734c8d7cd1b9bf21aa67efa5f94774f5fc706a
parent059853567646760110686f831d985211db4ddaa6 (diff)
parentc30cf0ee814337109941876b08323a42b440a724 (diff)
downloadscala-fc15cfc2399661f1de7d91b2ca0f5d12f32bc708.tar.gz
scala-fc15cfc2399661f1de7d91b2ca0f5d12f32bc708.tar.bz2
scala-fc15cfc2399661f1de7d91b2ca0f5d12f32bc708.zip
Merge pull request #3448 from retronym/topic/opt10
Optimizations in tail calls
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala27
1 files changed, 23 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index b471d16ddd..5973c70583 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -128,6 +128,7 @@ abstract class TailCalls extends Transform {
logResult(msg)(method.newValue(nme.THIS, pos, SYNTHETIC) setInfo currentClass.typeOfThis)
}
override def toString = s"${method.name} tparams=$tparams tailPos=$tailPos label=$label label info=${label.info}"
+
}
object EmptyTailContext extends TailContext {
@@ -185,6 +186,18 @@ abstract class TailCalls extends Transform {
private def noTailContext() = new ClonedTailContext(ctx, tailPos = false)
private def yesTailContext() = new ClonedTailContext(ctx, tailPos = true)
+
+ override def transformUnit(unit: CompilationUnit): Unit = {
+ try {
+ super.transformUnit(unit)
+ } finally {
+ // OPT clear these after each compilation unit
+ failPositions.clear()
+ failReasons.clear()
+ accessed.clear()
+ }
+ }
+
/** Rewrite this tree to contain no tail recursive calls */
def transform(tree: Tree, nctx: TailContext): Tree = {
val saved = ctx
@@ -218,12 +231,12 @@ abstract class TailCalls extends Transform {
*/
def fail(reason: String) = {
debuglog("Cannot rewrite recursive call at: " + fun.pos + " because: " + reason)
- failReasons(ctx) = reason
+ if (ctx.isMandatory) failReasons(ctx) = reason
treeCopy.Apply(tree, noTailTransform(target), transformArgs)
}
/* Position of failure is that of the tree being considered. */
def failHere(reason: String) = {
- failPositions(ctx) = fun.pos
+ if (ctx.isMandatory) failPositions(ctx) = fun.pos
fail(reason)
}
def rewriteTailCall(recv: Tree): Tree = {
@@ -237,7 +250,8 @@ abstract class TailCalls extends Transform {
if (!ctx.isEligible) fail("it is neither private nor final so can be overridden")
else if (!isRecursiveCall) {
- if (receiverIsSuper) failHere("it contains a recursive call targeting a supertype")
+ if (ctx.isMandatory && receiverIsSuper) // OPT expensive check, avoid unless we will actually report the error
+ failHere("it contains a recursive call targeting a supertype")
else failHere(defaultReason)
}
else if (!matchesTypeArgs) failHere("it is called recursively with different type arguments")
@@ -245,6 +259,11 @@ abstract class TailCalls extends Transform {
else if (!receiverIsSame) failHere("it changes type of 'this' on a polymorphic recursive call")
else rewriteTailCall(receiver)
}
+
+ def isEligible(tree: DefDef) = {
+ val sym = tree.symbol
+ !(sym.hasAccessorFlag || sym.isConstructor)
+ }
tree match {
case ValDef(_, _, _, _) =>
@@ -253,7 +272,7 @@ abstract class TailCalls extends Transform {
super.transform(tree)
- case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if !dd.symbol.hasAccessorFlag =>
+ case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if isEligible(dd) =>
val newCtx = new DefDefTailContext(dd)
if (newCtx.isMandatory && !(newCtx containsRecursiveCall rhs0))
unit.error(tree.pos, "@tailrec annotated method contains no recursive calls")