diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index b6b51d54d95b..bc3a251065cf 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -407,8 +407,11 @@ class TailRec extends MiniPhase { assert(false, "We should never have gotten inside a pattern") tree - case _: ValDef | _: DefDef | _: Super | _: This | - _: Literal | _: TypeTree | _: TypeDef | EmptyTree => + case tree: ValOrDefDef => + if (isMandatory) noTailTransform(tree.rhs) + tree + + case _: Super | _: This | _: Literal | _: TypeTree | _: TypeDef | EmptyTree => tree case Labeled(bind, expr) => diff --git a/tests/neg-tailcall/t1672b.scala b/tests/neg-tailcall/t1672b.scala index fa1b12c57cbd..84ebb6155e6d 100644 --- a/tests/neg-tailcall/t1672b.scala +++ b/tests/neg-tailcall/t1672b.scala @@ -43,12 +43,12 @@ object Test1772B { // the `liftedTree` local method will prevent a tail call here. @tailrec - def bar(i : Int) : Int = { // error: TailRec optimisation not applicable + def bar(i : Int) : Int = { if (i == 0) 0 else 1 + (try { throw new RuntimeException } catch { - case _: Throwable => bar(i - 1) // old error: cannot rewrite recursive call + case _: Throwable => bar(i - 1) // error: it is not in tail position }) } } diff --git a/tests/neg/i5397.scala b/tests/neg/i5397.scala new file mode 100644 index 000000000000..d38b0e67bff9 --- /dev/null +++ b/tests/neg/i5397.scala @@ -0,0 +1,41 @@ +import annotation.tailrec + +object Test { + def foo(x: => Int) = 1 + def bar(x: Int => Int) = 1 + + @tailrec def rec1: Int = + foo(rec1) // error: not in tail position + + @tailrec def rec2: Int = + bar(_ => rec2) // error: not in tail position + + @tailrec def rec3: Int = + 1 + (try ??? catch { + case _: Throwable => + rec3 // error: not in tail position + }) + + @tailrec def rec4: Unit = { + def local = rec4 // error: not in tail position + } + + @tailrec def rec5: Int = { + val x = { + rec5 // error: not in tail position + 1 + } + x + } +} + +object Test4649 { + @tailrec + def lazyFilter[E](s: Stream[E], p: E => Boolean): Stream[E] = s match { + case h #:: t => + if (p(h)) h #:: lazyFilter(t, p) // error: not in tail position + else lazyFilter(t, p) + case _ => + Stream.empty + } +} diff --git a/tests/pos/ErasureAnd.scala b/tests/pos/ErasureAnd.scala index 38c5f4c94ea0..1c86ee4b9086 100644 --- a/tests/pos/ErasureAnd.scala +++ b/tests/pos/ErasureAnd.scala @@ -1,6 +1,4 @@ -import scala.annotation.tailrec trait A { self: B => - @tailrec private def foo(arg1: Int, arg2: Int): Int = { def bar = this.foo(arg1, arg2) foo(arg1, arg2) diff --git a/tests/pos/tailcall/t4649.scala b/tests/pos/tailcall/t4649.scala deleted file mode 100644 index 12ebe095894b..000000000000 --- a/tests/pos/tailcall/t4649.scala +++ /dev/null @@ -1,29 +0,0 @@ -import annotation.tailrec - -object Test4649 { - @tailrec - def lazyFilter[E](s: Stream[E], p: E => Boolean): Stream[E] = s match { - case h #:: t => - if (p(h)) h #:: lazyFilter(t, p) // Ok: not a tail call but in a closure - else lazyFilter(t, p) - case _ => - Stream.empty - } - - def cond: Boolean = ??? - def foo(x: => Int): Int = ??? - - @tailrec - def bar: Int = { - if (cond) foo(bar) // Ok: not a tail call but in a closure - else bar - } - - def foo2(x: Int => Int) = ??? - - @tailrec - def bar2: Int = { - if (cond) foo2(_ => bar2) // Ok: not a tail call but in a closure - else bar2 - } -}