diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 916b9279da09..9ee3aa5b1a8c 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -286,11 +286,23 @@ class TailRec extends MiniPhase { def yesTailTransform(tree: Tree)(using Context): Tree = transform(tree, tailPosition = true) + /** If not in tail position a tree traversal may not be needed. + * + * A recursive call may still be in tail position if within the return + * expression of a labeled block. + * A tree traversal may also be needed to report a failure to transform + * a recursive call of a @tailrec annotated method (i.e. `isMandatory`). + */ + private def isTraversalNeeded = + isMandatory || tailPositionLabeledSyms.size > 0 + def noTailTransform(tree: Tree)(using Context): Tree = - transform(tree, tailPosition = false) + if (isTraversalNeeded) transform(tree, tailPosition = false) + else tree def noTailTransforms[Tr <: Tree](trees: List[Tr])(using Context): List[Tr] = - trees.mapConserve(noTailTransform).asInstanceOf[List[Tr]] + if (isTraversalNeeded) trees.mapConserve(noTailTransform).asInstanceOf[List[Tr]] + else trees override def transform(tree: Tree)(using Context): Tree = { /* Rewrite an Apply to be considered for tail call transformation. */ @@ -441,7 +453,7 @@ class TailRec extends MiniPhase { case Return(expr, from) => val fromSym = from.symbol - val inTailPosition = !fromSym.is(Label) || tailPositionLabeledSyms.contains(fromSym) + val inTailPosition = fromSym.is(Label) && tailPositionLabeledSyms.contains(fromSym) cpy.Return(tree)(transform(expr, inTailPosition), from) case _ => diff --git a/tests/run/tailrec-return.check b/tests/run/tailrec-return.check deleted file mode 100644 index 361e76d8a285..000000000000 --- a/tests/run/tailrec-return.check +++ /dev/null @@ -1,7 +0,0 @@ -6 -false -true -false -true -Ada Lovelace, Alan Turing -List(9, 10) diff --git a/tests/run/tailrec-return.scala b/tests/run/tailrec-return.scala deleted file mode 100644 index aa760960403d..000000000000 --- a/tests/run/tailrec-return.scala +++ /dev/null @@ -1,66 +0,0 @@ -object Test: - - @annotation.tailrec - def sum(n: Int, acc: Int = 0): Int = - if n != 0 then return sum(n - 1, acc + n) - acc - - @annotation.tailrec - def isEven(n: Int): Boolean = - if n != 0 && n != 1 then return isEven(n - 2) - if n == 1 then return false - true - - @annotation.tailrec - def isEvenApply(n: Int): Boolean = - // Return inside an `Apply.fun` - ( - if n != 0 && n != 1 then return isEvenApply(n - 2) - else if n == 1 then return false - else (x: Boolean) => x - )(true) - - @annotation.tailrec - def isEvenWhile(n: Int): Boolean = - // Return inside a `WhileDo.cond` - while( - if n != 0 && n != 1 then return isEvenWhile(n - 2) - else if n == 1 then return false - else true - ) {} - true - - @annotation.tailrec - def isEvenReturn(n: Int): Boolean = - // Return inside a `Return` - return - if n != 0 && n != 1 then return isEvenReturn(n - 2) - else if n == 1 then return false - else true - - @annotation.tailrec - def names(l: List[(String, String) | Null], acc: List[String] = Nil): List[String] = - l match - case Nil => acc.reverse - case x :: xs => - if x == null then return names(xs, acc) - - val displayName = x._1 + " " + x._2 - names(xs, displayName :: acc) - - def nonTail(l: List[Int]): List[Int] = - l match - case Nil => Nil - case x :: xs => - // The call to nonTail should *not* be eliminated - (x + 1) :: nonTail(xs) - - - def main(args: Array[String]): Unit = - println(sum(3)) - println(isEven(5)) - println(isEvenApply(6)) - println(isEvenWhile(7)) - println(isEvenReturn(8)) - println(names(List(("Ada", "Lovelace"), null, ("Alan", "Turing"))).mkString(", ")) - println(nonTail(List(8, 9)))