diff options
author | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2016-04-18 22:19:10 +0200 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2016-04-18 22:19:10 +0200 |
commit | d8bad7adaba9af5083bf8b92454fb50dfb48b925 (patch) | |
tree | beec6f991d88ee545a468de3245abb10923cc22f | |
parent | ca47bea3eed87eaa6005161c831805cd68fd6e59 (diff) | |
download | dotty-d8bad7adaba9af5083bf8b92454fb50dfb48b925.tar.gz dotty-d8bad7adaba9af5083bf8b92454fb50dfb48b925.tar.bz2 dotty-d8bad7adaba9af5083bf8b92454fb50dfb48b925.zip |
Tailrec:report error if method containing @tailrec callsite isn't final
-rw-r--r-- | src/dotty/tools/dotc/transform/TailRec.scala | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala index 427884e14..efa0633d8 100644 --- a/src/dotty/tools/dotc/transform/TailRec.scala +++ b/src/dotty/tools/dotc/transform/TailRec.scala @@ -73,6 +73,20 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete final val labelPrefix = "tailLabel" final val labelFlags = Flags.Synthetic | Flags.Label + /** Symbols of methods that have @tailrec annotatios inside */ + private val methodsWithInnerAnnots = new collection.mutable.HashSet[Symbol]() + + override def transformUnit(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = { + methodsWithInnerAnnots.clear() + tree + } + + override def transformTyped(tree: Typed)(implicit ctx: Context, info: TransformerInfo): Tree = { + if (tree.tpt.tpe.hasAnnotation(defn.TailrecAnnot)) + methodsWithInnerAnnots += ctx.owner.enclosingMethod + tree + } + private def mkLabel(method: Symbol, abstractOverClass: Boolean)(implicit c: Context): TermSymbol = { val name = c.freshName(labelPrefix) @@ -137,10 +151,10 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete } }) } - case d: DefDef if d.symbol.hasAnnotation(defn.TailrecAnnot) => + case d: DefDef if d.symbol.hasAnnotation(defn.TailrecAnnot) || methodsWithInnerAnnots.contains(d.symbol) => ctx.error("TailRec optimisation not applicable, method is neither private nor final so can be overridden", d.pos) d - case d if d.symbol.hasAnnotation(defn.TailrecAnnot) => + case d if d.symbol.hasAnnotation(defn.TailrecAnnot) || methodsWithInnerAnnots.contains(d.symbol) => ctx.error("TailRec optimisation not applicable, not a method", d.pos) d case _ => tree |