diff --git a/.travis.yml b/.travis.yml index b236dd26..f783ed63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ language: scala scala: - 2.13.3 + - 0.27.0-RC1 env: - ADOPTOPENJDK=8 diff --git a/build.sbt b/build.sbt index 11c68e25..8fb949c2 100644 --- a/build.sbt +++ b/build.sbt @@ -1,15 +1,26 @@ Global / cancelable := true publish / skip := true // in root +Global / scalacOptions ++= ( + if (isDotty.value) Seq("-language:implicitConversions") // TODO check again on 3.0.0-M1 + else Seq() +) + lazy val commonSettings: Seq[Setting[_]] = ScalaModulePlugin.scalaModuleSettings ++ Seq( - Compile / compile / scalacOptions += "-Werror" + Compile / compile / scalacOptions --= (if (isDotty.value) Seq("-Xlint") + else Seq()), + Compile / compile / scalacOptions ++= (if (isDotty.value) Seq() + else Seq("-Werror")), ) lazy val core = project.in(file("core")) .settings(commonSettings) .settings( - name := "scala-parallel-collections" + name := "scala-parallel-collections", + // don't run Dottydoc, it errors and isn't needed anyway + Compile / doc / sources := (if (isDotty.value) Seq() else (Compile / doc/ sources).value), + Compile / packageDoc / publishArtifact := !isDotty.value, ) lazy val junit = project.in(file("junit")) @@ -20,13 +31,22 @@ lazy val junit = project.in(file("junit")) libraryDependencies += "javax.xml.bind" % "jaxb-api" % "2.3.1" % Test, testOptions += Tests.Argument(TestFrameworks.JUnit, "-a", "-v"), Test / fork := true, - publish / skip := true + publish / skip := true, + // https://github.com/sbt/sbt/pull/5919 adds this to sbt itself, + // so we should revisit once sbt 1.4.1 is available + Test / unmanagedSourceDirectories += { + val major = CrossVersion.partialVersion(scalaVersion.value) match { + case Some((0 | 3, _)) => "3" + case _ => "2" + } + baseDirectory.value / "src" / "test" / s"scala-$major" + }, ).dependsOn(testmacros, core) lazy val scalacheck = project.in(file("scalacheck")) .settings(commonSettings) .settings( - libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.14.3", + libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.15.0-M1" withDottyCompat(scalaVersion.value), Test / fork := true, Test / testOptions += Tests.Argument(TestFrameworks.ScalaCheck, "-workers", "1", "-minSize", "0", "-maxSize", "4000", "-minSuccessfulTests", "5"), publish / skip := true @@ -36,5 +56,14 @@ lazy val testmacros = project.in(file("testmacros")) .settings(commonSettings) .settings( libraryDependencies += scalaOrganization.value % "scala-compiler" % scalaVersion.value, - publish / skip := true + publish / skip := true, + // https://github.com/sbt/sbt/pull/5919 adds this to sbt itself, + // so we should revisit once sbt 1.4.1 is available + Compile / unmanagedSourceDirectories += { + val major = CrossVersion.partialVersion(scalaVersion.value) match { + case Some((0 | 3, _)) => "3" + case _ => "2" + } + baseDirectory.value / "src" / "main" / s"scala-$major" + }, ) diff --git a/core/src/main/scala/scala/collection/CustomParallelizable.scala b/core/src/main/scala/scala/collection/CustomParallelizable.scala index 54d57603..51dbec3b 100644 --- a/core/src/main/scala/scala/collection/CustomParallelizable.scala +++ b/core/src/main/scala/scala/collection/CustomParallelizable.scala @@ -13,10 +13,8 @@ package scala package collection -import parallel.Combiner - trait CustomParallelizable[+A, +ParRepr <: Parallel] extends Any with Parallelizable[A, ParRepr] { override def par: ParRepr - override protected[this] def parCombiner: Combiner[A, ParRepr] = throw new UnsupportedOperationException("") + override protected[this] def parCombiner = throw new UnsupportedOperationException("") } diff --git a/core/src/main/scala/scala/collection/Parallelizable.scala b/core/src/main/scala/scala/collection/Parallelizable.scala index 0b2dda97..0825f6f1 100644 --- a/core/src/main/scala/scala/collection/Parallelizable.scala +++ b/core/src/main/scala/scala/collection/Parallelizable.scala @@ -14,6 +14,7 @@ package scala package collection import parallel.Combiner +import scala.annotation.unchecked.uncheckedVariance /** This trait describes collections which can be turned into parallel collections * by invoking the method `par`. Parallelizable collections may be parameterized with @@ -48,6 +49,6 @@ trait Parallelizable[+A, +ParRepr <: Parallel] extends Any { * * @return a combiner for the parallel collection of type `ParRepr` */ - protected[this] def parCombiner: Combiner[A, ParRepr] + protected[this] def parCombiner: Combiner[A @uncheckedVariance, ParRepr] } diff --git a/core/src/main/scala/scala/collection/generic/GenericParTemplate.scala b/core/src/main/scala/scala/collection/generic/GenericParTemplate.scala index 04d1ac4c..e98e1a93 100644 --- a/core/src/main/scala/scala/collection/generic/GenericParTemplate.scala +++ b/core/src/main/scala/scala/collection/generic/GenericParTemplate.scala @@ -31,12 +31,9 @@ trait GenericParTemplate[+A, +CC[X] <: ParIterable[X]] { def companion: GenericParCompanion[CC] - protected[this] override def newBuilder: scala.collection.mutable.Builder[A, CC[A]] = newCombiner + protected[this] override def newBuilder = newCombiner - protected[this] override def newCombiner: Combiner[A, CC[A]] = { - val cb = companion.newCombiner[A] - cb - } + protected[this] override def newCombiner = companion.newCombiner[A] override def genericBuilder[B]: Combiner[B, CC[B]] = genericCombiner[B] @@ -50,7 +47,7 @@ trait GenericParTemplate[+A, +CC[X] <: ParIterable[X]] trait GenericParMapTemplate[K, +V, +CC[X, Y] <: ParMap[X, Y]] extends GenericParTemplate[(K, V), ParIterable] { - protected[this] override def newCombiner: Combiner[(K, V), CC[K, V]] = { + protected[this] override def newCombiner: Combiner[(K, V @uncheckedVariance), CC[K, V @uncheckedVariance]] = { val cb = mapCompanion.newCombiner[K, V] cb } diff --git a/core/src/main/scala/scala/collection/generic/GenericTraversableTemplate.scala b/core/src/main/scala/scala/collection/generic/GenericTraversableTemplate.scala index a1524eb1..c541bc58 100644 --- a/core/src/main/scala/scala/collection/generic/GenericTraversableTemplate.scala +++ b/core/src/main/scala/scala/collection/generic/GenericTraversableTemplate.scala @@ -63,7 +63,7 @@ trait GenericTraversableTemplate[+A, +CC[X] <: ParIterable[X]] extends HasNewBui /** The builder that builds instances of type $Coll[A] */ - protected[this] def newBuilder: Builder[A, CC[A]] = companion.newBuilder[A] + protected[this] def newBuilder: Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = companion.newBuilder[A] /** The generic builder that builds instances of $Coll * at arbitrary element types. diff --git a/core/src/main/scala/scala/collection/generic/HasNewBuilder.scala b/core/src/main/scala/scala/collection/generic/HasNewBuilder.scala index 5d788f27..7c407dc3 100644 --- a/core/src/main/scala/scala/collection/generic/HasNewBuilder.scala +++ b/core/src/main/scala/scala/collection/generic/HasNewBuilder.scala @@ -15,8 +15,9 @@ package collection package generic import mutable.Builder +import scala.annotation.unchecked.uncheckedVariance trait HasNewBuilder[+A, +Repr] extends Any { /** The builder that builds instances of Repr */ - protected[this] def newBuilder: Builder[A, Repr] + protected[this] def newBuilder: Builder[A @uncheckedVariance, Repr] } diff --git a/core/src/main/scala/scala/collection/generic/HasNewCombiner.scala b/core/src/main/scala/scala/collection/generic/HasNewCombiner.scala index f2059975..568e6d96 100644 --- a/core/src/main/scala/scala/collection/generic/HasNewCombiner.scala +++ b/core/src/main/scala/scala/collection/generic/HasNewCombiner.scala @@ -15,8 +15,9 @@ package collection package generic import scala.collection.parallel.Combiner +import scala.annotation.unchecked.uncheckedVariance trait HasNewCombiner[+T, +Repr] { - protected[this] def newCombiner: Combiner[T, Repr] + protected[this] def newCombiner: Combiner[T @uncheckedVariance, Repr] } diff --git a/core/src/main/scala/scala/collection/parallel/ParIterableLike.scala b/core/src/main/scala/scala/collection/parallel/ParIterableLike.scala index 9908a617..5efedcc7 100644 --- a/core/src/main/scala/scala/collection/parallel/ParIterableLike.scala +++ b/core/src/main/scala/scala/collection/parallel/ParIterableLike.scala @@ -20,7 +20,7 @@ import scala.collection.{CustomParallelizable, IterableOps, Parallel} import scala.collection.generic._ import immutable.HashMapCombiner import scala.reflect.ClassTag - +import scala.annotation.unchecked.uncheckedVariance /** A template trait for parallel collections of type `ParIterable[T]`. * @@ -144,11 +144,11 @@ import scala.reflect.ClassTag * @define Coll `ParIterable` * @define coll parallel iterable */ -trait ParIterableLike[+T, +CC[X] <: ParIterable[X], +Repr <: ParIterable[T], +Sequential <: Iterable[T] with IterableOps[T, Iterable, Sequential]] -extends IterableOnce[T] - with CustomParallelizable[T, Repr] +trait ParIterableLike[+T, +CC[X] <: ParIterable[X], +Repr <: ParIterable[T], +Sequential <: Iterable[T] with IterableOps[T, Iterable, Sequential @uncheckedVariance]] +extends IterableOnce[T @uncheckedVariance] + with CustomParallelizable[T @uncheckedVariance, Repr] with Parallel - with HasNewCombiner[T, Repr] + with HasNewCombiner[T @uncheckedVariance, Repr] { self => def size: Int @@ -332,7 +332,7 @@ extends IterableOnce[T] def asCombiner = cb.asInstanceOf[Combiner[Elem, To]] } - protected[this] def sequentially[S, That <: Parallel](b: Sequential => Sequential) = newCombiner.fromSequential(b(seq)) + protected[this] def sequentially[S, That <: Parallel](b: (Sequential => Sequential) @uncheckedVariance) = newCombiner.fromSequential(b(seq)) def mkString(start: String, sep: String, end: String): String = seq.mkString(start, sep, end) @@ -542,7 +542,7 @@ extends IterableOnce[T] * concurrent parallel collections, the combiners of which allow * thread safe access. */ - protected[this] def combinerFactory = { + protected[this] def combinerFactory: CombinerFactory[T @uncheckedVariance, Repr @uncheckedVariance] = { val combiner = newCombiner combiner.combinerTaskSupport = tasksupport if (combiner.canBeShared) new CombinerFactory[T, Repr] { @@ -849,7 +849,7 @@ extends IterableOnce[T] protected trait Accessor[R, Tp] extends StrictSplitterCheckTask[R, Tp] { protected[this] val pit: IterableSplitter[T] - protected[this] def newSubtask(p: IterableSplitter[T]): Accessor[R, Tp] + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]): Accessor[R, Tp] def shouldSplitFurther = pit.shouldSplitFurther(self.repr, tasksupport.parallelismLevel) def split = pit.splitWithSignalling.map(newSubtask(_)) // default split procedure private[parallel] override def signalAbort() = pit.abort() @@ -918,111 +918,111 @@ extends IterableOnce[T] protected trait Transformer[R, Tp] extends Accessor[R, Tp] - protected[this] class Foreach[S](op: T => S, protected[this] val pit: IterableSplitter[T]) + protected[this] class Foreach[S](op: T => S, protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[Unit, Foreach[S]] { @volatile var result: Unit = () def leaf(prevr: Option[Unit]) = pit.foreach(op) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Foreach[S](op, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Foreach[S](op, p) } - protected[this] class Count(pred: T => Boolean, protected[this] val pit: IterableSplitter[T]) + protected[this] class Count(pred: T => Boolean, protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[Int, Count] { // val pittxt = pit.toString @volatile var result: Int = 0 def leaf(prevr: Option[Int]) = result = pit.count(pred) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Count(pred, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Count(pred, p) override def merge(that: Count) = result = result + that.result // override def toString = "CountTask(" + pittxt + ")" } - protected[this] class Reduce[U >: T](op: (U, U) => U, protected[this] val pit: IterableSplitter[T]) + protected[this] class Reduce[U >: T](op: (U, U) => U, protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[Option[U], Reduce[U]] { @volatile var result: Option[U] = None def leaf(prevr: Option[Option[U]]) = if (pit.remaining > 0) result = Some(pit.reduce(op)) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Reduce(op, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Reduce(op, p) override def merge(that: Reduce[U]) = if (this.result == None) result = that.result else if (that.result != None) result = Some(op(result.get, that.result.get)) override def requiresStrictSplitters = true } - protected[this] class Fold[U >: T](z: U, op: (U, U) => U, protected[this] val pit: IterableSplitter[T]) + protected[this] class Fold[U >: T](z: U, op: (U, U) => U, protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[U, Fold[U]] { @volatile var result: U = null.asInstanceOf[U] def leaf(prevr: Option[U]) = result = pit.fold(z)(op) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Fold(z, op, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Fold(z, op, p) override def merge(that: Fold[U]) = result = op(result, that.result) } - protected[this] class Aggregate[S](z: () => S, seqop: (S, T) => S, combop: (S, S) => S, protected[this] val pit: IterableSplitter[T]) + protected[this] class Aggregate[S](z: () => S, seqop: (S, T) => S, combop: (S, S) => S, protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[S, Aggregate[S]] { @volatile var result: S = null.asInstanceOf[S] def leaf(prevr: Option[S]) = result = pit.foldLeft(z())(seqop) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Aggregate(z, seqop, combop, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Aggregate(z, seqop, combop, p) override def merge(that: Aggregate[S]) = result = combop(result, that.result) } - protected[this] class Sum[U >: T](num: Numeric[U], protected[this] val pit: IterableSplitter[T]) + protected[this] class Sum[U >: T](num: Numeric[U], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[U, Sum[U]] { @volatile var result: U = null.asInstanceOf[U] def leaf(prevr: Option[U]) = result = pit.sum(num) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Sum(num, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Sum(num, p) override def merge(that: Sum[U]) = result = num.plus(result, that.result) } - protected[this] class Product[U >: T](num: Numeric[U], protected[this] val pit: IterableSplitter[T]) + protected[this] class Product[U >: T](num: Numeric[U], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[U, Product[U]] { @volatile var result: U = null.asInstanceOf[U] def leaf(prevr: Option[U]) = result = pit.product(num) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Product(num, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Product(num, p) override def merge(that: Product[U]) = result = num.times(result, that.result) } - protected[this] class Min[U >: T](ord: Ordering[U], protected[this] val pit: IterableSplitter[T]) + protected[this] class Min[U >: T](ord: Ordering[U], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[Option[U], Min[U]] { @volatile var result: Option[U] = None def leaf(prevr: Option[Option[U]]) = if (pit.remaining > 0) result = Some(pit.min(ord)) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Min(ord, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Min(ord, p) override def merge(that: Min[U]) = if (this.result == None) result = that.result else if (that.result != None) result = if (ord.lteq(result.get, that.result.get)) result else that.result override def requiresStrictSplitters = true } - protected[this] class Max[U >: T](ord: Ordering[U], protected[this] val pit: IterableSplitter[T]) + protected[this] class Max[U >: T](ord: Ordering[U], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[Option[U], Max[U]] { @volatile var result: Option[U] = None def leaf(prevr: Option[Option[U]]) = if (pit.remaining > 0) result = Some(pit.max(ord)) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Max(ord, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Max(ord, p) override def merge(that: Max[U]) = if (this.result == None) result = that.result else if (that.result != None) result = if (ord.gteq(result.get, that.result.get)) result else that.result override def requiresStrictSplitters = true } - protected[this] class Map[S, That](f: T => S, cbf: CombinerFactory[S, That], protected[this] val pit: IterableSplitter[T]) + protected[this] class Map[S, That](f: T => S, cbf: CombinerFactory[S, That], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[S, That], Map[S, That]] { @volatile var result: Combiner[S, That] = null def leaf(prev: Option[Combiner[S, That]]) = result = pit.map2combiner(f, reuse(prev, cbf())) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Map(f, cbf, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Map(f, cbf, p) override def merge(that: Map[S, That]) = result = result combine that.result } protected[this] class Collect[S, That] - (pf: PartialFunction[T, S], pbf: CombinerFactory[S, That], protected[this] val pit: IterableSplitter[T]) + (pf: PartialFunction[T, S], pbf: CombinerFactory[S, That], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[S, That], Collect[S, That]] { @volatile var result: Combiner[S, That] = null def leaf(prev: Option[Combiner[S, That]]) = result = pit.collect2combiner[S, That](pf, pbf()) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Collect(pf, pbf, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Collect(pf, pbf, p) override def merge(that: Collect[S, That]) = result = result combine that.result } protected[this] class FlatMap[S, That] - (f: T => IterableOnce[S], pbf: CombinerFactory[S, That], protected[this] val pit: IterableSplitter[T]) + (f: T => IterableOnce[S], pbf: CombinerFactory[S, That], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[S, That], FlatMap[S, That]] { @volatile var result: Combiner[S, That] = null def leaf(prev: Option[Combiner[S, That]]) = result = pit.flatmap2combiner(f, pbf()) - protected[this] def newSubtask(p: IterableSplitter[T]) = new FlatMap(f, pbf, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new FlatMap(f, pbf, p) override def merge(that: FlatMap[S, That]) = { //debuglog("merging " + result + " and " + that.result) result = result combine that.result @@ -1030,71 +1030,71 @@ extends IterableOnce[T] } } - protected[this] class Forall(pred: T => Boolean, protected[this] val pit: IterableSplitter[T]) + protected[this] class Forall(pred: T => Boolean, protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[Boolean, Forall] { @volatile var result: Boolean = true def leaf(prev: Option[Boolean]) = { if (!pit.isAborted) result = pit.forall(pred); if (result == false) pit.abort() } - protected[this] def newSubtask(p: IterableSplitter[T]) = new Forall(pred, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Forall(pred, p) override def merge(that: Forall) = result = result && that.result } - protected[this] class Exists(pred: T => Boolean, protected[this] val pit: IterableSplitter[T]) + protected[this] class Exists(pred: T => Boolean, protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[Boolean, Exists] { @volatile var result: Boolean = false def leaf(prev: Option[Boolean]) = { if (!pit.isAborted) result = pit.exists(pred); if (result == true) pit.abort() } - protected[this] def newSubtask(p: IterableSplitter[T]) = new Exists(pred, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Exists(pred, p) override def merge(that: Exists) = result = result || that.result } - protected[this] class Find[U >: T](pred: T => Boolean, protected[this] val pit: IterableSplitter[T]) + protected[this] class Find[U >: T](pred: T => Boolean, protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[Option[U], Find[U]] { @volatile var result: Option[U] = None def leaf(prev: Option[Option[U]]) = { if (!pit.isAborted) result = pit.find(pred); if (result != None) pit.abort() } - protected[this] def newSubtask(p: IterableSplitter[T]) = new Find(pred, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Find(pred, p) override def merge(that: Find[U]) = if (this.result == None) result = that.result } - protected[this] class Filter[U >: T, This >: Repr](pred: T => Boolean, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T]) + protected[this] class Filter[U >: T, This >: Repr](pred: T => Boolean, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[U, This], Filter[U, This]] { @volatile var result: Combiner[U, This] = null def leaf(prev: Option[Combiner[U, This]]) = { result = pit.filter2combiner(pred, reuse(prev, cbf())) } - protected[this] def newSubtask(p: IterableSplitter[T]) = new Filter(pred, cbf, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Filter(pred, cbf, p) override def merge(that: Filter[U, This]) = result = result combine that.result } - protected[this] class FilterNot[U >: T, This >: Repr](pred: T => Boolean, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T]) + protected[this] class FilterNot[U >: T, This >: Repr](pred: T => Boolean, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[U, This], FilterNot[U, This]] { @volatile var result: Combiner[U, This] = null def leaf(prev: Option[Combiner[U, This]]) = { result = pit.filterNot2combiner(pred, reuse(prev, cbf())) } - protected[this] def newSubtask(p: IterableSplitter[T]) = new FilterNot(pred, cbf, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new FilterNot(pred, cbf, p) override def merge(that: FilterNot[U, This]) = result = result combine that.result } - protected class Copy[U >: T, That](cfactory: CombinerFactory[U, That], protected[this] val pit: IterableSplitter[T]) + protected class Copy[U >: T, That](cfactory: CombinerFactory[U, That], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[U, That], Copy[U, That]] { @volatile var result: Combiner[U, That] = null def leaf(prev: Option[Combiner[U, That]]) = result = pit.copy2builder[U, That, Combiner[U, That]](reuse(prev, cfactory())) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Copy[U, That](cfactory, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Copy[U, That](cfactory, p) override def merge(that: Copy[U, That]) = result = result combine that.result } protected[this] class Partition[U >: T, This >: Repr] - (pred: T => Boolean, cbfTrue: CombinerFactory[U, This], cbfFalse: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T]) + (pred: T => Boolean, cbfTrue: CombinerFactory[U, This], cbfFalse: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[(Combiner[U, This], Combiner[U, This]), Partition[U, This]] { @volatile var result: (Combiner[U, This], Combiner[U, This]) = null def leaf(prev: Option[(Combiner[U, This], Combiner[U, This])]) = result = pit.partition2combiners(pred, reuse(prev.map(_._1), cbfTrue()), reuse(prev.map(_._2), cbfFalse())) - protected[this] def newSubtask(p: IterableSplitter[T]) = new Partition(pred, cbfTrue, cbfFalse, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new Partition(pred, cbfTrue, cbfFalse, p) override def merge(that: Partition[U, This]) = result = (result._1 combine that.result._1, result._2 combine that.result._2) } protected[this] class GroupBy[K, U >: T]( f: U => K, mcf: () => HashMapCombiner[K, U], - protected[this] val pit: IterableSplitter[T] + protected[this] val pit: IterableSplitter[T @uncheckedVariance] ) extends Transformer[HashMapCombiner[K, U], GroupBy[K, U]] { @volatile var result: Result = null final def leaf(prev: Option[Result]) = { @@ -1106,7 +1106,7 @@ extends IterableOnce[T] } result = cb } - protected[this] def newSubtask(p: IterableSplitter[T]) = new GroupBy(f, mcf, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new GroupBy(f, mcf, p) override def merge(that: GroupBy[K, U]) = { // note: this works because we know that a HashMapCombiner doesn't merge same keys until evaluation // --> we know we're not dropping any mappings @@ -1115,13 +1115,13 @@ extends IterableOnce[T] } protected[this] class Take[U >: T, This >: Repr] - (n: Int, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T]) + (n: Int, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[U, This], Take[U, This]] { @volatile var result: Combiner[U, This] = null def leaf(prev: Option[Combiner[U, This]]) = { result = pit.take2combiner(n, reuse(prev, cbf())) } - protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling val sizes = pits.scanLeft(0)(_ + _.remaining) @@ -1135,11 +1135,11 @@ extends IterableOnce[T] } protected[this] class Drop[U >: T, This >: Repr] - (n: Int, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T]) + (n: Int, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[U, This], Drop[U, This]] { @volatile var result: Combiner[U, This] = null def leaf(prev: Option[Combiner[U, This]]) = result = pit.drop2combiner(n, reuse(prev, cbf())) - protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling val sizes = pits.scanLeft(0)(_ + _.remaining) @@ -1153,11 +1153,11 @@ extends IterableOnce[T] } protected[this] class Slice[U >: T, This >: Repr] - (from: Int, until: Int, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T]) + (from: Int, until: Int, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[U, This], Slice[U, This]] { @volatile var result: Combiner[U, This] = null def leaf(prev: Option[Combiner[U, This]]) = result = pit.slice2combiner(from, until, reuse(prev, cbf())) - protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling val sizes = pits.scanLeft(0)(_ + _.remaining) @@ -1172,11 +1172,11 @@ extends IterableOnce[T] } protected[this] class SplitAt[U >: T, This >: Repr] - (at: Int, cbfBefore: CombinerFactory[U, This], cbfAfter: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T]) + (at: Int, cbfBefore: CombinerFactory[U, This], cbfAfter: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[(Combiner[U, This], Combiner[U, This]), SplitAt[U, This]] { @volatile var result: (Combiner[U, This], Combiner[U, This]) = null def leaf(prev: Option[(Combiner[U, This], Combiner[U, This])]) = result = pit.splitAt2combiners(at, reuse(prev.map(_._1), cbfBefore()), reuse(prev.map(_._2), cbfAfter())) - protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling val sizes = pits.scanLeft(0)(_ + _.remaining) @@ -1187,14 +1187,14 @@ extends IterableOnce[T] } protected[this] class TakeWhile[U >: T, This >: Repr] - (pos: Int, pred: T => Boolean, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T]) + (pos: Int, pred: T => Boolean, cbf: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[(Combiner[U, This], Boolean), TakeWhile[U, This]] { @volatile var result: (Combiner[U, This], Boolean) = null def leaf(prev: Option[(Combiner[U, This], Boolean)]) = if (pos < pit.indexFlag) { result = pit.takeWhile2combiner(pred, reuse(prev.map(_._1), cbf())) if (!result._2) pit.setIndexFlagIfLesser(pos) } else result = (reuse(prev.map(_._1), cbf()), false) - protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(0)(_ + _.remaining)) yield new TakeWhile(pos + untilp, pred, cbf, p) @@ -1206,7 +1206,7 @@ extends IterableOnce[T] } protected[this] class Span[U >: T, This >: Repr] - (pos: Int, pred: T => Boolean, cbfBefore: CombinerFactory[U, This], cbfAfter: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T]) + (pos: Int, pred: T => Boolean, cbfBefore: CombinerFactory[U, This], cbfAfter: CombinerFactory[U, This], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[(Combiner[U, This], Combiner[U, This]), Span[U, This]] { @volatile var result: (Combiner[U, This], Combiner[U, This]) = null def leaf(prev: Option[(Combiner[U, This], Combiner[U, This])]) = if (pos < pit.indexFlag) { @@ -1219,7 +1219,7 @@ extends IterableOnce[T] } else { result = (reuse(prev.map(_._2), cbfBefore()), pit.copy2builder[U, This, Combiner[U, This]](reuse(prev.map(_._2), cbfAfter()))) } - protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(0)(_ + _.remaining)) yield new Span(pos + untilp, pred, cbfBefore, cbfAfter, p) @@ -1232,11 +1232,11 @@ extends IterableOnce[T] override def requiresStrictSplitters = true } - protected[this] class Zip[U >: T, S, That](pbf: CombinerFactory[(U, S), That], protected[this] val pit: IterableSplitter[T], val othpit: SeqSplitter[S]) + protected[this] class Zip[U >: T, S, That](pbf: CombinerFactory[(U, S), That], protected[this] val pit: IterableSplitter[T @uncheckedVariance], val othpit: SeqSplitter[S]) extends Transformer[Combiner[(U, S), That], Zip[U, S, That]] { @volatile var result: Result = null def leaf(prev: Option[Result]) = result = pit.zip2combiner[U, S, That](othpit, pbf()) - protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling val sizes = pits.map(_.remaining) @@ -1248,11 +1248,11 @@ extends IterableOnce[T] } protected[this] class ZipAll[U >: T, S, That] - (len: Int, thiselem: U, thatelem: S, pbf: CombinerFactory[(U, S), That], protected[this] val pit: IterableSplitter[T], val othpit: SeqSplitter[S]) + (len: Int, thiselem: U, thatelem: S, pbf: CombinerFactory[(U, S), That], protected[this] val pit: IterableSplitter[T @uncheckedVariance], val othpit: SeqSplitter[S]) extends Transformer[Combiner[(U, S), That], ZipAll[U, S, That]] { @volatile var result: Result = null def leaf(prev: Option[Result]) = result = pit.zipAll2combiner[U, S, That](othpit, thiselem, thatelem, pbf()) - protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = if (pit.remaining <= len) { val pits = pit.splitWithSignalling val sizes = pits.map(_.remaining) @@ -1270,11 +1270,11 @@ extends IterableOnce[T] override def requiresStrictSplitters = true } - protected[this] class CopyToArray[U >: T, This >: Repr](from: Int, len: Int, array: Array[U], protected[this] val pit: IterableSplitter[T]) + protected[this] class CopyToArray[U >: T, This >: Repr](from: Int, len: Int, array: Array[U], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Accessor[Unit, CopyToArray[U, This]] { @volatile var result: Unit = () def leaf(prev: Option[Unit]) = pit.copyToArray(array, from, len) - protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(0)(_ + _.remaining); if untilp < len) yield { @@ -1285,29 +1285,29 @@ extends IterableOnce[T] override def requiresStrictSplitters = true } - protected[this] class ToParCollection[U >: T, That](cbf: CombinerFactory[U, That], protected[this] val pit: IterableSplitter[T]) + protected[this] class ToParCollection[U >: T, That](cbf: CombinerFactory[U, That], protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[Combiner[U, That], ToParCollection[U, That]] { @volatile var result: Result = null def leaf(prev: Option[Combiner[U, That]]): Unit = { result = cbf() while (pit.hasNext) result += pit.next() } - protected[this] def newSubtask(p: IterableSplitter[T]) = new ToParCollection[U, That](cbf, p) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new ToParCollection[U, That](cbf, p) override def merge(that: ToParCollection[U, That]) = result = result combine that.result } - protected[this] class ToParMap[K, V, That](cbf: CombinerFactory[(K, V), That], protected[this] val pit: IterableSplitter[T])(implicit ev: T <:< (K, V)) + protected[this] class ToParMap[K, V, That](cbf: CombinerFactory[(K, V), That], protected[this] val pit: IterableSplitter[T @uncheckedVariance])(implicit ev: T <:< (K, V)) extends Transformer[Combiner[(K, V), That], ToParMap[K, V, That]] { @volatile var result: Result = null def leaf(prev: Option[Combiner[(K, V), That]]): Unit = { result = cbf() while (pit.hasNext) result += pit.next() } - protected[this] def newSubtask(p: IterableSplitter[T]) = new ToParMap[K, V, That](cbf, p)(ev) + protected[this] def newSubtask(p: IterableSplitter[T @uncheckedVariance]) = new ToParMap[K, V, That](cbf, p)(ev) override def merge(that: ToParMap[K, V, That]) = result = result combine that.result } - protected[this] class CreateScanTree[U >: T](from: Int, len: Int, z: U, op: (U, U) => U, protected[this] val pit: IterableSplitter[T]) + protected[this] class CreateScanTree[U >: T](from: Int, len: Int, z: U, op: (U, U) => U, protected[this] val pit: IterableSplitter[T @uncheckedVariance]) extends Transformer[ScanTree[U], CreateScanTree[U]] { @volatile var result: ScanTree[U] = null def leaf(prev: Option[ScanTree[U]]) = if (pit.remaining > 0) { @@ -1331,7 +1331,7 @@ extends IterableOnce[T] val half = howmany / 2 ScanNode(mergeTrees(trees, from, half), mergeTrees(trees, from + half, howmany - half)) } else trees(from) - protected[this] def newSubtask(pit: IterableSplitter[T]) = throw new UnsupportedOperationException + protected[this] def newSubtask(pit: IterableSplitter[T @uncheckedVariance]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(from)(_ + _.remaining)) yield { diff --git a/core/src/main/scala/scala/collection/parallel/ParSeqLike.scala b/core/src/main/scala/scala/collection/parallel/ParSeqLike.scala index f2edf418..2b91d54e 100644 --- a/core/src/main/scala/scala/collection/parallel/ParSeqLike.scala +++ b/core/src/main/scala/scala/collection/parallel/ParSeqLike.scala @@ -18,6 +18,7 @@ import scala.collection.generic.DefaultSignalling import scala.collection.generic.AtomicIndexFlag import scala.collection.generic.VolatileAbort import scala.collection.parallel.ParallelCollectionImplicits._ +import scala.annotation.unchecked.uncheckedVariance /** A template trait for sequences of type `ParSeq[T]`, representing * parallel sequences with element type `T`. @@ -67,7 +68,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] def canEqual(other: Any): Boolean = true - protected[this] type SuperParIterator = IterableSplitter[T] + protected[this] type SuperParIterator = IterableSplitter[T @uncheckedVariance] /** A more refined version of the iterator found in the `ParallelIterable` trait, * this iterator can be split into arbitrary subsets of iterators. @@ -474,7 +475,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] protected trait ParSeqLikeTransformer[R, Tp] extends ParSeqLikeAccessor[R, Tp] with Transformer[R, Tp] - protected[this] class SegmentLength(pred: T => Boolean, from: Int, protected[this] val pit: SeqSplitter[T]) + protected[this] class SegmentLength(pred: T => Boolean, from: Int, protected[this] val pit: SeqSplitter[T @uncheckedVariance]) extends ParSeqLikeAccessor[(Int, Boolean), SegmentLength] { @volatile var result: (Int, Boolean) = null def leaf(prev: Option[(Int, Boolean)]) = if (from < pit.indexFlag) { @@ -492,7 +493,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] override def requiresStrictSplitters = true } - protected[this] class IndexWhere(pred: T => Boolean, from: Int, protected[this] val pit: SeqSplitter[T]) + protected[this] class IndexWhere(pred: T => Boolean, from: Int, protected[this] val pit: SeqSplitter[T @uncheckedVariance]) extends ParSeqLikeAccessor[Int, IndexWhere] { @volatile var result: Int = -1 def leaf(prev: Option[Int]) = if (from < pit.indexFlag) { @@ -513,7 +514,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] override def requiresStrictSplitters = true } - protected[this] class LastIndexWhere(pred: T => Boolean, pos: Int, protected[this] val pit: SeqSplitter[T]) + protected[this] class LastIndexWhere(pred: T => Boolean, pos: Int, protected[this] val pit: SeqSplitter[T @uncheckedVariance]) extends ParSeqLikeAccessor[Int, LastIndexWhere] { @volatile var result: Int = -1 def leaf(prev: Option[Int]) = if (pos > pit.indexFlag) { @@ -534,7 +535,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] override def requiresStrictSplitters = true } - protected[this] class Reverse[U >: T, This >: Repr](cbf: () => Combiner[U, This], protected[this] val pit: SeqSplitter[T]) + protected[this] class Reverse[U >: T, This >: Repr](cbf: () => Combiner[U, This], protected[this] val pit: SeqSplitter[T @uncheckedVariance]) extends ParSeqLikeTransformer[Combiner[U, This], Reverse[U, This]] { @volatile var result: Combiner[U, This] = null def leaf(prev: Option[Combiner[U, This]]) = result = pit.reverse2combiner(reuse(prev, cbf())) @@ -542,7 +543,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] override def merge(that: Reverse[U, This]) = result = that.result combine result } - protected[this] class ReverseMap[S, That](f: T => S, pbf: () => Combiner[S, That], protected[this] val pit: SeqSplitter[T]) + protected[this] class ReverseMap[S, That](f: T => S, pbf: () => Combiner[S, That], protected[this] val pit: SeqSplitter[T @uncheckedVariance]) extends ParSeqLikeTransformer[Combiner[S, That], ReverseMap[S, That]] { @volatile var result: Combiner[S, That] = null def leaf(prev: Option[Combiner[S, That]]) = result = pit.reverseMap2combiner(f, pbf()) @@ -550,7 +551,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] override def merge(that: ReverseMap[S, That]) = result = that.result combine result } - protected[this] class SameElements[U >: T](protected[this] val pit: SeqSplitter[T], val otherpit: SeqSplitter[U]) + protected[this] class SameElements[U >: T](protected[this] val pit: SeqSplitter[T @uncheckedVariance], val otherpit: SeqSplitter[U @uncheckedVariance]) extends ParSeqLikeAccessor[Boolean, SameElements[U]] { @volatile var result: Boolean = true def leaf(prev: Option[Boolean]) = if (!pit.isAborted) { @@ -567,7 +568,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] override def requiresStrictSplitters = true } - protected[this] class Updated[U >: T, That](pos: Int, elem: U, pbf: CombinerFactory[U, That], protected[this] val pit: SeqSplitter[T]) + protected[this] class Updated[U >: T, That](pos: Int, elem: U, pbf: CombinerFactory[U, That], protected[this] val pit: SeqSplitter[T @uncheckedVariance]) extends ParSeqLikeTransformer[Combiner[U, That], Updated[U, That]] { @volatile var result: Combiner[U, That] = null def leaf(prev: Option[Combiner[U, That]]) = result = pit.updated2combiner(pos, elem, pbf()) @@ -580,7 +581,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] override def requiresStrictSplitters = true } - protected[this] class ParSeqLikeZip[U >: T, S, That](len: Int, cf: CombinerFactory[(U, S), That], protected[this] val pit: SeqSplitter[T], val otherpit: SeqSplitter[S]) + protected[this] class ParSeqLikeZip[U >: T, S, That](len: Int, cf: CombinerFactory[(U, S), That], protected[this] val pit: SeqSplitter[T @uncheckedVariance], val otherpit: SeqSplitter[S]) extends ParSeqLikeTransformer[Combiner[(U, S), That], ParSeqLikeZip[U, S, That]] { @volatile var result: Result = null def leaf(prev: Option[Result]) = result = pit.zip2combiner[U, S, That](otherpit, cf()) @@ -598,7 +599,7 @@ extends ParIterableLike[T, CC, Repr, Sequential] override def merge(that: ParSeqLikeZip[U, S, That]) = result = result combine that.result } - protected[this] class Corresponds[S](corr: (T, S) => Boolean, protected[this] val pit: SeqSplitter[T], val otherpit: SeqSplitter[S]) + protected[this] class Corresponds[S](corr: (T, S) => Boolean, protected[this] val pit: SeqSplitter[T @uncheckedVariance], val otherpit: SeqSplitter[S]) extends ParSeqLikeAccessor[Boolean, Corresponds[S]] { @volatile var result: Boolean = true def leaf(prev: Option[Boolean]) = if (!pit.isAborted) { diff --git a/core/src/main/scala/scala/collection/parallel/RemainsIterator.scala b/core/src/main/scala/scala/collection/parallel/RemainsIterator.scala index 34d269d8..6e81e8e2 100644 --- a/core/src/main/scala/scala/collection/parallel/RemainsIterator.scala +++ b/core/src/main/scala/scala/collection/parallel/RemainsIterator.scala @@ -18,6 +18,7 @@ import scala.collection.generic.DelegatedSignalling import scala.collection.generic.IdleSignalling import scala.collection.mutable.Builder import scala.collection.parallel.immutable.repetition +import scala.annotation.unchecked.uncheckedVariance private[collection] trait RemainsIterator[+T] extends Iterator[T] { /** The number of elements this iterator has yet to iterate. @@ -425,7 +426,7 @@ self => def next() = { remaining -= 1; self.next() } def dup: IterableSplitter[T] = self.dup.take(taken) def split: Seq[IterableSplitter[T]] = takeSeq(self.split) { (p, n) => p.take(n) } - protected[this] def takeSeq[PI <: IterableSplitter[T]](sq: Seq[PI])(taker: (PI, Int) => PI) = { + protected[this] def takeSeq[PI <: IterableSplitter[T @uncheckedVariance]](sq: Seq[PI])(taker: (PI, Int) => PI) = { val sizes = sq.scanLeft(0)(_ + _.remaining) val shortened = for ((it, (from, until)) <- sq zip (sizes.init zip sizes.tail)) yield if (until < remaining) it else taker(it, remaining - from) diff --git a/core/src/main/scala/scala/collection/parallel/package.scala b/core/src/main/scala/scala/collection/parallel/package.scala index 17b0038e..8c61fef5 100644 --- a/core/src/main/scala/scala/collection/parallel/package.scala +++ b/core/src/main/scala/scala/collection/parallel/package.scala @@ -15,7 +15,6 @@ package collection import scala.collection.parallel.mutable.ParArray import scala.collection.mutable.UnrolledBuffer -import scala.annotation.unchecked.uncheckedVariance import scala.language.implicitConversions /** Package object for parallel collections. @@ -168,7 +167,7 @@ package parallel { (private val bucketnumber: Int) extends Combiner[Elem, To] { //self: EnvironmentPassingCombiner[Elem, To] => - protected var buckets: Array[UnrolledBuffer[Buck]] @uncheckedVariance = new Array[UnrolledBuffer[Buck]](bucketnumber) + protected var buckets: Array[UnrolledBuffer[Buck]] = new Array[UnrolledBuffer[Buck]](bucketnumber) protected var sz: Int = 0 def size = sz diff --git a/junit/src/test/scala/scala/SerializationStabilityTest.scala b/junit/src/test/scala-2/scala/SerializationStabilityTest.scala similarity index 76% rename from junit/src/test/scala/scala/SerializationStabilityTest.scala rename to junit/src/test/scala-2/scala/SerializationStabilityTest.scala index 6ff32aab..484d8f65 100644 --- a/junit/src/test/scala/scala/SerializationStabilityTest.scala +++ b/junit/src/test/scala-2/scala/SerializationStabilityTest.scala @@ -18,72 +18,12 @@ import org.junit.Test // This test is self-modifying when run as follows: // -// junit/testOnly scala.SerializationStabilityTest -- -Doverwrite.source=src/test/scala/scala/SerializationStabilityTest.scala +// junit/testOnly scala.SerializationStabilityTest -- -Doverwrite.source=src/test/scala-2/scala/SerializationStabilityTest.scala // // Use this to re-establish a baseline for serialization compatibility. // based on run/t8549.scala partest -object SerializationStability extends App { - - val overwrite: Option[Path] = - sys.props.get("overwrite.source") - .map(s => Paths.get(s).toAbsolutePath) - - def serialize(o: AnyRef): String = { - val bos = new java.io.ByteArrayOutputStream() - val out = new java.io.ObjectOutputStream(bos) - out.writeObject(o) - out.flush() - printBase64Binary(bos.toByteArray()) - } - - def amend(path: Path)(f: String => String): Unit = { - val old = new String(java.nio.file.Files.readAllBytes(path)) - Files.write(path, f(old).getBytes) - } - - def quote(s: String) = List("\"", s, "\"").mkString - - def patch(path: Path, line: Int, prevResult: String, result: String): Unit = { - amend(path) { - content => - content.linesIterator.toList.zipWithIndex.map { - case (content, i) if i == line - 1 => - val newContent = content.replace(quote(prevResult), quote(result)) - if (newContent != content) - println(s"- $content\n+ $newContent\n") - newContent - case (content, _) => content - }.mkString("\n") - } - } - - def updateComment(path: Path): Unit = { - val timestamp = { - import java.text.SimpleDateFormat - val sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss") - sdf.format(new java.util.Date) - } - val newComment = s" // Generated on $timestamp with Scala ${scala.util.Properties.versionString})" - amend(path) { - content => - content.linesIterator.toList.map { - f => f.replaceAll("""^ +// Generated on.*""", newComment) - }.mkString("\n") - } - } - - def deserialize(string: String): AnyRef = { - val bis = new java.io.ByteArrayInputStream(parseBase64Binary(string)) - val in = new java.io.ObjectInputStream(bis) - in.readObject() - } - - def checkRoundTrip[T <: AnyRef](instance: T)(f: T => AnyRef): Unit = { - val result = serialize(instance) - val reconstituted = deserialize(result).asInstanceOf[T] - assert(f(instance) == f(reconstituted), (f(instance), f(reconstituted))) - } +object SerializationStability extends App with SerializationStabilityBase { def check[T <: AnyRef](instance: => T)(prevResult: String, f: T => AnyRef = (x: T) => x): Unit = { val result = serialize(instance) @@ -98,7 +38,7 @@ object SerializationStability extends App { } } - // Generated on 20190328-12:57:02 with Scala version 2.13.0-pre-59975bb) + // Generated on 20201015-13:14:45 with Scala version 2.13.3) overwrite.foreach(updateComment) // check(new collection.concurrent.TrieMap[Any, Any]())( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLmNvbmN1cnJlbnQuVHJpZU1hcKckxpgOIYHPAwAETAALZXF1YWxpdHlvYmp0ABJMc2NhbGEvbWF0aC9FcXVpdjtMAApoYXNoaW5nb2JqdAAcTHNjYWxhL3V0aWwvaGFzaGluZy9IYXNoaW5nO0wABHJvb3R0ABJMamF2YS9sYW5nL09iamVjdDtMAAtyb290dXBkYXRlcnQAOUxqYXZhL3V0aWwvY29uY3VycmVudC9hdG9taWMvQXRvbWljUmVmZXJlbmNlRmllbGRVcGRhdGVyO3hwc3IAMnNjYWxhLmNvbGxlY3Rpb24uY29uY3VycmVudC5UcmllTWFwJE1hbmdsZWRIYXNoaW5nhTBoJQ/mgb0CAAB4cHNyABhzY2FsYS5tYXRoLkVxdWl2JCRhbm9uJDLBbyx4dy/qGwIAAHhwc3IANHNjYWxhLmNvbGxlY3Rpb24uY29uY3VycmVudC5UcmllTWFwU2VyaWFsaXphdGlvbkVuZCSbjdgbbGCt2gIAAHhweA==") diff --git a/junit/src/test/scala-3/scala/SerializationStabilityTest.scala b/junit/src/test/scala-3/scala/SerializationStabilityTest.scala new file mode 100644 index 00000000..f084795e --- /dev/null +++ b/junit/src/test/scala-3/scala/SerializationStabilityTest.scala @@ -0,0 +1,61 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package scala + +import javax.xml.bind.DatatypeConverter._ +import java.nio.file.{ Path, Paths, Files } +import org.junit.Test + +// This test is self-modifying when run as follows: +// +// junit/testOnly scala.SerializationStabilityTest -- -Doverwrite.source=src/test/scala-3/scala/SerializationStabilityTest.scala +// +// Use this to re-establish a baseline for serialization compatibility. + +// based on run/t8549.scala partest +object SerializationStability extends App with SerializationStabilityBase { + + def check[T <: AnyRef](instance: => T)(prevResult: String, f: T => AnyRef = (x: T) => x): Unit = { + val result = serialize(instance) + overwrite match { + case Some(f) => + val lineNumberOfLiteralString = Thread.currentThread.getStackTrace.apply(2).getLineNumber + patch(f, lineNumberOfLiteralString, prevResult, result) + case None => + checkRoundTrip(instance)(f) + assert(f(deserialize(prevResult).asInstanceOf[T]) == f(instance), s"$instance != f(deserialize(prevResult))") + assert(prevResult == result, s"instance = $instance : ${instance.getClass}\n serialization unstable: ${prevResult}\n found: ${result}") + } + } + + // Generated on 20201015-13:11:40 with Scala version 2.13.3) + overwrite.foreach(updateComment) + + // check(new collection.concurrent.TrieMap[Any, Any]())( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLmNvbmN1cnJlbnQuVHJpZU1hcKckxpgOIYHPAwAETAALZXF1YWxpdHlvYmp0ABJMc2NhbGEvbWF0aC9FcXVpdjtMAApoYXNoaW5nb2JqdAAcTHNjYWxhL3V0aWwvaGFzaGluZy9IYXNoaW5nO0wABHJvb3R0ABJMamF2YS9sYW5nL09iamVjdDtMAAtyb290dXBkYXRlcnQAOUxqYXZhL3V0aWwvY29uY3VycmVudC9hdG9taWMvQXRvbWljUmVmZXJlbmNlRmllbGRVcGRhdGVyO3hwc3IAMnNjYWxhLmNvbGxlY3Rpb24uY29uY3VycmVudC5UcmllTWFwJE1hbmdsZWRIYXNoaW5nhTBoJQ/mgb0CAAB4cHNyABhzY2FsYS5tYXRoLkVxdWl2JCRhbm9uJDLBbyx4dy/qGwIAAHhwc3IANHNjYWxhLmNvbGxlY3Rpb24uY29uY3VycmVudC5UcmllTWFwU2VyaWFsaXphdGlvbkVuZCSbjdgbbGCt2gIAAHhweA==") + // not sure why this one needs stable serialization. + + import collection.parallel + check(parallel.immutable.ParHashMap(1 -> 2))( "rO0ABXNyAC5zY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLmltbXV0YWJsZS5QYXJIYXNoTWFwAAAAAAAAAAMCAARKAAkwYml0bWFwJDFMAA1TY2FuTGVhZiRsenkxdAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5MZWFmJDtMAA1TY2FuTm9kZSRsenkxdAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5Ob2RlJDtMAAR0cmlldAAnTHNjYWxhL2NvbGxlY3Rpb24vaW1tdXRhYmxlL09sZEhhc2hNYXA7eHAAAAAAAAAAAHBwc3IAMXNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLk9sZEhhc2hNYXAkT2xkSGFzaE1hcDEu846aGc5HjAIABEkABGhhc2hMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAAJrdnQADkxzY2FsYS9UdXBsZTI7TAAFdmFsdWVxAH4ABnhyACVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5PbGRIYXNoTWFwGzyZ5OayDwECAAB4cP+DzudzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNyAAxzY2FsYS5UdXBsZTIB+93NIuc0egIAAkwAAl8xcQB+AAZMAAJfMnEAfgAGeHBxAH4ADHNxAH4ACgAAAAJxAH4ADw==") + check(parallel.immutable.ParHashSet(1, 2, 3))( "rO0ABXNyAC5zY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLmltbXV0YWJsZS5QYXJIYXNoU2V0AAAAAAAAAAECAARKAAkwYml0bWFwJDFMAA1TY2FuTGVhZiRsenkxdAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5MZWFmJDtMAA1TY2FuTm9kZSRsenkxdAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5Ob2RlJDtMAAR0cmlldAAnTHNjYWxhL2NvbGxlY3Rpb24vaW1tdXRhYmxlL09sZEhhc2hTZXQ7eHAAAAAAAAAAAHBwc3IAMXNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLk9sZEhhc2hTZXQkSGFzaFRyaWVTZXTiTcUmrrCZogIAA0kABmJpdG1hcEkABXNpemUwWwAFZWxlbXN0AChbTHNjYWxhL2NvbGxlY3Rpb24vaW1tdXRhYmxlL09sZEhhc2hTZXQ7eHIAJXNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLk9sZEhhc2hTZXRY25CS1TvmFgIAAHhwABBAgAAAAAN1cgAoW0xzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5PbGRIYXNoU2V0OwgA+jL9wEgOAgAAeHAAAAADc3IAMXNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLk9sZEhhc2hTZXQkT2xkSGFzaFNldDEdQIAs6u3ODgIAAkkABGhhc2hMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDt4cgA0c2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuT2xkSGFzaFNldCRMZWFmT2xkSGFzaFNldF2Et+1jWqbdAgAAeHEAfgAH/4PO53NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3EAfgAL/4OsznNxAH4ADwAAAAJzcQB+AAv/g4rUc3EAfgAPAAAAAw==") + // TODO SI-8576 Uninitialized field under -Xcheckinit + // check(new parallel.immutable.ParRange(new Range(0, 1, 2)))( "rO0ABXNyACxzY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLmltbXV0YWJsZS5QYXJSYW5nZQAAAAAAAAABAgAETAAXUGFyUmFuZ2VJdGVyYXRvciRtb2R1bGV0AEBMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9pbW11dGFibGUvUGFyUmFuZ2UkUGFyUmFuZ2VJdGVyYXRvciQ7TAAPU2NhbkxlYWYkbW9kdWxldAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5MZWFmJDtMAA9TY2FuTm9kZSRtb2R1bGV0ADVMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9QYXJJdGVyYWJsZUxpa2UkU2Nhbk5vZGUkO0wABXJhbmdldAAiTHNjYWxhL2NvbGxlY3Rpb24vaW1tdXRhYmxlL1JhbmdlO3hwcHBwc3IAIHNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLlJhbmdlabujVKsVMg0CAAdJAANlbmRaAAdpc0VtcHR5SQALbGFzdEVsZW1lbnRJABBudW1SYW5nZUVsZW1lbnRzSQAFc3RhcnRJAARzdGVwSQAPdGVybWluYWxFbGVtZW50eHAAAAABAAAAAAAAAAABAAAAAAAAAAIAAAAC") + // TODO SI-8576 unstable under -Xcheckinit + // check(parallel.mutable.ParArray(1, 2, 3))( "rO0ABXNyACpzY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLm11dGFibGUuUGFyQXJyYXkAAAAAAAAAAQMABEwAF1BhckFycmF5SXRlcmF0b3IkbW9kdWxldAA+THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvbXV0YWJsZS9QYXJBcnJheSRQYXJBcnJheUl0ZXJhdG9yJDtMAA9TY2FuTGVhZiRtb2R1bGV0ADVMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9QYXJJdGVyYWJsZUxpa2UkU2NhbkxlYWYkO0wAD1NjYW5Ob2RlJG1vZHVsZXQANUxzY2FsYS9jb2xsZWN0aW9uL3BhcmFsbGVsL1Bhckl0ZXJhYmxlTGlrZSRTY2FuTm9kZSQ7TAAIYXJyYXlzZXF0ACNMc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL0FycmF5U2VxO3hwcHBwc3IAMXNjYWxhLmNvbGxlY3Rpb24ucGFyYWxsZWwubXV0YWJsZS5FeHBvc2VkQXJyYXlTZXGx2OTefAodSQIAAkkABmxlbmd0aFsABWFycmF5dAATW0xqYXZhL2xhbmcvT2JqZWN0O3hyACFzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuQXJyYXlTZXEVPD3SKEkOcwIAAkkABmxlbmd0aFsABWFycmF5cQB+AAd4cAAAAAN1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAADcHBwAAAAA3VxAH4ACgAAABBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ADQAAAAJzcQB+AA0AAAADcHBwcHBwcHBwcHBwcHg=") + check(parallel.mutable.ParHashMap(1 -> 2))( "rO0ABXNyACxzY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLm11dGFibGUuUGFySGFzaE1hcAAAAAAAAAADAwAJSgAJMGJpdG1hcCQxSQALX2xvYWRGYWN0b3JJAAlzZWVkdmFsdWVJAAl0YWJsZVNpemVJAAl0aHJlc2hvbGRMAA1TY2FuTGVhZiRsenkxdAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5MZWFmJDtMAA1TY2FuTm9kZSRsenkxdAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5Ob2RlJDtbAAdzaXplbWFwdAACW0lbAAV0YWJsZXQAJVtMc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL0hhc2hFbnRyeTt4cHcNAAAC7gAAAAEAAAAEAXNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3EAfgAGAAAAAng=") + check(parallel.mutable.ParHashSet(1, 2, 3))( "rO0ABXNyACxzY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLm11dGFibGUuUGFySGFzaFNldAAAAAAAAAABAwAJSgAJMGJpdG1hcCQxSQALX2xvYWRGYWN0b3JJAAlzZWVkdmFsdWVJAAl0YWJsZVNpemVJAAl0aHJlc2hvbGRMAA1TY2FuTGVhZiRsenkxdAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5MZWFmJDtMAA1TY2FuTm9kZSRsenkxdAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5Ob2RlJDtbAAdzaXplbWFwdAACW0lbAAV0YWJsZXQAE1tMamF2YS9sYW5nL09iamVjdDt4cHcNAAABwgAAAAMAAAAbAXNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3EAfgAGAAAAAnNxAH4ABgAAAAN4") +} + +class SerializationStabilityTest { + @Test + def testAll: Unit = SerializationStability.main(new Array[String](0)) +} diff --git a/junit/src/test/scala/SerializationStabilityBase.scala b/junit/src/test/scala/SerializationStabilityBase.scala new file mode 100644 index 00000000..503031c8 --- /dev/null +++ b/junit/src/test/scala/SerializationStabilityBase.scala @@ -0,0 +1,81 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package scala + +import javax.xml.bind.DatatypeConverter._ +import java.nio.file.{ Path, Paths, Files } +import org.junit.Test + +trait SerializationStabilityBase { + + val overwrite: Option[Path] = + sys.props.get("overwrite.source") + .map(s => Paths.get(s).toAbsolutePath) + + def serialize(o: AnyRef): String = { + val bos = new java.io.ByteArrayOutputStream() + val out = new java.io.ObjectOutputStream(bos) + out.writeObject(o) + out.flush() + printBase64Binary(bos.toByteArray()) + } + + def amend(path: Path)(f: String => String): Unit = { + val old = new String(java.nio.file.Files.readAllBytes(path)) + Files.write(path, f(old).getBytes) + } + + def quote(s: String) = List("\"", s, "\"").mkString + + def patch(path: Path, line: Int, prevResult: String, result: String): Unit = { + amend(path) { + content => + content.linesIterator.toList.zipWithIndex.map { + case (content, i) if i == line - 1 => + val newContent = content.replace(quote(prevResult), quote(result)) + if (newContent != content) + println(s"- $content\n+ $newContent\n") + newContent + case (content, _) => content + }.mkString("\n") + } + } + + def updateComment(path: Path): Unit = { + val timestamp = { + import java.text.SimpleDateFormat + val sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss") + sdf.format(new java.util.Date) + } + val newComment = s" // Generated on $timestamp with Scala ${scala.util.Properties.versionString})" + amend(path) { + content => + content.linesIterator.toList.map { + f => f.replaceAll("""^ +// Generated on.*""", newComment) + }.mkString("\n") + } + } + + def deserialize(string: String): AnyRef = { + val bis = new java.io.ByteArrayInputStream(parseBase64Binary(string)) + val in = new java.io.ObjectInputStream(bis) + in.readObject() + } + + def checkRoundTrip[T <: AnyRef](instance: T)(f: T => AnyRef): Unit = { + val result = serialize(instance) + val reconstituted = deserialize(result).asInstanceOf[T] + assert(f(instance) == f(reconstituted), (f(instance), f(reconstituted))) + } + +} diff --git a/project/plugins.sbt b/project/plugins.sbt index 81fac909..669c840e 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1 +1,3 @@ addSbtPlugin("org.scala-lang.modules" % "sbt-scala-module" % "2.2.3") +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.4.2") + diff --git a/testmacros/src/main/scala/testutil/ShouldNotTypecheck.scala b/testmacros/src/main/scala-2/testutil/ShouldNotTypecheck.scala similarity index 100% rename from testmacros/src/main/scala/testutil/ShouldNotTypecheck.scala rename to testmacros/src/main/scala-2/testutil/ShouldNotTypecheck.scala diff --git a/testmacros/src/main/scala-3/testutil/ShouldNotTypecheck.scala b/testmacros/src/main/scala-3/testutil/ShouldNotTypecheck.scala new file mode 100644 index 00000000..ec1963d8 --- /dev/null +++ b/testmacros/src/main/scala-3/testutil/ShouldNotTypecheck.scala @@ -0,0 +1,23 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package testutil + +import scala.compiletime.testing._ + +/** + * Ensures that a code snippet does not typecheck. + */ +object ShouldNotTypecheck { + inline def apply(code: String): Unit = assert(!typeChecks(code)) + inline def apply(code: String, expected: String): Unit = apply(code) +}