Skip to content

Commit 4b17dc3

Browse files
committed
Cleanup Tailrec
1 parent 2cc525a commit 4b17dc3

File tree

19 files changed

+216
-261
lines changed

19 files changed

+216
-261
lines changed

compiler/src/dotty/tools/dotc/config/Printers.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ object Printers {
3232
val plugins: Printer = noPrinter
3333
val simplify: Printer = noPrinter
3434
val subtyping: Printer = noPrinter
35+
val tailrec: Printer = noPrinter
3536
val transforms: Printer = noPrinter
3637
val typr: Printer = noPrinter
3738
val unapp: Printer = noPrinter

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,12 +1801,11 @@ object messages {
18011801
case class TailrecNotApplicable(symbol: Symbol)(implicit ctx: Context)
18021802
extends Message(TailrecNotApplicableID) {
18031803
val kind: String = "Syntax"
1804-
val symbolKind: String = symbol.showKind
18051804
val msg: String =
18061805
if (symbol.is(Method))
1807-
hl"TailRec optimisation not applicable, $symbol is neither ${"private"} nor ${"final"}."
1806+
"TailRec optimisation not applicable, method not tail recursive"
18081807
else
1809-
hl"TailRec optimisation not applicable, ${symbolKind} isn't a method."
1808+
hl"TailRec optimisation not applicable, ${symbol.showKind} isn't a method."
18101809
val explanation: String =
18111810
hl"A method annotated ${"@tailrec"} must be declared ${"private"} or ${"final"} so it can't be overridden."
18121811
}

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

Lines changed: 148 additions & 163 deletions
Large diffs are not rendered by default.

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,8 +1507,8 @@ class ErrorMessagesTests extends ErrorMessagesTest {
15071507
implicit val ctx: Context = ictx
15081508
assertMessageCount(4, messages)
15091509

1510-
val tailRegMessages = messages.map({ case m: TailrecNotApplicable => m.symbolKind }).toSet
1511-
assertEquals(tailRegMessages, Set("variable", "value", "object", "class"))
1510+
val tailRecMessages = messages.map({ case TailrecNotApplicable(sym) => sym.showKind }).toSet
1511+
assertEquals(tailRecMessages, Set("variable", "value", "object", "class"))
15121512
}
15131513

15141514
@Test def notAnExtractor() =

tests/neg-tailcall/t1672b.check

Lines changed: 0 additions & 16 deletions
This file was deleted.

tests/neg-tailcall/t1672b.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import annotation.tailrec
2+
13
object Test1772B {
2-
@annotation.tailrec
4+
@tailrec
35
def bar : Nothing = { // error: TailRec optimisation not applicable
46
try {
57
throw new RuntimeException
@@ -10,7 +12,7 @@ object Test1772B {
1012
}
1113
}
1214

13-
@annotation.tailrec
15+
@tailrec
1416
def baz : Nothing = { // error: TailRec optimisation not applicable
1517
try {
1618
throw new RuntimeException
@@ -21,7 +23,7 @@ object Test1772B {
2123
}
2224
}
2325

24-
@annotation.tailrec
26+
@tailrec
2527
def boz : Nothing = { // error: TailRec optimisation not applicable
2628
try {
2729
throw new RuntimeException
@@ -30,7 +32,7 @@ object Test1772B {
3032
}
3133
}
3234

33-
@annotation.tailrec
35+
@tailrec
3436
def bez : Nothing = { // error: TailRec optimisation not applicable
3537
try {
3638
bez // error: it is not in tail position
@@ -40,7 +42,7 @@ object Test1772B {
4042
}
4143

4244
// the `liftedTree` local method will prevent a tail call here.
43-
@annotation.tailrec
45+
@tailrec
4446
def bar(i : Int) : Int = { // error: TailRec optimisation not applicable
4547
if (i == 0) 0
4648
else 1 + (try {

tests/neg-tailcall/t3275.check

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/neg-tailcall/t3275.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
object Test {
2-
@annotation.tailrec def foo() = 5 // error
2+
@annotation.tailrec def foo() = 5 // error: not recursive
33
}

tests/neg-tailcall/t6574.check

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/neg-tailcall/t6574.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import annotation.tailrec
2+
13
class Bad[X, Y](val v: Int) extends AnyVal {
2-
@annotation.tailrec final def notTailPos[Z](a: Int)(b: String): Unit = { // error
3-
this.notTailPos[Z](a)(b) // error
4+
@tailrec final def notTailPos[Z](a: Int)(b: String): Unit = { // error: TailRec optimisation not applicable
5+
this.notTailPos[Z](a)(b) // error: it is not in tail position
46
println("tail")
57
}
68

7-
@annotation.tailrec final def differentTypeArgs: Unit = {
9+
@tailrec final def differentTypeArgs: Unit = {
810
{(); new Bad[String, Unit](0)}.differentTypeArgs
911
}
1012
}

tests/neg-tailcall/tailrec-2.check

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/neg-tailcall/tailrec-2.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
1+
import annotation.tailrec
2+
13
sealed abstract class Super[+A] {
24
def f[B >: A](mem: List[B]) : List[B]
35
def g(mem: List[_]) = ???
46
}
57
// This one should fail, target is a supertype
68
class Bop1[+A](val element: A) extends Super[A] {
79

8-
@annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Super[A]).f(mem)
9-
@annotation.tailrec final def f1[B >: A](mem: List[B]): List[B] = this.g(mem)
10+
@tailrec final def f[B >: A](mem: List[B]): List[B] = // error: TailRec optimisation not applicable
11+
(null: Super[A]).f(mem)
12+
13+
@tailrec final def f1[B >: A](mem: List[B]): List[B] = this.g(mem) // error: TailRec optimisation not applicable
1014
}
1115
// These succeed
1216
class Bop2[+A](val element: A) extends Super[A] {
13-
@annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Bop2[A]).f(mem)
17+
@tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Bop2[A]).f(mem)
1418
}
1519
object Bop3 extends Super[Nothing] {
16-
@annotation.tailrec final def f[B](mem: List[B]): List[B] = (???: Bop3.type).f(mem) // error // error
20+
@tailrec final def f[B](mem: List[B]): List[B] = (??? : Bop3.type).f(mem)
1721
}
1822
class Bop4[+A](val element: A) extends Super[A] {
19-
@annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = Other.f[A].f(mem)
23+
@tailrec final def f[B >: A](mem: List[B]): List[B] = Other.f[A].f(mem)
2024
}
2125

2226
object Other {

tests/neg-tailcall/tailrec-3.check

Lines changed: 0 additions & 10 deletions
This file was deleted.

tests/neg-tailcall/tailrec-3.scala

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1+
12
import annotation.tailrec
23

34
object Test {
4-
@tailrec private def quux(xs: List[String]): List[String] = quux(quux(xs)) // error
5+
@tailrec private def quux(xs: List[String]): List[String] =
6+
quux(
7+
quux(xs) // error: not in tail position
8+
)
59
@tailrec private def quux2(xs: List[String]): List[String] = xs match {
6-
case x1 :: x2 :: rest => quux2(x1 :: quux2(rest)) // error
7-
case _ => Nil
10+
case x1 :: x2 :: rest => quux2(
11+
x1 :: quux2(rest)) // error: not in tail position
12+
case _ => Nil
813
}
914
@tailrec private def quux3(xs: List[String]): Boolean = xs match {
10-
case x :: xs if quux3(List("abc")) => quux3(xs) // error
11-
case _ => false
15+
case x :: xs if quux3(List("abc")) => // error: not in tail position
16+
quux3(xs)
17+
case _ => false
1218
}
1319
}
14-

tests/neg-tailcall/tailrec.check

Lines changed: 0 additions & 16 deletions
This file was deleted.

tests/pos/tailcall/t4649.flags

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/pos/tailcall/t4649.scala

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
1+
import annotation.tailrec
2+
13
object Test4649 {
2-
// @annotation.tailrec
4+
@tailrec
35
def lazyFilter[E](s: Stream[E], p: E => Boolean): Stream[E] = s match {
4-
case h #:: t => if (p(h)) h #:: lazyFilter(t, p) else lazyFilter(t, p)
6+
case h #:: t =>
7+
if (p(h)) h #:: lazyFilter(t, p) // Ok: not a tail call but in a closure
8+
else lazyFilter(t, p)
9+
case _ =>
10+
Stream.empty
11+
}
12+
13+
def cond: Boolean = ???
14+
def foo(x: => Int): Int = ???
15+
16+
@tailrec
17+
def bar: Int = {
18+
if (cond) foo(bar) // Ok: not a tail call but in a closure
19+
else bar
20+
}
21+
22+
def foo2(x: Int => Int) = ???
23+
24+
@tailrec
25+
def bar2: Int = {
26+
if (cond) foo2(_ => bar2) // Ok: not a tail call but in a closure
27+
else bar2
528
}
629
}

tests/pos/tailcall/t6891.flags

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/pos/tailcall/t6891.scala

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,22 @@
1+
import annotation.tailrec
2+
13
object O6891 {
24
implicit class Foo[A](val value: String) extends AnyVal {
35
def bippy() = {
4-
@annotation.tailrec def loop(x: A): Unit = loop(x)
6+
@tailrec def loop(x: A): Unit = loop(x)
57
()
68
}
79

810
def boppy() = {
9-
@annotation.tailrec def loop(x: value.type): Unit = loop(x)
11+
@tailrec def loop(x: value.type): Unit = loop(x)
1012
()
1113
}
1214

1315
def beppy[C](c: => C) = {
1416
() => c
15-
@annotation.tailrec def loop(x: value.type): Unit = loop(x)
17+
@tailrec def loop(x: value.type): Unit = loop(x)
1618
() => c
1719
()
1820
}
1921
}
20-
// uncaught exception during compilation: Types$TypeError("type mismatch;
21-
// found : A(in method bippy$extension)
22-
// required: A(in class Foo)") @ scala.tools.nsc.typechecker.Contexts$Context.issueCommon(Contexts.scala:396)
23-
// error: scala.reflect.internal.Types$TypeError: type mismatch;
24-
// found : A(in method bippy$extension)
25-
// required: A(in class Foo)
2622
}

0 commit comments

Comments
 (0)