summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-10-21 22:06:43 +0000
committerPaul Phillips <paulp@improving.org>2009-10-21 22:06:43 +0000
commitdc64c686606f8dde6be4d5ff185806331c693842 (patch)
treec4844c1316207efb73755ed233e598e96e20a6c0 /src
parent991c819cb54c40fbc0553a82bb4450ced648c61d (diff)
downloadscala-dc64c686606f8dde6be4d5ff185806331c693842.tar.gz
scala-dc64c686606f8dde6be4d5ff185806331c693842.tar.bz2
scala-dc64c686606f8dde6be4d5ff185806331c693842.zip
Added -Ytailrecommend option.
much tail recursion you're missing out on, if only you knew where to sprinkle the finals and privates. If the option is given it will report on all methods it could have transformed.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala30
2 files changed, 25 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 68bf6aeabf..c85242f937 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -834,6 +834,7 @@ trait ScalacSettings {
val Ytyperdebug = BooleanSetting ("-Ytyper-debug", "Trace all type assignements")
val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.")
val Xwarnings = BooleanSetting ("-Xstrict-warnings", "Emit extra (usually spurious) warnings.")
+ val Ytailrec = BooleanSetting ("-Ytailrecommend", "Alert methods which would be tail-recursive if private or final.")
/**
* -P "Plugin" settings
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index c3cdc55ad6..93cb5baefa 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -163,19 +163,31 @@ abstract class TailCalls extends Transform
newCtx.tailPos = true
val isEligible = newCtx.currentMethod.isFinal || (newCtx.currentMethod.enclClass hasFlag Flags.MODULE)
- if (isEligible) {
+ // If -Ytailrecommend is given, we speculatively try transforming ineligible methods and
+ // report where we would have been successful.
+ val recommend = settings.Ytailrec.value
+ val savedFlags: Option[Long] = if (recommend) Some(newCtx.currentMethod.flags) else None
+
+ if (isEligible || recommend) {
+ if (recommend)
+ newCtx.currentMethod.flags |= Flags.FINAL
+
newCtx.tparams = Nil
log(" Considering " + name + " for tailcalls")
tree.symbol.tpe match {
case PolyType(tpes, restpe) =>
newCtx.tparams = tparams map (_.symbol)
newCtx.label.setInfo(
- newCtx.label.tpe.substSym(tpes, tparams map (_.symbol)))
+ newCtx.label.tpe.substSym(tpes, tparams map (_.symbol)))
case _ =>
}
}
- val t1 = treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt,
- transform(rhs, newCtx) match {
+
+ val t1 = treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt, {
+ val transformed = transform(rhs, newCtx)
+ savedFlags foreach (newCtx.currentMethod.flags = _)
+
+ transformed match {
case newRHS if isEligible && newCtx.accessed =>
log("Rewrote def " + newCtx.currentMethod)
isTransformed = true
@@ -188,9 +200,15 @@ abstract class TailCalls extends Transform
List(ValDef(newThis, This(currentClass))),
LabelDef(newCtx.label, newThis :: (vparams.flatten map (_.symbol)), newRHS)
)))
- case rhs => rhs
+ case _ if recommend =>
+ if (newCtx.accessed)
+ unit.warning(dd.pos, "method is tailrecommended")
+ // transform with the original flags restored
+ transform(rhs, newCtx)
+
+ case rhs => rhs
}
- )
+ })
if (!forMSIL && !isTransformed && tailrecRequired(dd))
unit.error(dd.pos, "could not optimize @tailrec annotated method")