From 6ebf6e2c3ef270f226a0fb42ebd59d24449942cf Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Fri, 4 Apr 2014 12:14:43 +0200 Subject: TailRec phase and tests for it. Ported tailcall phase from scalac with such changes: - all transformation is done in the phase itself (previously half of the work was done in backend) - it is now able to run before uncurry - it is now a treeTransform - renamed to tailrec to make it more obvious that this phase transforms only recursive calls. For now this is a single phase which speculatively transforms DefDefs. Speculation can be potentially removed by splitting into 2 phases: one detecting which methods should be transformed second performing transformation. But, as transformation requires as same amount of work as detection, I believe it will be simpler to maintain it as a single phase. Conflicts: tests/pos/typers.scala --- tests/neg/tailcall/t1672b.check | 16 ++++++++++ tests/neg/tailcall/t1672b.scala | 52 ++++++++++++++++++++++++++++++ tests/neg/tailcall/t3275.check | 4 +++ tests/neg/tailcall/t3275.scala | 3 ++ tests/neg/tailcall/t6574.check | 7 ++++ tests/neg/tailcall/t6574.scala | 10 ++++++ tests/neg/tailcall/tailrec-2.check | 7 ++++ tests/neg/tailcall/tailrec-2.scala | 29 +++++++++++++++++ tests/neg/tailcall/tailrec-3.check | 10 ++++++ tests/neg/tailcall/tailrec-3.scala | 14 ++++++++ tests/neg/tailcall/tailrec.check | 16 ++++++++++ tests/neg/tailcall/tailrec.scala | 65 ++++++++++++++++++++++++++++++++++++++ tests/pos/tailcall/t1672.scala | 10 ++++++ tests/pos/tailcall/t4649.flags | 1 + tests/pos/tailcall/t4649.scala | 6 ++++ tests/pos/tailcall/t6479.scala | 56 ++++++++++++++++++++++++++++++++ tests/pos/tailcall/t6574.scala | 19 +++++++++++ tests/pos/tailcall/t6891.flags | 1 + tests/pos/tailcall/t6891.scala | 26 +++++++++++++++ tests/pos/tailcall/tailcall.scala | 5 +++ tests/pos/typers.scala | 2 +- tests/untried/neg/t1672b.check | 16 ---------- tests/untried/neg/t1672b.scala | 52 ------------------------------ tests/untried/neg/t3275.check | 4 --- tests/untried/neg/t3275.scala | 3 -- tests/untried/neg/t6574.check | 7 ---- tests/untried/neg/t6574.scala | 10 ------ tests/untried/neg/tailrec-2.check | 7 ---- tests/untried/neg/tailrec-2.scala | 29 ----------------- tests/untried/neg/tailrec-3.check | 10 ------ tests/untried/neg/tailrec-3.scala | 14 -------- tests/untried/neg/tailrec.check | 16 ---------- tests/untried/neg/tailrec.scala | 65 -------------------------------------- tests/untried/pos/t1672.scala | 10 ------ tests/untried/pos/t4649.flags | 1 - tests/untried/pos/t4649.scala | 6 ---- tests/untried/pos/t6479.scala | 56 -------------------------------- tests/untried/pos/t6574.scala | 19 ----------- tests/untried/pos/t6891.flags | 1 - tests/untried/pos/t6891.scala | 26 --------------- 40 files changed, 358 insertions(+), 353 deletions(-) create mode 100644 tests/neg/tailcall/t1672b.check create mode 100644 tests/neg/tailcall/t1672b.scala create mode 100644 tests/neg/tailcall/t3275.check create mode 100644 tests/neg/tailcall/t3275.scala create mode 100644 tests/neg/tailcall/t6574.check create mode 100644 tests/neg/tailcall/t6574.scala create mode 100644 tests/neg/tailcall/tailrec-2.check create mode 100644 tests/neg/tailcall/tailrec-2.scala create mode 100644 tests/neg/tailcall/tailrec-3.check create mode 100644 tests/neg/tailcall/tailrec-3.scala create mode 100644 tests/neg/tailcall/tailrec.check create mode 100644 tests/neg/tailcall/tailrec.scala create mode 100644 tests/pos/tailcall/t1672.scala create mode 100644 tests/pos/tailcall/t4649.flags create mode 100644 tests/pos/tailcall/t4649.scala create mode 100644 tests/pos/tailcall/t6479.scala create mode 100644 tests/pos/tailcall/t6574.scala create mode 100644 tests/pos/tailcall/t6891.flags create mode 100644 tests/pos/tailcall/t6891.scala create mode 100644 tests/pos/tailcall/tailcall.scala delete mode 100644 tests/untried/neg/t1672b.check delete mode 100644 tests/untried/neg/t1672b.scala delete mode 100644 tests/untried/neg/t3275.check delete mode 100644 tests/untried/neg/t3275.scala delete mode 100644 tests/untried/neg/t6574.check delete mode 100644 tests/untried/neg/t6574.scala delete mode 100644 tests/untried/neg/tailrec-2.check delete mode 100644 tests/untried/neg/tailrec-2.scala delete mode 100644 tests/untried/neg/tailrec-3.check delete mode 100644 tests/untried/neg/tailrec-3.scala delete mode 100644 tests/untried/neg/tailrec.check delete mode 100644 tests/untried/neg/tailrec.scala delete mode 100644 tests/untried/pos/t1672.scala delete mode 100644 tests/untried/pos/t4649.flags delete mode 100644 tests/untried/pos/t4649.scala delete mode 100644 tests/untried/pos/t6479.scala delete mode 100644 tests/untried/pos/t6574.scala delete mode 100644 tests/untried/pos/t6891.flags delete mode 100644 tests/untried/pos/t6891.scala (limited to 'tests') diff --git a/tests/neg/tailcall/t1672b.check b/tests/neg/tailcall/t1672b.check new file mode 100644 index 000000000..60ccf7717 --- /dev/null +++ b/tests/neg/tailcall/t1672b.check @@ -0,0 +1,16 @@ +t1672b.scala:3: error: could not optimize @tailrec annotated method bar: it contains a recursive call not in tail position + def bar : Nothing = { + ^ +t1672b.scala:14: error: could not optimize @tailrec annotated method baz: it contains a recursive call not in tail position + def baz : Nothing = { + ^ +t1672b.scala:29: error: could not optimize @tailrec annotated method boz: it contains a recursive call not in tail position + case _: Throwable => boz; ??? + ^ +t1672b.scala:34: error: could not optimize @tailrec annotated method bez: it contains a recursive call not in tail position + def bez : Nothing = { + ^ +t1672b.scala:46: error: could not optimize @tailrec annotated method bar: it contains a recursive call not in tail position + else 1 + (try { + ^ +5 errors found diff --git a/tests/neg/tailcall/t1672b.scala b/tests/neg/tailcall/t1672b.scala new file mode 100644 index 000000000..f05d05c34 --- /dev/null +++ b/tests/neg/tailcall/t1672b.scala @@ -0,0 +1,52 @@ +object Test1772B { + @annotation.tailrec + def bar : Nothing = { + try { + throw new RuntimeException + } catch { + case _: Throwable => bar + } finally { + bar + } + } + + @annotation.tailrec + def baz : Nothing = { + try { + throw new RuntimeException + } catch { + case _: Throwable => baz + } finally { + ??? + } + } + + @annotation.tailrec + def boz : Nothing = { + try { + throw new RuntimeException + } catch { + case _: Throwable => boz; ??? + } + } + + @annotation.tailrec + def bez : Nothing = { + try { + bez + } finally { + ??? + } + } + + // the `liftedTree` local method will prevent a tail call here. + @annotation.tailrec + def bar(i : Int) : Int = { + if (i == 0) 0 + else 1 + (try { + throw new RuntimeException + } catch { + case _: Throwable => bar(i - 1) + }) + } +} diff --git a/tests/neg/tailcall/t3275.check b/tests/neg/tailcall/t3275.check new file mode 100644 index 000000000..117c79232 --- /dev/null +++ b/tests/neg/tailcall/t3275.check @@ -0,0 +1,4 @@ +t3275.scala:2: error: @tailrec annotated method contains no recursive calls + @annotation.tailrec def foo() = 5 + ^ +one error found diff --git a/tests/neg/tailcall/t3275.scala b/tests/neg/tailcall/t3275.scala new file mode 100644 index 000000000..18e38a1a9 --- /dev/null +++ b/tests/neg/tailcall/t3275.scala @@ -0,0 +1,3 @@ +object Test { + @annotation.tailrec def foo() = 5 +} diff --git a/tests/neg/tailcall/t6574.check b/tests/neg/tailcall/t6574.check new file mode 100644 index 000000000..c67b4ed80 --- /dev/null +++ b/tests/neg/tailcall/t6574.check @@ -0,0 +1,7 @@ +t6574.scala:4: error: could not optimize @tailrec annotated method notTailPos$extension: it contains a recursive call not in tail position + println("tail") + ^ +t6574.scala:8: error: could not optimize @tailrec annotated method differentTypeArgs$extension: it is called recursively with different type arguments + {(); new Bad[String, Unit](0)}.differentTypeArgs + ^ +two errors found diff --git a/tests/neg/tailcall/t6574.scala b/tests/neg/tailcall/t6574.scala new file mode 100644 index 000000000..59f3108ad --- /dev/null +++ b/tests/neg/tailcall/t6574.scala @@ -0,0 +1,10 @@ +class Bad[X, Y](val v: Int) extends AnyVal { + @annotation.tailrec final def notTailPos[Z](a: Int)(b: String): Unit = { + this.notTailPos[Z](a)(b) + println("tail") + } + + @annotation.tailrec final def differentTypeArgs : Unit = { + {(); new Bad[String, Unit](0)}.differentTypeArgs + } +} diff --git a/tests/neg/tailcall/tailrec-2.check b/tests/neg/tailcall/tailrec-2.check new file mode 100644 index 000000000..1daad6922 --- /dev/null +++ b/tests/neg/tailcall/tailrec-2.check @@ -0,0 +1,7 @@ +tailrec-2.scala:8: error: could not optimize @tailrec annotated method f: it contains a recursive call targeting a supertype + @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Super[A]).f(mem) + ^ +tailrec-2.scala:9: error: @tailrec annotated method contains no recursive calls + @annotation.tailrec final def f1[B >: A](mem: List[B]): List[B] = this.g(mem) + ^ +two errors found diff --git a/tests/neg/tailcall/tailrec-2.scala b/tests/neg/tailcall/tailrec-2.scala new file mode 100644 index 000000000..d6b8b1355 --- /dev/null +++ b/tests/neg/tailcall/tailrec-2.scala @@ -0,0 +1,29 @@ +sealed abstract class Super[+A] { + def f[B >: A](mem: List[B]) : List[B] + def g(mem: List[_]) = ??? +} +// This one should fail, target is a supertype +class Bop1[+A](val element: A) extends Super[A] { + + @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Super[A]).f(mem) + @annotation.tailrec final def f1[B >: A](mem: List[B]): List[B] = this.g(mem) +} +// These succeed +class Bop2[+A](val element: A) extends Super[A] { + @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Bop2[A]).f(mem) +} +object Bop3 extends Super[Nothing] { + @annotation.tailrec final def f[B](mem: List[B]): List[B] = (null: Bop3.type).f(mem) +} +class Bop4[+A](val element: A) extends Super[A] { + @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = Other.f[A].f(mem) +} + +object Other { + def f[T] : Bop4[T] = sys.error("") +} + +object Bop { + def m1[A] : Super[A] = sys.error("") + def m2[A] : Bop2[A] = sys.error("") +} diff --git a/tests/neg/tailcall/tailrec-3.check b/tests/neg/tailcall/tailrec-3.check new file mode 100644 index 000000000..a3542fb56 --- /dev/null +++ b/tests/neg/tailcall/tailrec-3.check @@ -0,0 +1,10 @@ +tailrec-3.scala:4: error: could not optimize @tailrec annotated method quux: it contains a recursive call not in tail position + @tailrec private def quux(xs: List[String]): List[String] = quux(quux(xs)) + ^ +tailrec-3.scala:6: error: could not optimize @tailrec annotated method quux2: it contains a recursive call not in tail position + case x1 :: x2 :: rest => quux2(x1 :: quux2(rest)) + ^ +tailrec-3.scala:10: error: could not optimize @tailrec annotated method quux3: it contains a recursive call not in tail position + case x :: xs if quux3(List("abc")) => quux3(xs) + ^ +three errors found diff --git a/tests/neg/tailcall/tailrec-3.scala b/tests/neg/tailcall/tailrec-3.scala new file mode 100644 index 000000000..20361658e --- /dev/null +++ b/tests/neg/tailcall/tailrec-3.scala @@ -0,0 +1,14 @@ +import annotation.tailrec + +object Test { + @tailrec private def quux(xs: List[String]): List[String] = quux(quux(xs)) + @tailrec private def quux2(xs: List[String]): List[String] = xs match { + case x1 :: x2 :: rest => quux2(x1 :: quux2(rest)) + case _ => Nil + } + @tailrec private def quux3(xs: List[String]): Boolean = xs match { + case x :: xs if quux3(List("abc")) => quux3(xs) + case _ => false + } +} + diff --git a/tests/neg/tailcall/tailrec.check b/tests/neg/tailcall/tailrec.check new file mode 100644 index 000000000..946d3421e --- /dev/null +++ b/tests/neg/tailcall/tailrec.check @@ -0,0 +1,16 @@ +tailrec.scala:45: error: could not optimize @tailrec annotated method facfail: it contains a recursive call not in tail position + else n * facfail(n - 1) + ^ +tailrec.scala:50: error: could not optimize @tailrec annotated method fail1: it is neither private nor final so can be overridden + @tailrec def fail1(x: Int): Int = fail1(x) + ^ +tailrec.scala:53: error: could not optimize @tailrec annotated method fail2: it contains a recursive call not in tail position + @tailrec final def fail2[T](xs: List[T]): List[T] = xs match { + ^ +tailrec.scala:59: error: could not optimize @tailrec annotated method fail3: it is called recursively with different type arguments + @tailrec final def fail3[T](x: Int): Int = fail3(x - 1) + ^ +tailrec.scala:63: error: could not optimize @tailrec annotated method fail4: it changes type of 'this' on a polymorphic recursive call + @tailrec final def fail4[U](other: Tom[U], x: Int): Int = other.fail4[U](other, x - 1) + ^ +5 errors found diff --git a/tests/neg/tailcall/tailrec.scala b/tests/neg/tailcall/tailrec.scala new file mode 100644 index 000000000..83a0c1a9e --- /dev/null +++ b/tests/neg/tailcall/tailrec.scala @@ -0,0 +1,65 @@ +import scala.annotation.tailrec + +// putting @tailrec through the paces +object Winners { + @tailrec + def facsucc(n: Int, acc: Int): Int = + if (n == 0) acc + else facsucc(n - 1, n * acc) + + @tailrec def loopsucc1(x: Int): Int = loopsucc1(x - 1) + @tailrec def loopsucc2[T](x: Int): Int = loopsucc2[T](x - 1) + + def ding(): Unit = { + object dong { + @tailrec def loopsucc3(x: Int): Int = loopsucc3(x) + } + () + } + + def inner(q: Int) = { + @tailrec + def loopsucc4(x: Int): Int = loopsucc4(x + 1) + + loopsucc4(q) + } + + object innerBob { + @tailrec def loopsucc5(x: Int): Int = loopsucc5(x) + } +} + +class Winners { + @tailrec private def succ1(x: Int): Int = succ1(x) + @tailrec final def succ2(x: Int): Int = succ2(x) + @tailrec final def succ3[T](in: List[T], acc: List[T]): List[T] = in match { + case Nil => Nil + case x :: xs => succ3(xs, x :: acc) + } +} + +object Failures { + @tailrec + def facfail(n: Int): Int = + if (n == 0) 1 + else n * facfail(n - 1) +} + +class Failures { + // not private, not final + @tailrec def fail1(x: Int): Int = fail1(x) + + // a typical between-chair-and-keyboard error + @tailrec final def fail2[T](xs: List[T]): List[T] = xs match { + case Nil => Nil + case x :: xs => x :: fail2[T](xs) + } + + // unsafe + @tailrec final def fail3[T](x: Int): Int = fail3(x - 1) + + // unsafe + class Tom[T](x: Int) { + @tailrec final def fail4[U](other: Tom[U], x: Int): Int = other.fail4[U](other, x - 1) + } +} diff --git a/tests/pos/tailcall/t1672.scala b/tests/pos/tailcall/t1672.scala new file mode 100644 index 000000000..9be5c6066 --- /dev/null +++ b/tests/pos/tailcall/t1672.scala @@ -0,0 +1,10 @@ +object Test1672 { + @annotation.tailrec + def bar(x: Int)(y: Int) : Nothing = { + try { + throw new RuntimeException + } catch { + case _: Throwable => bar(x)(y) + } + } +} diff --git a/tests/pos/tailcall/t4649.flags b/tests/pos/tailcall/t4649.flags new file mode 100644 index 000000000..e8fb65d50 --- /dev/null +++ b/tests/pos/tailcall/t4649.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/tests/pos/tailcall/t4649.scala b/tests/pos/tailcall/t4649.scala new file mode 100644 index 000000000..5f009b7a4 --- /dev/null +++ b/tests/pos/tailcall/t4649.scala @@ -0,0 +1,6 @@ +object Test4649 { + // @annotation.tailrec + def lazyFilter[E](s: Stream[E], p: E => Boolean): Stream[E] = s match { + case h #:: t => if (p(h)) h #:: lazyFilter(t, p) else lazyFilter(t, p) + } +} diff --git a/tests/pos/tailcall/t6479.scala b/tests/pos/tailcall/t6479.scala new file mode 100644 index 000000000..e4a4ff601 --- /dev/null +++ b/tests/pos/tailcall/t6479.scala @@ -0,0 +1,56 @@ +object TailrecAfterTryCatch { + + @annotation.tailrec + final def good1(): Unit = { + 1 match { + case 2 => { + try { + // return + } catch { + case e: ClassNotFoundException => + } + good1() + } + } + } + + @annotation.tailrec + final def good2(): Unit = { + //1 match { + // case 2 => { + try { + return + } catch { + case e: ClassNotFoundException => + } + good2() + // } + //} + } + + @annotation.tailrec + final def good3(): Unit = { + val 1 = 2 + try { + return + } catch { + case e: ClassNotFoundException => + } + good3() + } + + @annotation.tailrec + final def bad(): Unit = { + 1 match { + case 2 => { + try { + return + } catch { + case e: ClassNotFoundException => + } + bad() + } + } + } + +} diff --git a/tests/pos/tailcall/t6574.scala b/tests/pos/tailcall/t6574.scala new file mode 100644 index 000000000..cd0fdbb8d --- /dev/null +++ b/tests/pos/tailcall/t6574.scala @@ -0,0 +1,19 @@ +class Bad[X, Y](val v: Int) extends AnyVal { + def vv = v + @annotation.tailrec final def foo[Z](a: Int)(b: String): Unit = { + this.foo[Z](a)(b) + } + + @annotation.tailrec final def differentReceiver : Unit = { + {(); new Bad[X, Y](0)}.differentReceiver + } + + @annotation.tailrec final def dependent[Z](a: Int)(b: String): b.type = { + this.dependent[Z](a)(b) + } +} + +class HK[M[_]](val v: Int) extends AnyVal { + def hk[N[_]]: Unit = if (false) hk[M] else () +} + diff --git a/tests/pos/tailcall/t6891.flags b/tests/pos/tailcall/t6891.flags new file mode 100644 index 000000000..fe048006a --- /dev/null +++ b/tests/pos/tailcall/t6891.flags @@ -0,0 +1 @@ +-Ycheck:extmethods -Xfatal-warnings \ No newline at end of file diff --git a/tests/pos/tailcall/t6891.scala b/tests/pos/tailcall/t6891.scala new file mode 100644 index 000000000..edbe6f097 --- /dev/null +++ b/tests/pos/tailcall/t6891.scala @@ -0,0 +1,26 @@ +object O6891 { + implicit class Foo[A](val value: String) extends AnyVal { + def bippy() = { + @annotation.tailrec def loop(x: A): Unit = loop(x) + () + } + + def boppy() = { + @annotation.tailrec def loop(x: value.type): Unit = loop(x) + () + } + + def beppy[C](c: => C) = { + () => c + @annotation.tailrec def loop(x: value.type): Unit = loop(x) + () => c + () + } + } + // uncaught exception during compilation: Types$TypeError("type mismatch; + // found : A(in method bippy$extension) + // required: A(in class Foo)") @ scala.tools.nsc.typechecker.Contexts$Context.issueCommon(Contexts.scala:396) + // error: scala.reflect.internal.Types$TypeError: type mismatch; + // found : A(in method bippy$extension) + // required: A(in class Foo) +} diff --git a/tests/pos/tailcall/tailcall.scala b/tests/pos/tailcall/tailcall.scala new file mode 100644 index 000000000..9cf373cf0 --- /dev/null +++ b/tests/pos/tailcall/tailcall.scala @@ -0,0 +1,5 @@ +class tailcall { + val shift = 1 + final def fact(x: Int, acc: Int = 1): Int = if (x == 0) acc else fact(x - shift, acc * x) + def id[T <: AnyRef](x: T): T = if (x eq null) x else id(x) +} diff --git a/tests/pos/typers.scala b/tests/pos/typers.scala index 4f012e7bf..a95af558e 100644 --- a/tests/pos/typers.scala +++ b/tests/pos/typers.scala @@ -77,7 +77,7 @@ object typers { class C { - @tailrec def factorial(acc: Int, n: Int): Int = (n: @switch) match { + @tailrec final def factorial(acc: Int, n: Int): Int = (n: @switch) match { case 0 => acc case _ => factorial(acc * n, n - 1) } diff --git a/tests/untried/neg/t1672b.check b/tests/untried/neg/t1672b.check deleted file mode 100644 index 60ccf7717..000000000 --- a/tests/untried/neg/t1672b.check +++ /dev/null @@ -1,16 +0,0 @@ -t1672b.scala:3: error: could not optimize @tailrec annotated method bar: it contains a recursive call not in tail position - def bar : Nothing = { - ^ -t1672b.scala:14: error: could not optimize @tailrec annotated method baz: it contains a recursive call not in tail position - def baz : Nothing = { - ^ -t1672b.scala:29: error: could not optimize @tailrec annotated method boz: it contains a recursive call not in tail position - case _: Throwable => boz; ??? - ^ -t1672b.scala:34: error: could not optimize @tailrec annotated method bez: it contains a recursive call not in tail position - def bez : Nothing = { - ^ -t1672b.scala:46: error: could not optimize @tailrec annotated method bar: it contains a recursive call not in tail position - else 1 + (try { - ^ -5 errors found diff --git a/tests/untried/neg/t1672b.scala b/tests/untried/neg/t1672b.scala deleted file mode 100644 index 0ccdd0363..000000000 --- a/tests/untried/neg/t1672b.scala +++ /dev/null @@ -1,52 +0,0 @@ -object Test { - @annotation.tailrec - def bar : Nothing = { - try { - throw new RuntimeException - } catch { - case _: Throwable => bar - } finally { - bar - } - } - - @annotation.tailrec - def baz : Nothing = { - try { - throw new RuntimeException - } catch { - case _: Throwable => baz - } finally { - ??? - } - } - - @annotation.tailrec - def boz : Nothing = { - try { - throw new RuntimeException - } catch { - case _: Throwable => boz; ??? - } - } - - @annotation.tailrec - def bez : Nothing = { - try { - bez - } finally { - ??? - } - } - - // the `liftedTree` local method will prevent a tail call here. - @annotation.tailrec - def bar(i : Int) : Int = { - if (i == 0) 0 - else 1 + (try { - throw new RuntimeException - } catch { - case _: Throwable => bar(i - 1) - }) - } -} diff --git a/tests/untried/neg/t3275.check b/tests/untried/neg/t3275.check deleted file mode 100644 index 117c79232..000000000 --- a/tests/untried/neg/t3275.check +++ /dev/null @@ -1,4 +0,0 @@ -t3275.scala:2: error: @tailrec annotated method contains no recursive calls - @annotation.tailrec def foo() = 5 - ^ -one error found diff --git a/tests/untried/neg/t3275.scala b/tests/untried/neg/t3275.scala deleted file mode 100644 index 18e38a1a9..000000000 --- a/tests/untried/neg/t3275.scala +++ /dev/null @@ -1,3 +0,0 @@ -object Test { - @annotation.tailrec def foo() = 5 -} diff --git a/tests/untried/neg/t6574.check b/tests/untried/neg/t6574.check deleted file mode 100644 index c67b4ed80..000000000 --- a/tests/untried/neg/t6574.check +++ /dev/null @@ -1,7 +0,0 @@ -t6574.scala:4: error: could not optimize @tailrec annotated method notTailPos$extension: it contains a recursive call not in tail position - println("tail") - ^ -t6574.scala:8: error: could not optimize @tailrec annotated method differentTypeArgs$extension: it is called recursively with different type arguments - {(); new Bad[String, Unit](0)}.differentTypeArgs - ^ -two errors found diff --git a/tests/untried/neg/t6574.scala b/tests/untried/neg/t6574.scala deleted file mode 100644 index 9e1d624e5..000000000 --- a/tests/untried/neg/t6574.scala +++ /dev/null @@ -1,10 +0,0 @@ -class Bad[X, Y](val v: Int) extends AnyVal { - @annotation.tailrec final def notTailPos[Z](a: Int)(b: String): Unit = { - this.notTailPos[Z](a)(b) - println("tail") - } - - @annotation.tailrec final def differentTypeArgs {: Unit = - {(); new Bad[String, Unit](0)}.differentTypeArgs - } -} diff --git a/tests/untried/neg/tailrec-2.check b/tests/untried/neg/tailrec-2.check deleted file mode 100644 index 1daad6922..000000000 --- a/tests/untried/neg/tailrec-2.check +++ /dev/null @@ -1,7 +0,0 @@ -tailrec-2.scala:8: error: could not optimize @tailrec annotated method f: it contains a recursive call targeting a supertype - @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Super[A]).f(mem) - ^ -tailrec-2.scala:9: error: @tailrec annotated method contains no recursive calls - @annotation.tailrec final def f1[B >: A](mem: List[B]): List[B] = this.g(mem) - ^ -two errors found diff --git a/tests/untried/neg/tailrec-2.scala b/tests/untried/neg/tailrec-2.scala deleted file mode 100644 index d6b8b1355..000000000 --- a/tests/untried/neg/tailrec-2.scala +++ /dev/null @@ -1,29 +0,0 @@ -sealed abstract class Super[+A] { - def f[B >: A](mem: List[B]) : List[B] - def g(mem: List[_]) = ??? -} -// This one should fail, target is a supertype -class Bop1[+A](val element: A) extends Super[A] { - - @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Super[A]).f(mem) - @annotation.tailrec final def f1[B >: A](mem: List[B]): List[B] = this.g(mem) -} -// These succeed -class Bop2[+A](val element: A) extends Super[A] { - @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Bop2[A]).f(mem) -} -object Bop3 extends Super[Nothing] { - @annotation.tailrec final def f[B](mem: List[B]): List[B] = (null: Bop3.type).f(mem) -} -class Bop4[+A](val element: A) extends Super[A] { - @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = Other.f[A].f(mem) -} - -object Other { - def f[T] : Bop4[T] = sys.error("") -} - -object Bop { - def m1[A] : Super[A] = sys.error("") - def m2[A] : Bop2[A] = sys.error("") -} diff --git a/tests/untried/neg/tailrec-3.check b/tests/untried/neg/tailrec-3.check deleted file mode 100644 index a3542fb56..000000000 --- a/tests/untried/neg/tailrec-3.check +++ /dev/null @@ -1,10 +0,0 @@ -tailrec-3.scala:4: error: could not optimize @tailrec annotated method quux: it contains a recursive call not in tail position - @tailrec private def quux(xs: List[String]): List[String] = quux(quux(xs)) - ^ -tailrec-3.scala:6: error: could not optimize @tailrec annotated method quux2: it contains a recursive call not in tail position - case x1 :: x2 :: rest => quux2(x1 :: quux2(rest)) - ^ -tailrec-3.scala:10: error: could not optimize @tailrec annotated method quux3: it contains a recursive call not in tail position - case x :: xs if quux3(List("abc")) => quux3(xs) - ^ -three errors found diff --git a/tests/untried/neg/tailrec-3.scala b/tests/untried/neg/tailrec-3.scala deleted file mode 100644 index 20361658e..000000000 --- a/tests/untried/neg/tailrec-3.scala +++ /dev/null @@ -1,14 +0,0 @@ -import annotation.tailrec - -object Test { - @tailrec private def quux(xs: List[String]): List[String] = quux(quux(xs)) - @tailrec private def quux2(xs: List[String]): List[String] = xs match { - case x1 :: x2 :: rest => quux2(x1 :: quux2(rest)) - case _ => Nil - } - @tailrec private def quux3(xs: List[String]): Boolean = xs match { - case x :: xs if quux3(List("abc")) => quux3(xs) - case _ => false - } -} - diff --git a/tests/untried/neg/tailrec.check b/tests/untried/neg/tailrec.check deleted file mode 100644 index 946d3421e..000000000 --- a/tests/untried/neg/tailrec.check +++ /dev/null @@ -1,16 +0,0 @@ -tailrec.scala:45: error: could not optimize @tailrec annotated method facfail: it contains a recursive call not in tail position - else n * facfail(n - 1) - ^ -tailrec.scala:50: error: could not optimize @tailrec annotated method fail1: it is neither private nor final so can be overridden - @tailrec def fail1(x: Int): Int = fail1(x) - ^ -tailrec.scala:53: error: could not optimize @tailrec annotated method fail2: it contains a recursive call not in tail position - @tailrec final def fail2[T](xs: List[T]): List[T] = xs match { - ^ -tailrec.scala:59: error: could not optimize @tailrec annotated method fail3: it is called recursively with different type arguments - @tailrec final def fail3[T](x: Int): Int = fail3(x - 1) - ^ -tailrec.scala:63: error: could not optimize @tailrec annotated method fail4: it changes type of 'this' on a polymorphic recursive call - @tailrec final def fail4[U](other: Tom[U], x: Int): Int = other.fail4[U](other, x - 1) - ^ -5 errors found diff --git a/tests/untried/neg/tailrec.scala b/tests/untried/neg/tailrec.scala deleted file mode 100644 index 83a0c1a9e..000000000 --- a/tests/untried/neg/tailrec.scala +++ /dev/null @@ -1,65 +0,0 @@ -import scala.annotation.tailrec - -// putting @tailrec through the paces -object Winners { - @tailrec - def facsucc(n: Int, acc: Int): Int = - if (n == 0) acc - else facsucc(n - 1, n * acc) - - @tailrec def loopsucc1(x: Int): Int = loopsucc1(x - 1) - @tailrec def loopsucc2[T](x: Int): Int = loopsucc2[T](x - 1) - - def ding(): Unit = { - object dong { - @tailrec def loopsucc3(x: Int): Int = loopsucc3(x) - } - () - } - - def inner(q: Int) = { - @tailrec - def loopsucc4(x: Int): Int = loopsucc4(x + 1) - - loopsucc4(q) - } - - object innerBob { - @tailrec def loopsucc5(x: Int): Int = loopsucc5(x) - } -} - -class Winners { - @tailrec private def succ1(x: Int): Int = succ1(x) - @tailrec final def succ2(x: Int): Int = succ2(x) - @tailrec final def succ3[T](in: List[T], acc: List[T]): List[T] = in match { - case Nil => Nil - case x :: xs => succ3(xs, x :: acc) - } -} - -object Failures { - @tailrec - def facfail(n: Int): Int = - if (n == 0) 1 - else n * facfail(n - 1) -} - -class Failures { - // not private, not final - @tailrec def fail1(x: Int): Int = fail1(x) - - // a typical between-chair-and-keyboard error - @tailrec final def fail2[T](xs: List[T]): List[T] = xs match { - case Nil => Nil - case x :: xs => x :: fail2[T](xs) - } - - // unsafe - @tailrec final def fail3[T](x: Int): Int = fail3(x - 1) - - // unsafe - class Tom[T](x: Int) { - @tailrec final def fail4[U](other: Tom[U], x: Int): Int = other.fail4[U](other, x - 1) - } -} diff --git a/tests/untried/pos/t1672.scala b/tests/untried/pos/t1672.scala deleted file mode 100644 index 5ee6bb175..000000000 --- a/tests/untried/pos/t1672.scala +++ /dev/null @@ -1,10 +0,0 @@ -object Test { - @annotation.tailrec - def bar : Nothing = { - try { - throw new RuntimeException - } catch { - case _: Throwable => bar - } - } -} diff --git a/tests/untried/pos/t4649.flags b/tests/untried/pos/t4649.flags deleted file mode 100644 index e8fb65d50..000000000 --- a/tests/untried/pos/t4649.flags +++ /dev/null @@ -1 +0,0 @@ --Xfatal-warnings \ No newline at end of file diff --git a/tests/untried/pos/t4649.scala b/tests/untried/pos/t4649.scala deleted file mode 100644 index 0d6caa8d7..000000000 --- a/tests/untried/pos/t4649.scala +++ /dev/null @@ -1,6 +0,0 @@ -object Test { - // @annotation.tailrec - def lazyFilter[E](s: Stream[E], p: E => Boolean): Stream[E] = s match { - case h #:: t => if (p(h)) h #:: lazyFilter(t, p) else lazyFilter(t, p) - } -} diff --git a/tests/untried/pos/t6479.scala b/tests/untried/pos/t6479.scala deleted file mode 100644 index e4a4ff601..000000000 --- a/tests/untried/pos/t6479.scala +++ /dev/null @@ -1,56 +0,0 @@ -object TailrecAfterTryCatch { - - @annotation.tailrec - final def good1(): Unit = { - 1 match { - case 2 => { - try { - // return - } catch { - case e: ClassNotFoundException => - } - good1() - } - } - } - - @annotation.tailrec - final def good2(): Unit = { - //1 match { - // case 2 => { - try { - return - } catch { - case e: ClassNotFoundException => - } - good2() - // } - //} - } - - @annotation.tailrec - final def good3(): Unit = { - val 1 = 2 - try { - return - } catch { - case e: ClassNotFoundException => - } - good3() - } - - @annotation.tailrec - final def bad(): Unit = { - 1 match { - case 2 => { - try { - return - } catch { - case e: ClassNotFoundException => - } - bad() - } - } - } - -} diff --git a/tests/untried/pos/t6574.scala b/tests/untried/pos/t6574.scala deleted file mode 100644 index 6bb0042c6..000000000 --- a/tests/untried/pos/t6574.scala +++ /dev/null @@ -1,19 +0,0 @@ -class Bad[X, Y](val v: Int) extends AnyVal { - def vv = v - @annotation.tailrec final def foo[Z](a: Int)(b: String): Unit = { - this.foo[Z](a)(b) - } - - @annotation.tailrec final def differentReceiver {: Unit = - {(); new Bad[X, Y](0)}.differentReceiver - } - - @annotation.tailrec final def dependent[Z](a: Int)(b: String): b.type = { - this.dependent[Z](a)(b) - } -} - -class HK[M[_]](val v: Int) extends AnyVal { - def hk[N[_]]: Unit = if (false) hk[M] else () -} - diff --git a/tests/untried/pos/t6891.flags b/tests/untried/pos/t6891.flags deleted file mode 100644 index fe048006a..000000000 --- a/tests/untried/pos/t6891.flags +++ /dev/null @@ -1 +0,0 @@ --Ycheck:extmethods -Xfatal-warnings \ No newline at end of file diff --git a/tests/untried/pos/t6891.scala b/tests/untried/pos/t6891.scala deleted file mode 100644 index bed2d0d77..000000000 --- a/tests/untried/pos/t6891.scala +++ /dev/null @@ -1,26 +0,0 @@ -object O { - implicit class Foo[A](val value: String) extends AnyVal { - def bippy() = { - @annotation.tailrec def loop(x: A): Unit = loop(x) - () - } - - def boppy() = { - @annotation.tailrec def loop(x: value.type): Unit = loop(x) - () - } - - def beppy[C](c: => C) = { - () => c - @annotation.tailrec def loop(x: value.type): Unit = loop(x) - () => c - () - } - } - // uncaught exception during compilation: Types$TypeError("type mismatch; - // found : A(in method bippy$extension) - // required: A(in class Foo)") @ scala.tools.nsc.typechecker.Contexts$Context.issueCommon(Contexts.scala:396) - // error: scala.reflect.internal.Types$TypeError: type mismatch; - // found : A(in method bippy$extension) - // required: A(in class Foo) -} -- cgit v1.2.3