summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-06-07 23:43:14 +0000
committerPaul Phillips <paulp@improving.org>2010-06-07 23:43:14 +0000
commitcaa6bf0e7a9c02b7519549c289f7a455bad281b1 (patch)
treeddd2a4da3fe7969776a039f8ccc44dd6aa2d4292
parentd6896c490acea8617247cf593060fa67ed82c79c (diff)
downloadscala-caa6bf0e7a9c02b7519549c289f7a455bad281b1.tar.gz
scala-caa6bf0e7a9c02b7519549c289f7a455bad281b1.tar.bz2
scala-caa6bf0e7a9c02b7519549c289f7a455bad281b1.zip
Most of the iterate implementations were callin...
Most of the iterate implementations were calling the given function one too many times, leading to tragic failure if the function could not handle this (such as repeatedly applying tail.) Closes #3540, review by prokopec.
-rw-r--r--src/library/scala/Array.scala17
-rw-r--r--src/library/scala/collection/generic/TraversableFactory.scala16
-rw-r--r--test/files/run/bug3540.scala7
3 files changed, 28 insertions, 12 deletions
diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala
index 9712990d73..250fd09602 100644
--- a/src/library/scala/Array.scala
+++ b/src/library/scala/Array.scala
@@ -363,13 +363,18 @@ object Array extends FallbackArrayBuilding {
*/
def iterate[T: ClassManifest](start: T, len: Int)(f: T => T): Array[T] = {
val b = newBuilder[T]
- b.sizeHint(len)
- var acc = start
- var i = 0
- while (i < len) {
+
+ if (len > 0) {
+ b.sizeHint(len)
+ var acc = start
+ var i = 1
b += acc
- acc = f(acc)
- i += 1
+
+ while (i < len) {
+ acc = f(acc)
+ i += 1
+ b += acc
+ }
}
b.result
}
diff --git a/src/library/scala/collection/generic/TraversableFactory.scala b/src/library/scala/collection/generic/TraversableFactory.scala
index d8541d2714..c6f5ce4dde 100644
--- a/src/library/scala/collection/generic/TraversableFactory.scala
+++ b/src/library/scala/collection/generic/TraversableFactory.scala
@@ -224,13 +224,17 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl
*/
def iterate[A](start: A, len: Int)(f: A => A): CC[A] = {
val b = newBuilder[A]
- b.sizeHint(len)
- var acc = start
- var i = 0
- while (i < len) {
+ if (len > 0) {
+ b.sizeHint(len)
+ var acc = start
+ var i = 1
b += acc
- acc = f(acc)
- i += 1
+
+ while (i < len) {
+ acc = f(acc)
+ i += 1
+ b += acc
+ }
}
b.result
}
diff --git a/test/files/run/bug3540.scala b/test/files/run/bug3540.scala
new file mode 100644
index 0000000000..5ffacb5dff
--- /dev/null
+++ b/test/files/run/bug3540.scala
@@ -0,0 +1,7 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ assert(List.iterate(List(1,2,3), 4)(_.tail).last.isEmpty)
+ assert(Stream.iterate(Stream(1,2,3), 4)(_.tail).last.isEmpty)
+ assert(Array.iterate(Array(1,2,3), 4)(_.tail).last.isEmpty)
+ }
+}