Skip to content

Commit

Permalink
Visit all trees
Browse files Browse the repository at this point in the history
  • Loading branch information
mbovel committed Dec 30, 2021
1 parent a349775 commit 4368847
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 14 deletions.
16 changes: 2 additions & 14 deletions compiler/src/dotty/tools/dotc/transform/TailRec.scala
Expand Up @@ -277,23 +277,11 @@ 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 =
if (isTraversalNeeded) transform(tree, tailPosition = false)
else tree
transform(tree, tailPosition = false)

def noTailTransforms[Tr <: Tree](trees: List[Tr])(using Context): List[Tr] =
if (isTraversalNeeded) trees.mapConserve(noTailTransform).asInstanceOf[List[Tr]]
else trees
trees.mapConserve(noTailTransform).asInstanceOf[List[Tr]]

override def transform(tree: Tree)(using Context): Tree = {
/* Rewrite an Apply to be considered for tail call transformation. */
Expand Down
5 changes: 5 additions & 0 deletions tests/run/tailrec-return.check
@@ -1,2 +1,7 @@
6
false
true
false
true
Ada Lovelace, Alan Turing
List(9, 10)
50 changes: 50 additions & 0 deletions tests/run/tailrec-return.scala
Expand Up @@ -11,6 +11,56 @@ object Test:
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)))

0 comments on commit 4368847

Please sign in to comment.