diff options
author | Paul Phillips <paulp@improving.org> | 2011-01-10 07:21:56 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-01-10 07:21:56 +0000 |
commit | e05dfaeabf430dac8909ff9e5a5911b0c94101ae (patch) | |
tree | 397ce22c41c4c5b95390625ef73fcb70cef856b6 /test/files | |
parent | 58b5c24df8ba06c02b92723922bc21381fedeb93 (diff) | |
download | scala-e05dfaeabf430dac8909ff9e5a5911b0c94101ae.tar.gz scala-e05dfaeabf430dac8909ff9e5a5911b0c94101ae.tar.bz2 scala-e05dfaeabf430dac8909ff9e5a5911b0c94101ae.zip |
A pretty severe bug in the recognition of tail ...
A pretty severe bug in the recognition of tail call elimination.
It turns out that Tailcalls will perform "partial elimination" in
situations such as:
@annotation.tailrec final def f(x: Int): Int = f(f(x))
The outer call to f1 becomes a jump, but the inner call remains as
it was. I implemented @tailrec under the impression that if the
optimization had taken place, it had gone all the way. So this is now
fixed with a direct examination of the rewritten tree.
While I was in there I threw in some improved error reporting: the error
positioning is now on the call which is not in tail position rather than
the method declaration.
Closes #4135, no review.
Diffstat (limited to 'test/files')
-rw-r--r-- | test/files/neg/tailrec-2.check | 4 | ||||
-rw-r--r-- | test/files/neg/tailrec-3.check | 10 | ||||
-rw-r--r-- | test/files/neg/tailrec-3.scala | 14 | ||||
-rw-r--r-- | test/files/neg/tailrec.check | 24 |
4 files changed, 38 insertions, 14 deletions
diff --git a/test/files/neg/tailrec-2.check b/test/files/neg/tailrec-2.check index ab6733946d..4f763a1c8d 100644 --- a/test/files/neg/tailrec-2.check +++ b/test/files/neg/tailrec-2.check @@ -1,4 +1,4 @@ -tailrec-2.scala:6: error: could not optimize @tailrec annotated method: it contains a recursive call targetting a supertype +tailrec-2.scala:6: error: could not optimize @tailrec annotated method f: it contains a recursive call targetting a supertype @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Super[A]).f(mem) - ^ + ^ one error found diff --git a/test/files/neg/tailrec-3.check b/test/files/neg/tailrec-3.check new file mode 100644 index 0000000000..a3542fb564 --- /dev/null +++ b/test/files/neg/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/test/files/neg/tailrec-3.scala b/test/files/neg/tailrec-3.scala new file mode 100644 index 0000000000..20361658ea --- /dev/null +++ b/test/files/neg/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/test/files/neg/tailrec.check b/test/files/neg/tailrec.check index 27d99f632e..f6865b2f9d 100644 --- a/test/files/neg/tailrec.check +++ b/test/files/neg/tailrec.check @@ -1,16 +1,16 @@ -tailrec.scala:43: error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position - def facfail(n: Int): Int = - ^ -tailrec.scala:50: error: could not optimize @tailrec annotated method: it is neither private nor final so can be overridden +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: 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: it is called recursively with different type arguments + ^ +tailrec.scala:55: error: could not optimize @tailrec annotated method fail2: it contains a recursive call not in tail position + case x :: xs => x :: fail2[T](xs) + ^ +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: it changes type of 'this' on a polymorphic recursive call + ^ +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 |