Skip to content

Commit d8bad7a

Browse files
committed
Tailrec:report error if method containing @tailrec callsite isn't final
1 parent ca47bea commit d8bad7a

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

src/dotty/tools/dotc/transform/TailRec.scala

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
7373
final val labelPrefix = "tailLabel"
7474
final val labelFlags = Flags.Synthetic | Flags.Label
7575

76+
/** Symbols of methods that have @tailrec annotatios inside */
77+
private val methodsWithInnerAnnots = new collection.mutable.HashSet[Symbol]()
78+
79+
override def transformUnit(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = {
80+
methodsWithInnerAnnots.clear()
81+
tree
82+
}
83+
84+
override def transformTyped(tree: Typed)(implicit ctx: Context, info: TransformerInfo): Tree = {
85+
if (tree.tpt.tpe.hasAnnotation(defn.TailrecAnnot))
86+
methodsWithInnerAnnots += ctx.owner.enclosingMethod
87+
tree
88+
}
89+
7690
private def mkLabel(method: Symbol, abstractOverClass: Boolean)(implicit c: Context): TermSymbol = {
7791
val name = c.freshName(labelPrefix)
7892

@@ -137,10 +151,10 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
137151
}
138152
})
139153
}
140-
case d: DefDef if d.symbol.hasAnnotation(defn.TailrecAnnot) =>
154+
case d: DefDef if d.symbol.hasAnnotation(defn.TailrecAnnot) || methodsWithInnerAnnots.contains(d.symbol) =>
141155
ctx.error("TailRec optimisation not applicable, method is neither private nor final so can be overridden", d.pos)
142156
d
143-
case d if d.symbol.hasAnnotation(defn.TailrecAnnot) =>
157+
case d if d.symbol.hasAnnotation(defn.TailrecAnnot) || methodsWithInnerAnnots.contains(d.symbol) =>
144158
ctx.error("TailRec optimisation not applicable, not a method", d.pos)
145159
d
146160
case _ => tree

0 commit comments

Comments
 (0)