From 67c3c68da5de6284c5e37ef4b5f907d0079f0490 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 16 Mar 2009 17:46:58 +0000 Subject: The birth of the @switch and @tailrec annotations. They are located in package scala.annotation. Also in this patch: * numerous test cases for both annotations * addition of @tailrec and @switch in a few strategic locations * fixes for critical section NewScanners methods which were not being compiled into switches, immediately proving the value of @switch * tail recursive implementations for Iterator.{ dropWhile, drop} and List.dropWhile tagged with @tailrec, closing bug #1376 --- test/files/neg/switch.check | 10 +++++++ test/files/neg/switch.scala | 66 ++++++++++++++++++++++++++++++++++++++++++++ test/files/neg/tailrec.check | 10 +++++++ test/files/neg/tailrec.scala | 53 +++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 test/files/neg/switch.check create mode 100644 test/files/neg/switch.scala create mode 100644 test/files/neg/tailrec.check create mode 100644 test/files/neg/tailrec.scala (limited to 'test/files') diff --git a/test/files/neg/switch.check b/test/files/neg/switch.check new file mode 100644 index 0000000000..7212c1a22b --- /dev/null +++ b/test/files/neg/switch.check @@ -0,0 +1,10 @@ +switch.scala:28: error: could not emit switch for @switch annotated match + def fail1(c: Char) = (c: @switch) match { + ^ +switch.scala:38: error: could not emit switch for @switch annotated match + def fail2(c: Char) = (c: @switch @unchecked) match { + ^ +switch.scala:45: error: could not emit switch for @switch annotated match + def fail3(c: Char) = (c: @unchecked @switch) match { + ^ +three errors found diff --git a/test/files/neg/switch.scala b/test/files/neg/switch.scala new file mode 100644 index 0000000000..a5a6f9e789 --- /dev/null +++ b/test/files/neg/switch.scala @@ -0,0 +1,66 @@ +import scala.annotation.switch + +// this is testing not so much how things ought to be but how they are; +// the test is supposed to start failing if the behavior changes at all. +object Other { + val C1 = 'P' // fails: not final + final val C2 = 'Q' // succeeds: singleton type Char('Q') inferred + final val C3: Char = 'R' // fails: type Char specified + final val C4 = '\u000A' // succeeds like C2 but more unicodey +} + +object Main { + def succ1(c: Char) = (c: @switch) match { + case 'A' | 'B' | 'C' => true + case 'd' => true + case 'f' | 'g' => true + case _ => false + } + + def succ2(c: Char) = (c: @switch) match { + case 'A' | 'B' | 'C' => true + case Other.C2 => true + case Other.C4 => true + case _ => false + } + + // has a guard + def fail1(c: Char) = (c: @switch) match { + case 'A' | 'B' | 'C' => true + case x if x == 'A' => true + case _ => false + } + + // throwing in @unchecked on the next two to make sure + // multiple annotations are processed correctly + + // thinks a val in an object is constant... so naive + def fail2(c: Char) = (c: @switch @unchecked) match { + case 'A' => true + case Other.C1 => true + case _ => false + } + + // more naivete + def fail3(c: Char) = (c: @unchecked @switch) match { + case 'A' => true + case Other.C3 => true + case _ => false + } + + // guard case done correctly + def succ3(c: Char) = (c: @switch) match { + case 'A' | 'B' | 'C' => true + case x => x == 'A' + } + + // some ints just to mix it up a bit + def succ4(x: Int, y: Int) = ((x+y): @switch) match { + case 1 => 5 + case 2 => 10 + case 3 => 20 + case 4 => 50 + case 5|6|7|8 => 100 + case _ => -1 + } +} \ No newline at end of file diff --git a/test/files/neg/tailrec.check b/test/files/neg/tailrec.check new file mode 100644 index 0000000000..22d70e82a0 --- /dev/null +++ b/test/files/neg/tailrec.check @@ -0,0 +1,10 @@ +tailrec.scala:6: error: could not optimize @tailrec annotated method + def facfail(n: Int): Int = + ^ +tailrec.scala:42: error: could not optimize @tailrec annotated method + @tailrec def fail1(x: Int): Int = fail1(x) + ^ +tailrec.scala:45: error: could not optimize @tailrec annotated method + @tailrec def fail2[T](xs: List[T]): List[T] = xs match { + ^ +three errors found diff --git a/test/files/neg/tailrec.scala b/test/files/neg/tailrec.scala new file mode 100644 index 0000000000..4c45672f93 --- /dev/null +++ b/test/files/neg/tailrec.scala @@ -0,0 +1,53 @@ +import scala.annotation.tailrec + +// putting @tailrec through the paces +object Main { + @tailrec + def facfail(n: Int): Int = + if (n == 0) 1 + else n * facfail(n - 1) + + @tailrec + def facsucc(n: Int, acc: Int): Int = + if (n == 0) acc + else facsucc(n - 1, n * acc) + + @tailrec def loopy1(x: Int): Int = loopy1(x - 1) + + def ding { + object dong { + @tailrec def loopy2(x: Int): Int = loopy2(x) + } + () + } + + def inner(q: Int) = { + @tailrec + def loopy3(x: Int): Int = loopy3(x + 1) + + loopy3(q) + } +} + +class Bob { + // these should work + @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) + } + + // not private, not final + @tailrec def fail1(x: Int): Int = fail1(x) + + // a typical between-chair-and-keyboard error + @tailrec def fail2[T](xs: List[T]): List[T] = xs match { + case Nil => Nil + case x :: xs => x :: fail2(xs) + } + + object innerBob { + @tailrec def succ4(x: Int): Int = succ4(x) + } +} -- cgit v1.2.3