summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRex Kerr <ichoran@gmail.com>2015-02-18 18:52:46 -0800
committerRex Kerr <ichoran@gmail.com>2015-02-20 00:07:44 -0800
commit1d4a1f721d360c73b9f2468368c7e9b2b4c17fea (patch)
tree9cd0a2db1374c03934adde0483f43dd96cac235a
parent18870094f2464e39067baeea71c4ae7ab8dfc6d9 (diff)
downloadscala-1d4a1f721d360c73b9f2468368c7e9b2b4c17fea.tar.gz
scala-1d4a1f721d360c73b9f2468368c7e9b2b4c17fea.tar.bz2
scala-1d4a1f721d360c73b9f2468368c7e9b2b4c17fea.zip
SI-9126 Missing .seqs causes problems with parallel GenXs
Added `.seq` in two essential places so that a parallel collection passed as an argument won't mess up side-effecting sequential computations in `List.flatMap` and `GenericTraversableTemplate.transpose` (thanks to retronym for finding the danger spots). Tests that `.seq` is called by constructing a `GenSeq` whose `.seq` disagrees with anything non-`.seq` (idea & working implementation from retronym). Also updates the `.seq` test for `Vector#++` to use the new more efficient method.
-rw-r--r--src/library/scala/collection/generic/GenericTraversableTemplate.scala2
-rw-r--r--src/library/scala/collection/immutable/List.scala2
-rw-r--r--test/junit/scala/collection/ParallelConsistencyTest.scala44
-rw-r--r--test/junit/scala/collection/immutable/VectorTest.scala20
4 files changed, 46 insertions, 22 deletions
diff --git a/src/library/scala/collection/generic/GenericTraversableTemplate.scala b/src/library/scala/collection/generic/GenericTraversableTemplate.scala
index 54455c531a..bdd91ba7a4 100644
--- a/src/library/scala/collection/generic/GenericTraversableTemplate.scala
+++ b/src/library/scala/collection/generic/GenericTraversableTemplate.scala
@@ -216,7 +216,7 @@ trait GenericTraversableTemplate[+A, +CC[X] <: GenTraversable[X]] extends HasNew
val bs: IndexedSeq[Builder[B, CC[B]]] = IndexedSeq.fill(headSize)(genericBuilder[B])
for (xs <- sequential) {
var i = 0
- for (x <- asTraversable(xs)) {
+ for (x <- asTraversable(xs).seq) {
if (i >= headSize) fail
bs(i) += x
i += 1
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index a46b4adabb..254f14f13c 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -324,7 +324,7 @@ sealed abstract class List[+A] extends AbstractSeq[A]
var h: ::[B] = null
var t: ::[B] = null
while (rest ne Nil) {
- f(rest.head).foreach{ b =>
+ f(rest.head).seq.foreach{ b =>
if (!found) {
h = new ::(b, Nil)
t = h
diff --git a/test/junit/scala/collection/ParallelConsistencyTest.scala b/test/junit/scala/collection/ParallelConsistencyTest.scala
new file mode 100644
index 0000000000..da96362413
--- /dev/null
+++ b/test/junit/scala/collection/ParallelConsistencyTest.scala
@@ -0,0 +1,44 @@
+package scala.collection.immutable
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class ParallelConsistencyTest {
+
+ private val theSeq = Seq(1,2,3)
+
+ // This collection will throw an exception if you do anything but call .length or .seq
+ private val mustCallSeq: collection.GenSeq[Int] = new collection.parallel.ParSeq[Int] {
+ def length = 3
+
+ // This method is surely sequential & safe -- want all access to go through here
+ def seq = theSeq
+
+ def notSeq = throw new Exception("Access to parallel collection not via .seq")
+
+ // These methods could possibly be used dangerously explicitly or internally
+ // (apply could also be used safely; if it is, do test with mustCallSeq)
+ def apply(i: Int) = notSeq
+ def splitter = notSeq
+ }
+
+ // Test Vector ++ with a small parallel collection concatenation (SI-9072).
+ @Test
+ def testPlusPlus(): Unit = {
+ assert((Vector.empty ++ mustCallSeq) == theSeq, "Vector ++ unsafe with parallel vectors")
+ }
+
+ // SI-9126, 1 of 2
+ @Test
+ def testTranspose(): Unit = {
+ assert(List(mustCallSeq).transpose.flatten == theSeq, "Transposing inner parallel collection unsafe")
+ }
+
+ // SI-9126, 2 of 2
+ @Test
+ def testList_flatMap(): Unit = {
+ assert(List(1).flatMap(_ => mustCallSeq) == theSeq, "List#flatMap on inner parallel collection unsafe")
+ }
+}
diff --git a/test/junit/scala/collection/immutable/VectorTest.scala b/test/junit/scala/collection/immutable/VectorTest.scala
deleted file mode 100644
index e7edba3e43..0000000000
--- a/test/junit/scala/collection/immutable/VectorTest.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package scala.collection.immutable
-
-import org.junit.{Assert, Test}
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(classOf[JUnit4])
-class VectorTest {
- /**
- * Test Vector ++ with a small parallel collection concatenation (SI-9072).
- *
- */
- @Test
- def testPlusPlus(): Unit = {
- val smallVec = (0 to 1)
- val smallParVec = smallVec.par
- val testElementsSize = (0 to 1000).map( _ => Vector.empty ++ smallParVec )
- Assert.assertTrue(testElementsSize.forall( v => v.size == 2 ))
- }
-}