@@ -128,6 +128,7 @@ abstract class TailCalls extends Transform {
128
128
logResult(msg)(method.newValue(nme.THIS , pos, SYNTHETIC ) setInfo currentClass.typeOfThis)
129
129
}
130
130
override def toString = s " ${method.name} tparams= $tparams tailPos= $tailPos label= $label label info= ${label.info}"
131
+
131
132
}
132
133
133
134
object EmptyTailContext extends TailContext {
@@ -185,6 +186,18 @@ abstract class TailCalls extends Transform {
185
186
private def noTailContext () = new ClonedTailContext (ctx, tailPos = false )
186
187
private def yesTailContext () = new ClonedTailContext (ctx, tailPos = true )
187
188
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
+
188
201
/** Rewrite this tree to contain no tail recursive calls */
189
202
def transform (tree : Tree , nctx : TailContext ): Tree = {
190
203
val saved = ctx
@@ -218,12 +231,12 @@ abstract class TailCalls extends Transform {
218
231
*/
219
232
def fail (reason : String ) = {
220
233
debuglog(" Cannot rewrite recursive call at: " + fun.pos + " because: " + reason)
221
- failReasons(ctx) = reason
234
+ if (ctx.isMandatory) failReasons(ctx) = reason
222
235
treeCopy.Apply (tree, noTailTransform(target), transformArgs)
223
236
}
224
237
/* Position of failure is that of the tree being considered. */
225
238
def failHere (reason : String ) = {
226
- failPositions(ctx) = fun.pos
239
+ if (ctx.isMandatory) failPositions(ctx) = fun.pos
227
240
fail(reason)
228
241
}
229
242
def rewriteTailCall (recv : Tree ): Tree = {
@@ -237,14 +250,20 @@ abstract class TailCalls extends Transform {
237
250
238
251
if (! ctx.isEligible) fail(" it is neither private nor final so can be overridden" )
239
252
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" )
241
255
else failHere(defaultReason)
242
256
}
243
257
else if (! matchesTypeArgs) failHere(" it is called recursively with different type arguments" )
244
258
else if (receiver == EmptyTree ) rewriteTailCall(This (currentClass))
245
259
else if (! receiverIsSame) failHere(" it changes type of 'this' on a polymorphic recursive call" )
246
260
else rewriteTailCall(receiver)
247
261
}
262
+
263
+ def isEligible (tree : DefDef ) = {
264
+ val sym = tree.symbol
265
+ ! (sym.hasAccessorFlag || sym.isConstructor)
266
+ }
248
267
249
268
tree match {
250
269
case ValDef (_, _, _, _) =>
@@ -253,7 +272,7 @@ abstract class TailCalls extends Transform {
253
272
254
273
super .transform(tree)
255
274
256
- case dd @ DefDef (_, name, _, vparamss0, _, rhs0) if ! dd.symbol.hasAccessorFlag =>
275
+ case dd @ DefDef (_, name, _, vparamss0, _, rhs0) if isEligible(dd) =>
257
276
val newCtx = new DefDefTailContext (dd)
258
277
if (newCtx.isMandatory && ! (newCtx containsRecursiveCall rhs0))
259
278
unit.error(tree.pos, " @tailrec annotated method contains no recursive calls" )
0 commit comments