summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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")