From dc64c686606f8dde6be4d5ff185806331c693842 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 21 Oct 2009 22:06:43 +0000 Subject: 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. --- src/compiler/scala/tools/nsc/Settings.scala | 1 + .../scala/tools/nsc/transform/TailCalls.scala | 30 +++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'src') 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") -- cgit v1.2.3