Skip to content

Commit fc15cfc

Browse files
committed
Merge pull request scala#3448 from retronym/topic/opt10
Optimizations in tail calls
2 parents 0598535 + c30cf0e commit fc15cfc

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

src/compiler/scala/tools/nsc/transform/TailCalls.scala

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ abstract class TailCalls extends Transform {
128128
logResult(msg)(method.newValue(nme.THIS, pos, SYNTHETIC) setInfo currentClass.typeOfThis)
129129
}
130130
override def toString = s"${method.name} tparams=$tparams tailPos=$tailPos label=$label label info=${label.info}"
131+
131132
}
132133

133134
object EmptyTailContext extends TailContext {
@@ -185,6 +186,18 @@ abstract class TailCalls extends Transform {
185186
private def noTailContext() = new ClonedTailContext(ctx, tailPos = false)
186187
private def yesTailContext() = new ClonedTailContext(ctx, tailPos = true)
187188

189+
190+
override def transformUnit(unit: CompilationUnit): Unit = {
191+
try {
192+
super.transformUnit(unit)
193+
} finally {
194+
// OPT clear these after each compilation unit
195+
failPositions.clear()
196+
failReasons.clear()
197+
accessed.clear()
198+
}
199+
}
200+
188201
/** Rewrite this tree to contain no tail recursive calls */
189202
def transform(tree: Tree, nctx: TailContext): Tree = {
190203
val saved = ctx
@@ -218,12 +231,12 @@ abstract class TailCalls extends Transform {
218231
*/
219232
def fail(reason: String) = {
220233
debuglog("Cannot rewrite recursive call at: " + fun.pos + " because: " + reason)
221-
failReasons(ctx) = reason
234+
if (ctx.isMandatory) failReasons(ctx) = reason
222235
treeCopy.Apply(tree, noTailTransform(target), transformArgs)
223236
}
224237
/* Position of failure is that of the tree being considered. */
225238
def failHere(reason: String) = {
226-
failPositions(ctx) = fun.pos
239+
if (ctx.isMandatory) failPositions(ctx) = fun.pos
227240
fail(reason)
228241
}
229242
def rewriteTailCall(recv: Tree): Tree = {
@@ -237,14 +250,20 @@ abstract class TailCalls extends Transform {
237250

238251
if (!ctx.isEligible) fail("it is neither private nor final so can be overridden")
239252
else if (!isRecursiveCall) {
240-
if (receiverIsSuper) failHere("it contains a recursive call targeting a supertype")
253+
if (ctx.isMandatory && receiverIsSuper) // OPT expensive check, avoid unless we will actually report the error
254+
failHere("it contains a recursive call targeting a supertype")
241255
else failHere(defaultReason)
242256
}
243257
else if (!matchesTypeArgs) failHere("it is called recursively with different type arguments")
244258
else if (receiver == EmptyTree) rewriteTailCall(This(currentClass))
245259
else if (!receiverIsSame) failHere("it changes type of 'this' on a polymorphic recursive call")
246260
else rewriteTailCall(receiver)
247261
}
262+
263+
def isEligible(tree: DefDef) = {
264+
val sym = tree.symbol
265+
!(sym.hasAccessorFlag || sym.isConstructor)
266+
}
248267

249268
tree match {
250269
case ValDef(_, _, _, _) =>
@@ -253,7 +272,7 @@ abstract class TailCalls extends Transform {
253272

254273
super.transform(tree)
255274

256-
case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if !dd.symbol.hasAccessorFlag =>
275+
case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if isEligible(dd) =>
257276
val newCtx = new DefDefTailContext(dd)
258277
if (newCtx.isMandatory && !(newCtx containsRecursiveCall rhs0))
259278
unit.error(tree.pos, "@tailrec annotated method contains no recursive calls")

0 commit comments

Comments
 (0)