From b5bfbab2eb699d064850de289c9928a1a221c903 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 6 Nov 2023 17:54:30 +0100 Subject: [PATCH] Change stdlib collections to be compiled under capture checking --- tests/pos-special/stdlib/Test1.scala | 34 ++ tests/pos-special/stdlib/Test2.scala | 232 +++++++ .../stdlib/collection/ArrayOps.scala | 113 ++-- .../stdlib/collection/BitSet.scala | 6 +- .../stdlib/collection/BufferedIterator.scala | 2 +- .../stdlib/collection/BuildFrom.scala | 36 +- .../stdlib/collection/DefaultMap.scala | 2 +- .../stdlib/collection/Factory.scala | 106 ++-- .../stdlib/collection/Hashing.scala | 1 + .../stdlib/collection/IndexedSeq.scala | 9 +- .../stdlib/collection/IndexedSeqView.scala | 85 +-- .../stdlib/collection/Iterable.scala | 157 ++--- .../stdlib/collection/IterableOnce.scala | 145 ++--- .../stdlib/collection/Iterator.scala | 148 ++--- .../stdlib/collection/JavaConverters.scala | 1 + .../stdlib/collection/LazyZipOps.scala | 21 +- .../stdlib/collection/LinearSeq.scala | 9 +- tests/pos-special/stdlib/collection/Map.scala | 36 +- .../stdlib/collection/MapView.scala | 69 ++- .../stdlib/collection/Searching.scala | 1 + tests/pos-special/stdlib/collection/Seq.scala | 52 +- .../stdlib/collection/SeqMap.scala | 1 + .../stdlib/collection/SeqView.scala | 105 ++-- tests/pos-special/stdlib/collection/Set.scala | 10 +- .../stdlib/collection/SortedMap.scala | 12 +- .../stdlib/collection/SortedOps.scala | 1 + .../stdlib/collection/SortedSet.scala | 5 +- .../stdlib/collection/Stepper.scala | 40 +- .../stdlib/collection/StepperShape.scala | 3 +- .../StrictOptimizedIterableOps.scala | 24 +- .../collection/StrictOptimizedMapOps.scala | 8 +- .../collection/StrictOptimizedSeqOps.scala | 14 +- .../collection/StrictOptimizedSetOps.scala | 1 + .../StrictOptimizedSortedMapOps.scala | 3 +- .../stdlib/collection/StringOps.scala | 37 +- .../stdlib/collection/StringParsers.scala | 17 +- .../pos-special/stdlib/collection/View.scala | 140 +++-- .../stdlib/collection/WithFilter.scala | 8 +- .../stdlib/collection/concurrent/Map.scala | 1 + .../collection/concurrent/TrieMap.scala | 39 +- .../collection/convert/AsJavaConverters.scala | 1 + .../collection/convert/AsJavaExtensions.scala | 1 + .../convert/AsScalaConverters.scala | 1 + .../convert/AsScalaExtensions.scala | 1 + .../convert/ImplicitConversions.scala | 1 + .../convert/JavaCollectionWrappers.scala | 12 +- .../collection/convert/StreamExtensions.scala | 1 + .../convert/impl/ArrayStepper.scala | 1 + .../convert/impl/BinaryTreeStepper.scala | 3 +- .../convert/impl/BitSetStepper.scala | 9 +- .../convert/impl/ChampStepper.scala | 1 + .../convert/impl/InOrderStepperBase.scala | 1 + .../convert/impl/IndexedSeqStepper.scala | 1 + .../convert/impl/IndexedStepperBase.scala | 1 + .../convert/impl/IteratorStepper.scala | 1 + .../convert/impl/NumericRangeStepper.scala | 1 + .../convert/impl/RangeStepper.scala | 3 +- .../convert/impl/StringStepper.scala | 1 + .../convert/impl/TableStepper.scala | 1 + .../convert/impl/VectorStepper.scala | 7 +- .../collection/generic/BitOperations.scala | 1 + .../generic/DefaultSerializationProxy.scala | 5 +- .../collection/generic/IsIterable.scala | 1 + .../collection/generic/IsIterableOnce.scala | 1 + .../stdlib/collection/generic/IsMap.scala | 1 + .../stdlib/collection/generic/IsSeq.scala | 41 +- .../collection/generic/Subtractable.scala | 1 + .../stdlib/collection/generic/package.scala | 1 + .../collection/immutable/ArraySeq.scala | 53 +- .../stdlib/collection/immutable/BitSet.scala | 5 +- .../collection/immutable/ChampCommon.scala | 3 +- .../stdlib/collection/immutable/HashMap.scala | 22 +- .../stdlib/collection/immutable/HashSet.scala | 22 +- .../stdlib/collection/immutable/IntMap.scala | 18 +- .../collection/immutable/Iterable.scala | 4 +- ...{LazyList.scala => LazyListIterable.scala} | 499 ++++++++------- .../stdlib/collection/immutable/List.scala | 25 +- .../stdlib/collection/immutable/ListMap.scala | 12 +- .../stdlib/collection/immutable/ListSet.scala | 4 +- .../stdlib/collection/immutable/LongMap.scala | 16 +- .../stdlib/collection/immutable/Map.scala | 32 +- .../collection/immutable/NumericRange.scala | 4 +- .../stdlib/collection/immutable/Queue.scala | 7 +- .../stdlib/collection/immutable/Range.scala | 5 +- .../collection/immutable/RedBlackTree.scala | 7 +- .../stdlib/collection/immutable/Seq.scala | 12 +- .../stdlib/collection/immutable/SeqMap.scala | 10 +- .../stdlib/collection/immutable/Set.scala | 12 +- .../collection/immutable/SortedMap.scala | 13 +- .../collection/immutable/SortedSet.scala | 3 +- .../stdlib/collection/immutable/Stream.scala | 568 ------------------ .../immutable/StrictOptimizedSeqOps.scala | 8 +- .../stdlib/collection/immutable/TreeMap.scala | 16 +- .../collection/immutable/TreeSeqMap.scala | 26 +- .../stdlib/collection/immutable/TreeSet.scala | 9 +- .../stdlib/collection/immutable/Vector.scala | 54 +- .../collection/immutable/VectorMap.scala | 8 +- .../collection/immutable/WrappedString.scala | 18 +- .../stdlib/collection/immutable/package.scala | 2 +- .../stdlib/collection/mutable/AnyRefMap.scala | 60 +- .../collection/mutable/ArrayBuffer.scala | 35 +- .../collection/mutable/ArrayBuilder.scala | 7 +- .../collection/mutable/ArrayDeque.scala | 19 +- .../stdlib/collection/mutable/ArraySeq.scala | 26 +- .../stdlib/collection/mutable/BitSet.scala | 9 +- .../stdlib/collection/mutable/Buffer.scala | 22 +- .../stdlib/collection/mutable/Builder.scala | 14 +- .../mutable/CheckedIndexedSeqView.scala | 63 +- .../stdlib/collection/mutable/Cloneable.scala | 2 +- .../mutable/CollisionProofHashMap.scala | 35 +- .../stdlib/collection/mutable/Growable.scala | 8 +- .../collection/mutable/GrowableBuilder.scala | 4 +- .../stdlib/collection/mutable/HashMap.scala | 19 +- .../stdlib/collection/mutable/HashSet.scala | 19 +- .../stdlib/collection/mutable/HashTable.scala | 5 +- .../collection/mutable/ImmutableBuilder.scala | 1 + .../collection/mutable/IndexedSeq.scala | 1 + .../stdlib/collection/mutable/Iterable.scala | 5 +- .../collection/mutable/LinkedHashMap.scala | 11 +- .../collection/mutable/LinkedHashSet.scala | 11 +- .../collection/mutable/ListBuffer.scala | 20 +- .../stdlib/collection/mutable/ListMap.scala | 9 +- .../stdlib/collection/mutable/LongMap.scala | 51 +- .../stdlib/collection/mutable/Map.scala | 13 +- .../stdlib/collection/mutable/MultiMap.scala | 3 +- .../collection/mutable/MutationTracker.scala | 3 +- .../collection/mutable/OpenHashMap.scala | 11 +- .../collection/mutable/PriorityQueue.scala | 17 +- .../stdlib/collection/mutable/Queue.scala | 9 +- .../collection/mutable/RedBlackTree.scala | 33 +- .../collection/mutable/ReusableBuilder.scala | 1 + .../stdlib/collection/mutable/Seq.scala | 1 + .../stdlib/collection/mutable/SeqMap.scala | 1 + .../stdlib/collection/mutable/Set.scala | 1 + .../collection/mutable/Shrinkable.scala | 5 +- .../stdlib/collection/mutable/SortedMap.scala | 9 +- .../stdlib/collection/mutable/SortedSet.scala | 1 + .../stdlib/collection/mutable/Stack.scala | 10 +- .../collection/mutable/StringBuilder.scala | 9 +- .../stdlib/collection/mutable/TreeMap.scala | 9 +- .../stdlib/collection/mutable/TreeSet.scala | 9 +- .../collection/mutable/UnrolledBuffer.scala | 19 +- .../collection/mutable/WeakHashMap.scala | 9 +- .../stdlib/collection/mutable/package.scala | 1 + .../stdlib/collection/package.scala | 1 + 145 files changed, 1983 insertions(+), 1980 deletions(-) create mode 100644 tests/pos-special/stdlib/Test1.scala create mode 100644 tests/pos-special/stdlib/Test2.scala rename tests/pos-special/stdlib/collection/immutable/{LazyList.scala => LazyListIterable.scala} (66%) delete mode 100644 tests/pos-special/stdlib/collection/immutable/Stream.scala diff --git a/tests/pos-special/stdlib/Test1.scala b/tests/pos-special/stdlib/Test1.scala new file mode 100644 index 000000000000..9ee4e7cfa6a1 --- /dev/null +++ b/tests/pos-special/stdlib/Test1.scala @@ -0,0 +1,34 @@ +import language.experimental.captureChecking +import collection.{View, Seq} +import collection.mutable.{ArrayBuffer, ListBuffer} + +import java.io.* + +object Test0: + + def usingLogFile[sealed T](op: FileOutputStream^ => T): T = + val logFile = FileOutputStream("log") + val result = op(logFile) + logFile.close() + result + + def test(xs: List[Int]) = + usingLogFile: f => + xs.map: x => + f.write(x) + x * x + +object Test1: + def test(it: Iterator[Int]^, v: View[Int]^) = + val isEven: Int ->{cap[test]} Boolean = _ % 2 == 0 + val it2 = it.filter(isEven) + val _: Iterator[Int]^{it, isEven} = it2 + val it2c: Iterator[Int]^{it2} = it2 + val v2 = v.filter(isEven) + val _: View[Int]^{v, isEven} = v2 + val v2c: View[Int]^{v2} = v2 + val v3 = v.drop(2) + val _: View[Int]^{v} = v3 + val v3c: View[Int]^{v3} = v3 + val (xs6, xs7) = v.partition(isEven) + val (xs6a, xs7a) = v.partition(_ % 2 == 0) diff --git a/tests/pos-special/stdlib/Test2.scala b/tests/pos-special/stdlib/Test2.scala new file mode 100644 index 000000000000..a59da522b183 --- /dev/null +++ b/tests/pos-special/stdlib/Test2.scala @@ -0,0 +1,232 @@ +import scala.reflect.ClassTag +import language.experimental.captureChecking +import collection.{View, Seq} +import collection.mutable.{ArrayBuffer, ListBuffer} + +object Test { + + def seqOps(xs: Seq[Int]) = { // try with Seq[Int]^{cap} + val strPlusInt: (String, Int) => String = _ + _ + val intPlusStr: (Int, String) => String = _ + _ + val isEven: Int => Boolean = _ % 2 == 0 + val isNonNeg: Int => Boolean = _ > 0 + val flips: Int => List[Int] = x => x :: -x :: Nil + val x1 = xs.foldLeft("")(strPlusInt) + val y1: String = x1 + val x2 = xs.foldRight("")(intPlusStr) + val y2: String = x2 + val x3 = xs.indexWhere(isEven) + val y3: Int = x3 + val x4 = xs.head + val y4: Int = x4 + val x5 = xs.to(List) + val y5: List[Int] = x5 + val (xs6, xs7) = xs.partition(isEven) + val ys6: Seq[Int] = xs6 + val ys7: Seq[Int] = xs7 + val xs8 = xs.drop(2) + val ys8: Seq[Int] = xs8 + val xs9 = xs.map(isNonNeg) + val ys9: Seq[Boolean] = xs9 + val xs10 = xs.flatMap(flips) + val ys10: Seq[Int] = xs10 + val xs11 = xs ++ xs + val ys11: Seq[Int] = xs11 + val xs12 = xs ++ Nil + val ys12: Seq[Int] = xs12 + val xs13 = Nil ++ xs + val ys13: Seq[Int] = xs13 + val xs14 = xs ++ ("a" :: Nil) + val ys14: Seq[Any] = xs14 + val xs15 = xs.zip(xs9) + val ys15: Seq[(Int, Boolean)] = xs15 + val xs16 = xs.reverse + val ys16: Seq[Int] = xs16 + println("-------") + println(x1) + println(x2) + println(x3) + println(x4) + println(x5) + println(xs6) + println(xs7) + println(xs8) + println(xs9) + println(xs10) + println(xs11) + println(xs12) + println(xs13) + println(xs14) + println(xs15) + println(xs16) + } + + def iterOps(xs: => Iterator[Int]^) = + val strPlusInt: (String, Int) => String = _ + _ + val intPlusStr: (Int, String) => String = _ + _ + val isEven: Int ->{cap[iterOps]} Boolean = _ % 2 == 0 + val isNonNeg: Int => Boolean = _ > 0 + val flips: Int => List[Int] = x => x :: -x :: Nil + val x1 = xs.foldLeft("")(strPlusInt) + val y1: String = x1 + val x2 = xs.foldRight("")(intPlusStr) + val y2: String = x2 + val x4 = xs.next() + val y4: Int = x4 + val x5 = xs.to(List) + val y5: List[Int] = x5 + val (xs6, xs7) = xs.partition(isEven) + val ys6: Iterator[Int]^{xs6, isEven} = xs6 + val ys7: Iterator[Int]^{xs7, isEven} = xs7 + val (xs6a, xs7a) = xs.partition(_ % 2 == 0) + val ys6a: Iterator[Int]^{xs6} = xs6 + val ys7a: Iterator[Int]^{xs7} = xs7 + val xs8 = xs.drop(2) + val ys8: Iterator[Int]^{xs8} = xs8 + val xs9 = xs.map(isNonNeg) + val ys9: Iterator[Boolean]^{xs9} = xs9 + val xs10 = xs.flatMap(flips) + val ys10: Iterator[Int]^{xs10} = xs10 + val xs11 = xs ++ xs + val ys11: Iterator[Int]^{xs11} = xs11 + val xs12 = xs ++ Nil + val ys12: Iterator[Int]^{xs12} = xs12 + val xs13 = Nil ++ xs + val ys13: List[Int] = xs13 + val xs14 = xs ++ ("a" :: Nil) + val ys14: Iterator[Any]^{xs14} = xs14 + val xs15 = xs.zip(xs9) + val ys15: Iterator[(Int, Boolean)]^{xs15} = xs15 + println("-------") + println(x1) + println(x2) + println(x4) + println(x5) + println(xs6.to(List)) + println(xs7.to(List)) + println(xs8.to(List)) + println(xs9.to(List)) + println(xs10.to(List)) + println(xs11.to(List)) + println(xs12.to(List)) + println(xs13.to(List)) + println(xs14.to(List)) + println(xs15.to(List)) + + def viewOps(xs: View[Int]^) = { + val strPlusInt: (String, Int) => String = _ + _ + val intPlusStr: (Int, String) => String = _ + _ + val isEven: Int ->{cap[viewOps]} Boolean = _ % 2 == 0 + val isNonNeg: Int => Boolean = _ > 0 + val flips: Int => List[Int] = x => x :: -x :: Nil + val x1 = xs.foldLeft("")(strPlusInt) + val y1: String = x1 + val x2 = xs.foldRight("")(intPlusStr) + val y2: String = x2 + //val x3 = xs.indexWhere(_ % 2 == 0) // indexWhere does not exist on View + //val y3: Int = x3 + val x4 = xs.head + val y4: Int = x4 + val x5 = xs.to(List) + val y5: List[Int] = x5 + val (xs6, xs7) = xs.partition(isEven) + val ys6: View[Int]^{xs6, isEven} = xs6 + val ys7: View[Int]^{xs7, isEven} = xs7 + val (xs6a, xs7a) = xs.partition(_ % 2 == 0) + val ys6a: View[Int]^{xs6} = xs6 + val ys7a: View[Int]^{xs7} = xs7 + val xs8 = xs.drop(2) + val ys8: View[Int]^{xs8} = xs8 + val xs9 = xs.map(isNonNeg) + val ys9: View[Boolean]^{xs9} = xs9 + val xs10 = xs.flatMap(flips) + val ys10: View[Int]^{xs10} = xs10 + val xs11 = xs ++ xs + val ys11: View[Int]^{xs11} = xs11 + val xs12 = xs ++ Nil + val ys12: View[Int]^{xs12} = xs12 + val xs13 = Nil ++ xs + val ys13: List[Int] = xs13 + val xs14 = xs ++ ("a" :: Nil) + val ys14: View[Any]^{xs14} = xs14 + val xs15 = xs.zip(xs9) + val ys15: View[(Int, Boolean)]^{xs15} = xs15 + println("-------") + println(x1) + println(x2) + println(x4) + println(x5) + println(xs6.to(List)) + println(xs7.to(List)) + println(xs8.to(List)) + println(xs9.to(List)) + println(xs10.to(List)) + println(xs11.to(List)) + println(xs12.to(List)) + println(xs13.to(List)) + println(xs14.to(List)) + println(xs15.to(List)) + } + + def stringOps(xs: String) = { + val x1 = xs.foldLeft("")(_ + _) + val y1: String = x1 + val x2 = xs.foldRight("")(_ + _) + val y2: String = x2 + val x3 = xs.indexWhere(_ % 2 == 0) + val y3: Int = x3 + val x4 = xs.head + val y4: Int = x4 + val x5 = xs.to(List) + val y5: List[Char] = x5 + val (xs6, xs7) = xs.partition(_ % 2 == 0) + val ys6: String = xs6 + val ys7: String = xs7 + val xs8 = xs.drop(2) + val ys8: String = xs8 + val xs9 = xs.map(_ + 1) + val ys9: Seq[Int] = xs9 + val xs9a = xs.map(_.toUpper) + val ys9a: String = xs9a + val xs10 = xs.flatMap((x: Char) => s"$x,$x") + val ys10: String = xs10 + val xs11 = xs ++ xs + val ys11: String = xs11 + val ops = collection.StringOps(xs) // !!! otherwise we can a "cannot establish reference" + val xs13 = Nil ++ ops.iterator + val ys13: List[Char] = xs13 + val xs14 = xs ++ ("xyz" :: Nil) + val ys14: Seq[Any] = xs14 + val xs15 = xs.zip(xs9) + val ys15: Seq[(Char, Int)] = xs15 + println("-------") + println(x1) + println(x2) + println(x3) + println(x4) + println(x5) + println(xs6) + println(xs7) + println(xs8) + println(xs9) + println(xs9a) + println(xs10) + println(xs11) + println(xs13) + println(xs14) + println(xs15) + } + + def main(args: Array[String]) = { + val ints = List(1, 2, 3) + val intsBuf = ints.to(ArrayBuffer) + val intsListBuf = ints.to(ListBuffer) + val intsView = ints.view + seqOps(ints) + seqOps(intsBuf) + seqOps(intsListBuf) + viewOps(intsView) + iterOps(ints.iterator) + stringOps("abc") + } +} diff --git a/tests/pos-special/stdlib/collection/ArrayOps.scala b/tests/pos-special/stdlib/collection/ArrayOps.scala index 485427886625..a52fd0dbd162 100644 --- a/tests/pos-special/stdlib/collection/ArrayOps.scala +++ b/tests/pos-special/stdlib/collection/ArrayOps.scala @@ -15,6 +15,7 @@ package collection import java.lang.Math.{max, min} import java.util.Arrays +import language.experimental.captureChecking import scala.Predef.{ // unimport all array-related implicit conversions to avoid triggering them accidentally genericArrayOps => _, @@ -53,14 +54,14 @@ import scala.util.Sorting object ArrayOps { @SerialVersionUID(3L) - private class ArrayView[A](xs: Array[A]) extends AbstractIndexedSeqView[A] { + private class ArrayView[sealed A](xs: Array[A]) extends AbstractIndexedSeqView[A] { def length = xs.length def apply(n: Int) = xs(n) override def toString: String = immutable.ArraySeq.unsafeWrapArray(xs).mkString("ArrayView(", ", ", ")") } /** A lazy filtered array. No filtering is applied until one of `foreach`, `map` or `flatMap` is called. */ - class WithFilter[A](p: A => Boolean, xs: Array[A]) { + class WithFilter[sealed A](p: A => Boolean, xs: Array[A]) { /** Apply `f` to each element for its side effects. * Note: [U] parameter needed to help scalac's type inference. @@ -82,7 +83,7 @@ object ArrayOps { * @return a new array resulting from applying the given function * `f` to each element of this array and collecting the results. */ - def map[B: ClassTag](f: A => B): Array[B] = { + def map[sealed B: ClassTag](f: A => B): Array[B] = { val b = ArrayBuilder.make[B] var i = 0 while (i < xs.length) { @@ -101,7 +102,7 @@ object ArrayOps { * @return a new array resulting from applying the given collection-valued function * `f` to each element of this array and concatenating the results. */ - def flatMap[B: ClassTag](f: A => IterableOnce[B]): Array[B] = { + def flatMap[sealed B: ClassTag](f: A => IterableOnce[B]): Array[B] = { val b = ArrayBuilder.make[B] var i = 0 while(i < xs.length) { @@ -112,15 +113,15 @@ object ArrayOps { b.result() } - def flatMap[BS, B](f: A => BS)(implicit asIterable: BS => Iterable[B], m: ClassTag[B]): Array[B] = + def flatMap[BS, sealed B](f: A => BS)(implicit asIterable: BS => Iterable[B], m: ClassTag[B]): Array[B] = flatMap[B](x => asIterable(f(x))) /** Creates a new non-strict filter which combines this filter with the given predicate. */ - def withFilter(q: A => Boolean): WithFilter[A] = new WithFilter[A](a => p(a) && q(a), xs) + def withFilter(q: A => Boolean): WithFilter[A]^{this, q} = new WithFilter[A](a => p(a) && q(a), xs) } @SerialVersionUID(3L) - private[collection] final class ArrayIterator[@specialized(Specializable.Everything) A](xs: Array[A]) extends AbstractIterator[A] with Serializable { + private[collection] final class ArrayIterator[@specialized(Specializable.Everything) sealed A](xs: Array[A]) extends AbstractIterator[A] with Serializable { private[this] var pos = 0 private[this] val len = xs.length override def knownSize: Int = len - pos @@ -143,7 +144,7 @@ object ArrayOps { } @SerialVersionUID(3L) - private final class ReverseIterator[@specialized(Specializable.Everything) A](xs: Array[A]) extends AbstractIterator[A] with Serializable { + private final class ReverseIterator[@specialized(Specializable.Everything) sealed A](xs: Array[A]) extends AbstractIterator[A] with Serializable { private[this] var pos = xs.length-1 def hasNext: Boolean = pos >= 0 def next(): A = { @@ -160,7 +161,7 @@ object ArrayOps { } @SerialVersionUID(3L) - private final class GroupedIterator[A](xs: Array[A], groupSize: Int) extends AbstractIterator[Array[A]] with Serializable { + private final class GroupedIterator[sealed A](xs: Array[A], groupSize: Int) extends AbstractIterator[Array[A]] with Serializable { private[this] var pos = 0 def hasNext: Boolean = pos < xs.length def next(): Array[A] = { @@ -196,7 +197,7 @@ object ArrayOps { * * @tparam A type of the elements contained in this array. */ -final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { +final class ArrayOps[sealed A](private val xs: Array[A]) extends AnyVal { @`inline` private[this] implicit def elemTag: ClassTag[A] = ClassTag(xs.getClass.getComponentType) @@ -366,7 +367,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { def inits: Iterator[Array[A]] = iterateUntilEmpty(xs => new ArrayOps(xs).init) // A helper for tails and inits. - private[this] def iterateUntilEmpty(f: Array[A] => Array[A]): Iterator[Array[A]] = + private[this] def iterateUntilEmpty(f: Array[A] => Array[A]): Iterator[Array[A]]^{f} = Iterator.iterate(xs)(f).takeWhile(x => x.length != 0) ++ Iterator.single(Array.empty[A]) /** An array containing the first `n` elements of this array. */ @@ -504,7 +505,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * * @return a pair of arrays: the first one made of those values returned by `f` that were wrapped in [[scala.util.Left]], * and the second one made of those wrapped in [[scala.util.Right]]. */ - def partitionMap[A1: ClassTag, A2: ClassTag](f: A => Either[A1, A2]): (Array[A1], Array[A2]) = { + def partitionMap[sealed A1: ClassTag, sealed A2: ClassTag](f: A => Either[A1, A2]): (Array[A1], Array[A2]) = { val res1 = ArrayBuilder.make[A1] val res2 = ArrayBuilder.make[A2] var i = 0 @@ -663,7 +664,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * All these operations apply to those elements of this array * which satisfy the predicate `p`. */ - def withFilter(p: A => Boolean): ArrayOps.WithFilter[A] = new ArrayOps.WithFilter[A](p, xs) + def withFilter(p: A => Boolean): ArrayOps.WithFilter[A]^{p} = new ArrayOps.WithFilter[A](p, xs) /** Finds index of first occurrence of some value in this array after or at some start index. * @@ -776,7 +777,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * Returns `z` if this array is empty. */ def foldLeft[B](z: B)(op: (B, A) => B): B = { - def f[@specialized(Specializable.Everything) T](xs: Array[T], op: (Any, Any) => Any, z: Any): Any = { + def f[@specialized(Specializable.Everything) sealed T](xs: Array[T], op: (Any, Any) => Any, z: Any): Any = { val length = xs.length var v: Any = z var i = 0 @@ -815,7 +816,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * }}} * */ - def scanLeft[ B : ClassTag ](z: B)(op: (B, A) => B): Array[B] = { + def scanLeft[sealed B : ClassTag](z: B)(op: (B, A) => B): Array[B] = { var v = z var i = 0 val res = new Array[B](xs.length + 1) @@ -838,7 +839,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * * @return a new array containing the prefix scan of the elements in this array */ - def scan[B >: A : ClassTag](z: B)(op: (B, B) => B): Array[B] = scanLeft(z)(op) + def scan[sealed B >: A : ClassTag](z: B)(op: (B, B) => B): Array[B] = scanLeft(z)(op) /** Produces an array containing cumulative results of applying the binary * operator going right to left. @@ -854,7 +855,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * }}} * */ - def scanRight[ B : ClassTag ](z: B)(op: (A, B) => B): Array[B] = { + def scanRight[sealed B : ClassTag](z: B)(op: (A, B) => B): Array[B] = { var v = z var i = xs.length - 1 val res = new Array[B](xs.length + 1) @@ -882,7 +883,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * Returns `z` if this array is empty. */ def foldRight[B](z: B)(op: (A, B) => B): B = { - def f[@specialized(Specializable.Everything) T](xs: Array[T], op: (Any, Any) => Any, z: Any): Any = { + def f[@specialized(Specializable.Everything) sealed T](xs: Array[T], op: (Any, Any) => Any, z: Any): Any = { var v = z var i = xs.length - 1 while(i >= 0) { @@ -925,7 +926,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @return a new array resulting from applying the given function * `f` to each element of this array and collecting the results. */ - def map[B](f: A => B)(implicit ct: ClassTag[B]): Array[B] = { + def map[sealed B](f: A => B)(implicit ct: ClassTag[B]): Array[B] = { val len = xs.length val ys = new Array[B](len) if(len > 0) { @@ -962,7 +963,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @return a new array resulting from applying the given collection-valued function * `f` to each element of this array and concatenating the results. */ - def flatMap[B : ClassTag](f: A => IterableOnce[B]): Array[B] = { + def flatMap[sealed B : ClassTag](f: A => IterableOnce[B]): Array[B] = { val b = ArrayBuilder.make[B] var i = 0 while(i < xs.length) { @@ -972,7 +973,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { b.result() } - def flatMap[BS, B](f: A => BS)(implicit asIterable: BS => Iterable[B], m: ClassTag[B]): Array[B] = + def flatMap[BS, sealed B](f: A => BS)(implicit asIterable: BS => Iterable[B], m: ClassTag[B]): Array[B] = flatMap[B](x => asIterable(f(x))) /** Flattens a two-dimensional array by concatenating all its rows @@ -982,7 +983,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @param asIterable A function that converts elements of this array to rows - Iterables of type `B`. * @return An array obtained by concatenating rows of this array. */ - def flatten[B](implicit asIterable: A => IterableOnce[B], m: ClassTag[B]): Array[B] = { + def flatten[sealed B](implicit asIterable: A => IterableOnce[B], m: ClassTag[B]): Array[B] = { val b = ArrayBuilder.make[B] val len = xs.length var size = 0 @@ -1015,7 +1016,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * `pf` to each element on which it is defined and collecting the results. * The order of the elements is preserved. */ - def collect[B: ClassTag](pf: PartialFunction[A, B]): Array[B] = { + def collect[sealed B: ClassTag](pf: PartialFunction[A, B]): Array[B] = { val fallback: Any => Any = ArrayOps.fallback val b = ArrayBuilder.make[B] var i = 0 @@ -1049,7 +1050,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @return a new array containing pairs consisting of corresponding elements of this array and `that`. * The length of the returned array is the minimum of the lengths of this array and `that`. */ - def zip[B](that: IterableOnce[B]): Array[(A, B)] = { + def zip[sealed B](that: IterableOnce[B]): Array[(A, B)] = { val b = new ArrayBuilder.ofRef[(A, B)]() val k = that.knownSize b.sizeHint(if(k >= 0) min(k, xs.length) else xs.length) @@ -1094,7 +1095,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * If this array is shorter than `that`, `thisElem` values are used to pad the result. * If `that` is shorter than this array, `thatElem` values are used to pad the result. */ - def zipAll[A1 >: A, B](that: Iterable[B], thisElem: A1, thatElem: B): Array[(A1, B)] = { + def zipAll[sealed A1 >: A, sealed B](that: Iterable[B], thisElem: A1, thatElem: B): Array[(A1, B)] = { val b = new ArrayBuilder.ofRef[(A1, B)]() val k = that.knownSize b.sizeHint(max(k, xs.length)) @@ -1131,26 +1132,26 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { } /** A copy of this array with an element appended. */ - def appended[B >: A : ClassTag](x: B): Array[B] = { + def appended[sealed B >: A : ClassTag](x: B): Array[B] = { val dest = Array.copyAs[B](xs, xs.length+1) dest(xs.length) = x dest } - @`inline` final def :+ [B >: A : ClassTag](x: B): Array[B] = appended(x) + @`inline` final def :+ [sealed B >: A : ClassTag](x: B): Array[B] = appended(x) /** A copy of this array with an element prepended. */ - def prepended[B >: A : ClassTag](x: B): Array[B] = { + def prepended[sealed B >: A : ClassTag](x: B): Array[B] = { val dest = new Array[B](xs.length + 1) dest(0) = x Array.copy(xs, 0, dest, 1, xs.length) dest } - @`inline` final def +: [B >: A : ClassTag](x: B): Array[B] = prepended(x) + @`inline` final def +: [sealed B >: A : ClassTag](x: B): Array[B] = prepended(x) /** A copy of this array with all elements of a collection prepended. */ - def prependedAll[B >: A : ClassTag](prefix: IterableOnce[B]): Array[B] = { + def prependedAll[sealed B >: A : ClassTag](prefix: IterableOnce[B]): Array[B] = { val b = ArrayBuilder.make[B] val k = prefix.knownSize if(k >= 0) b.sizeHint(k + xs.length) @@ -1161,18 +1162,18 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { } /** A copy of this array with all elements of an array prepended. */ - def prependedAll[B >: A : ClassTag](prefix: Array[_ <: B]): Array[B] = { + def prependedAll[sealed B >: A : ClassTag](prefix: Array[_ <: B]): Array[B] = { val dest = Array.copyAs[B](prefix, prefix.length+xs.length) Array.copy(xs, 0, dest, prefix.length, xs.length) dest } - @`inline` final def ++: [B >: A : ClassTag](prefix: IterableOnce[B]): Array[B] = prependedAll(prefix) + @`inline` final def ++: [sealed B >: A : ClassTag](prefix: IterableOnce[B]): Array[B] = prependedAll(prefix) - @`inline` final def ++: [B >: A : ClassTag](prefix: Array[_ <: B]): Array[B] = prependedAll(prefix) + @`inline` final def ++: [sealed B >: A : ClassTag](prefix: Array[_ <: B]): Array[B] = prependedAll(prefix) /** A copy of this array with all elements of a collection appended. */ - def appendedAll[B >: A : ClassTag](suffix: IterableOnce[B]): Array[B] = { + def appendedAll[sealed B >: A : ClassTag](suffix: IterableOnce[B]): Array[B] = { val b = ArrayBuilder.make[B] val k = suffix.knownSize if(k >= 0) b.sizeHint(k + xs.length) @@ -1182,23 +1183,23 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { } /** A copy of this array with all elements of an array appended. */ - def appendedAll[B >: A : ClassTag](suffix: Array[_ <: B]): Array[B] = { + def appendedAll[sealed B >: A : ClassTag](suffix: Array[_ <: B]): Array[B] = { val dest = Array.copyAs[B](xs, xs.length+suffix.length) Array.copy(suffix, 0, dest, xs.length, suffix.length) dest } - @`inline` final def :++ [B >: A : ClassTag](suffix: IterableOnce[B]): Array[B] = appendedAll(suffix) + @`inline` final def :++ [sealed B >: A : ClassTag](suffix: IterableOnce[B]): Array[B] = appendedAll(suffix) - @`inline` final def :++ [B >: A : ClassTag](suffix: Array[_ <: B]): Array[B] = appendedAll(suffix) + @`inline` final def :++ [sealed B >: A : ClassTag](suffix: Array[_ <: B]): Array[B] = appendedAll(suffix) - @`inline` final def concat[B >: A : ClassTag](suffix: IterableOnce[B]): Array[B] = appendedAll(suffix) + @`inline` final def concat[sealed B >: A : ClassTag](suffix: IterableOnce[B]): Array[B] = appendedAll(suffix) - @`inline` final def concat[B >: A : ClassTag](suffix: Array[_ <: B]): Array[B] = appendedAll(suffix) + @`inline` final def concat[sealed B >: A : ClassTag](suffix: Array[_ <: B]): Array[B] = appendedAll(suffix) - @`inline` final def ++[B >: A : ClassTag](xs: IterableOnce[B]): Array[B] = appendedAll(xs) + @`inline` final def ++[sealed B >: A : ClassTag](xs: IterableOnce[B]): Array[B] = appendedAll(xs) - @`inline` final def ++[B >: A : ClassTag](xs: Array[_ <: B]): Array[B] = appendedAll(xs) + @`inline` final def ++[sealed B >: A : ClassTag](xs: Array[_ <: B]): Array[B] = appendedAll(xs) /** Tests whether this array contains a given value as an element. * @@ -1217,7 +1218,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @param other The patch values * @param replaced The number of values in the original array that are replaced by the patch. */ - def patch[B >: A : ClassTag](from: Int, other: IterableOnce[B], replaced: Int): Array[B] = { + def patch[sealed B >: A : ClassTag](from: Int, other: IterableOnce[B], replaced: Int): Array[B] = { val b = ArrayBuilder.make[B] val k = other.knownSize val r = if(replaced < 0) 0 else replaced @@ -1243,7 +1244,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @return a pair of Arrays, containing, respectively, the first and second half * of each element pair of this Array. */ - def unzip[A1, A2](implicit asPair: A => (A1, A2), ct1: ClassTag[A1], ct2: ClassTag[A2]): (Array[A1], Array[A2]) = { + def unzip[sealed A1, sealed A2](implicit asPair: A => (A1, A2), ct1: ClassTag[A1], ct2: ClassTag[A2]): (Array[A1], Array[A2]) = { val a1 = new Array[A1](xs.length) val a2 = new Array[A2](xs.length) var i = 0 @@ -1272,7 +1273,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @return a triple of Arrays, containing, respectively, the first, second, and third * elements from each element triple of this Array. */ - def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3), ct1: ClassTag[A1], ct2: ClassTag[A2], + def unzip3[sealed A1, sealed A2, sealed A3](implicit asTriple: A => (A1, A2, A3), ct1: ClassTag[A1], ct2: ClassTag[A2], ct3: ClassTag[A3]): (Array[A1], Array[A2], Array[A3]) = { val a1 = new Array[A1](xs.length) val a2 = new Array[A2](xs.length) @@ -1294,7 +1295,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @param asArray A function that converts elements of this array to rows - arrays of type `B`. * @return An array obtained by replacing elements of this arrays with rows the represent. */ - def transpose[B](implicit asArray: A => Array[B]): Array[Array[B]] = { + def transpose[sealed B](implicit asArray: A => Array[B]): Array[Array[B]] = { val aClass = xs.getClass.getComponentType val bb = new ArrayBuilder.ofRef[Array[B]]()(ClassTag[Array[B]](aClass)) if (xs.length == 0) bb.result() @@ -1345,7 +1346,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @tparam B the type of the elements after being transformed by `f` * @return a new array consisting of all the elements of this array without duplicates. */ - def distinctBy[B](f: A => B): Array[A] = + def distinctBy[B](f: A -> B): Array[A] = ArrayBuilder.make[A].addAll(iterator.distinctBy(f)).result() /** A copy of this array with an element value appended until a given target length is reached. @@ -1357,7 +1358,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * all elements of this array followed by the minimal number of occurrences of `elem` so * that the resulting collection has a length of at least `len`. */ - def padTo[B >: A : ClassTag](len: Int, elem: B): Array[B] = { + def padTo[sealed B >: A : ClassTag](len: Int, elem: B): Array[B] = { var i = xs.length val newlen = max(i, len) val dest = Array.copyAs[B](xs, newlen) @@ -1417,7 +1418,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @tparam K the type of keys returned by the discriminator function * @tparam B the type of values returned by the transformation function */ - def groupMap[K, B : ClassTag](key: A => K)(f: A => B): immutable.Map[K, Array[B]] = { + def groupMap[K, sealed B : ClassTag](key: A => K)(f: A => B): immutable.Map[K, Array[B]] = { val m = mutable.Map.empty[K, ArrayBuilder[B]] val len = xs.length var i = 0 @@ -1444,7 +1445,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @param xs the array to fill. * @tparam B the type of the elements of the array. */ - def copyToArray[B >: A](xs: Array[B]): Int = copyToArray(xs, 0) + def copyToArray[sealed B >: A](xs: Array[B]): Int = copyToArray(xs, 0) /** Copy elements of this array to another array. * Fills the given array `xs` starting at index `start`. @@ -1455,7 +1456,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @param start the starting index within the destination array. * @tparam B the type of the elements of the array. */ - def copyToArray[B >: A](xs: Array[B], start: Int): Int = copyToArray(xs, start, Int.MaxValue) + def copyToArray[sealed B >: A](xs: Array[B], start: Int): Int = copyToArray(xs, start, Int.MaxValue) /** Copy elements of this array to another array. * Fills the given array `xs` starting at index `start` with at most `len` values. @@ -1467,7 +1468,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @param len the maximal number of elements to copy. * @tparam B the type of the elements of the array. */ - def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = { + def copyToArray[sealed B >: A](xs: Array[B], start: Int, len: Int): Int = { val copied = IterableOnce.elemsToCopyToArray(this.xs.length, xs.length, start, len) if (copied > 0) { Array.copy(this.xs, 0, xs, start, copied) @@ -1476,7 +1477,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { } /** Create a copy of this array with the specified element type. */ - def toArray[B >: A: ClassTag]: Array[B] = { + def toArray[sealed B >: A: ClassTag]: Array[B] = { val destination = new Array[B](xs.length) copyToArray(destination, 0) destination @@ -1495,7 +1496,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { // can't use a default arg because we already have another overload with a default arg /** Tests whether this array starts with the given array. */ - @`inline` def startsWith[B >: A](that: Array[B]): Boolean = startsWith(that, 0) + @`inline` def startsWith[sealed B >: A](that: Array[B]): Boolean = startsWith(that, 0) /** Tests whether this array contains the given array at a given index. * @@ -1504,7 +1505,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @return `true` if the array `that` is contained in this array at * index `offset`, otherwise `false`. */ - def startsWith[B >: A](that: Array[B], offset: Int): Boolean = { + def startsWith[sealed B >: A](that: Array[B], offset: Int): Boolean = { val safeOffset = offset.max(0) val thatl = that.length if(thatl > xs.length-safeOffset) thatl == 0 @@ -1523,7 +1524,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @param that the array to test * @return `true` if this array has `that` as a suffix, `false` otherwise. */ - def endsWith[B >: A](that: Array[B]): Boolean = { + def endsWith[sealed B >: A](that: Array[B]): Boolean = { val thatl = that.length val off = xs.length - thatl if(off < 0) false @@ -1543,7 +1544,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @return a new array which is a copy of this array with the element at position `index` replaced by `elem`. * @throws IndexOutOfBoundsException if `index` does not satisfy `0 <= index < length`. */ - def updated[B >: A : ClassTag](index: Int, elem: B): Array[B] = { + def updated[sealed B >: A : ClassTag](index: Int, elem: B): Array[B] = { if(index < 0 || index >= xs.length) throw new IndexOutOfBoundsException(s"$index is out of bounds (min 0, max ${xs.length-1})") val dest = toArray[B] dest(index) = elem diff --git a/tests/pos-special/stdlib/collection/BitSet.scala b/tests/pos-special/stdlib/collection/BitSet.scala index e8ca89806455..39c15dbe808f 100644 --- a/tests/pos-special/stdlib/collection/BitSet.scala +++ b/tests/pos-special/stdlib/collection/BitSet.scala @@ -18,7 +18,7 @@ import java.io.{ObjectInputStream, ObjectOutputStream} import scala.annotation.nowarn import scala.collection.Stepper.EfficientSplit import scala.collection.mutable.Builder - +import language.experimental.captureChecking /** Base type of bitsets. * @@ -33,7 +33,7 @@ import scala.collection.mutable.Builder * @define Coll `BitSet` */ trait BitSet extends SortedSet[Int] with BitSetOps[BitSet] { - override protected def fromSpecific(coll: IterableOnce[Int]): BitSet = bitSetFactory.fromSpecific(coll) + override protected def fromSpecific(coll: IterableOnce[Int]^): BitSet = bitSetFactory.fromSpecific(coll) override protected def newSpecificBuilder: Builder[Int, BitSet] = bitSetFactory.newBuilder override def empty: BitSet = bitSetFactory.empty @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""") @@ -48,7 +48,7 @@ object BitSet extends SpecificIterableFactory[Int, BitSet] { def empty: BitSet = immutable.BitSet.empty def newBuilder: Builder[Int, BitSet] = immutable.BitSet.newBuilder - def fromSpecific(it: IterableOnce[Int]): BitSet = immutable.BitSet.fromSpecific(it) + def fromSpecific(it: IterableOnce[Int]^): BitSet = immutable.BitSet.fromSpecific(it) @SerialVersionUID(3L) private[collection] abstract class SerializationProxy(@transient protected val coll: BitSet) extends Serializable { diff --git a/tests/pos-special/stdlib/collection/BufferedIterator.scala b/tests/pos-special/stdlib/collection/BufferedIterator.scala index bc35ee0a25da..cca40dd31d40 100644 --- a/tests/pos-special/stdlib/collection/BufferedIterator.scala +++ b/tests/pos-special/stdlib/collection/BufferedIterator.scala @@ -11,7 +11,7 @@ */ package scala.collection - +import language.experimental.captureChecking /** Buffered iterators are iterators which provide a method `head` * that inspects the next element without discarding it. diff --git a/tests/pos-special/stdlib/collection/BuildFrom.scala b/tests/pos-special/stdlib/collection/BuildFrom.scala index bc9c49d9493c..0a3cc199d4dc 100644 --- a/tests/pos-special/stdlib/collection/BuildFrom.scala +++ b/tests/pos-special/stdlib/collection/BuildFrom.scala @@ -16,6 +16,8 @@ import scala.annotation.implicitNotFound import scala.collection.mutable.Builder import scala.collection.immutable.WrappedString import scala.reflect.ClassTag +import language.experimental.captureChecking +import caps.unsafe.unsafeAssumePure /** Builds a collection of type `C` from elements of type `A` when a source collection of type `From` is available. * Implicit instances of `BuildFrom` are available for all collection types. @@ -26,7 +28,11 @@ import scala.reflect.ClassTag */ @implicitNotFound(msg = "Cannot construct a collection of type ${C} with elements of type ${A} based on a collection of type ${From}.") trait BuildFrom[-From, -A, +C] extends Any { self => - def fromSpecific(from: From)(it: IterableOnce[A]): C + def fromSpecific(from: From)(it: IterableOnce[A]^): C + // !!! this is wrong, we need two versions of fromSpecific; one mapping + // to C^{it} when C is an Iterable, and one mapping to C when C is a Seq, Map, or Set. + // But that requires a large scale refactoring of BuildFrom. The unsafeAssumePure + // calls in this file are needed to sweep that problem under the carpet. /** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer. * Building collections with `fromSpecific` is preferred because it can be lazy for lazy collections. */ @@ -37,7 +43,7 @@ trait BuildFrom[-From, -A, +C] extends Any { self => /** Partially apply a BuildFrom to a Factory */ def toFactory(from: From): Factory[A, C] = new Factory[A, C] { - def fromSpecific(it: IterableOnce[A]): C = self.fromSpecific(from)(it) + def fromSpecific(it: IterableOnce[A]^): C = self.fromSpecific(from)(it) def newBuilder: Builder[A, C] = self.newBuilder(from) } } @@ -48,42 +54,42 @@ object BuildFrom extends BuildFromLowPriority1 { implicit def buildFromMapOps[CC[X, Y] <: Map[X, Y] with MapOps[X, Y, CC, _], K0, V0, K, V]: BuildFrom[CC[K0, V0] with Map[K0, V0], (K, V), CC[K, V] with Map[K, V]] = new BuildFrom[CC[K0, V0], (K, V), CC[K, V]] { //TODO: Reuse a prototype instance def newBuilder(from: CC[K0, V0]): Builder[(K, V), CC[K, V]] = (from: MapOps[K0, V0, CC, _]).mapFactory.newBuilder[K, V] - def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]): CC[K, V] = (from: MapOps[K0, V0, CC, _]).mapFactory.from(it) + def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]^): CC[K, V] = (from: MapOps[K0, V0, CC, _]).mapFactory.from(it) } /** Build the source collection type from a SortedMapOps */ implicit def buildFromSortedMapOps[CC[X, Y] <: SortedMap[X, Y] with SortedMapOps[X, Y, CC, _], K0, V0, K : Ordering, V]: BuildFrom[CC[K0, V0] with SortedMap[K0, V0], (K, V), CC[K, V] with SortedMap[K, V]] = new BuildFrom[CC[K0, V0], (K, V), CC[K, V]] { def newBuilder(from: CC[K0, V0]): Builder[(K, V), CC[K, V]] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.newBuilder[K, V] - def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]): CC[K, V] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.from(it) + def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]^): CC[K, V] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.from(it) } implicit def buildFromBitSet[C <: BitSet with BitSetOps[C]]: BuildFrom[C, Int, C] = new BuildFrom[C, Int, C] { - def fromSpecific(from: C)(it: IterableOnce[Int]): C = from.bitSetFactory.fromSpecific(it) + def fromSpecific(from: C)(it: IterableOnce[Int]^): C = from.bitSetFactory.fromSpecific(it) def newBuilder(from: C): Builder[Int, C] = from.bitSetFactory.newBuilder } implicit val buildFromString: BuildFrom[String, Char, String] = new BuildFrom[String, Char, String] { - def fromSpecific(from: String)(it: IterableOnce[Char]): String = Factory.stringFactory.fromSpecific(it) + def fromSpecific(from: String)(it: IterableOnce[Char]^): String = Factory.stringFactory.fromSpecific(it) def newBuilder(from: String): Builder[Char, String] = Factory.stringFactory.newBuilder } implicit val buildFromWrappedString: BuildFrom[WrappedString, Char, WrappedString] = new BuildFrom[WrappedString, Char, WrappedString] { - def fromSpecific(from: WrappedString)(it: IterableOnce[Char]): WrappedString = WrappedString.fromSpecific(it) + def fromSpecific(from: WrappedString)(it: IterableOnce[Char]^): WrappedString = WrappedString.fromSpecific(it) def newBuilder(from: WrappedString): mutable.Builder[Char, WrappedString] = WrappedString.newBuilder } - implicit def buildFromArray[A : ClassTag]: BuildFrom[Array[_], A, Array[A]] = + implicit def buildFromArray[sealed A : ClassTag]: BuildFrom[Array[_], A, Array[A]] = new BuildFrom[Array[_], A, Array[A]] { - def fromSpecific(from: Array[_])(it: IterableOnce[A]): Array[A] = Factory.arrayFactory[A].fromSpecific(it) + def fromSpecific(from: Array[_])(it: IterableOnce[A]^): Array[A] = Factory.arrayFactory[A].fromSpecific(it) def newBuilder(from: Array[_]): Builder[A, Array[A]] = Factory.arrayFactory[A].newBuilder } - implicit def buildFromView[A, B]: BuildFrom[View[A], B, View[B]] = + implicit def buildFromView[A, sealed B]: BuildFrom[View[A], B, View[B]] = new BuildFrom[View[A], B, View[B]] { - def fromSpecific(from: View[A])(it: IterableOnce[B]): View[B] = View.from(it) + def fromSpecific(from: View[A])(it: IterableOnce[B]^): View[B] = View.from(it).unsafeAssumePure def newBuilder(from: View[A]): Builder[B, View[B]] = View.newBuilder } @@ -97,12 +103,12 @@ trait BuildFromLowPriority1 extends BuildFromLowPriority2 { // test in test/junit/scala/collection/BuildFromTest.scala and discussion in https://github.com/scala/scala/pull/10209 implicit def buildFromSortedSetOps[CC[X] <: SortedSet[X] with SortedSetOps[X, CC, _], A0, A : Ordering]: BuildFrom[CC[A0] with SortedSet[A0], A, CC[A] with SortedSet[A]] = new BuildFrom[CC[A0], A, CC[A]] { def newBuilder(from: CC[A0]): Builder[A, CC[A]] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.newBuilder[A] - def fromSpecific(from: CC[A0])(it: IterableOnce[A]): CC[A] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.from(it) + def fromSpecific(from: CC[A0])(it: IterableOnce[A]^): CC[A] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.from(it) } implicit def fallbackStringCanBuildFrom[A]: BuildFrom[String, A, immutable.IndexedSeq[A]] = new BuildFrom[String, A, immutable.IndexedSeq[A]] { - def fromSpecific(from: String)(it: IterableOnce[A]): immutable.IndexedSeq[A] = immutable.IndexedSeq.from(it) + def fromSpecific(from: String)(it: IterableOnce[A]^): immutable.IndexedSeq[A] = immutable.IndexedSeq.from(it) def newBuilder(from: String): Builder[A, immutable.IndexedSeq[A]] = immutable.IndexedSeq.newBuilder[A] } } @@ -112,11 +118,11 @@ trait BuildFromLowPriority2 { implicit def buildFromIterableOps[CC[X] <: Iterable[X] with IterableOps[X, CC, _], A0, A]: BuildFrom[CC[A0], A, CC[A]] = new BuildFrom[CC[A0], A, CC[A]] { //TODO: Reuse a prototype instance def newBuilder(from: CC[A0]): Builder[A, CC[A]] = (from: IterableOps[A0, CC, _]).iterableFactory.newBuilder[A] - def fromSpecific(from: CC[A0])(it: IterableOnce[A]): CC[A] = (from: IterableOps[A0, CC, _]).iterableFactory.from(it) + def fromSpecific(from: CC[A0])(it: IterableOnce[A]^): CC[A] = (from: IterableOps[A0, CC, _]).iterableFactory.from(it).unsafeAssumePure } implicit def buildFromIterator[A]: BuildFrom[Iterator[_], A, Iterator[A]] = new BuildFrom[Iterator[_], A, Iterator[A]] { def newBuilder(from: Iterator[_]): mutable.Builder[A, Iterator[A]] = Iterator.newBuilder - def fromSpecific(from: Iterator[_])(it: IterableOnce[A]): Iterator[A] = Iterator.from(it) + def fromSpecific(from: Iterator[_])(it: IterableOnce[A]^): Iterator[A] = Iterator.from(it).unsafeAssumePure } } diff --git a/tests/pos-special/stdlib/collection/DefaultMap.scala b/tests/pos-special/stdlib/collection/DefaultMap.scala index cbc61d8c0268..baa9eceadae5 100644 --- a/tests/pos-special/stdlib/collection/DefaultMap.scala +++ b/tests/pos-special/stdlib/collection/DefaultMap.scala @@ -12,7 +12,7 @@ package scala package collection - +import language.experimental.captureChecking /** A default map which builds a default `immutable.Map` implementation for all * transformations. diff --git a/tests/pos-special/stdlib/collection/Factory.scala b/tests/pos-special/stdlib/collection/Factory.scala index 2b15f1cc15d1..c45776b62b9c 100644 --- a/tests/pos-special/stdlib/collection/Factory.scala +++ b/tests/pos-special/stdlib/collection/Factory.scala @@ -18,6 +18,8 @@ import scala.language.implicitConversions import scala.collection.mutable.Builder import scala.annotation.unchecked.uncheckedVariance import scala.reflect.ClassTag +import language.experimental.captureChecking +import caps.unsafe.unsafeAssumePure /** * A factory that builds a collection of type `C` with elements of type `A`. @@ -29,14 +31,14 @@ import scala.reflect.ClassTag * @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.) * @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.) */ -trait Factory[-A, +C] extends Any { +trait Factory[-A, +C] extends Pure { /** * @return A collection of type `C` containing the same elements * as the source collection `it`. * @param it Source collection */ - def fromSpecific(it: IterableOnce[A]): C + def fromSpecific(it: IterableOnce[A]^): C /** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer. * Building collections with `fromSpecific` is preferred because it can be lazy for lazy collections. */ @@ -48,7 +50,7 @@ object Factory { implicit val stringFactory: Factory[Char, String] = new StringFactory @SerialVersionUID(3L) private class StringFactory extends Factory[Char, String] with Serializable { - def fromSpecific(it: IterableOnce[Char]): String = { + def fromSpecific(it: IterableOnce[Char]^): String = { val b = new mutable.StringBuilder(scala.math.max(0, it.knownSize)) b ++= it b.result() @@ -56,10 +58,10 @@ object Factory { def newBuilder: Builder[Char, String] = new mutable.StringBuilder() } - implicit def arrayFactory[A: ClassTag]: Factory[A, Array[A]] = new ArrayFactory[A] + implicit def arrayFactory[sealed A: ClassTag]: Factory[A, Array[A]] = new ArrayFactory[A] @SerialVersionUID(3L) - private class ArrayFactory[A: ClassTag] extends Factory[A, Array[A]] with Serializable { - def fromSpecific(it: IterableOnce[A]): Array[A] = { + private class ArrayFactory[sealed A: ClassTag] extends Factory[A, Array[A]] with Serializable { + def fromSpecific(it: IterableOnce[A]^): Array[A] = { val b = newBuilder b.sizeHint(scala.math.max(0, it.knownSize)) b ++= it @@ -80,7 +82,7 @@ object Factory { * @define coll collection * @define Coll `Iterable` */ -trait IterableFactory[+CC[_]] extends Serializable { +trait IterableFactory[+CC[_]] extends Serializable, Pure { /** Creates a target $coll from an existing source collection * @@ -88,7 +90,7 @@ trait IterableFactory[+CC[_]] extends Serializable { * @tparam A the type of the collection’s elements * @return a new $coll with the elements of `source` */ - def from[A](source: IterableOnce[A]): CC[A] + def from[A](source: IterableOnce[A]^): CC[A]^{source} /** An empty collection * @tparam A the type of the ${coll}'s elements @@ -109,7 +111,7 @@ trait IterableFactory[+CC[_]] extends Serializable { * @param f the function that's repeatedly applied * @return a $coll with `len` values in the sequence `start, f(start), f(f(start)), ...` */ - def iterate[A](start: A, len: Int)(f: A => A): CC[A] = from(new View.Iterate(start, len)(f)) + def iterate[A](start: A, len: Int)(f: A => A): CC[A]^{f} = from(new View.Iterate(start, len)(f)) /** Produces a $coll that uses a function `f` to produce elements of type `A` * and update an internal state of type `S`. @@ -121,7 +123,7 @@ trait IterableFactory[+CC[_]] extends Serializable { * @tparam S Type of the internal state * @return a $coll that produces elements using `f` until `f` returns `None` */ - def unfold[A, S](init: S)(f: S => Option[(A, S)]): CC[A] = from(new View.Unfold(init)(f)) + def unfold[A, S](init: S)(f: S => Option[(A, S)]): CC[A]^{f} = from(new View.Unfold(init)(f)) /** Produces a $coll containing a sequence of increasing of integers. * @@ -150,7 +152,7 @@ trait IterableFactory[+CC[_]] extends Serializable { * @param elem the element computation * @return A $coll that contains the results of `n` evaluations of `elem`. */ - def fill[A](n: Int)(elem: => A): CC[A] = from(new View.Fill(n)(elem)) + def fill[A](n: Int)(elem: => A): CC[A]^{elem} = from(new View.Fill(n)(elem)) /** Produces a two-dimensional $coll containing the results of some element computation a number of times. * @param n1 the number of elements in the 1st dimension @@ -158,7 +160,8 @@ trait IterableFactory[+CC[_]] extends Serializable { * @param elem the element computation * @return A $coll that contains the results of `n1 x n2` evaluations of `elem`. */ - def fill[A](n1: Int, n2: Int)(elem: => A): CC[CC[A] @uncheckedVariance] = fill(n1)(fill(n2)(elem)) + def fill[A](n1: Int, n2: Int)(elem: => A): CC[CC[A] @uncheckedVariance]^{elem} = // !!! problem with checking rhs under cc + ??? // fill(n1)(fill(n2)(elem)) /** Produces a three-dimensional $coll containing the results of some element computation a number of times. * @param n1 the number of elements in the 1st dimension @@ -167,7 +170,8 @@ trait IterableFactory[+CC[_]] extends Serializable { * @param elem the element computation * @return A $coll that contains the results of `n1 x n2 x n3` evaluations of `elem`. */ - def fill[A](n1: Int, n2: Int, n3: Int)(elem: => A): CC[CC[CC[A]] @uncheckedVariance] = fill(n1)(fill(n2, n3)(elem)) + def fill[A](n1: Int, n2: Int, n3: Int)(elem: => A): CC[CC[CC[A]] @uncheckedVariance]^{elem} = // !!! problem with checking rhs under cc + ??? // fill(n1)(fill(n2, n3)(elem)).unsafeAssumePure /** Produces a four-dimensional $coll containing the results of some element computation a number of times. * @param n1 the number of elements in the 1st dimension @@ -177,8 +181,8 @@ trait IterableFactory[+CC[_]] extends Serializable { * @param elem the element computation * @return A $coll that contains the results of `n1 x n2 x n3 x n4` evaluations of `elem`. */ - def fill[A](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => A): CC[CC[CC[CC[A]]] @uncheckedVariance] = - fill(n1)(fill(n2, n3, n4)(elem)) + def fill[A](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => A): CC[CC[CC[CC[A]]] @uncheckedVariance]^{elem} = // !!! problem with checking rhs under cc + ??? // fill(n1)(fill(n2, n3, n4)(elem)) /** Produces a five-dimensional $coll containing the results of some element computation a number of times. * @param n1 the number of elements in the 1st dimension @@ -189,15 +193,15 @@ trait IterableFactory[+CC[_]] extends Serializable { * @param elem the element computation * @return A $coll that contains the results of `n1 x n2 x n3 x n4 x n5` evaluations of `elem`. */ - def fill[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance] = - fill(n1)(fill(n2, n3, n4, n5)(elem)) + def fill[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance]^{elem} = // !!! problem with checking rhs under cc + ??? // fill(n1)(fill(n2, n3, n4, n5)(elem)) /** Produces a $coll containing values of a given function over a range of integer values starting from 0. * @param n The number of elements in the $coll * @param f The function computing element values * @return A $coll consisting of elements `f(0), ..., f(n -1)` */ - def tabulate[A](n: Int)(f: Int => A): CC[A] = from(new View.Tabulate(n)(f)) + def tabulate[A](n: Int)(f: Int => A): CC[A]^{f} = from(new View.Tabulate(n)(f)) /** Produces a two-dimensional $coll containing values of a given function over ranges of integer values starting from 0. * @param n1 the number of elements in the 1st dimension @@ -206,8 +210,8 @@ trait IterableFactory[+CC[_]] extends Serializable { * @return A $coll consisting of elements `f(i1, i2)` * for `0 <= i1 < n1` and `0 <= i2 < n2`. */ - def tabulate[A](n1: Int, n2: Int)(f: (Int, Int) => A): CC[CC[A] @uncheckedVariance] = - tabulate(n1)(i1 => tabulate(n2)(f(i1, _))) + def tabulate[A](n1: Int, n2: Int)(f: (Int, Int) => A): CC[CC[A] @uncheckedVariance]^{f} = // !!! problem with checking rhs under cc + ??? // tabulate(n1)(i1 => tabulate(n2)(f(i1, _))) /** Produces a three-dimensional $coll containing values of a given function over ranges of integer values starting from 0. * @param n1 the number of elements in the 1st dimension @@ -217,8 +221,8 @@ trait IterableFactory[+CC[_]] extends Serializable { * @return A $coll consisting of elements `f(i1, i2, i3)` * for `0 <= i1 < n1`, `0 <= i2 < n2`, and `0 <= i3 < n3`. */ - def tabulate[A](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => A): CC[CC[CC[A]] @uncheckedVariance] = - tabulate(n1)(i1 => tabulate(n2, n3)(f(i1, _, _))) + def tabulate[A](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => A): CC[CC[CC[A]] @uncheckedVariance]^{f} = // !!! problem with checking rhs under cc + ??? // tabulate(n1)(i1 => tabulate(n2, n3)(f(i1, _, _))) /** Produces a four-dimensional $coll containing values of a given function over ranges of integer values starting from 0. * @param n1 the number of elements in the 1st dimension @@ -229,8 +233,8 @@ trait IterableFactory[+CC[_]] extends Serializable { * @return A $coll consisting of elements `f(i1, i2, i3, i4)` * for `0 <= i1 < n1`, `0 <= i2 < n2`, `0 <= i3 < n3`, and `0 <= i4 < n4`. */ - def tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => A): CC[CC[CC[CC[A]]] @uncheckedVariance] = - tabulate(n1)(i1 => tabulate(n2, n3, n4)(f(i1, _, _, _))) + def tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => A): CC[CC[CC[CC[A]]] @uncheckedVariance]^{f} = // !!! problem with checking rhs under cc + ??? // tabulate(n1)(i1 => tabulate(n2, n3, n4)(f(i1, _, _, _))) /** Produces a five-dimensional $coll containing values of a given function over ranges of integer values starting from 0. * @param n1 the number of elements in the 1st dimension @@ -242,8 +246,8 @@ trait IterableFactory[+CC[_]] extends Serializable { * @return A $coll consisting of elements `f(i1, i2, i3, i4, i5)` * for `0 <= i1 < n1`, `0 <= i2 < n2`, `0 <= i3 < n3`, `0 <= i4 < n4`, and `0 <= i5 < n5`. */ - def tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance] = - tabulate(n1)(i1 => tabulate(n2, n3, n4, n5)(f(i1, _, _, _, _))) + def tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance]^{f} = // !!! problem with checking rhs under cc + ??? // tabulate(n1)(i1 => tabulate(n2, n3, n4, n5)(f(i1, _, _, _, _))) /** Concatenates all argument collections into a single $coll. * @@ -271,13 +275,15 @@ object IterableFactory { @SerialVersionUID(3L) private[this] class ToFactory[A, CC[_]](factory: IterableFactory[CC]) extends Factory[A, CC[A]] with Serializable { - def fromSpecific(it: IterableOnce[A]): CC[A] = factory.from[A](it) + def fromSpecific(it: IterableOnce[A]^): CC[A] = factory.from[A](it).unsafeAssumePure + // unsafeAssumePure needed but is unsound, since we confuse Seq and Iterable fromSpecific def newBuilder: Builder[A, CC[A]] = factory.newBuilder[A] } implicit def toBuildFrom[A, CC[_]](factory: IterableFactory[CC]): BuildFrom[Any, A, CC[A]] = new BuildFrom[Any, A, CC[A]] { - def fromSpecific(from: Any)(it: IterableOnce[A]) = factory.from(it) + def fromSpecific(from: Any)(it: IterableOnce[A]^): CC[A] = + factory.from(it).unsafeAssumePure // !!! see remark in BuildFrom why this is necessary def newBuilder(from: Any) = factory.newBuilder } @@ -285,15 +291,20 @@ object IterableFactory { class Delegate[CC[_]](delegate: IterableFactory[CC]) extends IterableFactory[CC] { override def apply[A](elems: A*): CC[A] = delegate.apply(elems: _*) def empty[A]: CC[A] = delegate.empty - def from[E](it: IterableOnce[E]): CC[E] = delegate.from(it) + def from[E](it: IterableOnce[E]^): CC[E]^{it} = delegate.from(it) def newBuilder[A]: Builder[A, CC[A]] = delegate.newBuilder[A] } } +// !!! Needed to add this separate trait +trait FreeSeqFactory[+CC[A]] extends IterableFactory[CC]: + def from[A](source: IterableOnce[A]^): CC[A] + override def apply[A](elems: A*): CC[A] = from(elems) + /** * @tparam CC Collection type constructor (e.g. `List`) */ -trait SeqFactory[+CC[A] <: SeqOps[A, Seq, Seq[A]]] extends IterableFactory[CC] { +trait SeqFactory[+CC[A] <: SeqOps[A, Seq, Seq[A]]] extends FreeSeqFactory[CC] { import SeqFactory.UnapplySeqWrapper final def unapplySeq[A](x: CC[A] @uncheckedVariance): UnapplySeqWrapper[A] = new UnapplySeqWrapper(x) // TODO is uncheckedVariance sound here? } @@ -303,7 +314,7 @@ object SeqFactory { class Delegate[CC[A] <: SeqOps[A, Seq, Seq[A]]](delegate: SeqFactory[CC]) extends SeqFactory[CC] { override def apply[A](elems: A*): CC[A] = delegate.apply(elems: _*) def empty[A]: CC[A] = delegate.empty - def from[E](it: IterableOnce[E]): CC[E] = delegate.from(it) + def from[E](it: IterableOnce[E]^): CC[E] = delegate.from(it) def newBuilder[A]: Builder[A, CC[A]] = delegate.newBuilder[A] } @@ -366,6 +377,8 @@ trait StrictOptimizedSeqFactory[+CC[A] <: SeqOps[A, Seq, Seq[A]]] extends SeqFac * @define Coll `Iterable` */ trait SpecificIterableFactory[-A, +C] extends Factory[A, C] { + this: SpecificIterableFactory[A, C] => + def empty: C def apply(xs: A*): C = fromSpecific(xs) def fill(n: Int)(elem: => A): C = fromSpecific(new View.Fill(n)(elem)) @@ -381,7 +394,7 @@ trait SpecificIterableFactory[-A, +C] extends Factory[A, C] { * @define coll collection * @define Coll `Iterable` */ -trait MapFactory[+CC[_, _]] extends Serializable { +trait MapFactory[+CC[_, _]] extends Serializable, Pure { /** * An empty Map @@ -391,7 +404,7 @@ trait MapFactory[+CC[_, _]] extends Serializable { /** * A collection of type Map generated from given iterable object. */ - def from[K, V](it: IterableOnce[(K, V)]): CC[K, V] + def from[K, V](it: IterableOnce[(K, V)]^): CC[K, V] /** * A collection of type Map that contains given key/value bindings. @@ -424,20 +437,20 @@ object MapFactory { @SerialVersionUID(3L) private[this] class ToFactory[K, V, CC[_, _]](factory: MapFactory[CC]) extends Factory[(K, V), CC[K, V]] with Serializable { - def fromSpecific(it: IterableOnce[(K, V)]): CC[K, V] = factory.from[K, V](it) + def fromSpecific(it: IterableOnce[(K, V)]^): CC[K, V] = factory.from[K, V](it) def newBuilder: Builder[(K, V), CC[K, V]] = factory.newBuilder[K, V] } implicit def toBuildFrom[K, V, CC[_, _]](factory: MapFactory[CC]): BuildFrom[Any, (K, V), CC[K, V]] = new BuildFrom[Any, (K, V), CC[K, V]] { - def fromSpecific(from: Any)(it: IterableOnce[(K, V)]) = factory.from(it) + def fromSpecific(from: Any)(it: IterableOnce[(K, V)]^) = factory.from(it) def newBuilder(from: Any) = factory.newBuilder[K, V] } @SerialVersionUID(3L) class Delegate[C[_, _]](delegate: MapFactory[C]) extends MapFactory[C] { override def apply[K, V](elems: (K, V)*): C[K, V] = delegate.apply(elems: _*) - def from[K, V](it: IterableOnce[(K, V)]): C[K, V] = delegate.from(it) + def from[K, V](it: IterableOnce[(K, V)]^): C[K, V] = delegate.from(it) def empty[K, V]: C[K, V] = delegate.empty def newBuilder[K, V]: Builder[(K, V), C[K, V]] = delegate.newBuilder } @@ -454,9 +467,9 @@ object MapFactory { * @define coll collection * @define Coll `Iterable` */ -trait EvidenceIterableFactory[+CC[_], Ev[_]] extends Serializable { +trait EvidenceIterableFactory[+CC[_], Ev[_]] extends Serializable, Pure { - def from[E : Ev](it: IterableOnce[E]): CC[E] + def from[E : Ev](it: IterableOnce[E]^): CC[E] def empty[A : Ev]: CC[A] @@ -517,13 +530,13 @@ object EvidenceIterableFactory { @SerialVersionUID(3L) private[this] class ToFactory[Ev[_], A: Ev, CC[_]](factory: EvidenceIterableFactory[CC, Ev]) extends Factory[A, CC[A]] with Serializable { - def fromSpecific(it: IterableOnce[A]): CC[A] = factory.from[A](it) + def fromSpecific(it: IterableOnce[A]^): CC[A] = factory.from[A](it) def newBuilder: Builder[A, CC[A]] = factory.newBuilder[A] } implicit def toBuildFrom[Ev[_], A: Ev, CC[_]](factory: EvidenceIterableFactory[CC, Ev]): BuildFrom[Any, A, CC[A]] = new EvidenceIterableFactoryToBuildFrom(factory) private class EvidenceIterableFactoryToBuildFrom[Ev[_], A: Ev, CC[_]](factory: EvidenceIterableFactory[CC, Ev]) extends BuildFrom[Any, A, CC[A]] { - def fromSpecific(from: Any)(it: IterableOnce[A]): CC[A] = factory.from[A](it) + def fromSpecific(from: Any)(it: IterableOnce[A]^): CC[A] = factory.from[A](it) def newBuilder(from: Any): Builder[A, CC[A]] = factory.newBuilder[A] } @@ -531,7 +544,7 @@ object EvidenceIterableFactory { class Delegate[CC[_], Ev[_]](delegate: EvidenceIterableFactory[CC, Ev]) extends EvidenceIterableFactory[CC, Ev] { override def apply[A: Ev](xs: A*): CC[A] = delegate.apply(xs: _*) def empty[A : Ev]: CC[A] = delegate.empty - def from[E : Ev](it: IterableOnce[E]): CC[E] = delegate.from(it) + def from[E : Ev](it: IterableOnce[E]^): CC[E] = delegate.from(it) def newBuilder[A : Ev]: Builder[A, CC[A]] = delegate.newBuilder[A] } } @@ -668,7 +681,7 @@ object ClassTagIterableFactory { @SerialVersionUID(3L) class AnyIterableDelegate[CC[_]](delegate: ClassTagIterableFactory[CC]) extends IterableFactory[CC] { def empty[A]: CC[A] = delegate.empty(ClassTag.Any).asInstanceOf[CC[A]] - def from[A](it: IterableOnce[A]): CC[A] = delegate.from[Any](it)(ClassTag.Any).asInstanceOf[CC[A]] + def from[A](it: IterableOnce[A]^): CC[A] = delegate.from[Any](it)(ClassTag.Any).asInstanceOf[CC[A]] def newBuilder[A]: Builder[A, CC[A]] = delegate.newBuilder(ClassTag.Any).asInstanceOf[Builder[A, CC[A]]] override def apply[A](elems: A*): CC[A] = delegate.apply[Any](elems: _*)(ClassTag.Any).asInstanceOf[CC[A]] override def iterate[A](start: A, len: Int)(f: A => A): CC[A] = delegate.iterate[A](start, len)(f)(ClassTag.Any.asInstanceOf[ClassTag[A]]) @@ -734,10 +747,11 @@ trait StrictOptimizedClassTagSeqFactory[+CC[A] <: SeqOps[A, Seq, Seq[A]]] extend * @define Coll `Iterable` */ trait SortedMapFactory[+CC[_, _]] extends Serializable { + this: SortedMapFactory[CC] => def empty[K : Ordering, V]: CC[K, V] - def from[K : Ordering, V](it: IterableOnce[(K, V)]): CC[K, V] + def from[K : Ordering, V](it: IterableOnce[(K, V)]^): CC[K, V] def apply[K : Ordering, V](elems: (K, V)*): CC[K, V] = from(elems) @@ -764,20 +778,20 @@ object SortedMapFactory { @SerialVersionUID(3L) private[this] class ToFactory[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]) extends Factory[(K, V), CC[K, V]] with Serializable { - def fromSpecific(it: IterableOnce[(K, V)]): CC[K, V] = factory.from[K, V](it) + def fromSpecific(it: IterableOnce[(K, V)]^): CC[K, V] = factory.from[K, V](it) def newBuilder: Builder[(K, V), CC[K, V]] = factory.newBuilder[K, V] } implicit def toBuildFrom[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]): BuildFrom[Any, (K, V), CC[K, V]] = new SortedMapFactoryToBuildFrom(factory) private class SortedMapFactoryToBuildFrom[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]) extends BuildFrom[Any, (K, V), CC[K, V]] { - def fromSpecific(from: Any)(it: IterableOnce[(K, V)]) = factory.from(it) + def fromSpecific(from: Any)(it: IterableOnce[(K, V)]^) = factory.from(it) def newBuilder(from: Any) = factory.newBuilder[K, V] } @SerialVersionUID(3L) class Delegate[CC[_, _]](delegate: SortedMapFactory[CC]) extends SortedMapFactory[CC] { override def apply[K: Ordering, V](elems: (K, V)*): CC[K, V] = delegate.apply(elems: _*) - def from[K : Ordering, V](it: IterableOnce[(K, V)]): CC[K, V] = delegate.from(it) + def from[K : Ordering, V](it: IterableOnce[(K, V)]^): CC[K, V] = delegate.from(it) def empty[K : Ordering, V]: CC[K, V] = delegate.empty def newBuilder[K : Ordering, V]: Builder[(K, V), CC[K, V]] = delegate.newBuilder } diff --git a/tests/pos-special/stdlib/collection/Hashing.scala b/tests/pos-special/stdlib/collection/Hashing.scala index 4e1fd872b8b5..772dcf5c65da 100644 --- a/tests/pos-special/stdlib/collection/Hashing.scala +++ b/tests/pos-special/stdlib/collection/Hashing.scala @@ -12,6 +12,7 @@ package scala package collection +import language.experimental.captureChecking protected[collection] object Hashing { diff --git a/tests/pos-special/stdlib/collection/IndexedSeq.scala b/tests/pos-special/stdlib/collection/IndexedSeq.scala index a82d5384779a..a2d4cc942231 100644 --- a/tests/pos-special/stdlib/collection/IndexedSeq.scala +++ b/tests/pos-special/stdlib/collection/IndexedSeq.scala @@ -17,6 +17,9 @@ import scala.annotation.{nowarn, tailrec} import scala.collection.Searching.{Found, InsertionPoint, SearchResult} import scala.collection.Stepper.EfficientSplit import scala.math.Ordering +import language.experimental.captureChecking +import caps.unsafe.unsafeAssumePure + /** Base trait for indexed sequences that have efficient `apply` and `length` */ trait IndexedSeq[+A] extends Seq[A] @@ -32,7 +35,7 @@ trait IndexedSeq[+A] extends Seq[A] object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](immutable.IndexedSeq) /** Base trait for indexed Seq operations */ -trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self => +trait IndexedSeqOps[+A, +CC[_], +C] extends Any with IndexedSeqViewOps[A, CC, C] with SeqOps[A, CC, C] { self => def iterator: Iterator[A] = view.iterator @@ -85,7 +88,7 @@ trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self => override def dropRight(n: Int): C = fromSpecific(new IndexedSeqView.DropRight(this, n)) - override def map[B](f: A => B): CC[B] = iterableFactory.from(new IndexedSeqView.Map(this, f)) + override def map[B](f: A => B): CC[B] = iterableFactory.from(new IndexedSeqView.Map(this, f)).unsafeAssumePure override def reverse: C = fromSpecific(new IndexedSeqView.Reverse(this)) @@ -103,7 +106,7 @@ trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self => override def knownSize: Int = length - override final def lengthCompare(that: Iterable[_]): Int = { + override final def lengthCompare(that: Iterable[_]^): Int = { val res = that.sizeCompare(length) // can't just invert the result, because `-Int.MinValue == Int.MinValue` if (res == Int.MinValue) 1 else -res diff --git a/tests/pos-special/stdlib/collection/IndexedSeqView.scala b/tests/pos-special/stdlib/collection/IndexedSeqView.scala index 737f032d2060..a16e06fa707d 100644 --- a/tests/pos-special/stdlib/collection/IndexedSeqView.scala +++ b/tests/pos-special/stdlib/collection/IndexedSeqView.scala @@ -14,33 +14,38 @@ package scala package collection import scala.annotation.nowarn +import language.experimental.captureChecking +trait IndexedSeqViewOps[+A, +CC[_], +C] extends Any with SeqViewOps[A, CC, C] { + self: IndexedSeqViewOps[A, CC, C]^ => +} /** View defined in terms of indexing a range */ -trait IndexedSeqView[+A] extends IndexedSeqOps[A, View, View[A]] with SeqView[A] { self => +trait IndexedSeqView[+A] extends IndexedSeqViewOps[A, View, View[A]] with SeqView[A] { + self: IndexedSeqView[A]^ => - override def view: IndexedSeqView[A] = this + override def view: IndexedSeqView[A]^{this} = this @deprecated("Use .view.slice(from, until) instead of .view(from, until)", "2.13.0") - override def view(from: Int, until: Int): IndexedSeqView[A] = view.slice(from, until) - - override def iterator: Iterator[A] = new IndexedSeqView.IndexedSeqViewIterator(this) - override def reverseIterator: Iterator[A] = new IndexedSeqView.IndexedSeqViewReverseIterator(this) - - override def appended[B >: A](elem: B): IndexedSeqView[B] = new IndexedSeqView.Appended(this, elem) - override def prepended[B >: A](elem: B): IndexedSeqView[B] = new IndexedSeqView.Prepended(elem, this) - override def take(n: Int): IndexedSeqView[A] = new IndexedSeqView.Take(this, n) - override def takeRight(n: Int): IndexedSeqView[A] = new IndexedSeqView.TakeRight(this, n) - override def drop(n: Int): IndexedSeqView[A] = new IndexedSeqView.Drop(this, n) - override def dropRight(n: Int): IndexedSeqView[A] = new IndexedSeqView.DropRight(this, n) - override def map[B](f: A => B): IndexedSeqView[B] = new IndexedSeqView.Map(this, f) - override def reverse: IndexedSeqView[A] = new IndexedSeqView.Reverse(this) - override def slice(from: Int, until: Int): IndexedSeqView[A] = new IndexedSeqView.Slice(this, from, until) - override def tapEach[U](f: A => U): IndexedSeqView[A] = new IndexedSeqView.Map(this, { (a: A) => f(a); a}) - - def concat[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new IndexedSeqView.Concat(this, suffix) - def appendedAll[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new IndexedSeqView.Concat(this, suffix) - def prependedAll[B >: A](prefix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new IndexedSeqView.Concat(prefix, this) + override def view(from: Int, until: Int): IndexedSeqView[A]^{this} = view.slice(from, until) + + override def iterator: Iterator[A]^{this} = new IndexedSeqView.IndexedSeqViewIterator(this) + override def reverseIterator: Iterator[A]^{this} = new IndexedSeqView.IndexedSeqViewReverseIterator(this) + + override def appended[B >: A](elem: B): IndexedSeqView[B]^{this} = new IndexedSeqView.Appended(this, elem) + override def prepended[B >: A](elem: B): IndexedSeqView[B]^{this} = new IndexedSeqView.Prepended(elem, this) + override def take(n: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.Take(this, n) + override def takeRight(n: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.TakeRight(this, n) + override def drop(n: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.Drop(this, n) + override def dropRight(n: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.DropRight(this, n) + override def map[B](f: A => B): IndexedSeqView[B]^{this, f} = new IndexedSeqView.Map(this, f) + override def reverse: IndexedSeqView[A]^{this} = new IndexedSeqView.Reverse(this) + override def slice(from: Int, until: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.Slice(this, from, until) + override def tapEach[U](f: A => U): IndexedSeqView[A]^{this, f} = new IndexedSeqView.Map(this, { (a: A) => f(a); a}) + + def concat[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B]^{this} = new IndexedSeqView.Concat(this, suffix) + def appendedAll[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B]^{this} = new IndexedSeqView.Concat(this, suffix) + def prependedAll[B >: A](prefix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B]^{this} = new IndexedSeqView.Concat(prefix, this) @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""") override protected[this] def stringPrefix: String = "IndexedSeqView" @@ -49,7 +54,8 @@ trait IndexedSeqView[+A] extends IndexedSeqOps[A, View, View[A]] with SeqView[A] object IndexedSeqView { @SerialVersionUID(3L) - private[collection] class IndexedSeqViewIterator[A](self: IndexedSeqView[A]) extends AbstractIterator[A] with Serializable { + private[collection] class IndexedSeqViewIterator[A](self: IndexedSeqView[A]^) extends AbstractIterator[A] with Serializable { + this: IndexedSeqViewIterator[A]^ => private[this] var current = 0 private[this] var remainder = self.length override def knownSize: Int = remainder @@ -63,7 +69,7 @@ object IndexedSeqView { r } else Iterator.empty.next() - override def drop(n: Int): Iterator[A] = { + override def drop(n: Int): Iterator[A]^{this} = { if (n > 0) { current += n remainder = Math.max(0, remainder - n) @@ -71,7 +77,7 @@ object IndexedSeqView { this } - override protected def sliceIterator(from: Int, until: Int): Iterator[A] = { + override protected def sliceIterator(from: Int, until: Int): Iterator[A]^{this} = { def formatRange(value : Int) : Int = if (value < 0) 0 else if (value > remainder) remainder else value @@ -83,7 +89,8 @@ object IndexedSeqView { } } @SerialVersionUID(3L) - private[collection] class IndexedSeqViewReverseIterator[A](self: IndexedSeqView[A]) extends AbstractIterator[A] with Serializable { + private[collection] class IndexedSeqViewReverseIterator[A](self: IndexedSeqView[A]^) extends AbstractIterator[A] with Serializable { + this: IndexedSeqViewReverseIterator[A]^ => private[this] var remainder = self.length private[this] var pos = remainder - 1 @inline private[this] def _hasNext: Boolean = remainder > 0 @@ -98,7 +105,7 @@ object IndexedSeqView { // from < 0 means don't move pos, until < 0 means don't limit remainder // - override protected def sliceIterator(from: Int, until: Int): Iterator[A] = { + override protected def sliceIterator(from: Int, until: Int): Iterator[A]^{this} = { if (_hasNext) { if (remainder <= from) remainder = 0 // exhausted by big skip else if (from <= 0) { // no skip, pos is same @@ -117,47 +124,47 @@ object IndexedSeqView { } } - /** An `IndexedSeqOps` whose collection type and collection type constructor are unknown */ - type SomeIndexedSeqOps[A] = IndexedSeqOps[A, AnyConstr, _] + /** An `IndexedSeqViewOps` whose collection type and collection type constructor are unknown */ + type SomeIndexedSeqOps[A] = IndexedSeqViewOps[A, AnyConstr, _] @SerialVersionUID(3L) - class Id[+A](underlying: SomeIndexedSeqOps[A]) + class Id[+A](underlying: SomeIndexedSeqOps[A]^) extends SeqView.Id(underlying) with IndexedSeqView[A] @SerialVersionUID(3L) - class Appended[+A](underlying: SomeIndexedSeqOps[A], elem: A) + class Appended[+A](underlying: SomeIndexedSeqOps[A]^, elem: A) extends SeqView.Appended(underlying, elem) with IndexedSeqView[A] @SerialVersionUID(3L) - class Prepended[+A](elem: A, underlying: SomeIndexedSeqOps[A]) + class Prepended[+A](elem: A, underlying: SomeIndexedSeqOps[A]^) extends SeqView.Prepended(elem, underlying) with IndexedSeqView[A] @SerialVersionUID(3L) - class Concat[A](prefix: SomeIndexedSeqOps[A], suffix: SomeIndexedSeqOps[A]) + class Concat[A](prefix: SomeIndexedSeqOps[A]^, suffix: SomeIndexedSeqOps[A]^) extends SeqView.Concat[A](prefix, suffix) with IndexedSeqView[A] @SerialVersionUID(3L) - class Take[A](underlying: SomeIndexedSeqOps[A], n: Int) + class Take[A](underlying: SomeIndexedSeqOps[A]^, n: Int) extends SeqView.Take(underlying, n) with IndexedSeqView[A] @SerialVersionUID(3L) - class TakeRight[A](underlying: SomeIndexedSeqOps[A], n: Int) + class TakeRight[A](underlying: SomeIndexedSeqOps[A]^, n: Int) extends SeqView.TakeRight(underlying, n) with IndexedSeqView[A] @SerialVersionUID(3L) - class Drop[A](underlying: SomeIndexedSeqOps[A], n: Int) + class Drop[A](underlying: SomeIndexedSeqOps[A]^, n: Int) extends SeqView.Drop[A](underlying, n) with IndexedSeqView[A] @SerialVersionUID(3L) - class DropRight[A](underlying: SomeIndexedSeqOps[A], n: Int) + class DropRight[A](underlying: SomeIndexedSeqOps[A]^, n: Int) extends SeqView.DropRight[A](underlying, n) with IndexedSeqView[A] @SerialVersionUID(3L) - class Map[A, B](underlying: SomeIndexedSeqOps[A], f: A => B) + class Map[A, B](underlying: SomeIndexedSeqOps[A]^, f: A => B) extends SeqView.Map(underlying, f) with IndexedSeqView[B] @SerialVersionUID(3L) - class Reverse[A](underlying: SomeIndexedSeqOps[A]) extends SeqView.Reverse[A](underlying) with IndexedSeqView[A] { + class Reverse[A](underlying: SomeIndexedSeqOps[A]^) extends SeqView.Reverse[A](underlying) with IndexedSeqView[A] { override def reverse: IndexedSeqView[A] = underlying match { case x: IndexedSeqView[A] => x case _ => super.reverse @@ -165,7 +172,7 @@ object IndexedSeqView { } @SerialVersionUID(3L) - class Slice[A](underlying: SomeIndexedSeqOps[A], from: Int, until: Int) extends AbstractIndexedSeqView[A] { + class Slice[A](underlying: SomeIndexedSeqOps[A]^, from: Int, until: Int) extends AbstractIndexedSeqView[A] { protected val lo = from max 0 protected val hi = (until max 0) min underlying.length protected val len = (hi - lo) max 0 diff --git a/tests/pos-special/stdlib/collection/Iterable.scala b/tests/pos-special/stdlib/collection/Iterable.scala index 04647f215963..bca80d7be108 100644 --- a/tests/pos-special/stdlib/collection/Iterable.scala +++ b/tests/pos-special/stdlib/collection/Iterable.scala @@ -17,6 +17,7 @@ import scala.annotation.nowarn import scala.annotation.unchecked.uncheckedVariance import scala.collection.mutable.Builder import scala.collection.View.{LeftPartitionMapped, RightPartitionMapped} +import language.experimental.captureChecking /** Base trait for generic collections. * @@ -28,6 +29,7 @@ import scala.collection.View.{LeftPartitionMapped, RightPartitionMapped} trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterable[A]] with IterableFactoryDefaults[A, Iterable] { + this: Iterable[A]^ => // The collection itself @deprecated("toIterable is internal and will be made protected; its name is similar to `toList` or `toSeq`, but it doesn't copy non-immutable collections", "2.13.7") @@ -94,7 +96,7 @@ trait Iterable[+A] extends IterableOnce[A] * @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs * or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported. */ - def lazyZip[B](that: Iterable[B]): LazyZip2[A, B, this.type] = new LazyZip2(this, this, that) + def lazyZip[B](that: Iterable[B]^): LazyZip2[A, B, this.type]^{this, that} = new LazyZip2(this, this, that) } /** Base trait for Iterable operations @@ -132,29 +134,31 @@ trait Iterable[+A] extends IterableOnce[A] * and may be nondeterministic. */ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with IterableOnceOps[A, CC, C] { + this: IterableOps[A, CC, C]^ => + /** * @return This collection as an `Iterable[A]`. No new collection will be built if `this` is already an `Iterable[A]`. */ // Should be `protected def asIterable`, or maybe removed altogether if it's not needed @deprecated("toIterable is internal and will be made protected; its name is similar to `toList` or `toSeq`, but it doesn't copy non-immutable collections", "2.13.7") - def toIterable: Iterable[A] + def toIterable: Iterable[A]^{this} /** Converts this $coll to an unspecified Iterable. Will return * the same collection if this instance is already Iterable. * @return An Iterable containing all elements of this $coll. */ @deprecated("toTraversable is internal and will be made protected; its name is similar to `toList` or `toSeq`, but it doesn't copy non-immutable collections", "2.13.0") - final def toTraversable: Traversable[A] = toIterable + final def toTraversable: Traversable[A]^{this} = toIterable override def isTraversableAgain: Boolean = true /** * @return This collection as a `C`. */ - protected def coll: C + protected def coll: C^{this} @deprecated("Use coll instead of repr in a collection implementation, use the collection value itself from the outside", "2.13.0") - final def repr: C = coll + final def repr: C^{this} = coll /** * Defines how to turn a given `Iterable[A]` into a collection of type `C`. @@ -174,7 +178,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * `Iterable[A]` obtained from `this` collection (as it is the case in the * implementations of operations where we use a `View[A]`), it is safe. */ - protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): C + protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]^): C^{coll} /** The companion object of this ${coll}, providing various factory methods. * @@ -251,7 +255,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable def lastOption: Option[A] = if (isEmpty) None else Some(last) /** A view over the elements of this collection. */ - def view: View[A] = View.fromIteratorProvider(() => iterator) + def view: View[A]^{this} = View.fromIteratorProvider(() => iterator) /** Compares the size of this $coll to a test value. * @@ -301,7 +305,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * this.sizeIs > size // this.sizeCompare(size) > 0 * }}} */ - @inline final def sizeIs: IterableOps.SizeCompareOps = new IterableOps.SizeCompareOps(this) + @inline final def sizeIs: IterableOps.SizeCompareOps^{this} = new IterableOps.SizeCompareOps(this) /** Compares the size of this $coll to the size of another `Iterable`. * @@ -317,7 +321,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * is `O(this.size min that.size)` instead of `O(this.size + that.size)`. * The method should be overridden if computing `size` is cheap and `knownSize` returns `-1`. */ - def sizeCompare(that: Iterable[_]): Int = { + def sizeCompare(that: Iterable[_]^): Int = { val thatKnownSize = that.knownSize if (thatKnownSize >= 0) this sizeCompare thatKnownSize @@ -342,7 +346,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable /** A view over a slice of the elements of this collection. */ @deprecated("Use .view.slice(from, until) instead of .view(from, until)", "2.13.0") - def view(from: Int, until: Int): View[A] = view.slice(from, until) + def view(from: Int, until: Int): View[A]^{this} = view.slice(from, until) /** Transposes this $coll of iterable collections into * a $coll of ${coll}s. @@ -378,7 +382,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @throws IllegalArgumentException if all collections in this $coll * are not of the same size. */ - def transpose[B](implicit asIterable: A => /*<: /*<: Boolean): C = fromSpecific(new View.Filter(this, pred, isFlipped = false)) + def filter(pred: A => Boolean): C^{this, pred} = fromSpecific(new View.Filter(this, pred, isFlipped = false)) - def filterNot(pred: A => Boolean): C = fromSpecific(new View.Filter(this, pred, isFlipped = true)) + def filterNot(pred: A => Boolean): C^{this, pred} = fromSpecific(new View.Filter(this, pred, isFlipped = true)) /** Creates a non-strict filter of this $coll. * @@ -417,7 +421,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * All these operations apply to those elements of this $coll * which satisfy the predicate `p`. */ - def withFilter(p: A => Boolean): collection.WithFilter[A, CC] = new IterableOps.WithFilter(this, p) + def withFilter(p: A => Boolean): collection.WithFilter[A, CC]^{this, p} = new IterableOps.WithFilter(this, p) /** A pair of, first, all elements that satisfy predicate `p` and, second, * all elements that do not. Interesting because it splits a collection in two. @@ -426,15 +430,15 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * Strict collections have an overridden version of `partition` in `StrictOptimizedIterableOps`, * which requires only a single traversal. */ - def partition(p: A => Boolean): (C, C) = { + def partition(p: A => Boolean): (C^{this, p}, C^{this, p}) = { val first = new View.Filter(this, p, false) val second = new View.Filter(this, p, true) (fromSpecific(first), fromSpecific(second)) } - override def splitAt(n: Int): (C, C) = (take(n), drop(n)) + override def splitAt(n: Int): (C^{this}, C^{this}) = (take(n), drop(n)) - def take(n: Int): C = fromSpecific(new View.Take(this, n)) + def take(n: Int): C^{this} = fromSpecific(new View.Take(this, n)) /** Selects the last ''n'' elements. * $orderDependent @@ -443,7 +447,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * or else the whole $coll, if it has less than `n` elements. * If `n` is negative, returns an empty $coll. */ - def takeRight(n: Int): C = fromSpecific(new View.TakeRight(this, n)) + def takeRight(n: Int): C^{this} = fromSpecific(new View.TakeRight(this, n)) /** Takes longest prefix of elements that satisfy a predicate. * $orderDependent @@ -451,11 +455,11 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @return the longest prefix of this $coll whose elements all satisfy * the predicate `p`. */ - def takeWhile(p: A => Boolean): C = fromSpecific(new View.TakeWhile(this, p)) + def takeWhile(p: A => Boolean): C^{this, p} = fromSpecific(new View.TakeWhile(this, p)) - def span(p: A => Boolean): (C, C) = (takeWhile(p), dropWhile(p)) + def span(p: A => Boolean): (C^{this, p}, C^{this, p}) = (takeWhile(p), dropWhile(p)) - def drop(n: Int): C = fromSpecific(new View.Drop(this, n)) + def drop(n: Int): C^{this} = fromSpecific(new View.Drop(this, n)) /** Selects all elements except last ''n'' ones. * $orderDependent @@ -464,9 +468,9 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * empty $coll, if this $coll has less than `n` elements. * If `n` is negative, don't drop any elements. */ - def dropRight(n: Int): C = fromSpecific(new View.DropRight(this, n)) + def dropRight(n: Int): C^{this} = fromSpecific(new View.DropRight(this, n)) - def dropWhile(p: A => Boolean): C = fromSpecific(new View.DropWhile(this, p)) + def dropWhile(p: A => Boolean): C^{this, p} = fromSpecific(new View.DropWhile(this, p)) /** Partitions elements in fixed size ${coll}s. * @see [[scala.collection.Iterator]], method `grouped` @@ -475,7 +479,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @return An iterator producing ${coll}s of size `size`, except the * last will be less than size `size` if the elements don't divide evenly. */ - def grouped(size: Int): Iterator[C] = + def grouped(size: Int): Iterator[C^{this}]^{this} = iterator.grouped(size).map(fromSpecific) /** Groups elements in fixed size blocks by passing a "sliding window" @@ -497,7 +501,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @example `List(1, 2).sliding(2) = Iterator(List(1, 2))` * @example `List(1, 2, 3).sliding(2) = Iterator(List(1, 2), List(2, 3))` */ - def sliding(size: Int): Iterator[C] = sliding(size, 1) + def sliding(size: Int): Iterator[C^{this}]^{this} = sliding(size, 1) /** Groups elements in fixed size blocks by passing a "sliding window" * over them (as opposed to partitioning them, as is done in grouped.) @@ -516,13 +520,13 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * element (which may be the only element) will be smaller * if there are fewer than `size` elements remaining to be grouped. * @example `List(1, 2, 3, 4, 5).sliding(2, 2) = Iterator(List(1, 2), List(3, 4), List(5))` - * @example `List(1, 2, 3, 4, 5, 6).sliding(2, 3) = Iterator(List(1, 2), List(4, 5))` + * @example `List(1, 2, 3, 4, 5, 6).sliding(2, 3) = Iterator(List(1, 2), List(4, 5))` */ - def sliding(size: Int, step: Int): Iterator[C] = + def sliding(size: Int, step: Int): Iterator[C^{this}]^{this} = iterator.sliding(size, step).map(fromSpecific) /** The rest of the collection without its first element. */ - def tail: C = { + def tail: C^{this} = { if (isEmpty) throw new UnsupportedOperationException drop(1) } @@ -530,12 +534,12 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable /** The initial part of the collection without its last element. * $willForceEvaluation */ - def init: C = { + def init: C^{this} = { if (isEmpty) throw new UnsupportedOperationException dropRight(1) } - def slice(from: Int, until: Int): C = + def slice(from: Int, until: Int): C^{this} = fromSpecific(new View.Drop(new View.Take(this, until), from)) /** Partitions this $coll into a map of ${coll}s according to some discriminator function. @@ -645,9 +649,9 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * * @return a new $coll containing the prefix scan of the elements in this $coll */ - def scan[B >: A](z: B)(op: (B, B) => B): CC[B] = scanLeft(z)(op) + def scan[B >: A](z: B)(op: (B, B) => B): CC[B]^{this, op} = scanLeft(z)(op) - def scanLeft[B](z: B)(op: (B, A) => B): CC[B] = iterableFactory.from(new View.ScanLeft(this, z, op)) + def scanLeft[B](z: B)(op: (B, A) => B): CC[B]^{this, op} = iterableFactory.from(new View.ScanLeft(this, z, op)) /** Produces a collection containing cumulative results of applying the operator going right to left. * The head of the collection is the last cumulative result. @@ -665,7 +669,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @param op the binary operator applied to the intermediate result and the element * @return collection with intermediate results */ - def scanRight[B](z: B)(op: (A, B) => B): CC[B] = { + def scanRight[B](z: B)(op: (A, B) => B): CC[B]^{this, op} = { class Scanner extends runtime.AbstractFunction1[A, Unit] { var acc = z var scanned = acc :: immutable.Nil @@ -679,13 +683,13 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable iterableFactory.from(scanner.scanned) } - def map[B](f: A => B): CC[B] = iterableFactory.from(new View.Map(this, f)) + def map[B](f: A => B): CC[B]^{this, f} = iterableFactory.from(new View.Map(this, f)) - def flatMap[B](f: A => IterableOnce[B]): CC[B] = iterableFactory.from(new View.FlatMap(this, f)) + def flatMap[B](f: A => IterableOnce[B]^): CC[B]^{this, f} = iterableFactory.from(new View.FlatMap(this, f)) - def flatten[B](implicit asIterable: A => IterableOnce[B]): CC[B] = flatMap(asIterable) + def flatten[B](implicit asIterable: A -> IterableOnce[B]): CC[B]^{this} = flatMap(asIterable) - def collect[B](pf: PartialFunction[A, B]): CC[B] = + def collect[B](pf: PartialFunction[A, B]^): CC[B]^{this, pf} = iterableFactory.from(new View.Collect(this, pf)) /** Applies a function `f` to each element of the $coll and returns a pair of ${coll}s: the first one @@ -706,12 +710,12 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @tparam A2 the element type of the second resulting collection * @param f the 'split function' mapping the elements of this $coll to an [[scala.util.Either]] * - * @return a pair of ${coll}s: the first one made of those values returned by `f` that were wrapped in [[scala.util.Left]], + * @return a pair of ${coll}s: the first one made of those values returned by `f` that were wrapped in [[scala.util.Left]], * and the second one made of those wrapped in [[scala.util.Right]]. */ - def partitionMap[A1, A2](f: A => Either[A1, A2]): (CC[A1], CC[A2]) = { - val left: View[A1] = new LeftPartitionMapped(this, f) - val right: View[A2] = new RightPartitionMapped(this, f) + def partitionMap[A1, A2](f: A => Either[A1, A2]): (CC[A1]^{this, f}, CC[A2]^{this, f}) = { + val left: View[A1]^{f, this} = new LeftPartitionMapped(this, f) + val right: View[A2]^{f, this} = new RightPartitionMapped(this, f) (iterableFactory.from(left), iterableFactory.from(right)) } @@ -724,13 +728,13 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @return a new $coll which contains all elements * of this $coll followed by all elements of `suffix`. */ - def concat[B >: A](suffix: IterableOnce[B]): CC[B] = iterableFactory.from(suffix match { + def concat[B >: A](suffix: IterableOnce[B]^): CC[B]^{this, suffix} = iterableFactory.from(suffix match { case xs: Iterable[B] => new View.Concat(this, xs) case xs => iterator ++ suffix.iterator }) /** Alias for `concat` */ - @`inline` final def ++ [B >: A](suffix: IterableOnce[B]): CC[B] = concat(suffix) + @`inline` final def ++ [B >: A](suffix: IterableOnce[B]^): CC[B]^{this, suffix} = concat(suffix) /** Returns a $coll formed from this $coll and another iterable collection * by combining corresponding elements in pairs. @@ -741,12 +745,12 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @return a new $coll containing pairs consisting of corresponding elements of this $coll and `that`. * The length of the returned collection is the minimum of the lengths of this $coll and `that`. */ - def zip[B](that: IterableOnce[B]): CC[(A @uncheckedVariance, B)] = iterableFactory.from(that match { // sound bcs of VarianceNote + def zip[B](that: IterableOnce[B]^): CC[(A @uncheckedVariance, B)]^{this, that} = iterableFactory.from(that match { // sound bcs of VarianceNote case that: Iterable[B] => new View.Zip(this, that) case _ => iterator.zip(that) }) - def zipWithIndex: CC[(A @uncheckedVariance, Int)] = iterableFactory.from(new View.ZipWithIndex(this)) + def zipWithIndex: CC[(A @uncheckedVariance, Int)]^{this} = iterableFactory.from(new View.ZipWithIndex(this)) /** Returns a $coll formed from this $coll and another iterable collection * by combining corresponding elements in pairs. @@ -762,7 +766,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * If this $coll is shorter than `that`, `thisElem` values are used to pad the result. * If `that` is shorter than this $coll, `thatElem` values are used to pad the result. */ - def zipAll[A1 >: A, B](that: Iterable[B], thisElem: A1, thatElem: B): CC[(A1, B)] = iterableFactory.from(new View.ZipAll(this, that, thisElem, thatElem)) + def zipAll[A1 >: A, B](that: Iterable[B]^, thisElem: A1, thatElem: B): CC[(A1, B)]^{this, that} = iterableFactory.from(new View.ZipAll(this, that, thisElem, thatElem)) /** Converts this $coll of pairs into two collections of the first and second * half of each pair. @@ -783,9 +787,9 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @return a pair of ${coll}s, containing the first, respectively second * half of each element pair of this $coll. */ - def unzip[A1, A2](implicit asPair: A => (A1, A2)): (CC[A1], CC[A2]) = { - val first: View[A1] = new View.Map[A, A1](this, asPair(_)._1) - val second: View[A2] = new View.Map[A, A2](this, asPair(_)._2) + def unzip[A1, A2](implicit asPair: A -> (A1, A2)): (CC[A1]^{this}, CC[A2]^{this}) = { + val first: View[A1]^{this} = new View.Map[A, A1](this, asPair(_)._1) + val second: View[A2]^{this} = new View.Map[A, A2](this, asPair(_)._2) (iterableFactory.from(first), iterableFactory.from(second)) } @@ -810,10 +814,10 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @return a triple of ${coll}s, containing the first, second, respectively * third member of each element triple of this $coll. */ - def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3)): (CC[A1], CC[A2], CC[A3]) = { - val first: View[A1] = new View.Map[A, A1](this, asTriple(_)._1) - val second: View[A2] = new View.Map[A, A2](this, asTriple(_)._2) - val third: View[A3] = new View.Map[A, A3](this, asTriple(_)._3) + def unzip3[A1, A2, A3](implicit asTriple: A -> (A1, A2, A3)): (CC[A1]^{this}, CC[A2]^{this}, CC[A3]^{this}) = { + val first: View[A1]^{this} = new View.Map[A, A1](this, asTriple(_)._1) + val second: View[A2]^{this} = new View.Map[A, A2](this, asTriple(_)._2) + val third: View[A3]^{this} = new View.Map[A, A3](this, asTriple(_)._3) (iterableFactory.from(first), iterableFactory.from(second), iterableFactory.from(third)) } @@ -824,7 +828,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @return an iterator over all the tails of this $coll * @example `List(1,2,3).tails = Iterator(List(1,2,3), List(2,3), List(3), Nil)` */ - def tails: Iterator[C] = iterateUntilEmpty(_.tail) + def tails: Iterator[C^{this}]^{this} = iterateUntilEmpty(_.tail) /** Iterates over the inits of this $coll. The first value will be this * $coll and the final one will be an empty $coll, with the intervening @@ -835,21 +839,24 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable * @return an iterator over all the inits of this $coll * @example `List(1,2,3).inits = Iterator(List(1,2,3), List(1,2), List(1), Nil)` */ - def inits: Iterator[C] = iterateUntilEmpty(_.init) + def inits: Iterator[C^{this}]^{this} = iterateUntilEmpty(_.init) - override def tapEach[U](f: A => U): C = fromSpecific(new View.Map(this, { (a: A) => f(a); a })) + override def tapEach[U](f: A => U): C^{this, f} = fromSpecific(new View.Map(this, { (a: A) => f(a); a })) // A helper for tails and inits. - private[this] def iterateUntilEmpty(f: Iterable[A] => Iterable[A]): Iterator[C] = { + private[this] def iterateUntilEmpty(f: Iterable[A]^{this} => Iterable[A]^{this}): Iterator[C^{this}]^{this, f} = { // toIterable ties the knot between `this: IterableOnceOps[A, CC, C]` and `this.tail: C` // `this.tail.tail` doesn't compile as `C` is unbounded // `Iterable.from(this)` would eagerly copy non-immutable collections - val it = Iterator.iterate(toIterable: @nowarn("cat=deprecation"))(f).takeWhile(_.nonEmpty) + val it = Iterator.iterate(toIterable: @nowarn("cat=deprecation"))(f) + .takeWhile((itble: Iterable[A]^) => itble.iterator.nonEmpty) + // CC TODO type annotation for itble needed. + // The previous code `.takeWhile(_.iterator.nonEmpty)` does not work. (it ++ Iterator.single(Iterable.empty)).map(fromSpecific) } @deprecated("Use ++ instead of ++: for collections of type Iterable", "2.13.0") - def ++:[B >: A](that: IterableOnce[B]): CC[B] = iterableFactory.from(that match { + def ++:[B >: A](that: IterableOnce[B]^): CC[B]^{this, that} = iterableFactory.from(that match { case xs: Iterable[B] => new View.Concat(xs, this) case _ => that.iterator ++ iterator }) @@ -862,7 +869,8 @@ object IterableOps { * These operations are implemented in terms of * [[scala.collection.IterableOps.sizeCompare(Int) `sizeCompare(Int)`]]. */ - final class SizeCompareOps private[collection](val it: IterableOps[_, AnyConstr, _]) extends AnyVal { + final class SizeCompareOps private[collection](val it: IterableOps[_, AnyConstr, _]^) extends AnyVal { + this: SizeCompareOps^{it} => /** Tests if the size of the collection is less than some value. */ @inline def <(size: Int): Boolean = it.sizeCompare(size) < 0 /** Tests if the size of the collection is less than or equal to some value. */ @@ -887,22 +895,22 @@ object IterableOps { */ @SerialVersionUID(3L) class WithFilter[+A, +CC[_]]( - self: IterableOps[A, CC, _], + self: IterableOps[A, CC, _]^, p: A => Boolean ) extends collection.WithFilter[A, CC] with Serializable { - protected def filtered: Iterable[A] = + protected def filtered: Iterable[A]^{this} = new View.Filter(self, p, isFlipped = false) - def map[B](f: A => B): CC[B] = + def map[B](f: A => B): CC[B]^{this, f} = self.iterableFactory.from(new View.Map(filtered, f)) - def flatMap[B](f: A => IterableOnce[B]): CC[B] = + def flatMap[B](f: A => IterableOnce[B]^): CC[B]^{this, f} = self.iterableFactory.from(new View.FlatMap(filtered, f)) def foreach[U](f: A => U): Unit = filtered.foreach(f) - def withFilter(q: A => Boolean): WithFilter[A, CC] = + def withFilter(q: A => Boolean): WithFilter[A, CC]^{this, q} = new WithFilter(self, (a: A) => p(a) && q(a)) } @@ -940,7 +948,7 @@ abstract class AbstractIterable[+A] extends Iterable[A] * same as `C`. */ trait IterableFactoryDefaults[+A, +CC[x] <: IterableOps[x, CC, CC[x]]] extends IterableOps[A, CC, CC[A @uncheckedVariance]] { - protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): CC[A @uncheckedVariance] = iterableFactory.from(coll) + protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]^): CC[A @uncheckedVariance]^{coll} = iterableFactory.from(coll) protected def newSpecificBuilder: Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = iterableFactory.newBuilder[A] // overridden for efficiency, since we know CC[A] =:= C @@ -958,7 +966,7 @@ trait IterableFactoryDefaults[+A, +CC[x] <: IterableOps[x, CC, CC[x]]] extends I trait EvidenceIterableFactoryDefaults[+A, +CC[x] <: IterableOps[x, CC, CC[x]], Ev[_]] extends IterableOps[A, CC, CC[A @uncheckedVariance]] { protected def evidenceIterableFactory: EvidenceIterableFactory[CC, Ev] implicit protected def iterableEvidence: Ev[A @uncheckedVariance] - override protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): CC[A @uncheckedVariance] = evidenceIterableFactory.from(coll) + override protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]^): CC[A @uncheckedVariance]^{coll} = evidenceIterableFactory.from(coll) override protected def newSpecificBuilder: Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = evidenceIterableFactory.newBuilder[A] override def empty: CC[A @uncheckedVariance] = evidenceIterableFactory.empty } @@ -980,11 +988,11 @@ trait SortedSetFactoryDefaults[+A, +WithFilterCC[x] <: IterableOps[x, WithFilterCC, WithFilterCC[x]] with Set[x]] extends SortedSetOps[A @uncheckedVariance, CC, CC[A @uncheckedVariance]] { self: IterableOps[A, WithFilterCC, _] => - override protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): CC[A @uncheckedVariance] = sortedIterableFactory.from(coll)(ordering) + override protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]^): CC[A @uncheckedVariance]^{coll} = sortedIterableFactory.from(coll)(ordering) override protected def newSpecificBuilder: mutable.Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = sortedIterableFactory.newBuilder[A](ordering) override def empty: CC[A @uncheckedVariance] = sortedIterableFactory.empty(ordering) - override def withFilter(p: A => Boolean): SortedSetOps.WithFilter[A, WithFilterCC, CC] = + override def withFilter(p: A => Boolean): SortedSetOps.WithFilter[A, WithFilterCC, CC]^{p} = new SortedSetOps.WithFilter[A, WithFilterCC, CC](this, p) } @@ -1004,7 +1012,8 @@ trait SortedSetFactoryDefaults[+A, trait MapFactoryDefaults[K, +V, +CC[x, y] <: IterableOps[(x, y), Iterable, Iterable[(x, y)]], +WithFilterCC[x] <: IterableOps[x, WithFilterCC, WithFilterCC[x]] with Iterable[x]] extends MapOps[K, V, CC, CC[K, V @uncheckedVariance]] with IterableOps[(K, V), WithFilterCC, CC[K, V @uncheckedVariance]] { - override protected def fromSpecific(coll: IterableOnce[(K, V @uncheckedVariance)]): CC[K, V @uncheckedVariance] = mapFactory.from(coll) + this: MapFactoryDefaults[K, V, CC, WithFilterCC] => + override protected def fromSpecific(coll: IterableOnce[(K, V @uncheckedVariance)]^): CC[K, V @uncheckedVariance]^{coll} = mapFactory.from(coll) override protected def newSpecificBuilder: mutable.Builder[(K, V @uncheckedVariance), CC[K, V @uncheckedVariance]] = mapFactory.newBuilder[K, V] override def empty: CC[K, V @uncheckedVariance] = (this: AnyRef) match { // Implemented here instead of in TreeSeqMap since overriding empty in TreeSeqMap is not forwards compatible (should be moved) @@ -1012,7 +1021,7 @@ trait MapFactoryDefaults[K, +V, case _ => mapFactory.empty } - override def withFilter(p: ((K, V)) => Boolean): MapOps.WithFilter[K, V, WithFilterCC, CC] = + override def withFilter(p: ((K, V)) => Boolean): MapOps.WithFilter[K, V, WithFilterCC, CC]^{p} = new MapOps.WithFilter[K, V, WithFilterCC, CC](this, p) } @@ -1035,9 +1044,9 @@ trait SortedMapFactoryDefaults[K, +V, self: IterableOps[(K, V), WithFilterCC, _] => override def empty: CC[K, V @uncheckedVariance] = sortedMapFactory.empty(ordering) - override protected def fromSpecific(coll: IterableOnce[(K, V @uncheckedVariance)]): CC[K, V @uncheckedVariance] = sortedMapFactory.from(coll)(ordering) + override protected def fromSpecific(coll: IterableOnce[(K, V @uncheckedVariance)]^): CC[K, V @uncheckedVariance]^{coll} = sortedMapFactory.from(coll)(ordering) override protected def newSpecificBuilder: mutable.Builder[(K, V @uncheckedVariance), CC[K, V @uncheckedVariance]] = sortedMapFactory.newBuilder[K, V](ordering) - override def withFilter(p: ((K, V)) => Boolean): collection.SortedMapOps.WithFilter[K, V, WithFilterCC, UnsortedCC, CC] = + override def withFilter(p: ((K, V)) => Boolean): collection.SortedMapOps.WithFilter[K, V, WithFilterCC, UnsortedCC, CC]^{p} = new collection.SortedMapOps.WithFilter[K, V, WithFilterCC, UnsortedCC, CC](this, p) } diff --git a/tests/pos-special/stdlib/collection/IterableOnce.scala b/tests/pos-special/stdlib/collection/IterableOnce.scala index 65d8dce08ae4..a88be4943c58 100644 --- a/tests/pos-special/stdlib/collection/IterableOnce.scala +++ b/tests/pos-special/stdlib/collection/IterableOnce.scala @@ -14,12 +14,13 @@ package scala package collection import scala.annotation.tailrec -import scala.annotation.unchecked.uncheckedVariance +import scala.annotation.unchecked.{uncheckedVariance, uncheckedCaptures} import scala.collection.mutable.StringBuilder import scala.language.implicitConversions import scala.math.{Numeric, Ordering} import scala.reflect.ClassTag import scala.runtime.AbstractFunction2 +import language.experimental.captureChecking /** * A template trait for collections which can be traversed either once only @@ -42,8 +43,10 @@ import scala.runtime.AbstractFunction2 * @define coll collection */ trait IterableOnce[+A] extends Any { + this: IterableOnce[A]^ => + /** Iterator can be used only once */ - def iterator: Iterator[A] + def iterator: Iterator[A]^{this} /** Returns a [[scala.collection.Stepper]] for the elements of this collection. * @@ -65,9 +68,9 @@ trait IterableOnce[+A] extends Any { * allow creating parallel streams, whereas bare Steppers can be converted only to sequential * streams. */ - def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S = { + def stepper[S <: Stepper[_]^{this}](implicit shape: StepperShape[A, S]): S = { import convert.impl._ - val s = shape.shape match { + val s: Any = shape.shape match { case StepperShape.IntShape => new IntIteratorStepper (iterator.asInstanceOf[Iterator[Int]]) case StepperShape.LongShape => new LongIteratorStepper (iterator.asInstanceOf[Iterator[Long]]) case StepperShape.DoubleShape => new DoubleIteratorStepper(iterator.asInstanceOf[Iterator[Double]]) @@ -84,7 +87,7 @@ trait IterableOnce[+A] extends Any { final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) extends AnyVal { @deprecated("Use .iterator.withFilter(...) instead", "2.13.0") - def withFilter(f: A => Boolean): Iterator[A] = it.iterator.withFilter(f) + def withFilter(f: A => Boolean): Iterator[A]^{f} = it.iterator.withFilter(f) @deprecated("Use .iterator.reduceLeftOption(...) instead", "2.13.0") def reduceLeftOption(f: (A, A) => A): Option[A] = it.iterator.reduceLeftOption(f) @@ -102,7 +105,7 @@ final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) ext def reduceRight(f: (A, A) => A): A = it.iterator.reduceRight(f) @deprecated("Use .iterator.maxBy(...) instead", "2.13.0") - def maxBy[B](f: A => B)(implicit cmp: Ordering[B]): A = it.iterator.maxBy(f) + def maxBy[B](f: A -> B)(implicit cmp: Ordering[B]): A = it.iterator.maxBy(f) @deprecated("Use .iterator.reduceLeft(...) instead", "2.13.0") def reduceLeft(f: (A, A) => A): A = it.iterator.reduceLeft(f) @@ -120,7 +123,7 @@ final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) ext def reduceOption(f: (A, A) => A): Option[A] = it.iterator.reduceOption(f) @deprecated("Use .iterator.minBy(...) instead", "2.13.0") - def minBy[B](f: A => B)(implicit cmp: Ordering[B]): A = it.iterator.minBy(f) + def minBy[B](f: A -> B)(implicit cmp: Ordering[B]): A = it.iterator.minBy(f) @deprecated("Use .iterator.size instead", "2.13.0") def size: Int = it.iterator.size @@ -132,7 +135,7 @@ final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) ext def collectFirst[B](f: PartialFunction[A, B]): Option[B] = it.iterator.collectFirst(f) @deprecated("Use .iterator.filter(...) instead", "2.13.0") - def filter(f: A => Boolean): Iterator[A] = it.iterator.filter(f) + def filter(f: A => Boolean): Iterator[A]^{f} = it.iterator.filter(f) @deprecated("Use .iterator.exists(...) instead", "2.13.0") def exists(f: A => Boolean): Boolean = it.iterator.exists(f) @@ -159,10 +162,10 @@ final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) ext def to[C1](factory: Factory[A, C1]): C1 = factory.fromSpecific(it) @deprecated("Use .iterator.to(ArrayBuffer) instead", "2.13.0") - def toBuffer[B >: A]: mutable.Buffer[B] = mutable.ArrayBuffer.from(it) + def toBuffer[sealed B >: A]: mutable.Buffer[B] = mutable.ArrayBuffer.from(it) @deprecated("Use .iterator.toArray", "2.13.0") - def toArray[B >: A: ClassTag]: Array[B] = it match { + def toArray[sealed B >: A: ClassTag]: Array[B] = it match { case it: Iterable[B] => it.toArray[B] case _ => it.iterator.toArray[B] } @@ -238,13 +241,13 @@ final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) ext @`inline` def :\ [B](z: B)(op: (A, B) => B): B = foldRight[B](z)(op) @deprecated("Use .iterator.map instead or consider requiring an Iterable", "2.13.0") - def map[B](f: A => B): IterableOnce[B] = it match { + def map[B](f: A => B): IterableOnce[B]^{f} = it match { case it: Iterable[A] => it.map(f) case _ => it.iterator.map(f) } @deprecated("Use .iterator.flatMap instead or consider requiring an Iterable", "2.13.0") - def flatMap[B](f: A => IterableOnce[B]): IterableOnce[B] = it match { + def flatMap[B](f: A => IterableOnce[B]^): IterableOnce[B]^{f} = it match { case it: Iterable[A] => it.flatMap(f) case _ => it.iterator.flatMap(f) } @@ -269,10 +272,11 @@ object IterableOnce { math.max(math.min(math.min(len, srcLen), destLen - start), 0) /** Calls `copyToArray` on the given collection, regardless of whether or not it is an `Iterable`. */ - @inline private[collection] def copyElemsToArray[A, B >: A](elems: IterableOnce[A], - xs: Array[B], - start: Int = 0, - len: Int = Int.MaxValue): Int = + @inline private[collection] def copyElemsToArray[A, sealed B >: A]( + elems: IterableOnce[A]^, + xs: Array[B], + start: Int = 0, + len: Int = Int.MaxValue): Int = elems match { case src: Iterable[A] => src.copyToArray[B](xs, start, len) case src => src.iterator.copyToArray[B](xs, start, len) @@ -315,9 +319,11 @@ object IterableOnce { * @define coll collection * */ -trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => +trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A]^ => /////////////////////////////////////////////////////////////// Abstract methods that must be implemented + import IterableOnceOps.Maximized + /** Produces a $coll containing cumulative results of applying the * operator going left to right, including the initial value. * @@ -329,7 +335,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @param op the binary operator applied to the intermediate result and the element * @return collection with intermediate results */ - def scanLeft[B](z: B)(op: (B, A) => B): CC[B] + def scanLeft[B](z: B)(op: (B, A) => B): CC[B]^{this, op} /** Selects all elements of this $coll which satisfy a predicate. * @@ -337,7 +343,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return a new $coll consisting of all elements of this $coll that satisfy the given * predicate `p`. The order of the elements is preserved. */ - def filter(p: A => Boolean): C + def filter(p: A => Boolean): C^{this, p} /** Selects all elements of this $coll which do not satisfy a predicate. * @@ -345,7 +351,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return a new $coll consisting of all elements of this $coll that do not satisfy the given * predicate `pred`. Their order may not be preserved. */ - def filterNot(pred: A => Boolean): C + def filterNot(p: A => Boolean): C^{this, p} /** Selects the first ''n'' elements. * $orderDependent @@ -354,7 +360,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * or else the whole $coll, if it has less than `n` elements. * If `n` is negative, returns an empty $coll. */ - def take(n: Int): C + def take(n: Int): C^{this} /** Takes longest prefix of elements that satisfy a predicate. * $orderDependent @@ -362,7 +368,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return the longest prefix of this $coll whose elements all satisfy * the predicate `p`. */ - def takeWhile(p: A => Boolean): C + def takeWhile(p: A => Boolean): C^{this, p} /** Selects all elements except first ''n'' ones. * $orderDependent @@ -371,7 +377,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * empty $coll, if this $coll has less than `n` elements. * If `n` is negative, don't drop any elements. */ - def drop(n: Int): C + def drop(n: Int): C^{this} /** Drops longest prefix of elements that satisfy a predicate. * $orderDependent @@ -379,7 +385,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return the longest suffix of this $coll whose first element * does not satisfy the predicate `p`. */ - def dropWhile(p: A => Boolean): C + def dropWhile(p: A => Boolean): C^{this, p} /** Selects an interval of elements. The returned $coll is made up * of all elements `x` which satisfy the invariant: @@ -394,7 +400,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * index `from` extending up to (but not including) index `until` * of this $coll. */ - def slice(from: Int, until: Int): C + def slice(from: Int, until: Int): C^{this} /** Builds a new $coll by applying a function to all elements of this $coll. * @@ -403,7 +409,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return a new $coll resulting from applying the given function * `f` to each element of this $coll and collecting the results. */ - def map[B](f: A => B): CC[B] + def map[B](f: A => B): CC[B]^{this, f} /** Builds a new $coll by applying a function to all elements of this $coll * and using the elements of the resulting collections. @@ -436,7 +442,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return a new $coll resulting from applying the given collection-valued function * `f` to each element of this $coll and concatenating the results. */ - def flatMap[B](f: A => IterableOnce[B]): CC[B] + def flatMap[B](f: A => IterableOnce[B]^): CC[B]^{this, f} /** Converts this $coll of iterable collections into * a $coll formed by the elements of these iterable @@ -464,7 +470,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * type of this $coll is an `Iterable`. * @return a new $coll resulting from concatenating all element ${coll}s. */ - def flatten[B](implicit asIterable: A => IterableOnce[B]): CC[B] + def flatten[B](implicit asIterable: A -> IterableOnce[B]): CC[B]^{this} /** Builds a new $coll by applying a partial function to all elements of this $coll * on which the function is defined. @@ -475,7 +481,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * `pf` to each element on which it is defined and collecting the results. * The order of the elements is preserved. */ - def collect[B](pf: PartialFunction[A, B]): CC[B] + def collect[B](pf: PartialFunction[A, B]^): CC[B]^{this, pf} /** Zips this $coll with its indices. * @@ -484,7 +490,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @example * `List("a", "b", "c").zipWithIndex == List(("a", 0), ("b", 1), ("c", 2))` */ - def zipWithIndex: CC[(A @uncheckedVariance, Int)] + def zipWithIndex: CC[(A @uncheckedVariance, Int)]^{this} /** Splits this $coll into a prefix/suffix pair according to a predicate. * @@ -497,7 +503,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return a pair consisting of the longest prefix of this $coll whose * elements all satisfy `p`, and the rest of this $coll. */ - def span(p: A => Boolean): (C, C) + def span(p: A => Boolean): (C^{this, p}, C^{this, p}) /** Splits this $coll into a prefix/suffix pair at a given position. * @@ -509,7 +515,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return a pair of ${coll}s consisting of the first `n` * elements of this $coll, and the other elements. */ - def splitAt(n: Int): (C, C) = { + def splitAt(n: Int): (C^{this}, C^{this}) = { class Spanner extends runtime.AbstractFunction1[A, Boolean] { var i = 0 def apply(a: A) = i < n && { i += 1 ; true } @@ -527,7 +533,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @tparam U the return type of f * @return The same logical collection as this */ - def tapEach[U](f: A => U): C + def tapEach[U](f: A => U): C^{this, f} /////////////////////////////////////////////////////////////// Concrete methods based on iterator @@ -802,7 +808,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => case _ => Some(reduceLeft(op)) } private final def reduceLeftOptionIterator[B >: A](op: (B, A) => B): Option[B] = reduceOptionIterator[A, B](iterator)(op) - private final def reduceOptionIterator[X >: A, B >: X](it: Iterator[X])(op: (B, X) => B): Option[B] = { + private final def reduceOptionIterator[X >: A, B >: X](it: Iterator[X]^)(op: (B, X) => B): Option[B] = { if (it.hasNext) { var acc: B = it.next() while (it.hasNext) @@ -884,7 +890,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @note Reuse: $consumesIterator */ @deprecatedOverriding("This should always forward to the 3-arg version of this method", since = "2.13.4") - def copyToArray[B >: A](xs: Array[B]): Int = copyToArray(xs, 0, Int.MaxValue) + def copyToArray[sealed B >: A](xs: Array[B]): Int = copyToArray(xs, 0, Int.MaxValue) /** Copy elements to an array, returning the number of elements written. * @@ -901,7 +907,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @note Reuse: $consumesIterator */ @deprecatedOverriding("This should always forward to the 3-arg version of this method", since = "2.13.4") - def copyToArray[B >: A](xs: Array[B], start: Int): Int = copyToArray(xs, start, Int.MaxValue) + def copyToArray[sealed B >: A](xs: Array[B], start: Int): Int = copyToArray(xs, start, Int.MaxValue) /** Copy elements to an array, returning the number of elements written. * @@ -918,7 +924,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * * @note Reuse: $consumesIterator */ - def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = { + def copyToArray[sealed B >: A](xs: Array[B], start: Int, len: Int): Int = { val it = iterator var i = start val end = start + math.min(len, xs.length - start) @@ -1041,35 +1047,12 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return the first element of this $coll with the largest value measured by function f * with respect to the ordering `cmp`. */ - def maxBy[B](f: A => B)(implicit ord: Ordering[B]): A = + def maxBy[B](f: A -> B)(implicit ord: Ordering[B]): A = knownSize match { case 0 => throw new UnsupportedOperationException("empty.maxBy") case _ => foldLeft(new Maximized[A, B]("maxBy")(f)(ord.gt))((m, a) => m(m, a)).result } - private class Maximized[X, B](descriptor: String)(f: X => B)(cmp: (B, B) => Boolean) extends AbstractFunction2[Maximized[X, B], X, Maximized[X, B]] { - var maxElem: X = null.asInstanceOf[X] - var maxF: B = null.asInstanceOf[B] - var nonEmpty = false - def toOption: Option[X] = if (nonEmpty) Some(maxElem) else None - def result: X = if (nonEmpty) maxElem else throw new UnsupportedOperationException(s"empty.$descriptor") - def apply(m: Maximized[X, B], a: X): Maximized[X, B] = - if (m.nonEmpty) { - val fa = f(a) - if (cmp(fa, maxF)) { - maxF = fa - maxElem = a - } - m - } - else { - m.nonEmpty = true - m.maxElem = a - m.maxF = f(a) - m - } - } - /** Finds the first element which yields the largest value measured by function f. * * $willNotTerminateInf @@ -1080,7 +1063,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return an option value containing the first element of this $coll with the * largest value measured by function f with respect to the ordering `cmp`. */ - def maxByOption[B](f: A => B)(implicit ord: Ordering[B]): Option[A] = + def maxByOption[B](f: A -> B)(implicit ord: Ordering[B]): Option[A] = knownSize match { case 0 => None case _ => foldLeft(new Maximized[A, B]("maxBy")(f)(ord.gt))((m, a) => m(m, a)).toOption @@ -1097,7 +1080,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * @return the first element of this $coll with the smallest value measured by function f * with respect to the ordering `cmp`. */ - def minBy[B](f: A => B)(implicit ord: Ordering[B]): A = + def minBy[B](f: A -> B)(implicit ord: Ordering[B]): A = knownSize match { case 0 => throw new UnsupportedOperationException("empty.minBy") case _ => foldLeft(new Maximized[A, B]("minBy")(f)(ord.lt))((m, a) => m(m, a)).result @@ -1114,7 +1097,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => * with the smallest value measured by function f * with respect to the ordering `cmp`. */ - def minByOption[B](f: A => B)(implicit ord: Ordering[B]): Option[A] = + def minByOption[B](f: A -> B)(implicit ord: Ordering[B]): Option[A] = knownSize match { case 0 => None case _ => foldLeft(new Maximized[A, B]("minBy")(f)(ord.lt))((m, a) => m(m, a)).toOption @@ -1310,7 +1293,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => def to[C1](factory: Factory[A, C1]): C1 = factory.fromSpecific(this) @deprecated("Use .iterator instead of .toIterator", "2.13.0") - @`inline` final def toIterator: Iterator[A] = iterator + @`inline` final def toIterator: Iterator[A]^{this} = iterator def toList: immutable.List[A] = immutable.List.from(this) @@ -1330,13 +1313,13 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => @deprecated("Use .to(LazyList) instead of .toStream", "2.13.0") @`inline` final def toStream: immutable.Stream[A] = to(immutable.Stream) - @`inline` final def toBuffer[B >: A]: mutable.Buffer[B] = mutable.Buffer.from(this) + @`inline` final def toBuffer[sealed B >: A]: mutable.Buffer[B] = mutable.Buffer.from(this) /** Convert collection to array. * * Implementation note: DO NOT call [[Array.from]] from this method. */ - def toArray[B >: A: ClassTag]: Array[B] = + def toArray[sealed B >: A: ClassTag]: Array[B] = if (knownSize >= 0) { val destination = new Array[B](knownSize) copyToArray(destination, 0) @@ -1352,3 +1335,31 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] => xs } } + +object IterableOnceOps: + + // Moved out of trait IterableOnceOps to here, since universal traits cannot + // have nested classes in Scala 3 + private class Maximized[X, B](descriptor: String)(f: X -> B)(cmp: (B, B) -> Boolean) extends AbstractFunction2[Maximized[X, B], X, Maximized[X, B]] { + var maxElem: X @uncheckedCaptures = null.asInstanceOf[X] + var maxF: B @uncheckedCaptures = null.asInstanceOf[B] + var nonEmpty = false + def toOption: Option[X] = if (nonEmpty) Some(maxElem) else None + def result: X = if (nonEmpty) maxElem else throw new UnsupportedOperationException(s"empty.$descriptor") + def apply(m: Maximized[X, B], a: X): Maximized[X, B] = + if (m.nonEmpty) { + val fa = f(a) + if (cmp(fa, maxF)) { + maxF = fa + maxElem = a + } + m + } + else { + m.nonEmpty = true + m.maxElem = a + m.maxF = f(a) + m + } + } +end IterableOnceOps \ No newline at end of file diff --git a/tests/pos-special/stdlib/collection/Iterator.scala b/tests/pos-special/stdlib/collection/Iterator.scala index 4b8338ed1b17..90fd387069b0 100644 --- a/tests/pos-special/stdlib/collection/Iterator.scala +++ b/tests/pos-special/stdlib/collection/Iterator.scala @@ -14,8 +14,11 @@ package scala.collection import scala.collection.mutable.{ArrayBuffer, ArrayBuilder, Builder, ImmutableBuilder} import scala.annotation.tailrec -import scala.annotation.unchecked.uncheckedVariance +import scala.annotation.unchecked.{uncheckedVariance, uncheckedCaptures} import scala.runtime.Statics +import language.experimental.captureChecking +import annotation.unchecked.uncheckedCaptures + /** Iterators are data structures that allow to iterate over a sequence * of elements. They have a `hasNext` method for checking @@ -71,7 +74,8 @@ import scala.runtime.Statics * iterators as well. * @define coll iterator */ -trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Iterator[A]] { self => +trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Iterator[A]] { + self: Iterator[A]^ => /** Check if there is a next element available. * @@ -93,7 +97,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite @throws[NoSuchElementException] def next(): A - @inline final def iterator = this + @inline final def iterator: Iterator[A]^{this} = this /** Wraps the value of `next()` in an option. * @@ -117,7 +121,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * @return a buffered iterator producing the same values as this iterator. * @note Reuse: $consumesAndProducesIterator */ - def buffered: BufferedIterator[A] = new AbstractIterator[A] with BufferedIterator[A] { + def buffered: BufferedIterator[A]^{this} = new AbstractIterator[A] with BufferedIterator[A] { private[this] var hd: A = _ private[this] var hdDefined: Boolean = false @@ -153,16 +157,16 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * A `GroupedIterator` is yielded by `grouped` and by `sliding`, * where the `step` may differ from the group `size`. */ - class GroupedIterator[B >: A](self: Iterator[B], size: Int, step: Int) extends AbstractIterator[immutable.Seq[B]] { + class GroupedIterator[B >: A](self: Iterator[B]^, size: Int, step: Int) extends AbstractIterator[immutable.Seq[B]] { require(size >= 1 && step >= 1, f"size=$size%d and step=$step%d, but both must be positive") - private[this] var buffer: Array[B] = null // current result - private[this] var prev: Array[B] = null // if sliding, overlap from previous result + private[this] var buffer: Array[B @uncheckedCaptures] = null // current result + private[this] var prev: Array[B @uncheckedCaptures] = null // if sliding, overlap from previous result private[this] var first = true // if !first, advancing may skip ahead private[this] var filled = false // whether the buffer is "hot" private[this] var partial = true // whether to emit partial sequence - private[this] var padding: () => B = null // what to pad short sequences with + private[this] var padding: () -> B @uncheckedCaptures = null // what to pad short sequences with private[this] def pad = padding != null // irrespective of partial flag private[this] def newBuilder = { val b = ArrayBuilder.make[Any] @@ -185,7 +189,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * @note This method is mutually exclusive with `withPartial`. * @group Configuration */ - def withPadding(x: => B): this.type = { + def withPadding(x: -> B): this.type = { padding = () => x partial = true // redundant, as padding always results in complete segment this @@ -254,7 +258,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite } // segment must have data, and must be complete unless they allow partial val ok = index > 0 && (partial || index == size) - if (ok) buffer = builder.result().asInstanceOf[Array[B]] + if (ok) buffer = builder.result().asInstanceOf[Array[B @uncheckedCaptures]] else prev = null ok } @@ -291,7 +295,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * all elements of this $coll followed by the minimal number of occurrences of `elem` so * that the resulting collection has a length of at least `len`. */ - def padTo[B >: A](len: Int, elem: B): Iterator[B] = new AbstractIterator[B] { + def padTo[B >: A](len: Int, elem: B): Iterator[B]^{this} = new AbstractIterator[B] { private[this] var i = 0 override def knownSize: Int = { @@ -321,7 +325,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * is the same as in the original iterator. * @note Reuse: $consumesOneAndProducesTwoIterators */ - def partition(p: A => Boolean): (Iterator[A], Iterator[A]) = { + def partition(p: A => Boolean): (Iterator[A]^{this, p}, Iterator[A]^{this, p}) = { val (a, b) = duplicate (a filter p, b filterNot p) } @@ -341,7 +345,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * * @note Reuse: $consumesAndProducesIterator */ - def grouped[B >: A](size: Int): GroupedIterator[B] = + def grouped[B >: A](size: Int): GroupedIterator[B]^{this} = new GroupedIterator[B](self, size, size) /** Returns an iterator which presents a "sliding window" view of @@ -377,13 +381,13 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * * @note Reuse: $consumesAndProducesIterator */ - def sliding[B >: A](size: Int, step: Int = 1): GroupedIterator[B] = + def sliding[B >: A](size: Int, step: Int = 1): GroupedIterator[B]^{this} = new GroupedIterator[B](self, size, step) - def scanLeft[B](z: B)(op: (B, A) => B): Iterator[B] = new AbstractIterator[B] { + def scanLeft[B](z: B)(op: (B, A) => B): Iterator[B]^{this, op} = new AbstractIterator[B] { // We use an intermediate iterator that iterates through the first element `z` // and then that will be modified to iterate through the collection - private[this] var current: Iterator[B] = + private[this] var current: Iterator[B]^{self, op} = new AbstractIterator[B] { override def knownSize = { val thisSize = self.knownSize @@ -412,7 +416,9 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite } @deprecated("Call scanRight on an Iterable instead.", "2.13.0") - def scanRight[B](z: B)(op: (A, B) => B): Iterator[B] = ArrayBuffer.from(this).scanRight(z)(op).iterator + def scanRight[B](z: B)(op: (A, B) => B): Iterator[B]^{this} = + ArrayBuffer.from[A @uncheckedCaptures](this).scanRight(z)(op).iterator + // @uncheckedCaptures is safe since the ArrayBuffer is local temporrary storage def indexWhere(p: A => Boolean, from: Int = 0): Int = { var i = math.max(from, 0) @@ -465,11 +471,11 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite @deprecatedOverriding("isEmpty is defined as !hasNext; override hasNext instead", "2.13.0") override def isEmpty: Boolean = !hasNext - def filter(p: A => Boolean): Iterator[A] = filterImpl(p, isFlipped = false) + def filter(p: A => Boolean): Iterator[A]^{this, p} = filterImpl(p, isFlipped = false) - def filterNot(p: A => Boolean): Iterator[A] = filterImpl(p, isFlipped = true) + def filterNot(p: A => Boolean): Iterator[A]^{this, p} = filterImpl(p, isFlipped = true) - private[collection] def filterImpl(p: A => Boolean, isFlipped: Boolean): Iterator[A] = new AbstractIterator[A] { + private[collection] def filterImpl(p: A => Boolean, isFlipped: Boolean): Iterator[A]^{this, p} = new AbstractIterator[A] { private[this] var hd: A = _ private[this] var hdDefined: Boolean = false @@ -479,9 +485,9 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite while (p(hd) == isFlipped) { if (!self.hasNext) return false hd = self.next() - } + } hdDefined = true - true + true } def next() = @@ -503,9 +509,9 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * @return an iterator which produces those values of this iterator which satisfy the predicate `p`. * @note Reuse: $consumesAndProducesIterator */ - def withFilter(p: A => Boolean): Iterator[A] = filter(p) + def withFilter(p: A => Boolean): Iterator[A]^{this, p} = filter(p) - def collect[B](pf: PartialFunction[A, B]): Iterator[B] = new AbstractIterator[B] with (A => B) { + def collect[B](pf: PartialFunction[A, B]^): Iterator[B]^{this, pf} = new AbstractIterator[B] with (A -> B) { // Manually buffer to avoid extra layer of wrapping with buffered private[this] var hd: B = _ @@ -541,7 +547,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * * @note Reuse: $consumesIterator */ - def distinct: Iterator[A] = distinctBy(identity) + def distinct: Iterator[A]^{this} = distinctBy(identity) /** * Builds a new iterator from this one without any duplicated elements as determined by `==` after applying @@ -553,9 +559,9 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * * @note Reuse: $consumesIterator */ - def distinctBy[B](f: A => B): Iterator[A] = new AbstractIterator[A] { + def distinctBy[B](f: A -> B): Iterator[A]^{this} = new AbstractIterator[A] { - private[this] val traversedValues = mutable.HashSet.empty[B] + private[this] val traversedValues = mutable.HashSet.empty[B @uncheckedCaptures] private[this] var nextElementDefined: Boolean = false private[this] var nextElement: A = _ @@ -578,14 +584,14 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite } } - def map[B](f: A => B): Iterator[B] = new AbstractIterator[B] { + def map[B](f: A => B): Iterator[B]^{this, f} = new AbstractIterator[B] { override def knownSize = self.knownSize def hasNext = self.hasNext def next() = f(self.next()) } - def flatMap[B](f: A => IterableOnce[B]): Iterator[B] = new AbstractIterator[B] { - private[this] var cur: Iterator[B] = Iterator.empty + def flatMap[B](f: A => IterableOnce[B]^): Iterator[B]^{this, f} = new AbstractIterator[B] { + private[this] var cur: Iterator[B]^{f} = Iterator.empty /** Trillium logic boolean: -1 = unknown, 0 = false, 1 = true */ private[this] var _hasNext: Int = -1 @@ -619,19 +625,19 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite } } - def flatten[B](implicit ev: A => IterableOnce[B]): Iterator[B] = + def flatten[B](implicit ev: A -> IterableOnce[B]): Iterator[B]^{this} = flatMap[B](ev) - def concat[B >: A](xs: => IterableOnce[B]): Iterator[B] = new Iterator.ConcatIterator[B](self).concat(xs) + def concat[B >: A](xs: => IterableOnce[B]^): Iterator[B]^{this, xs} = new Iterator.ConcatIterator[B](self).concat(xs) - @`inline` final def ++ [B >: A](xs: => IterableOnce[B]): Iterator[B] = concat(xs) + @`inline` final def ++ [B >: A](xs: => IterableOnce[B]^): Iterator[B]^{this, xs} = concat(xs) - def take(n: Int): Iterator[A] = sliceIterator(0, n max 0) + def take(n: Int): Iterator[A]^{this} = sliceIterator(0, n max 0) - def takeWhile(p: A => Boolean): Iterator[A] = new AbstractIterator[A] { + def takeWhile(p: A => Boolean): Iterator[A]^{self, p} = new AbstractIterator[A] { private[this] var hd: A = _ private[this] var hdDefined: Boolean = false - private[this] var tail: Iterator[A] = self + private[this] var tail: Iterator[A]^{self} = self def hasNext = hdDefined || tail.hasNext && { hd = tail.next() @@ -642,9 +648,9 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite def next() = if (hasNext) { hdDefined = false; hd } else Iterator.empty.next() } - def drop(n: Int): Iterator[A] = sliceIterator(n, -1) + def drop(n: Int): Iterator[A]^{this} = sliceIterator(n, -1) - def dropWhile(p: A => Boolean): Iterator[A] = new AbstractIterator[A] { + def dropWhile(p: A => Boolean): Iterator[A]^{this, p} = new AbstractIterator[A] { // Magic value: -1 = hasn't dropped, 0 = found first, 1 = defer to parent iterator private[this] var status = -1 // Local buffering to avoid double-wrap with .buffered @@ -680,7 +686,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * * @note Reuse: $consumesOneAndProducesTwoIterators */ - def span(p: A => Boolean): (Iterator[A], Iterator[A]) = { + def span(p: A => Boolean): (Iterator[A]^{this, p}, Iterator[A]^{this, p}) = { /* * Giving a name to following iterator (as opposed to trailing) because * anonymous class is represented as a structural type that trailing @@ -698,7 +704,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite */ private[this] var status = 0 private def store(a: A): Unit = { - if (lookahead == null) lookahead = new mutable.Queue[A] + if (lookahead == null) lookahead = new mutable.Queue[A @uncheckedCaptures] lookahead += a } def hasNext = { @@ -779,10 +785,10 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite (leading, trailing) } - def slice(from: Int, until: Int): Iterator[A] = sliceIterator(from, until max 0) + def slice(from: Int, until: Int): Iterator[A]^{this} = sliceIterator(from, until max 0) /** Creates an optionally bounded slice, unbounded if `until` is negative. */ - protected def sliceIterator(from: Int, until: Int): Iterator[A] = { + protected def sliceIterator(from: Int, until: Int): Iterator[A]^{this} = { val lo = from max 0 val rest = if (until < 0) -1 // unbounded @@ -793,14 +799,14 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite else new Iterator.SliceIterator(this, lo, rest) } - def zip[B](that: IterableOnce[B]): Iterator[(A, B)] = new AbstractIterator[(A, B)] { + def zip[B](that: IterableOnce[B]^): Iterator[(A, B)]^{this, that} = new AbstractIterator[(A, B)] { val thatIterator = that.iterator override def knownSize = self.knownSize min thatIterator.knownSize def hasNext = self.hasNext && thatIterator.hasNext def next() = (self.next(), thatIterator.next()) } - def zipAll[A1 >: A, B](that: IterableOnce[B], thisElem: A1, thatElem: B): Iterator[(A1, B)] = new AbstractIterator[(A1, B)] { + def zipAll[A1 >: A, B](that: IterableOnce[B]^, thisElem: A1, thatElem: B): Iterator[(A1, B)]^{this, that} = new AbstractIterator[(A1, B)] { val thatIterator = that.iterator override def knownSize = { val thisSize = self.knownSize @@ -817,7 +823,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite } } - def zipWithIndex: Iterator[(A, Int)] = new AbstractIterator[(A, Int)] { + def zipWithIndex: Iterator[(A, Int)]^{this} = new AbstractIterator[(A, Int)] { var idx = 0 override def knownSize = self.knownSize def hasNext = self.hasNext @@ -837,7 +843,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * * @inheritdoc */ - def sameElements[B >: A](that: IterableOnce[B]): Boolean = { + def sameElements[B >: A](that: IterableOnce[B]^): Boolean = { val those = that.iterator while (hasNext && those.hasNext) if (next() != those.next()) @@ -860,9 +866,9 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * iterated by one iterator but not yet by the other. * @note Reuse: $consumesOneAndProducesTwoIterators */ - def duplicate: (Iterator[A], Iterator[A]) = { - val gap = new scala.collection.mutable.Queue[A] - var ahead: Iterator[A] = null + def duplicate: (Iterator[A]^{this}, Iterator[A]^{this}) = { + val gap = new scala.collection.mutable.Queue[A @uncheckedCaptures] + var ahead: Iterator[A @uncheckedCaptures] = null // ahead is captured by Partner, so A is not recognized as parametric class Partner extends AbstractIterator[A] { override def knownSize: Int = self.synchronized { val thisSize = self.knownSize @@ -904,7 +910,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite * @param replaced The number of values in the original iterator that are replaced by the patch. * @note Reuse: $consumesTwoAndProducesOneIterator */ - def patch[B >: A](from: Int, patchElems: Iterator[B], replaced: Int): Iterator[B] = + def patch[B >: A](from: Int, patchElems: Iterator[B]^, replaced: Int): Iterator[B]^{this, patchElems} = new AbstractIterator[B] { private[this] var origElems = self // > 0 => that many more elems from `origElems` before switching to `patchElems` @@ -944,7 +950,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite } } - override def tapEach[U](f: A => U): Iterator[A] = new AbstractIterator[A] { + override def tapEach[U](f: A => U): Iterator[A]^{this, f} = new AbstractIterator[A] { override def knownSize = self.knownSize override def hasNext = self.hasNext override def next() = { @@ -981,7 +987,7 @@ object Iterator extends IterableFactory[Iterator] { * @tparam A the type of the collection’s elements * @return a new $coll with the elements of `source` */ - override def from[A](source: IterableOnce[A]): Iterator[A] = source.iterator + override def from[A](source: IterableOnce[A]^): Iterator[A]^{source} = source.iterator /** The iterator which produces no values. */ @`inline` final def empty[T]: Iterator[T] = _empty @@ -1012,7 +1018,7 @@ object Iterator extends IterableFactory[Iterator] { * @param elem the element computation * @return An iterator that produces the results of `n` evaluations of `elem`. */ - override def fill[A](len: Int)(elem: => A): Iterator[A] = new AbstractIterator[A] { + override def fill[A](len: Int)(elem: => A): Iterator[A]^{elem} = new AbstractIterator[A] { private[this] var i = 0 override def knownSize: Int = (len - i) max 0 def hasNext: Boolean = i < len @@ -1027,7 +1033,7 @@ object Iterator extends IterableFactory[Iterator] { * @param f The function computing element values * @return An iterator that produces the values `f(0), ..., f(n -1)`. */ - override def tabulate[A](end: Int)(f: Int => A): Iterator[A] = new AbstractIterator[A] { + override def tabulate[A](end: Int)(f: Int => A): Iterator[A]^{f} = new AbstractIterator[A] { private[this] var i = 0 override def knownSize: Int = (end - i) max 0 def hasNext: Boolean = i < end @@ -1100,7 +1106,7 @@ object Iterator extends IterableFactory[Iterator] { * @param f the function that's repeatedly applied * @return the iterator producing the infinite sequence of values `start, f(start), f(f(start)), ...` */ - def iterate[T](start: T)(f: T => T): Iterator[T] = new AbstractIterator[T] { + def iterate[T](start: T)(f: T => T): Iterator[T]^{f} = new AbstractIterator[T] { private[this] var first = true private[this] var acc = start def hasNext: Boolean = true @@ -1122,7 +1128,7 @@ object Iterator extends IterableFactory[Iterator] { * @tparam S Type of the internal state * @return an Iterator that produces elements using `f` until `f` returns `None` */ - override def unfold[A, S](init: S)(f: S => Option[(A, S)]): Iterator[A] = new UnfoldIterator(init)(f) + override def unfold[A, S](init: S)(f: S => Option[(A, S)]): Iterator[A]^{f} = new UnfoldIterator(init)(f) /** Creates an infinite-length iterator returning the results of evaluating an expression. * The expression is recomputed for every element. @@ -1130,7 +1136,7 @@ object Iterator extends IterableFactory[Iterator] { * @param elem the element computation. * @return the iterator containing an infinite number of results of evaluating `elem`. */ - def continually[A](elem: => A): Iterator[A] = new AbstractIterator[A] { + def continually[A](elem: => A): Iterator[A]^{elem} = new AbstractIterator[A] { def hasNext = true def next() = elem } @@ -1138,9 +1144,10 @@ object Iterator extends IterableFactory[Iterator] { /** Creates an iterator to which other iterators can be appended efficiently. * Nested ConcatIterators are merged to avoid blowing the stack. */ - private final class ConcatIterator[+A](private var current: Iterator[A @uncheckedVariance]) extends AbstractIterator[A] { - private var tail: ConcatIteratorCell[A @uncheckedVariance] = null - private var last: ConcatIteratorCell[A @uncheckedVariance] = null + private final class ConcatIterator[+A](val from: Iterator[A]^) extends AbstractIterator[A] { + private var current: Iterator[A @uncheckedCaptures]^{cap[ConcatIterator]} = from + private var tail: ConcatIteratorCell[A @uncheckedVariance @uncheckedCaptures] = null + private var last: ConcatIteratorCell[A @uncheckedVariance @uncheckedCaptures] = null private var currentHasNextChecked = false def hasNext = @@ -1194,8 +1201,8 @@ object Iterator extends IterableFactory[Iterator] { current.next() } else Iterator.empty.next() - override def concat[B >: A](that: => IterableOnce[B]): Iterator[B] = { - val c = new ConcatIteratorCell[B](that, null).asInstanceOf[ConcatIteratorCell[A]] + override def concat[B >: A](that: => IterableOnce[B]^): Iterator[B]^{this, that} = { + val c: ConcatIteratorCell[A] = new ConcatIteratorCell[B](that, null).asInstanceOf if (tail == null) { tail = c last = c @@ -1209,14 +1216,14 @@ object Iterator extends IterableFactory[Iterator] { } } - private[this] final class ConcatIteratorCell[A](head: => IterableOnce[A], var tail: ConcatIteratorCell[A]) { - def headIterator: Iterator[A] = head.iterator + private[this] final class ConcatIteratorCell[A](head: => IterableOnce[A]^, var tail: ConcatIteratorCell[A @uncheckedCaptures]) { + def headIterator: Iterator[A]^{this} = head.iterator // CC todo: can't use {head} as capture set, gives "cannot establish a reference" } /** Creates a delegating iterator capped by a limit count. Negative limit means unbounded. * Lazily skip to start on first evaluation. Avoids daisy-chained iterators due to slicing. */ - private[scala] final class SliceIterator[A](val underlying: Iterator[A], start: Int, limit: Int) extends AbstractIterator[A] { + private[scala] final class SliceIterator[A](val underlying: Iterator[A]^, start: Int, limit: Int) extends AbstractIterator[A] { private[this] var remaining = limit private[this] var dropping = start @inline private def unbounded = remaining < 0 @@ -1247,7 +1254,7 @@ object Iterator extends IterableFactory[Iterator] { else if (unbounded) underlying.next() else empty.next() } - override protected def sliceIterator(from: Int, until: Int): Iterator[A] = { + override protected def sliceIterator(from: Int, until: Int): Iterator[A]^{underlying} = { val lo = from max 0 def adjustedBound = if (unbounded) -1 @@ -1269,9 +1276,9 @@ object Iterator extends IterableFactory[Iterator] { /** Creates an iterator that uses a function `f` to produce elements of * type `A` and update an internal state of type `S`. */ - private final class UnfoldIterator[A, S](init: S)(f: S => Option[(A, S)]) extends AbstractIterator[A] { - private[this] var state: S = init - private[this] var nextResult: Option[(A, S)] = null + private final class UnfoldIterator[A, S](init: S)(f: S => Option[(A, S)])extends AbstractIterator[A] { + private[this] var state: S @uncheckedCaptures = init + private[this] var nextResult: Option[(A, S)] @uncheckedCaptures = null override def hasNext: Boolean = { if (nextResult eq null) { @@ -1297,4 +1304,5 @@ object Iterator extends IterableFactory[Iterator] { } /** Explicit instantiation of the `Iterator` trait to reduce class file size in subclasses. */ -abstract class AbstractIterator[+A] extends Iterator[A] +abstract class AbstractIterator[+A] extends Iterator[A]: + this: Iterator[A]^ => diff --git a/tests/pos-special/stdlib/collection/JavaConverters.scala b/tests/pos-special/stdlib/collection/JavaConverters.scala index 569e4e8c60a7..69130eae1829 100644 --- a/tests/pos-special/stdlib/collection/JavaConverters.scala +++ b/tests/pos-special/stdlib/collection/JavaConverters.scala @@ -17,6 +17,7 @@ import java.{lang => jl, util => ju} import scala.collection.convert._ import scala.language.implicitConversions +import language.experimental.captureChecking /** A variety of decorators that enable converting between * Scala and Java collections using extension methods, `asScala` and `asJava`. diff --git a/tests/pos-special/stdlib/collection/LazyZipOps.scala b/tests/pos-special/stdlib/collection/LazyZipOps.scala index 0553eb8edf7f..1bb4173d219f 100644 --- a/tests/pos-special/stdlib/collection/LazyZipOps.scala +++ b/tests/pos-special/stdlib/collection/LazyZipOps.scala @@ -13,6 +13,7 @@ package scala.collection import scala.language.implicitConversions +import language.experimental.captureChecking /** Decorator representing lazily zipped pairs. * @@ -21,7 +22,7 @@ import scala.language.implicitConversions * * Note: will not terminate for infinite-sized collections. */ -final class LazyZip2[+El1, +El2, C1] private[collection](src: C1, coll1: Iterable[El1], coll2: Iterable[El2]) { +final class LazyZip2[+El1, +El2, C1] private[collection](src: C1, coll1: Iterable[El1]^, coll2: Iterable[El2]^) { /** Zips `that` iterable collection with an existing `LazyZip2`. The elements in each collection are * not consumed until a strict operation is invoked on the returned `LazyZip3` decorator. @@ -31,7 +32,7 @@ final class LazyZip2[+El1, +El2, C1] private[collection](src: C1, coll1: Iterabl * @return a decorator `LazyZip3` that allows strict operations to be performed on the lazily evaluated tuples or * chained calls to `lazyZip`. Implicit conversion to `Iterable[(El1, El2, B)]` is also supported. */ - def lazyZip[B](that: Iterable[B]): LazyZip3[El1, El2, B, C1] = new LazyZip3(src, coll1, coll2, that) + def lazyZip[B](that: Iterable[B]^): LazyZip3[El1, El2, B, C1]^{this, that} = new LazyZip3(src, coll1, coll2, that) def map[B, C](f: (El1, El2) => B)(implicit bf: BuildFrom[C1, B, C]): C = { bf.fromSpecific(src)(new AbstractView[B] { @@ -147,9 +148,9 @@ object LazyZip2 { * Note: will not terminate for infinite-sized collections. */ final class LazyZip3[+El1, +El2, +El3, C1] private[collection](src: C1, - coll1: Iterable[El1], - coll2: Iterable[El2], - coll3: Iterable[El3]) { + coll1: Iterable[El1]^, + coll2: Iterable[El2]^, + coll3: Iterable[El3]^) { /** Zips `that` iterable collection with an existing `LazyZip3`. The elements in each collection are * not consumed until a strict operation is invoked on the returned `LazyZip4` decorator. @@ -159,7 +160,7 @@ final class LazyZip3[+El1, +El2, +El3, C1] private[collection](src: C1, * @return a decorator `LazyZip4` that allows strict operations to be performed on the lazily evaluated tuples. * Implicit conversion to `Iterable[(El1, El2, El3, B)]` is also supported. */ - def lazyZip[B](that: Iterable[B]): LazyZip4[El1, El2, El3, B, C1] = new LazyZip4(src, coll1, coll2, coll3, that) + def lazyZip[B](that: Iterable[B]^): LazyZip4[El1, El2, El3, B, C1]^{this, that} = new LazyZip4(src, coll1, coll2, coll3, that) def map[B, C](f: (El1, El2, El3) => B)(implicit bf: BuildFrom[C1, B, C]): C = { bf.fromSpecific(src)(new AbstractView[B] { @@ -288,10 +289,10 @@ object LazyZip3 { * Note: will not terminate for infinite-sized collections. */ final class LazyZip4[+El1, +El2, +El3, +El4, C1] private[collection](src: C1, - coll1: Iterable[El1], - coll2: Iterable[El2], - coll3: Iterable[El3], - coll4: Iterable[El4]) { + coll1: Iterable[El1]^, + coll2: Iterable[El2]^, + coll3: Iterable[El3]^, + coll4: Iterable[El4]^) { def map[B, C](f: (El1, El2, El3, El4) => B)(implicit bf: BuildFrom[C1, B, C]): C = { bf.fromSpecific(src)(new AbstractView[B] { diff --git a/tests/pos-special/stdlib/collection/LinearSeq.scala b/tests/pos-special/stdlib/collection/LinearSeq.scala index 449d58c866e3..393f5fda4187 100644 --- a/tests/pos-special/stdlib/collection/LinearSeq.scala +++ b/tests/pos-special/stdlib/collection/LinearSeq.scala @@ -14,6 +14,7 @@ package scala package collection import scala.annotation.{nowarn, tailrec} +import language.experimental.captureChecking /** Base trait for linearly accessed sequences that have efficient `head` and * `tail` operations. @@ -32,7 +33,7 @@ trait LinearSeq[+A] extends Seq[A] object LinearSeq extends SeqFactory.Delegate[LinearSeq](immutable.LinearSeq) /** Base trait for linear Seq operations */ -trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeqOps[A, CC, C]] extends Any with SeqOps[A, CC, C] { +trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeqOps[A, CC, C]] extends AnyRef with SeqOps[A, CC, C] { /** @inheritdoc * @@ -96,7 +97,7 @@ trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeq else loop(0, coll) } - override def lengthCompare(that: Iterable[_]): Int = { + override def lengthCompare(that: Iterable[_]^): Int = { val thatKnownSize = that.knownSize if (thatKnownSize >= 0) this lengthCompare thatKnownSize @@ -186,7 +187,7 @@ trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeq acc } - override def sameElements[B >: A](that: IterableOnce[B]): Boolean = { + override def sameElements[B >: A](that: IterableOnce[B]^): Boolean = { @tailrec def linearSeqEq(a: LinearSeq[B], b: LinearSeq[B]): Boolean = (a eq b) || { if (a.nonEmpty && b.nonEmpty && a.head == b.head) { @@ -259,7 +260,7 @@ trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeq } } -trait StrictOptimizedLinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with StrictOptimizedLinearSeqOps[A, CC, C]] extends Any with LinearSeqOps[A, CC, C] with StrictOptimizedSeqOps[A, CC, C] { +trait StrictOptimizedLinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with StrictOptimizedLinearSeqOps[A, CC, C]] extends AnyRef with LinearSeqOps[A, CC, C] with StrictOptimizedSeqOps[A, CC, C] { // A more efficient iterator implementation than the default LinearSeqIterator override def iterator: Iterator[A] = new AbstractIterator[A] { private[this] var current = StrictOptimizedLinearSeqOps.this diff --git a/tests/pos-special/stdlib/collection/Map.scala b/tests/pos-special/stdlib/collection/Map.scala index 0fb6df9a06dc..8ab25a3c13e0 100644 --- a/tests/pos-special/stdlib/collection/Map.scala +++ b/tests/pos-special/stdlib/collection/Map.scala @@ -17,13 +17,16 @@ import scala.annotation.nowarn import scala.collection.generic.DefaultSerializable import scala.collection.mutable.StringBuilder import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking +import caps.unsafe.unsafeAssumePure /** Base Map type */ trait Map[K, +V] extends Iterable[(K, V)] with MapOps[K, V, Map, Map[K, V]] with MapFactoryDefaults[K, V, Map, Iterable] - with Equals { + with Equals + with Pure { def mapFactory: scala.collection.MapFactory[Map] = Map @@ -101,8 +104,9 @@ trait Map[K, +V] trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C] extends IterableOps[(K, V), Iterable, C] with PartialFunction[K, V] { + this: MapOps[K, V, CC, C]^ => - override def view: MapView[K, V] = new MapView.Id(this) + override def view: MapView[K, V]^{this} = new MapView.Id(this) /** Returns a [[Stepper]] for the keys of this map. See method [[stepper]]. */ def keyStepper[S <: Stepper[_]](implicit shape: StepperShape[K, S]): S = { @@ -131,7 +135,7 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C] /** Similar to `fromIterable`, but returns a Map collection type. * Note that the return type is now `CC[K2, V2]`. */ - @`inline` protected final def mapFromIterable[K2, V2](it: Iterable[(K2, V2)]): CC[K2, V2] = mapFactory.from(it) + @`inline` protected final def mapFromIterable[K2, V2](it: Iterable[(K2, V2)]^): CC[K2, V2] = mapFactory.from(it) /** The companion object of this map, providing various factory methods. * @@ -251,7 +255,7 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C] * the predicate `p`. The resulting map wraps the original map without copying any elements. */ @deprecated("Use .view.filterKeys(f). A future version will include a strict version of this method (for now, .view.filterKeys(p).toMap).", "2.13.0") - def filterKeys(p: K => Boolean): MapView[K, V] = new MapView.FilterKeys(this, p) + def filterKeys(p: K => Boolean): MapView[K, V]^{this, p} = new MapView.FilterKeys(this, p) /** Transforms this map by applying a function to every retrieved value. * @param f the function used to transform values of this map. @@ -259,7 +263,7 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C] * to `f(this(key))`. The resulting map wraps the original map without copying any elements. */ @deprecated("Use .view.mapValues(f). A future version will include a strict version of this method (for now, .view.mapValues(f).toMap).", "2.13.0") - def mapValues[W](f: V => W): MapView[K, W] = new MapView.MapValues(this, f) + def mapValues[W](f: V => W): MapView[K, W]^{this, f} = new MapView.MapValues(this, f) /** Defines the default value computation for the map, * returned when a key is not found @@ -318,7 +322,7 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C] * @return a new $coll resulting from applying the given collection-valued function * `f` to each element of this $coll and concatenating the results. */ - def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = mapFactory.from(new View.FlatMap(this, f)) + def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]^): CC[K2, V2] = mapFactory.from(new View.FlatMap(this, f)) /** Returns a new $coll containing the elements from the left hand operand followed by the elements from the * right hand operand. The element type of the $coll is the most specific superclass encompassing @@ -328,7 +332,7 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C] * @return a new $coll which contains all elements * of this $coll followed by all elements of `suffix`. */ - def concat[V2 >: V](suffix: collection.IterableOnce[(K, V2)]): CC[K, V2] = mapFactory.from(suffix match { + def concat[V2 >: V](suffix: collection.IterableOnce[(K, V2)]^): CC[K, V2] = mapFactory.from(suffix match { case it: Iterable[(K, V2)] => new View.Concat(this, it) case _ => iterator.concat(suffix.iterator) }) @@ -336,7 +340,7 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C] // Not final because subclasses refine the result type, e.g. in SortedMap, the result type is // SortedMap's CC, while Map's CC is fixed to Map /** Alias for `concat` */ - /*@`inline` final*/ def ++ [V2 >: V](xs: collection.IterableOnce[(K, V2)]): CC[K, V2] = concat(xs) + /*@`inline` final*/ def ++ [V2 >: V](xs: collection.IterableOnce[(K, V2)]^): CC[K, V2] = concat(xs) override def addString(sb: StringBuilder, start: String, sep: String, end: String): sb.type = iterator.map { case (k, v) => s"$k -> $v" }.addString(sb, start, sep, end) @@ -350,14 +354,14 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C] mapFactory.from(new View.Concat(new View.Appended(new View.Appended(this, elem1), elem2), elems)) @deprecated("Consider requiring an immutable Map.", "2.13.0") - @`inline` def -- (keys: IterableOnce[K]): C = { + @`inline` def -- (keys: IterableOnce[K]^): C = { lazy val keysSet = keys.iterator.to(immutable.Set) - fromSpecific(this.view.filterKeys(k => !keysSet.contains(k))) + fromSpecific(this.view.filterKeys(k => !keysSet.contains(k))).unsafeAssumePure } @deprecated("Use ++ instead of ++: for collections of type Iterable", "2.13.0") - def ++: [V1 >: V](that: IterableOnce[(K,V1)]): CC[K,V1] = { - val thatIterable: Iterable[(K, V1)] = that match { + def ++: [V1 >: V](that: IterableOnce[(K,V1)]^): CC[K,V1] = { + val thatIterable: Iterable[(K, V1)]^{that} = that match { case that: Iterable[(K, V1)] => that case that => View.from(that) } @@ -373,17 +377,17 @@ object MapOps { */ @SerialVersionUID(3L) class WithFilter[K, +V, +IterableCC[_], +CC[_, _] <: IterableOps[_, AnyConstr, _]]( - self: MapOps[K, V, CC, _] with IterableOps[(K, V), IterableCC, _], + self: (MapOps[K, V, CC, _] with IterableOps[(K, V), IterableCC, _])^, p: ((K, V)) => Boolean ) extends IterableOps.WithFilter[(K, V), IterableCC](self, p) with Serializable { - def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = + def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2]^{this, f} = self.mapFactory.from(new View.Map(filtered, f)) - def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = + def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]^): CC[K2, V2]^{this, f} = self.mapFactory.from(new View.FlatMap(filtered, f)) - override def withFilter(q: ((K, V)) => Boolean): WithFilter[K, V, IterableCC, CC] = + override def withFilter(q: ((K, V)) => Boolean): WithFilter[K, V, IterableCC, CC]^{this, q} = new WithFilter[K, V, IterableCC, CC](self, (kv: (K, V)) => p(kv) && q(kv)) } diff --git a/tests/pos-special/stdlib/collection/MapView.scala b/tests/pos-special/stdlib/collection/MapView.scala index 7f84178a7c16..ac9e88466052 100644 --- a/tests/pos-special/stdlib/collection/MapView.scala +++ b/tests/pos-special/stdlib/collection/MapView.scala @@ -15,54 +15,57 @@ package scala.collection import scala.annotation.nowarn import scala.collection.MapView.SomeMapOps import scala.collection.mutable.Builder +import language.experimental.captureChecking +import caps.unsafe.unsafeAssumePure trait MapView[K, +V] extends MapOps[K, V, ({ type l[X, Y] = View[(X, Y)] })#l, View[(K, V)]] with View[(K, V)] { + this: MapView[K, V]^ => - override def view: MapView[K, V] = this + override def view: MapView[K, V]^{this} = this // Ideally this returns a `View`, but bincompat /** Creates a view over all keys of this map. * * @return the keys of this map as a view. */ - override def keys: Iterable[K] = new MapView.Keys(this) + override def keys: Iterable[K]^{this} = new MapView.Keys(this) // Ideally this returns a `View`, but bincompat /** Creates a view over all values of this map. * * @return the values of this map as a view. */ - override def values: Iterable[V] = new MapView.Values(this) + override def values: Iterable[V]^{this} = new MapView.Values(this) /** Filters this map by retaining only keys satisfying a predicate. * @param p the predicate used to test keys * @return an immutable map consisting only of those key value pairs of this map where the key satisfies * the predicate `p`. The resulting map wraps the original map without copying any elements. */ - override def filterKeys(p: K => Boolean): MapView[K, V] = new MapView.FilterKeys(this, p) + override def filterKeys(p: K => Boolean): MapView[K, V]^{this, p} = new MapView.FilterKeys(this, p) /** Transforms this map by applying a function to every retrieved value. * @param f the function used to transform values of this map. * @return a map view which maps every key of this map * to `f(this(key))`. The resulting map wraps the original map without copying any elements. */ - override def mapValues[W](f: V => W): MapView[K, W] = new MapView.MapValues(this, f) + override def mapValues[W](f: V => W): MapView[K, W]^{this, f} = new MapView.MapValues(this, f) - override def filter(pred: ((K, V)) => Boolean): MapView[K, V] = new MapView.Filter(this, false, pred) + override def filter(pred: ((K, V)) => Boolean): MapView[K, V]^{this, pred} = new MapView.Filter(this, false, pred) - override def filterNot(pred: ((K, V)) => Boolean): MapView[K, V] = new MapView.Filter(this, true, pred) + override def filterNot(pred: ((K, V)) => Boolean): MapView[K, V]^{this, pred} = new MapView.Filter(this, true, pred) - override def partition(p: ((K, V)) => Boolean): (MapView[K, V], MapView[K, V]) = (filter(p), filterNot(p)) + override def partition(p: ((K, V)) => Boolean): (MapView[K, V]^{this, p}, MapView[K, V]^{this, p}) = (filter(p), filterNot(p)) - override def tapEach[U](f: ((K, V)) => U): MapView[K, V] = new MapView.TapEach(this, f) + override def tapEach[U](f: ((K, V)) => U): MapView[K, V]^{this, f} = new MapView.TapEach(this, f) def mapFactory: MapViewFactory = MapView override def empty: MapView[K, V] = mapFactory.empty - override def withFilter(p: ((K, V)) => Boolean): MapOps.WithFilter[K, V, View, ({ type l[X, Y] = View[(X, Y)] })#l] = new MapOps.WithFilter(this, p) + override def withFilter(p: ((K, V)) => Boolean): MapOps.WithFilter[K, V, View, ({ type l[X, Y] = View[(X, Y)] })#l]^{this, p} = new MapOps.WithFilter(this, p) override def toString: String = super[View].toString @@ -78,7 +81,9 @@ object MapView extends MapViewFactory { type SomeMapOps[K, +V] = MapOps[K, V, SomeIterableConstr, _] @SerialVersionUID(3L) - private val EmptyMapView: MapView[Any, Nothing] = new AbstractMapView[Any, Nothing] { + object EmptyMapView extends AbstractMapView[Any, Nothing] { + // !!! cc problem: crash when we replace the line with + // private val EmptyMapView: MapView[Any, Nothing] = new AbstractMapView[Any, Nothing] { override def get(key: Any): Option[Nothing] = None override def iterator: Iterator[Nothing] = Iterator.empty[Nothing] override def knownSize: Int = 0 @@ -91,48 +96,48 @@ object MapView extends MapViewFactory { } @SerialVersionUID(3L) - class Id[K, +V](underlying: SomeMapOps[K, V]) extends AbstractMapView[K, V] { + class Id[K, +V](underlying: SomeMapOps[K, V]^) extends AbstractMapView[K, V] { def get(key: K): Option[V] = underlying.get(key) - def iterator: Iterator[(K, V)] = underlying.iterator + def iterator: Iterator[(K, V)]^{this} = underlying.iterator override def knownSize: Int = underlying.knownSize override def isEmpty: Boolean = underlying.isEmpty } // Ideally this is public, but bincompat @SerialVersionUID(3L) - private class Keys[K](underlying: SomeMapOps[K, _]) extends AbstractView[K] { - def iterator: Iterator[K] = underlying.keysIterator + private class Keys[K](underlying: SomeMapOps[K, _]^) extends AbstractView[K] { + def iterator: Iterator[K]^{this} = underlying.keysIterator override def knownSize: Int = underlying.knownSize override def isEmpty: Boolean = underlying.isEmpty } // Ideally this is public, but bincompat @SerialVersionUID(3L) - private class Values[+V](underlying: SomeMapOps[_, V]) extends AbstractView[V] { - def iterator: Iterator[V] = underlying.valuesIterator + private class Values[+V](underlying: SomeMapOps[_, V]^) extends AbstractView[V] { + def iterator: Iterator[V]^{this} = underlying.valuesIterator override def knownSize: Int = underlying.knownSize override def isEmpty: Boolean = underlying.isEmpty } @SerialVersionUID(3L) - class MapValues[K, +V, +W](underlying: SomeMapOps[K, V], f: V => W) extends AbstractMapView[K, W] { - def iterator: Iterator[(K, W)] = underlying.iterator.map(kv => (kv._1, f(kv._2))) + class MapValues[K, +V, +W](underlying: SomeMapOps[K, V]^, f: V => W) extends AbstractMapView[K, W] { + def iterator: Iterator[(K, W)]^{this} = underlying.iterator.map(kv => (kv._1, f(kv._2))) def get(key: K): Option[W] = underlying.get(key).map(f) override def knownSize: Int = underlying.knownSize override def isEmpty: Boolean = underlying.isEmpty } @SerialVersionUID(3L) - class FilterKeys[K, +V](underlying: SomeMapOps[K, V], p: K => Boolean) extends AbstractMapView[K, V] { - def iterator: Iterator[(K, V)] = underlying.iterator.filter { case (k, _) => p(k) } + class FilterKeys[K, +V](underlying: SomeMapOps[K, V]^, p: K => Boolean) extends AbstractMapView[K, V] { + def iterator: Iterator[(K, V)]^{this} = underlying.iterator.filter { case (k, _) => p(k) } def get(key: K): Option[V] = if (p(key)) underlying.get(key) else None override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize override def isEmpty: Boolean = iterator.isEmpty } @SerialVersionUID(3L) - class Filter[K, +V](underlying: SomeMapOps[K, V], isFlipped: Boolean, p: ((K, V)) => Boolean) extends AbstractMapView[K, V] { - def iterator: Iterator[(K, V)] = underlying.iterator.filterImpl(p, isFlipped) + class Filter[K, +V](underlying: SomeMapOps[K, V]^, isFlipped: Boolean, p: ((K, V)) => Boolean) extends AbstractMapView[K, V] { + def iterator: Iterator[(K, V)]^{this} = underlying.iterator.filterImpl(p, isFlipped) def get(key: K): Option[V] = underlying.get(key) match { case s @ Some(v) if p((key, v)) != isFlipped => s case _ => None @@ -142,7 +147,7 @@ object MapView extends MapViewFactory { } @SerialVersionUID(3L) - class TapEach[K, +V, +U](underlying: SomeMapOps[K, V], f: ((K, V)) => U) extends AbstractMapView[K, V] { + class TapEach[K, +V, +U](underlying: SomeMapOps[K, V]^, f: ((K, V)) => U) extends AbstractMapView[K, V] { override def get(key: K): Option[V] = { underlying.get(key) match { case s @ Some(v) => @@ -151,18 +156,21 @@ object MapView extends MapViewFactory { case None => None } } - override def iterator: Iterator[(K, V)] = underlying.iterator.tapEach(f) + override def iterator: Iterator[(K, V)]^{this} = underlying.iterator.tapEach(f) override def knownSize: Int = underlying.knownSize override def isEmpty: Boolean = underlying.isEmpty } - override def newBuilder[X, Y]: Builder[(X, Y), MapView[X, Y]] = mutable.HashMap.newBuilder[X, Y].mapResult(_.view) + override def newBuilder[sealed X, sealed Y]: Builder[(X, Y), MapView[X, Y]] = mutable.HashMap.newBuilder[X, Y].mapResult(_.view) override def empty[K, V]: MapView[K, V] = EmptyMapView.asInstanceOf[MapView[K, V]] - override def from[K, V](it: IterableOnce[(K, V)]): View[(K, V)] = View.from(it) + override def from[K, V](it: IterableOnce[(K, V)]^): View[(K, V)] = + View.from(it).unsafeAssumePure + // unsafeAssumePure needed here since MapViewFactory inherits from MapFactory, + // and the latter assumes maps are strict, so from's result captures nothing. - override def from[K, V](it: SomeMapOps[K, V]): MapView[K, V] = it match { + override def from[K, V](it: SomeMapOps[K, V]^): MapView[K, V]^{it} = it match { case mv: MapView[K, V] => mv case other => new MapView.Id(other) } @@ -176,12 +184,13 @@ trait MapViewFactory extends collection.MapFactory[({ type l[X, Y] = View[(X, Y) def empty[X, Y]: MapView[X, Y] - def from[K, V](it: SomeMapOps[K, V]): MapView[K, V] + def from[K, V](it: SomeMapOps[K, V]^): MapView[K, V]^{it} override def apply[K, V](elems: (K, V)*): MapView[K, V] = from(elems.toMap) } /** Explicit instantiation of the `MapView` trait to reduce class file size in subclasses. */ @SerialVersionUID(3L) -abstract class AbstractMapView[K, +V] extends AbstractView[(K, V)] with MapView[K, V] +abstract class AbstractMapView[K, +V] extends AbstractView[(K, V)] with MapView[K, V]: + this: AbstractMapView[K, V]^ => diff --git a/tests/pos-special/stdlib/collection/Searching.scala b/tests/pos-special/stdlib/collection/Searching.scala index 874a06449aa9..f5139422e24c 100644 --- a/tests/pos-special/stdlib/collection/Searching.scala +++ b/tests/pos-special/stdlib/collection/Searching.scala @@ -14,6 +14,7 @@ package scala.collection import scala.language.implicitConversions import scala.collection.generic.IsSeq +import language.experimental.captureChecking object Searching { diff --git a/tests/pos-special/stdlib/collection/Seq.scala b/tests/pos-special/stdlib/collection/Seq.scala index d960838fdcb7..365a1db1b849 100644 --- a/tests/pos-special/stdlib/collection/Seq.scala +++ b/tests/pos-special/stdlib/collection/Seq.scala @@ -16,6 +16,9 @@ import scala.collection.immutable.Range import scala.util.hashing.MurmurHash3 import Searching.{Found, InsertionPoint, SearchResult} import scala.annotation.nowarn +import language.experimental.captureChecking +import caps.unsafe.unsafeAssumePure +import scala.annotation.unchecked.uncheckedCaptures /** Base trait for sequence collections * @@ -27,6 +30,7 @@ trait Seq[+A] with SeqOps[A, Seq, Seq[A]] with IterableFactoryDefaults[A, Seq] with Equals { + this: Seq[A] => override def iterableFactory: SeqFactory[Seq] = Seq @@ -74,11 +78,12 @@ object Seq extends SeqFactory.Delegate[Seq](immutable.Seq) * @define coll sequence * @define Coll `Seq` */ -trait SeqOps[+A, +CC[_], +C] extends Any - with IterableOps[A, CC, C] { self => +trait SeqOps[+A, +CC[_], +C] extends Any with SeqViewOps[A, CC, C] { self => override def view: SeqView[A] = new SeqView.Id[A](this) + def iterableFactory: FreeSeqFactory[CC] + /** Get the element at the specified index. This operation is provided for convenience in `Seq`. It should * not be assumed to be efficient unless you have an `IndexedSeq`. */ @throws[IndexOutOfBoundsException] @@ -160,13 +165,13 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @return a new $coll which contains all elements of `prefix` followed * by all the elements of this $coll. */ - def prependedAll[B >: A](prefix: IterableOnce[B]): CC[B] = iterableFactory.from(prefix match { + def prependedAll[B >: A](prefix: IterableOnce[B]^): CC[B] = iterableFactory.from(prefix match { case prefix: Iterable[B] => new View.Concat(prefix, this) case _ => prefix.iterator ++ iterator }) /** Alias for `prependedAll` */ - @`inline` override final def ++: [B >: A](prefix: IterableOnce[B]): CC[B] = prependedAll(prefix) + @`inline` override final def ++: [B >: A](prefix: IterableOnce[B]^): CC[B] = prependedAll(prefix) /** Returns a new $coll containing the elements from the left hand operand followed by the elements from the * right hand operand. The element type of the $coll is the most specific superclass encompassing @@ -177,14 +182,15 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @return a new collection of type `CC[B]` which contains all elements * of this $coll followed by all elements of `suffix`. */ - def appendedAll[B >: A](suffix: IterableOnce[B]): CC[B] = super.concat(suffix) + def appendedAll[B >: A](suffix: IterableOnce[B]^): CC[B] = + super.concat(suffix).unsafeAssumePure /** Alias for `appendedAll` */ - @`inline` final def :++ [B >: A](suffix: IterableOnce[B]): CC[B] = appendedAll(suffix) + @`inline` final def :++ [B >: A](suffix: IterableOnce[B]^): CC[B] = appendedAll(suffix) // Make `concat` an alias for `appendedAll` so that it benefits from performance // overrides of this method - @`inline` final override def concat[B >: A](suffix: IterableOnce[B]): CC[B] = appendedAll(suffix) + @`inline` final override def concat[B >: A](suffix: IterableOnce[B]^): CC[B] = appendedAll(suffix) /** Produces a new sequence which contains all elements of this $coll and also all elements of * a given sequence. `xs union ys` is equivalent to `xs ++ ys`. @@ -212,7 +218,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @tparam B the type of the elements after being transformed by `f` * @return a new $coll consisting of all the elements of this $coll without duplicates. */ - def distinctBy[B](f: A => B): C = fromSpecific(new View.DistinctBy(this, f)) + def distinctBy[B](f: A -> B): C = fromSpecific(new View.DistinctBy(this, f)) /** Returns new $coll with elements in reversed order. * @@ -231,7 +237,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * * @return an iterator yielding the elements of this $coll in reversed order */ - def reverseIterator: Iterator[A] = reversed.iterator + override def reverseIterator: Iterator[A] = reversed.iterator /** Tests whether this $coll contains the given sequence at a given index. * @@ -243,7 +249,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @return `true` if the sequence `that` is contained in this $coll at * index `offset`, otherwise `false`. */ - def startsWith[B >: A](that: IterableOnce[B], offset: Int = 0): Boolean = { + def startsWith[B >: A](that: IterableOnce[B]^, offset: Int = 0): Boolean = { val i = iterator drop offset val j = that.iterator while (j.hasNext && i.hasNext) @@ -258,7 +264,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @param that the sequence to test * @return `true` if this $coll has `that` as a suffix, `false` otherwise. */ - def endsWith[B >: A](that: Iterable[B]): Boolean = { + def endsWith[B >: A](that: Iterable[B]^): Boolean = { if (that.isEmpty) true else { val i = iterator.drop(length - that.size) @@ -595,7 +601,8 @@ trait SeqOps[+A, +CC[_], +C] extends Any if (!hasNext) Iterator.empty.next() - val forcedElms = new mutable.ArrayBuffer[A](elms.size) ++= elms + val forcedElms = new mutable.ArrayBuffer[A @uncheckedCaptures](elms.size) ++= elms + // uncheckedCaptures OK since used only locally val result = (newSpecificBuilder ++= forcedElms).result() var i = idxs.length - 2 while(i >= 0 && idxs(i) >= idxs(i+1)) @@ -628,6 +635,9 @@ trait SeqOps[+A, +CC[_], +C] extends Any private[this] def init() = { val m = mutable.HashMap[A, Int]() + //val s1 = self.toGenericSeq map (e => (e, m.getOrElseUpdate(e, m.size))) + //val s2: Seq[(A, Int)] = s1 sortBy (_._2) + //val (es, is) = s2.unzip(using Predef.$conforms[(A, Int)]) val (es, is) = (self.toGenericSeq map (e => (e, m.getOrElseUpdate(e, m.size))) sortBy (_._2)).unzip (es.to(mutable.ArrayBuffer), is.toArray) @@ -807,7 +817,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any */ def lengthCompare(len: Int): Int = super.sizeCompare(len) - override final def sizeCompare(that: Iterable[_]): Int = lengthCompare(that) + override final def sizeCompare(that: Iterable[_]^): Int = lengthCompare(that) /** Compares the length of this $coll to the size of another `Iterable`. * @@ -822,7 +832,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * is `O(this.length min that.size)` instead of `O(this.length + that.size)`. * The method should be overridden if computing `size` is cheap and `knownSize` returns `-1`. */ - def lengthCompare(that: Iterable[_]): Int = super.sizeCompare(that) + def lengthCompare(that: Iterable[_]^): Int = super.sizeCompare(that) /** Returns a value class containing operations for comparing the length of this $coll to a test value. * @@ -845,7 +855,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any /** Are the elements of this collection the same (and in the same order) * as those of `that`? */ - def sameElements[B >: A](that: IterableOnce[B]): Boolean = { + def sameElements[B >: A](that: IterableOnce[B]^): Boolean = { val thisKnownSize = knownSize val knownSizeDifference = thisKnownSize != -1 && { val thatKnownSize = that.knownSize @@ -883,7 +893,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * part of the result, but any following occurrences will. */ def diff[B >: A](that: Seq[B]): C = { - val occ = occCounts(that) + val occ = occCounts[B @uncheckedCaptures](that) fromSpecific(iterator.filter { x => var include = false occ.updateWith(x) { @@ -908,7 +918,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * in the result, but any following occurrences will be omitted. */ def intersect[B >: A](that: Seq[B]): C = { - val occ = occCounts(that) + val occ = occCounts[B @uncheckedCaptures](that) fromSpecific(iterator.filter { x => var include = true occ.updateWith(x) { @@ -937,7 +947,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * except that `replaced` elements starting from `from` are replaced * by all the elements of `other`. */ - def patch[B >: A](from: Int, other: IterableOnce[B], replaced: Int): CC[B] = + def patch[B >: A](from: Int, other: IterableOnce[B]^, replaced: Int): CC[B] = iterableFactory.from(new View.Patched(this, from, other, replaced)) /** A copy of this $coll with one single replaced element. @@ -956,7 +966,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any iterableFactory.from(new View.Updated(this, index, elem)) } - protected[collection] def occCounts[B](sq: Seq[B]): mutable.Map[B, Int] = { + protected[collection] def occCounts[sealed B](sq: Seq[B]): mutable.Map[B, Int] = { val occ = new mutable.HashMap[B, Int]() for (y <- sq) occ.updateWith(y) { case None => Some(1) @@ -1004,11 +1014,11 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @return a `Found` value containing the index corresponding to the element in the * sequence, or the `InsertionPoint` where the element would be inserted if * the element is not in the sequence. - * + * * @note if `to <= from`, the search space is empty, and an `InsertionPoint` at `from` * is returned */ - def search[B >: A](elem: B, from: Int, to: Int) (implicit ord: Ordering[B]): SearchResult = + def search[B >: A](elem: B, from: Int, to: Int) (implicit ord: Ordering[B]): SearchResult = linearSearch(view.slice(from, to), elem, math.max(0, from))(ord) private[this] def linearSearch[B >: A](c: View[A], elem: B, offset: Int) diff --git a/tests/pos-special/stdlib/collection/SeqMap.scala b/tests/pos-special/stdlib/collection/SeqMap.scala index 05bf126aba02..a7f2c629b61d 100644 --- a/tests/pos-special/stdlib/collection/SeqMap.scala +++ b/tests/pos-special/stdlib/collection/SeqMap.scala @@ -11,6 +11,7 @@ */ package scala.collection +import language.experimental.captureChecking import scala.annotation.nowarn diff --git a/tests/pos-special/stdlib/collection/SeqView.scala b/tests/pos-special/stdlib/collection/SeqView.scala index ad16f01b9184..a4ca1143f8b4 100644 --- a/tests/pos-special/stdlib/collection/SeqView.scala +++ b/tests/pos-special/stdlib/collection/SeqView.scala @@ -14,26 +14,49 @@ package scala package collection import scala.annotation.nowarn +import language.experimental.captureChecking +import caps.unsafe.unsafeAssumePure +import scala.annotation.unchecked.uncheckedCaptures + +/** !!! Scala 2 difference: Need intermediate trait SeqViewOps to collect the + * necessary functionality over which SeqViews are defined, and at the same + * time allowing impure operations. Scala 2 uses SeqOps here, but SeqOps is + * pure, whereas SeqViews are Iterables which can be impure (for instance, + * mapping a SeqView with an impure function gives an impure view). + */ +trait SeqViewOps[+A, +CC[_], +C] extends Any with IterableOps[A, CC, C] { + self: SeqViewOps[A, CC, C]^ => + + def length: Int + def apply(x: Int): A + def appended[B >: A](elem: B): CC[B]^{this} + def prepended[B >: A](elem: B): CC[B]^{this} + def reverse: C^{this} + def sorted[B >: A](implicit ord: Ordering[B]): C^{this} + + def reverseIterator: Iterator[A]^{this} = reversed.iterator +} +trait SeqView[+A] extends SeqViewOps[A, View, View[A]] with View[A] { + self: SeqView[A]^ => -trait SeqView[+A] extends SeqOps[A, View, View[A]] with View[A] { - override def view: SeqView[A] = this + override def view: SeqView[A]^{this} = this - override def map[B](f: A => B): SeqView[B] = new SeqView.Map(this, f) - override def appended[B >: A](elem: B): SeqView[B] = new SeqView.Appended(this, elem) - override def prepended[B >: A](elem: B): SeqView[B] = new SeqView.Prepended(elem, this) - override def reverse: SeqView[A] = new SeqView.Reverse(this) - override def take(n: Int): SeqView[A] = new SeqView.Take(this, n) - override def drop(n: Int): SeqView[A] = new SeqView.Drop(this, n) - override def takeRight(n: Int): SeqView[A] = new SeqView.TakeRight(this, n) - override def dropRight(n: Int): SeqView[A] = new SeqView.DropRight(this, n) - override def tapEach[U](f: A => U): SeqView[A] = new SeqView.Map(this, { (a: A) => f(a); a }) + override def map[B](f: A => B): SeqView[B]^{this, f} = new SeqView.Map(this, f) + override def appended[B >: A](elem: B): SeqView[B]^{this} = new SeqView.Appended(this, elem) + override def prepended[B >: A](elem: B): SeqView[B]^{this} = new SeqView.Prepended(elem, this) + override def reverse: SeqView[A]^{this} = new SeqView.Reverse(this) + override def take(n: Int): SeqView[A]^{this} = new SeqView.Take(this, n) + override def drop(n: Int): SeqView[A]^{this} = new SeqView.Drop(this, n) + override def takeRight(n: Int): SeqView[A]^{this} = new SeqView.TakeRight(this, n) + override def dropRight(n: Int): SeqView[A]^{this} = new SeqView.DropRight(this, n) + override def tapEach[U](f: A => U): SeqView[A]^{this, f} = new SeqView.Map(this, { (a: A) => f(a); a }) - def concat[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B] = new SeqView.Concat(this, suffix) - def appendedAll[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B] = new SeqView.Concat(this, suffix) - def prependedAll[B >: A](prefix: SeqView.SomeSeqOps[B]): SeqView[B] = new SeqView.Concat(prefix, this) + def concat[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B]^{this} = new SeqView.Concat(this, suffix) + def appendedAll[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B]^{this} = new SeqView.Concat(this, suffix) + def prependedAll[B >: A](prefix: SeqView.SomeSeqOps[B]): SeqView[B]^{this} = new SeqView.Concat(prefix, this) - override def sorted[B >: A](implicit ord: Ordering[B]): SeqView[A] = new SeqView.Sorted(this, ord) + override def sorted[B >: A](implicit ord: Ordering[B]): SeqView[A]^{this} = new SeqView.Sorted(this, ord) @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""") override protected[this] def stringPrefix: String = "SeqView" @@ -42,38 +65,38 @@ trait SeqView[+A] extends SeqOps[A, View, View[A]] with View[A] { object SeqView { /** A `SeqOps` whose collection type and collection type constructor are unknown */ - private type SomeSeqOps[+A] = SeqOps[A, AnyConstr, _] + private type SomeSeqOps[+A] = SeqViewOps[A, AnyConstr, _] /** A view that doesn’t apply any transformation to an underlying sequence */ @SerialVersionUID(3L) - class Id[+A](underlying: SomeSeqOps[A]) extends AbstractSeqView[A] { + class Id[+A](underlying: SomeSeqOps[A]^) extends AbstractSeqView[A] { def apply(idx: Int): A = underlying.apply(idx) def length: Int = underlying.length - def iterator: Iterator[A] = underlying.iterator + def iterator: Iterator[A]^{this} = underlying.iterator override def knownSize: Int = underlying.knownSize override def isEmpty: Boolean = underlying.isEmpty } @SerialVersionUID(3L) - class Map[+A, +B](underlying: SomeSeqOps[A], f: A => B) extends View.Map[A, B](underlying, f) with SeqView[B] { + class Map[+A, +B](underlying: SomeSeqOps[A]^, f: A => B) extends View.Map[A, B](underlying, f) with SeqView[B] { def apply(idx: Int): B = f(underlying(idx)) def length: Int = underlying.length } @SerialVersionUID(3L) - class Appended[+A](underlying: SomeSeqOps[A], elem: A) extends View.Appended(underlying, elem) with SeqView[A] { + class Appended[+A](underlying: SomeSeqOps[A]^, elem: A) extends View.Appended(underlying, elem) with SeqView[A] { def apply(idx: Int): A = if (idx == underlying.length) elem else underlying(idx) def length: Int = underlying.length + 1 } @SerialVersionUID(3L) - class Prepended[+A](elem: A, underlying: SomeSeqOps[A]) extends View.Prepended(elem, underlying) with SeqView[A] { + class Prepended[+A](elem: A, underlying: SomeSeqOps[A]^) extends View.Prepended(elem, underlying) with SeqView[A] { def apply(idx: Int): A = if (idx == 0) elem else underlying(idx - 1) def length: Int = underlying.length + 1 } @SerialVersionUID(3L) - class Concat[A](prefix: SomeSeqOps[A], suffix: SomeSeqOps[A]) extends View.Concat[A](prefix, suffix) with SeqView[A] { + class Concat[A](prefix: SomeSeqOps[A]^, suffix: SomeSeqOps[A]^) extends View.Concat[A](prefix, suffix) with SeqView[A] { def apply(idx: Int): A = { val l = prefix.length if (idx < l) prefix(idx) else suffix(idx - l) @@ -82,16 +105,16 @@ object SeqView { } @SerialVersionUID(3L) - class Reverse[A](underlying: SomeSeqOps[A]) extends AbstractSeqView[A] { + class Reverse[A](underlying: SomeSeqOps[A]^) extends AbstractSeqView[A] { def apply(i: Int) = underlying.apply(size - 1 - i) def length = underlying.size - def iterator: Iterator[A] = underlying.reverseIterator + def iterator: Iterator[A]^{this} = underlying.reverseIterator override def knownSize: Int = underlying.knownSize override def isEmpty: Boolean = underlying.isEmpty } @SerialVersionUID(3L) - class Take[+A](underlying: SomeSeqOps[A], n: Int) extends View.Take(underlying, n) with SeqView[A] { + class Take[+A](underlying: SomeSeqOps[A]^, n: Int) extends View.Take(underlying, n) with SeqView[A] { def apply(idx: Int): A = if (idx < n) { underlying(idx) } else { @@ -101,7 +124,7 @@ object SeqView { } @SerialVersionUID(3L) - class TakeRight[+A](underlying: SomeSeqOps[A], n: Int) extends View.TakeRight(underlying, n) with SeqView[A] { + class TakeRight[+A](underlying: SomeSeqOps[A]^, n: Int) extends View.TakeRight(underlying, n) with SeqView[A] { private[this] val delta = (underlying.size - (n max 0)) max 0 def length = underlying.size - delta @throws[IndexOutOfBoundsException] @@ -109,15 +132,15 @@ object SeqView { } @SerialVersionUID(3L) - class Drop[A](underlying: SomeSeqOps[A], n: Int) extends View.Drop[A](underlying, n) with SeqView[A] { + class Drop[A](underlying: SomeSeqOps[A]^, n: Int) extends View.Drop[A](underlying, n) with SeqView[A] { def length = (underlying.size - normN) max 0 @throws[IndexOutOfBoundsException] def apply(i: Int) = underlying.apply(i + normN) - override def drop(n: Int): SeqView[A] = new Drop(underlying, this.n + n) + override def drop(n: Int): SeqView[A]^{this} = new Drop(underlying, this.n + n) } @SerialVersionUID(3L) - class DropRight[A](underlying: SomeSeqOps[A], n: Int) extends View.DropRight[A](underlying, n) with SeqView[A] { + class DropRight[A](underlying: SomeSeqOps[A]^, n: Int) extends View.DropRight[A](underlying, n) with SeqView[A] { private[this] val len = (underlying.size - (n max 0)) max 0 def length = len @throws[IndexOutOfBoundsException] @@ -125,15 +148,15 @@ object SeqView { } @SerialVersionUID(3L) - class Sorted[A, B >: A] private (private[this] var underlying: SomeSeqOps[A], + class Sorted[A, B >: A] private (private[this] var underlying: SomeSeqOps[A]^, private[this] val len: Int, ord: Ordering[B]) extends SeqView[A] { - outer => + outer: Sorted[A, B]^ => // force evaluation immediately by calling `length` so infinite collections // hang on `sorted`/`sortWith`/`sortBy` rather than on arbitrary method calls - def this(underlying: SomeSeqOps[A], ord: Ordering[B]) = this(underlying, underlying.length, ord) + def this(underlying: SomeSeqOps[A]^, ord: Ordering[B]) = this(underlying, underlying.length, ord) @SerialVersionUID(3L) private[this] class ReverseSorted extends SeqView[A] { @@ -141,15 +164,15 @@ object SeqView { def apply(i: Int): A = _reversed.apply(i) def length: Int = len - def iterator: Iterator[A] = Iterator.empty ++ _reversed.iterator // very lazy + def iterator: Iterator[A]^{this} = Iterator.empty ++ _reversed.iterator // very lazy override def knownSize: Int = len override def isEmpty: Boolean = len == 0 override def to[C1](factory: Factory[A, C1]): C1 = _reversed.to(factory) - override def reverse: SeqView[A] = outer - override protected def reversed: Iterable[A] = outer + override def reverse: SeqView[A]^{outer} = outer + override protected def reversed: Iterable[A] = outer.unsafeAssumePure - override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A] = - if (ord1 == Sorted.this.ord) outer + override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A]^{this} = + if (ord1 == Sorted.this.ord) outer.unsafeAssumePure else if (ord1.isReverseOf(Sorted.this.ord)) this else new Sorted(elems, len, ord1) } @@ -173,7 +196,7 @@ object SeqView { // contains items of another type, we'd get a CCE anyway) // - the cast doesn't actually do anything in the runtime because the // type of A is not known and Array[_] is Array[AnyRef] - immutable.ArraySeq.unsafeWrapArray(arr.asInstanceOf[Array[A]]) + immutable.ArraySeq.unsafeWrapArray(arr.asInstanceOf[Array[A @uncheckedCaptures]]) } } evaluated = true @@ -181,14 +204,14 @@ object SeqView { res } - private[this] def elems: SomeSeqOps[A] = { + private[this] def elems: SomeSeqOps[A]^{this} = { val orig = underlying if (evaluated) _sorted else orig } def apply(i: Int): A = _sorted.apply(i) def length: Int = len - def iterator: Iterator[A] = Iterator.empty ++ _sorted.iterator // very lazy + def iterator: Iterator[A]^{this} = Iterator.empty ++ _sorted.iterator // very lazy override def knownSize: Int = len override def isEmpty: Boolean = len == 0 override def to[C1](factory: Factory[A, C1]): C1 = _sorted.to(factory) @@ -197,7 +220,7 @@ object SeqView { // so this is acceptable for `reversed` override protected def reversed: Iterable[A] = new ReverseSorted - override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A] = + override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A]^{this} = if (ord1 == this.ord) this else if (ord1.isReverseOf(this.ord)) reverse else new Sorted(elems, len, ord1) diff --git a/tests/pos-special/stdlib/collection/Set.scala b/tests/pos-special/stdlib/collection/Set.scala index 0ea1e5689473..a9c279b82a49 100644 --- a/tests/pos-special/stdlib/collection/Set.scala +++ b/tests/pos-special/stdlib/collection/Set.scala @@ -17,6 +17,7 @@ import scala.util.hashing.MurmurHash3 import java.lang.String import scala.annotation.nowarn +import language.experimental.captureChecking /** Base trait for set collections. */ @@ -24,7 +25,9 @@ trait Set[A] extends Iterable[A] with SetOps[A, Set, Set[A]] with Equals - with IterableFactoryDefaults[A, Set] { + with IterableFactoryDefaults[A, Set] + with Pure { + self: Set[A] => def canEqual(that: Any) = true @@ -86,8 +89,7 @@ trait Set[A] * @define Coll `Set` */ trait SetOps[A, +CC[_], +C <: SetOps[A, CC, C]] - extends IterableOps[A, CC, C] - with (A => Boolean) { + extends IterableOps[A, CC, C], (A -> Boolean) { self => def contains(elem: A): Boolean @@ -234,7 +236,7 @@ trait SetOps[A, +CC[_], +C <: SetOps[A, CC, C]] case that: collection.Iterable[A] => new View.Concat(this, that) case _ => iterator.concat(that.iterator) }) - } + } @deprecated("Consider requiring an immutable Set or fall back to Set.union", "2.13.0") def + (elem: A): C = fromSpecific(new View.Appended(this, elem)) diff --git a/tests/pos-special/stdlib/collection/SortedMap.scala b/tests/pos-special/stdlib/collection/SortedMap.scala index 03ab0bb0dadc..7b9381ebb078 100644 --- a/tests/pos-special/stdlib/collection/SortedMap.scala +++ b/tests/pos-special/stdlib/collection/SortedMap.scala @@ -14,6 +14,7 @@ package scala package collection import scala.annotation.{implicitNotFound, nowarn} +import language.experimental.captureChecking /** A Map whose keys are sorted according to a [[scala.math.Ordering]]*/ trait SortedMap[K, +V] @@ -49,7 +50,8 @@ trait SortedMap[K, +V] trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMapOps[K, V, CC, C]] extends MapOps[K, V, Map, C] - with SortedOps[K, C] { + with SortedOps[K, C] + with Pure { /** The companion object of this sorted map, providing various factory methods. * @@ -176,13 +178,13 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] = sortedMapFactory.from(new View.Collect(this, pf)) - override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]): CC[K, V2] = sortedMapFactory.from(suffix match { + override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]^): CC[K, V2] = sortedMapFactory.from(suffix match { case it: Iterable[(K, V2)] => new View.Concat(this, it) case _ => iterator.concat(suffix.iterator) })(ordering) /** Alias for `concat` */ - @`inline` override final def ++ [V2 >: V](xs: IterableOnce[(K, V2)]): CC[K, V2] = concat(xs) + @`inline` override final def ++ [V2 >: V](xs: IterableOnce[(K, V2)]^): CC[K, V2] = concat(xs) @deprecated("Consider requiring an immutable Map or fall back to Map.concat", "2.13.0") override def + [V1 >: V](kv: (K, V1)): CC[K, V1] = sortedMapFactory.from(new View.Appended(this, kv))(ordering) @@ -206,10 +208,10 @@ object SortedMapOps { def map[K2 : Ordering, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = self.sortedMapFactory.from(new View.Map(filtered, f)) - def flatMap[K2 : Ordering, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = + def flatMap[K2 : Ordering, V2](f: ((K, V)) => IterableOnce[(K2, V2)]^): CC[K2, V2] = self.sortedMapFactory.from(new View.FlatMap(filtered, f)) - override def withFilter(q: ((K, V)) => Boolean): WithFilter[K, V, IterableCC, MapCC, CC] = + override def withFilter(q: ((K, V)) => Boolean): WithFilter[K, V, IterableCC, MapCC, CC]^{this, q} = new WithFilter[K, V, IterableCC, MapCC, CC](self, (kv: (K, V)) => p(kv) && q(kv)) } diff --git a/tests/pos-special/stdlib/collection/SortedOps.scala b/tests/pos-special/stdlib/collection/SortedOps.scala index 64e6376be042..16751d86d9d5 100644 --- a/tests/pos-special/stdlib/collection/SortedOps.scala +++ b/tests/pos-special/stdlib/collection/SortedOps.scala @@ -12,6 +12,7 @@ package scala.collection +import language.experimental.captureChecking /** Base trait for sorted collections */ trait SortedOps[A, +C] { diff --git a/tests/pos-special/stdlib/collection/SortedSet.scala b/tests/pos-special/stdlib/collection/SortedSet.scala index c98ca9ae5523..fb2f879edcd2 100644 --- a/tests/pos-special/stdlib/collection/SortedSet.scala +++ b/tests/pos-special/stdlib/collection/SortedSet.scala @@ -14,6 +14,7 @@ package scala.collection import scala.annotation.{implicitNotFound, nowarn} import scala.annotation.unchecked.uncheckedVariance +import language.experimental.captureChecking /** Base type of sorted sets */ trait SortedSet[A] extends Set[A] @@ -68,7 +69,7 @@ trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]] * @param start The lower-bound (inclusive) of the iterator */ def iteratorFrom(start: A): Iterator[A] - + @deprecated("Use `iteratorFrom` instead.", "2.13.0") @`inline` def keysIteratorFrom(start: A): Iterator[A] = iteratorFrom(start) @@ -178,7 +179,7 @@ object SortedSetOps { def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = self.sortedIterableFactory.from(new View.FlatMap(filtered, f)) - override def withFilter(q: A => Boolean): WithFilter[A, IterableCC, CC] = + override def withFilter(q: A => Boolean): WithFilter[A, IterableCC, CC]^{this, q} = new WithFilter[A, IterableCC, CC](self, (a: A) => p(a) && q(a)) } diff --git a/tests/pos-special/stdlib/collection/Stepper.scala b/tests/pos-special/stdlib/collection/Stepper.scala index 0eeb8a44cb72..0a0ac0075990 100644 --- a/tests/pos-special/stdlib/collection/Stepper.scala +++ b/tests/pos-special/stdlib/collection/Stepper.scala @@ -15,6 +15,7 @@ package scala.collection import java.util.function.{Consumer, DoubleConsumer, IntConsumer, LongConsumer} import java.util.{PrimitiveIterator, Spliterator, Iterator => JIterator} import java.{lang => jl} +import language.experimental.captureChecking import scala.collection.Stepper.EfficientSplit @@ -38,6 +39,8 @@ import scala.collection.Stepper.EfficientSplit * @tparam A the element type of the Stepper */ trait Stepper[@specialized(Double, Int, Long) +A] { + this: Stepper[A]^ => + /** Check if there's an element available. */ def hasStep: Boolean @@ -183,9 +186,11 @@ object Stepper { /** A Stepper for arbitrary element types. See [[Stepper]]. */ trait AnyStepper[+A] extends Stepper[A] { + this: AnyStepper[A]^ => + def trySplit(): AnyStepper[A] - def spliterator[B >: A]: Spliterator[B] = new AnyStepper.AnyStepperSpliterator(this) + def spliterator[B >: A]: Spliterator[B]^{this} = new AnyStepper.AnyStepperSpliterator(this) def javaIterator[B >: A]: JIterator[B] = new JIterator[B] { def hasNext: Boolean = hasStep @@ -194,10 +199,10 @@ trait AnyStepper[+A] extends Stepper[A] { } object AnyStepper { - class AnyStepperSpliterator[A](s: AnyStepper[A]) extends Spliterator[A] { + class AnyStepperSpliterator[A](s: AnyStepper[A]^) extends Spliterator[A] { def tryAdvance(c: Consumer[_ >: A]): Boolean = if (s.hasStep) { c.accept(s.nextStep()); true } else false - def trySplit(): Spliterator[A] = { + def trySplit(): Spliterator[A]^{this} = { val sp = s.trySplit() if (sp == null) null else sp.spliterator } @@ -253,9 +258,11 @@ object AnyStepper { /** A Stepper for Ints. See [[Stepper]]. */ trait IntStepper extends Stepper[Int] { + this: IntStepper^ => + def trySplit(): IntStepper - def spliterator[B >: Int]: Spliterator.OfInt = new IntStepper.IntStepperSpliterator(this) + def spliterator[B >: Int]: Spliterator.OfInt^{this} = new IntStepper.IntStepperSpliterator(this) def javaIterator[B >: Int]: PrimitiveIterator.OfInt = new PrimitiveIterator.OfInt { def hasNext: Boolean = hasStep @@ -263,7 +270,7 @@ trait IntStepper extends Stepper[Int] { } } object IntStepper { - class IntStepperSpliterator(s: IntStepper) extends Spliterator.OfInt { + class IntStepperSpliterator(s: IntStepper^) extends Spliterator.OfInt { def tryAdvance(c: IntConsumer): Boolean = if (s.hasStep) { c.accept(s.nextStep()); true } else false // Override for efficiency: don't wrap the function and call the `tryAdvance` overload @@ -272,7 +279,7 @@ object IntStepper { case _ => if (s.hasStep) { c.accept(jl.Integer.valueOf(s.nextStep())); true } else false } // override required for dotty#6152 - override def trySplit(): Spliterator.OfInt = { + override def trySplit(): Spliterator.OfInt^{this} = { val sp = s.trySplit() if (sp == null) null else sp.spliterator } @@ -291,18 +298,19 @@ object IntStepper { /** A Stepper for Doubles. See [[Stepper]]. */ trait DoubleStepper extends Stepper[Double] { + this: DoubleStepper^ => def trySplit(): DoubleStepper - def spliterator[B >: Double]: Spliterator.OfDouble = new DoubleStepper.DoubleStepperSpliterator(this) + def spliterator[B >: Double]: Spliterator.OfDouble^{this} = new DoubleStepper.DoubleStepperSpliterator(this) - def javaIterator[B >: Double]: PrimitiveIterator.OfDouble = new PrimitiveIterator.OfDouble { + def javaIterator[B >: Double]: PrimitiveIterator.OfDouble^{this} = new PrimitiveIterator.OfDouble { def hasNext: Boolean = hasStep def nextDouble(): Double = nextStep() } } object DoubleStepper { - class DoubleStepperSpliterator(s: DoubleStepper) extends Spliterator.OfDouble { + class DoubleStepperSpliterator(s: DoubleStepper^) extends Spliterator.OfDouble { def tryAdvance(c: DoubleConsumer): Boolean = if (s.hasStep) { c.accept(s.nextStep()); true } else false // Override for efficiency: don't wrap the function and call the `tryAdvance` overload @@ -311,7 +319,7 @@ object DoubleStepper { case _ => if (s.hasStep) { c.accept(java.lang.Double.valueOf(s.nextStep())); true } else false } // override required for dotty#6152 - override def trySplit(): Spliterator.OfDouble = { + override def trySplit(): Spliterator.OfDouble^{this} = { val sp = s.trySplit() if (sp == null) null else sp.spliterator } @@ -330,18 +338,20 @@ object DoubleStepper { /** A Stepper for Longs. See [[Stepper]]. */ trait LongStepper extends Stepper[Long] { - def trySplit(): LongStepper + this: LongStepper^ => + + def trySplit(): LongStepper^{this} - def spliterator[B >: Long]: Spliterator.OfLong = new LongStepper.LongStepperSpliterator(this) + def spliterator[B >: Long]: Spliterator.OfLong^{this} = new LongStepper.LongStepperSpliterator(this) - def javaIterator[B >: Long]: PrimitiveIterator.OfLong = new PrimitiveIterator.OfLong { + def javaIterator[B >: Long]: PrimitiveIterator.OfLong^{this} = new PrimitiveIterator.OfLong { def hasNext: Boolean = hasStep def nextLong(): Long = nextStep() } } object LongStepper { - class LongStepperSpliterator(s: LongStepper) extends Spliterator.OfLong { + class LongStepperSpliterator(s: LongStepper^) extends Spliterator.OfLong { def tryAdvance(c: LongConsumer): Boolean = if (s.hasStep) { c.accept(s.nextStep()); true } else false // Override for efficiency: don't wrap the function and call the `tryAdvance` overload @@ -350,7 +360,7 @@ object LongStepper { case _ => if (s.hasStep) { c.accept(java.lang.Long.valueOf(s.nextStep())); true } else false } // override required for dotty#6152 - override def trySplit(): Spliterator.OfLong = { + override def trySplit(): Spliterator.OfLong^{this} = { val sp = s.trySplit() if (sp == null) null else sp.spliterator } diff --git a/tests/pos-special/stdlib/collection/StepperShape.scala b/tests/pos-special/stdlib/collection/StepperShape.scala index 6712073b09e4..c6b520400d89 100644 --- a/tests/pos-special/stdlib/collection/StepperShape.scala +++ b/tests/pos-special/stdlib/collection/StepperShape.scala @@ -14,12 +14,13 @@ package scala.collection import java.{lang => jl} +import language.experimental.captureChecking import scala.collection.Stepper.EfficientSplit /** An implicit StepperShape instance is used in the [[IterableOnce.stepper]] to return a possibly * specialized Stepper `S` according to the element type `T`. */ -sealed trait StepperShape[-T, S <: Stepper[_]] { +sealed trait StepperShape[-T, S <: Stepper[_]^] extends Pure { /** Return the Int constant (as defined in the `StepperShape` companion object) for this `StepperShape`. */ def shape: StepperShape.Shape diff --git a/tests/pos-special/stdlib/collection/StrictOptimizedIterableOps.scala b/tests/pos-special/stdlib/collection/StrictOptimizedIterableOps.scala index a09766cfa912..5b504a2469b5 100644 --- a/tests/pos-special/stdlib/collection/StrictOptimizedIterableOps.scala +++ b/tests/pos-special/stdlib/collection/StrictOptimizedIterableOps.scala @@ -16,6 +16,7 @@ package collection import scala.annotation.nowarn import scala.annotation.unchecked.uncheckedVariance import scala.runtime.Statics +import language.experimental.captureChecking /** * Trait that overrides iterable operations to take advantage of strict builders. @@ -27,6 +28,7 @@ import scala.runtime.Statics trait StrictOptimizedIterableOps[+A, +CC[_], +C] extends Any with IterableOps[A, CC, C] { + this: StrictOptimizedIterableOps[A, CC, C] => // Optimized, push-based version of `partition` override def partition(p: A => Boolean): (C, C) = { @@ -55,7 +57,7 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] (first.result(), second.result()) } - override def unzip[A1, A2](implicit asPair: A => (A1, A2)): (CC[A1], CC[A2]) = { + override def unzip[A1, A2](implicit asPair: A -> (A1, A2)): (CC[A1], CC[A2]) = { val first = iterableFactory.newBuilder[A1] val second = iterableFactory.newBuilder[A2] foreach { a => @@ -66,7 +68,7 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] (first.result(), second.result()) } - override def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3)): (CC[A1], CC[A2], CC[A3]) = { + override def unzip3[A1, A2, A3](implicit asTriple: A -> (A1, A2, A3)): (CC[A1], CC[A2], CC[A3]) = { val b1 = iterableFactory.newBuilder[A1] val b2 = iterableFactory.newBuilder[A2] val b3 = iterableFactory.newBuilder[A3] @@ -102,7 +104,7 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] b.result() } - override def flatMap[B](f: A => IterableOnce[B]): CC[B] = + override def flatMap[B](f: A => IterableOnce[B]^): CC[B] = strictOptimizedFlatMap(iterableFactory.newBuilder, f) /** @@ -112,7 +114,7 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] * @tparam C2 Type of the resulting collection (e.g. `List[String]`) * @return The resulting collection */ - @inline protected[this] final def strictOptimizedFlatMap[B, C2](b: mutable.Builder[B, C2], f: A => IterableOnce[B]): C2 = { + @inline protected[this] final def strictOptimizedFlatMap[B, C2](b: mutable.Builder[B, C2], f: A => IterableOnce[B]^): C2 = { val it = iterator while (it.hasNext) { b ++= f(it.next()) @@ -127,13 +129,13 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] * @tparam C2 Type of the resulting collection (e.g. `List[Int]`) * @return The resulting collection */ - @inline protected[this] final def strictOptimizedConcat[B >: A, C2](that: IterableOnce[B], b: mutable.Builder[B, C2]): C2 = { + @inline protected[this] final def strictOptimizedConcat[B >: A, C2](that: IterableOnce[B]^, b: mutable.Builder[B, C2]): C2 = { b ++= this b ++= that b.result() } - override def collect[B](pf: PartialFunction[A, B]): CC[B] = + override def collect[B](pf: PartialFunction[A, B]^): CC[B] = strictOptimizedCollect(iterableFactory.newBuilder, pf) /** @@ -143,7 +145,7 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] * @tparam C2 Type of the resulting collection (e.g. `List[String]`) * @return The resulting collection */ - @inline protected[this] final def strictOptimizedCollect[B, C2](b: mutable.Builder[B, C2], pf: PartialFunction[A, B]): C2 = { + @inline protected[this] final def strictOptimizedCollect[B, C2](b: mutable.Builder[B, C2], pf: PartialFunction[A, B]^): C2 = { val marker = Statics.pfMarker val it = iterator while (it.hasNext) { @@ -154,7 +156,7 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] b.result() } - override def flatten[B](implicit toIterableOnce: A => IterableOnce[B]): CC[B] = + override def flatten[B](implicit toIterableOnce: A -> IterableOnce[B]): CC[B] = strictOptimizedFlatten(iterableFactory.newBuilder) /** @@ -164,7 +166,7 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] * @tparam C2 Type of the resulting collection (e.g. `List[Int]`) * @return The resulting collection */ - @inline protected[this] final def strictOptimizedFlatten[B, C2](b: mutable.Builder[B, C2])(implicit toIterableOnce: A => IterableOnce[B]): C2 = { + @inline protected[this] final def strictOptimizedFlatten[B, C2](b: mutable.Builder[B, C2])(implicit toIterableOnce: A -> IterableOnce[B]): C2 = { val it = iterator while (it.hasNext) { b ++= toIterableOnce(it.next()) @@ -172,7 +174,7 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] b.result() } - override def zip[B](that: IterableOnce[B]): CC[(A @uncheckedVariance, B)] = + override def zip[B](that: IterableOnce[B]^): CC[(A @uncheckedVariance, B)] = strictOptimizedZip(that, iterableFactory.newBuilder[(A, B)]) /** @@ -182,7 +184,7 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C] * @tparam C2 Type of the resulting collection (e.g. `List[(Int, String)]`) * @return The resulting collection */ - @inline protected[this] final def strictOptimizedZip[B, C2](that: IterableOnce[B], b: mutable.Builder[(A, B), C2]): C2 = { + @inline protected[this] final def strictOptimizedZip[B, C2](that: IterableOnce[B]^, b: mutable.Builder[(A, B), C2]): C2 = { val it1 = iterator val it2 = that.iterator while (it1.hasNext && it2.hasNext) { diff --git a/tests/pos-special/stdlib/collection/StrictOptimizedMapOps.scala b/tests/pos-special/stdlib/collection/StrictOptimizedMapOps.scala index 1f5791bbb718..a9c5e0af43b3 100644 --- a/tests/pos-special/stdlib/collection/StrictOptimizedMapOps.scala +++ b/tests/pos-special/stdlib/collection/StrictOptimizedMapOps.scala @@ -11,6 +11,7 @@ */ package scala.collection +import language.experimental.captureChecking /** * Trait that overrides map operations to take advantage of strict builders. @@ -22,15 +23,16 @@ package scala.collection */ trait StrictOptimizedMapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C] extends MapOps[K, V, CC, C] - with StrictOptimizedIterableOps[(K, V), Iterable, C] { + with StrictOptimizedIterableOps[(K, V), Iterable, C] + with Pure { override def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = strictOptimizedMap(mapFactory.newBuilder, f) - override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = + override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]^): CC[K2, V2] = strictOptimizedFlatMap(mapFactory.newBuilder, f) - override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]): CC[K, V2] = + override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]^): CC[K, V2] = strictOptimizedConcat(suffix, mapFactory.newBuilder) override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)]): CC[K2, V2] = diff --git a/tests/pos-special/stdlib/collection/StrictOptimizedSeqOps.scala b/tests/pos-special/stdlib/collection/StrictOptimizedSeqOps.scala index 396e53885081..bfea9eda8bd3 100644 --- a/tests/pos-special/stdlib/collection/StrictOptimizedSeqOps.scala +++ b/tests/pos-special/stdlib/collection/StrictOptimizedSeqOps.scala @@ -11,6 +11,8 @@ */ package scala.collection +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** * Trait that overrides operations on sequences in order @@ -21,9 +23,9 @@ trait StrictOptimizedSeqOps [+A, +CC[_], +C] with SeqOps[A, CC, C] with StrictOptimizedIterableOps[A, CC, C] { - override def distinctBy[B](f: A => B): C = { + override def distinctBy[B](f: A -> B): C = { val builder = newSpecificBuilder - val seen = mutable.HashSet.empty[B] + val seen = mutable.HashSet.empty[B @uncheckedCaptures] val it = this.iterator while (it.hasNext) { val next = it.next() @@ -52,10 +54,10 @@ trait StrictOptimizedSeqOps [+A, +CC[_], +C] b.result() } - override def appendedAll[B >: A](suffix: IterableOnce[B]): CC[B] = + override def appendedAll[B >: A](suffix: IterableOnce[B]^): CC[B] = strictOptimizedConcat(suffix, iterableFactory.newBuilder) - override def prependedAll[B >: A](prefix: IterableOnce[B]): CC[B] = { + override def prependedAll[B >: A](prefix: IterableOnce[B]^): CC[B] = { val b = iterableFactory.newBuilder[B] b ++= prefix b ++= this @@ -78,7 +80,7 @@ trait StrictOptimizedSeqOps [+A, +CC[_], +C] override def diff[B >: A](that: Seq[B]): C = if (isEmpty || that.isEmpty) coll else { - val occ = occCounts(that) + val occ = occCounts[B @uncheckedCaptures](that) val b = newSpecificBuilder for (x <- this) { occ.updateWith(x) { @@ -96,7 +98,7 @@ trait StrictOptimizedSeqOps [+A, +CC[_], +C] override def intersect[B >: A](that: Seq[B]): C = if (isEmpty || that.isEmpty) empty else { - val occ = occCounts(that) + val occ = occCounts[B @uncheckedCaptures](that) val b = newSpecificBuilder for (x <- this) { occ.updateWith(x) { diff --git a/tests/pos-special/stdlib/collection/StrictOptimizedSetOps.scala b/tests/pos-special/stdlib/collection/StrictOptimizedSetOps.scala index 356bd2883578..8ed337fff998 100644 --- a/tests/pos-special/stdlib/collection/StrictOptimizedSetOps.scala +++ b/tests/pos-special/stdlib/collection/StrictOptimizedSetOps.scala @@ -11,6 +11,7 @@ */ package scala.collection +import language.experimental.captureChecking /** * Trait that overrides set operations to take advantage of strict builders. diff --git a/tests/pos-special/stdlib/collection/StrictOptimizedSortedMapOps.scala b/tests/pos-special/stdlib/collection/StrictOptimizedSortedMapOps.scala index 1beaf1662abe..9a9e6e367922 100644 --- a/tests/pos-special/stdlib/collection/StrictOptimizedSortedMapOps.scala +++ b/tests/pos-special/stdlib/collection/StrictOptimizedSortedMapOps.scala @@ -13,6 +13,7 @@ package scala.collection import scala.annotation.implicitNotFound +import language.experimental.captureChecking /** * Trait that overrides sorted map operations to take advantage of strict builders. @@ -32,7 +33,7 @@ trait StrictOptimizedSortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOp override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] = strictOptimizedFlatMap(sortedMapFactory.newBuilder, f) - override def concat[V2 >: V](xs: IterableOnce[(K, V2)]): CC[K, V2] = + override def concat[V2 >: V](xs: IterableOnce[(K, V2)]^): CC[K, V2] = strictOptimizedConcat(xs, sortedMapFactory.newBuilder(ordering)) override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] = diff --git a/tests/pos-special/stdlib/collection/StringOps.scala b/tests/pos-special/stdlib/collection/StringOps.scala index f0be485af8ae..3e3e2f8d872e 100644 --- a/tests/pos-special/stdlib/collection/StringOps.scala +++ b/tests/pos-special/stdlib/collection/StringOps.scala @@ -22,6 +22,7 @@ import scala.collection.mutable.StringBuilder import scala.math.{ScalaNumber, max, min} import scala.reflect.ClassTag import scala.util.matching.Regex +import language.experimental.captureChecking object StringOps { // just statics for companion class. @@ -123,7 +124,7 @@ object StringOps { * @return a new collection resulting from applying the given collection-valued function * `f` to each char of this string and concatenating the results. */ - def flatMap[B](f: Char => IterableOnce[B]): immutable.IndexedSeq[B] = { + def flatMap[B](f: Char => IterableOnce[B]^): immutable.IndexedSeq[B] = { val len = s.length val b = immutable.IndexedSeq.newBuilder[B] var i = 0 @@ -155,7 +156,7 @@ object StringOps { } /** Creates a new non-strict filter which combines this filter with the given predicate. */ - def withFilter(q: Char => Boolean): WithFilter = new WithFilter(a => p(a) && q(a), s) + def withFilter(q: Char => Boolean): WithFilter^{p, q} = new WithFilter(a => p(a) && q(a), s) } /** Avoid an allocation in [[collect]]. */ @@ -238,7 +239,7 @@ final class StringOps(private val s: String) extends AnyVal { * @return a new collection resulting from applying the given collection-valued function * `f` to each char of this string and concatenating the results. */ - def flatMap[B](f: Char => IterableOnce[B]): immutable.IndexedSeq[B] = { + def flatMap[B](f: Char => IterableOnce[B]^): immutable.IndexedSeq[B] = { val len = s.length val b = immutable.IndexedSeq.newBuilder[B] var i = 0 @@ -313,7 +314,7 @@ final class StringOps(private val s: String) extends AnyVal { * @return a new collection which contains all chars * of this string followed by all elements of `suffix`. */ - def concat[B >: Char](suffix: IterableOnce[B]): immutable.IndexedSeq[B] = { + def concat[B >: Char](suffix: IterableOnce[B]^): immutable.IndexedSeq[B] = { val b = immutable.IndexedSeq.newBuilder[B] val k = suffix.knownSize b.sizeHint(s.length + (if(k >= 0) k else 16)) @@ -329,7 +330,7 @@ final class StringOps(private val s: String) extends AnyVal { * @return a new string which contains all chars * of this string followed by all chars of `suffix`. */ - def concat(suffix: IterableOnce[Char]): String = { + def concat(suffix: IterableOnce[Char]^): String = { val k = suffix.knownSize val sb = new JStringBuilder(s.length + (if(k >= 0) k else 16)) sb.append(s) @@ -347,10 +348,10 @@ final class StringOps(private val s: String) extends AnyVal { @`inline` def concat(suffix: String): String = s + suffix /** Alias for `concat` */ - @`inline` def ++[B >: Char](suffix: Iterable[B]): immutable.IndexedSeq[B] = concat(suffix) + @`inline` def ++[B >: Char](suffix: Iterable[B]^): immutable.IndexedSeq[B] = concat(suffix) /** Alias for `concat` */ - @`inline` def ++(suffix: IterableOnce[Char]): String = concat(suffix) + @`inline` def ++(suffix: IterableOnce[Char]^): String = concat(suffix) /** Alias for `concat` */ def ++(xs: String): String = concat(xs) @@ -422,7 +423,7 @@ final class StringOps(private val s: String) extends AnyVal { @`inline` def +: (c: Char): String = prepended(c) /** A copy of the string with all elements from a collection prepended */ - def prependedAll[B >: Char](prefix: IterableOnce[B]): immutable.IndexedSeq[B] = { + def prependedAll[B >: Char](prefix: IterableOnce[B]^): immutable.IndexedSeq[B] = { val b = immutable.IndexedSeq.newBuilder[B] val k = prefix.knownSize b.sizeHint(s.length + (if(k >= 0) k else 16)) @@ -432,7 +433,7 @@ final class StringOps(private val s: String) extends AnyVal { } /** Alias for `prependedAll` */ - @`inline` def ++: [B >: Char] (prefix: IterableOnce[B]): immutable.IndexedSeq[B] = prependedAll(prefix) + @`inline` def ++: [B >: Char] (prefix: IterableOnce[B]^): immutable.IndexedSeq[B] = prependedAll(prefix) /** A copy of the string with another string prepended */ def prependedAll(prefix: String): String = prefix + s @@ -460,11 +461,11 @@ final class StringOps(private val s: String) extends AnyVal { @`inline` def :+ (c: Char): String = appended(c) /** A copy of the string with all elements from a collection appended */ - @`inline` def appendedAll[B >: Char](suffix: IterableOnce[B]): immutable.IndexedSeq[B] = + @`inline` def appendedAll[B >: Char](suffix: IterableOnce[B]^): immutable.IndexedSeq[B] = concat(suffix) /** Alias for `appendedAll` */ - @`inline` def :++ [B >: Char](suffix: IterableOnce[B]): immutable.IndexedSeq[B] = + @`inline` def :++ [B >: Char](suffix: IterableOnce[B]^): immutable.IndexedSeq[B] = concat(suffix) /** A copy of the string with another string appended */ @@ -486,7 +487,7 @@ final class StringOps(private val s: String) extends AnyVal { * except that `replaced` chars starting from `from` are replaced * by `other`. */ - def patch[B >: Char](from: Int, other: IterableOnce[B], replaced: Int): immutable.IndexedSeq[B] = { + def patch[B >: Char](from: Int, other: IterableOnce[B]^, replaced: Int): immutable.IndexedSeq[B] = { val len = s.length @`inline` def slc(off: Int, length: Int): WrappedString = new WrappedString(s.substring(off, off+length)) @@ -515,7 +516,7 @@ final class StringOps(private val s: String) extends AnyVal { * by `other`. * @note $unicodeunaware */ - def patch(from: Int, other: IterableOnce[Char], replaced: Int): String = + def patch(from: Int, other: IterableOnce[Char]^, replaced: Int): String = patch(from, other.iterator.mkString, replaced) /** Produces a new string where a slice of characters in this string is replaced by another string. @@ -963,7 +964,7 @@ final class StringOps(private val s: String) extends AnyVal { else if (s.equalsIgnoreCase("false")) false else throw new IllegalArgumentException("For input string: \""+s+"\"") - def toArray[B >: Char](implicit tag: ClassTag[B]): Array[B] = + def toArray[sealed B >: Char](implicit tag: ClassTag[B]): Array[B] = if (tag == ClassTag.Char) s.toCharArray.asInstanceOf[Array[B]] else new WrappedString(s).toArray[B] @@ -1195,7 +1196,7 @@ final class StringOps(private val s: String) extends AnyVal { * All these operations apply to those chars of this string * which satisfy the predicate `p`. */ - def withFilter(p: Char => Boolean): StringOps.WithFilter = new StringOps.WithFilter(p, s) + def withFilter(p: Char => Boolean): StringOps.WithFilter^{p} = new StringOps.WithFilter(p, s) /** The rest of the string without its first char. * @note $unicodeunaware @@ -1246,7 +1247,7 @@ final class StringOps(private val s: String) extends AnyVal { def inits: Iterator[String] = iterateUntilEmpty(_.init) // A helper for tails and inits. - private[this] def iterateUntilEmpty(f: String => String): Iterator[String] = + private[this] def iterateUntilEmpty(f: String => String): Iterator[String]^{f} = Iterator.iterate(s)(f).takeWhile(x => !x.isEmpty) ++ Iterator.single("") /** Selects all chars of this string which satisfy a predicate. */ @@ -1464,7 +1465,7 @@ final class StringOps(private val s: String) extends AnyVal { * @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs * or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported. */ - def lazyZip[B](that: Iterable[B]): LazyZip2[Char, B, String] = new LazyZip2(s, new WrappedString(s), that) + def lazyZip[B](that: Iterable[B]^): LazyZip2[Char, B, String]^{that} = new LazyZip2(s, new WrappedString(s), that) /* ************************************************************************************************************ @@ -1512,7 +1513,7 @@ final class StringOps(private val s: String) extends AnyVal { * @return a new string consisting of all the chars of this string without duplicates. * @note $unicodeunaware */ - def distinctBy[B](f: Char => B): String = new WrappedString(s).distinctBy(f).unwrap + def distinctBy[B](f: Char -> B): String = new WrappedString(s).distinctBy(f).unwrap /** Sorts the characters of this string according to an Ordering. * diff --git a/tests/pos-special/stdlib/collection/StringParsers.scala b/tests/pos-special/stdlib/collection/StringParsers.scala index 5479a58d485f..47281815da71 100644 --- a/tests/pos-special/stdlib/collection/StringParsers.scala +++ b/tests/pos-special/stdlib/collection/StringParsers.scala @@ -14,6 +14,7 @@ package scala package collection import scala.annotation.tailrec +import language.experimental.captureChecking /** A module containing the implementations of parsers from strings to numeric types, and boolean */ @@ -34,7 +35,7 @@ private[scala] object StringParsers { @inline private[this] final def stepToOverflow(from: String, len: Int, agg: Int, isPositive: Boolean, min: Int): Option[Int] = { @tailrec - def rec(i: Int, agg: Int): Option[Int] = + def rec(i: Int, agg: Int): Option[Int] = if (agg < min) None else if (i == len) { if (!isPositive) Some(agg) @@ -131,11 +132,11 @@ private[scala] object StringParsers { else None } } - + final def parseLong(from: String): Option[Long] = { //like parseInt, but Longer val len = from.length() - + @tailrec def step(i: Int, agg: Long, isPositive: Boolean): Option[Long] = { if (i == len) { @@ -166,7 +167,7 @@ private[scala] object StringParsers { else None } } - + //floating point final def checkFloatFormat(format: String): Boolean = { //indices are tracked with a start index which points *at* the first index @@ -192,7 +193,7 @@ private[scala] object StringParsers { else i rec(from) } - + def isHexFloatLiteral(startIndex: Int, endIndex: Int): Boolean = { def isHexDigit(ch: Char) = ((ch >= '0' && ch <= '9') || @@ -231,7 +232,7 @@ private[scala] object StringParsers { val pIndex = format.indexWhere(ch => ch == 'p' || ch == 'P', startIndex) (pIndex <= endIndex) && prefixOK(startIndex, pIndex) && postfixOK(pIndex + 1, endIndex) } - + def isDecFloatLiteral(startIndex: Int, endIndex: Int): Boolean = { //invariant: endIndex > startIndex @@ -278,7 +279,7 @@ private[scala] object StringParsers { //count 0x00 to 0x20 as "whitespace", and nothing else val unspacedStart = format.indexWhere(ch => ch.toInt > 0x20) val unspacedEnd = format.lastIndexWhere(ch => ch.toInt > 0x20) + 1 - + if (unspacedStart == -1 || unspacedStart >= unspacedEnd || unspacedEnd <= 0) false else { //all formats can have a sign @@ -305,7 +306,7 @@ private[scala] object StringParsers { } } } - + @inline def parseFloat(from: String): Option[Float] = if (checkFloatFormat(from)) Some(java.lang.Float.parseFloat(from)) diff --git a/tests/pos-special/stdlib/collection/View.scala b/tests/pos-special/stdlib/collection/View.scala index 441790c3c6e5..d91fc0c49939 100644 --- a/tests/pos-special/stdlib/collection/View.scala +++ b/tests/pos-special/stdlib/collection/View.scala @@ -15,6 +15,8 @@ package scala.collection import scala.annotation.{nowarn, tailrec} import scala.collection.mutable.{ArrayBuffer, Builder} import scala.collection.immutable.LazyList +import scala.annotation.unchecked.uncheckedCaptures +import language.experimental.captureChecking /** Views are collections whose transformation operations are non strict: the resulting elements * are evaluated only when the view is effectively traversed (e.g. using `foreach` or `foldLeft`), @@ -23,8 +25,9 @@ import scala.collection.immutable.LazyList * @define Coll `View` */ trait View[+A] extends Iterable[A] with IterableOps[A, View, View[A]] with IterableFactoryDefaults[A, View] with Serializable { + this: View[A]^ => - override def view: View[A] = this + override def view: View[A]^{this} = this override def iterableFactory: IterableFactory[View] = View @@ -55,8 +58,8 @@ object View extends IterableFactory[View] { * * @tparam A View element type */ - def fromIteratorProvider[A](it: () => Iterator[A]): View[A] = new AbstractView[A] { - def iterator = it() + def fromIteratorProvider[A](it: () => Iterator[A]^): View[A]^{it} = new AbstractView[A] { + def iterator: Iterator[A]^{it} = it() } /** @@ -67,7 +70,7 @@ object View extends IterableFactory[View] { * * @tparam E View element type */ - def from[E](it: IterableOnce[E]): View[E] = it match { + def from[E](it: IterableOnce[E]^): View[E]^{it} = it match { case it: View[E] => it case it: Iterable[E] => View.fromIteratorProvider(() => it.iterator) case _ => LazyList.from(it).view @@ -75,7 +78,7 @@ object View extends IterableFactory[View] { def empty[A]: View[A] = Empty - def newBuilder[A]: Builder[A, View[A]] = ArrayBuffer.newBuilder[A].mapResult(from) + def newBuilder[sealed A]: Builder[A, View[A]] = ArrayBuffer.newBuilder[A].mapResult(from) override def apply[A](xs: A*): View[A] = new Elems(xs: _*) @@ -97,7 +100,7 @@ object View extends IterableFactory[View] { /** A view with given elements */ @SerialVersionUID(3L) - class Elems[A](xs: A*) extends AbstractView[A] { + class Elems[A](xs: A*) extends AbstractView[A], Pure { def iterator = xs.iterator override def knownSize = xs.knownSize override def isEmpty: Boolean = xs.isEmpty @@ -106,7 +109,7 @@ object View extends IterableFactory[View] { /** A view containing the results of some element computation a number of times. */ @SerialVersionUID(3L) class Fill[A](n: Int)(elem: => A) extends AbstractView[A] { - def iterator = Iterator.fill(n)(elem) + def iterator: Iterator[A]^{elem} = Iterator.fill(n)(elem) override def knownSize: Int = 0 max n override def isEmpty: Boolean = n <= 0 } @@ -114,7 +117,7 @@ object View extends IterableFactory[View] { /** A view containing values of a given function over a range of integer values starting from 0. */ @SerialVersionUID(3L) class Tabulate[A](n: Int)(f: Int => A) extends AbstractView[A] { - def iterator: Iterator[A] = Iterator.tabulate(n)(f) + def iterator: Iterator[A]^{f} = Iterator.tabulate(n)(f) override def knownSize: Int = 0 max n override def isEmpty: Boolean = n <= 0 } @@ -122,7 +125,7 @@ object View extends IterableFactory[View] { /** A view containing repeated applications of a function to a start value */ @SerialVersionUID(3L) class Iterate[A](start: A, len: Int)(f: A => A) extends AbstractView[A] { - def iterator: Iterator[A] = Iterator.iterate(start)(f).take(len) + def iterator: Iterator[A]^{f} = Iterator.iterate(start)(f).take(len) override def knownSize: Int = 0 max len override def isEmpty: Boolean = len <= 0 } @@ -132,7 +135,7 @@ object View extends IterableFactory[View] { */ @SerialVersionUID(3L) class Unfold[A, S](initial: S)(f: S => Option[(A, S)]) extends AbstractView[A] { - def iterator: Iterator[A] = Iterator.unfold(initial)(f) + def iterator: Iterator[A]^{f} = Iterator.unfold(initial)(f) } /** An `IterableOps` whose collection type and collection type constructor are unknown */ @@ -140,14 +143,14 @@ object View extends IterableFactory[View] { /** A view that filters an underlying collection. */ @SerialVersionUID(3L) - class Filter[A](val underlying: SomeIterableOps[A], val p: A => Boolean, val isFlipped: Boolean) extends AbstractView[A] { - def iterator = underlying.iterator.filterImpl(p, isFlipped) + class Filter[A](val underlying: SomeIterableOps[A]^, val p: A => Boolean, val isFlipped: Boolean) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying, p} = underlying.iterator.filterImpl(p, isFlipped) override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize override def isEmpty: Boolean = iterator.isEmpty } object Filter { - def apply[A](underlying: Iterable[A], p: A => Boolean, isFlipped: Boolean): Filter[A] = + def apply[A](underlying: Iterable[A]^, p: A => Boolean, isFlipped: Boolean): Filter[A]^{underlying, p} = underlying match { case filter: Filter[A] if filter.isFlipped == isFlipped => new Filter(filter.underlying, a => filter.p(a) && p(a), isFlipped) case _ => new Filter(underlying, p, isFlipped) @@ -156,15 +159,15 @@ object View extends IterableFactory[View] { /** A view that removes the duplicated elements as determined by the transformation function `f` */ @SerialVersionUID(3L) - class DistinctBy[A, B](underlying: SomeIterableOps[A], f: A => B) extends AbstractView[A] { - def iterator: Iterator[A] = underlying.iterator.distinctBy(f) + class DistinctBy[A, B](underlying: SomeIterableOps[A]^, f: A -> B) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying} = underlying.iterator.distinctBy(f) override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize override def isEmpty: Boolean = underlying.isEmpty } @SerialVersionUID(3L) - class LeftPartitionMapped[A, A1, A2](underlying: SomeIterableOps[A], f: A => Either[A1, A2]) extends AbstractView[A1] { - def iterator = new AbstractIterator[A1] { + class LeftPartitionMapped[A, A1, A2](underlying: SomeIterableOps[A]^, f: A => Either[A1, A2]) extends AbstractView[A1] { + def iterator: Iterator[A1]^{underlying, f} = new AbstractIterator[A1] { private[this] val self = underlying.iterator private[this] var hd: A1 = _ private[this] var hdDefined: Boolean = false @@ -188,8 +191,8 @@ object View extends IterableFactory[View] { } @SerialVersionUID(3L) - class RightPartitionMapped[A, A1, A2](underlying: SomeIterableOps[A], f: A => Either[A1, A2]) extends AbstractView[A2] { - def iterator = new AbstractIterator[A2] { + class RightPartitionMapped[A, A1, A2](underlying: SomeIterableOps[A]^, f: A => Either[A1, A2]) extends AbstractView[A2] { + def iterator: Iterator[A2]^{this} = new AbstractIterator[A2] { private[this] val self = underlying.iterator private[this] var hd: A2 = _ private[this] var hdDefined: Boolean = false @@ -214,8 +217,8 @@ object View extends IterableFactory[View] { /** A view that drops leading elements of the underlying collection. */ @SerialVersionUID(3L) - class Drop[A](underlying: SomeIterableOps[A], n: Int) extends AbstractView[A] { - def iterator = underlying.iterator.drop(n) + class Drop[A](underlying: SomeIterableOps[A]^, n: Int) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying} = underlying.iterator.drop(n) protected val normN = n max 0 override def knownSize = { val size = underlying.knownSize @@ -226,8 +229,8 @@ object View extends IterableFactory[View] { /** A view that drops trailing elements of the underlying collection. */ @SerialVersionUID(3L) - class DropRight[A](underlying: SomeIterableOps[A], n: Int) extends AbstractView[A] { - def iterator = dropRightIterator(underlying.iterator, n) + class DropRight[A](underlying: SomeIterableOps[A]^, n: Int) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying} = dropRightIterator(underlying.iterator, n) protected val normN = n max 0 override def knownSize = { val size = underlying.knownSize @@ -239,16 +242,16 @@ object View extends IterableFactory[View] { } @SerialVersionUID(3L) - class DropWhile[A](underlying: SomeIterableOps[A], p: A => Boolean) extends AbstractView[A] { - def iterator = underlying.iterator.dropWhile(p) + class DropWhile[A](underlying: SomeIterableOps[A]^, p: A => Boolean) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying, p} = underlying.iterator.dropWhile(p) override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize override def isEmpty: Boolean = iterator.isEmpty } /** A view that takes leading elements of the underlying collection. */ @SerialVersionUID(3L) - class Take[+A](underlying: SomeIterableOps[A], n: Int) extends AbstractView[A] { - def iterator = underlying.iterator.take(n) + class Take[+A](underlying: SomeIterableOps[A]^, n: Int) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying} = underlying.iterator.take(n) protected val normN = n max 0 override def knownSize = { val size = underlying.knownSize @@ -259,8 +262,8 @@ object View extends IterableFactory[View] { /** A view that takes trailing elements of the underlying collection. */ @SerialVersionUID(3L) - class TakeRight[+A](underlying: SomeIterableOps[A], n: Int) extends AbstractView[A] { - def iterator = takeRightIterator(underlying.iterator, n) + class TakeRight[+A](underlying: SomeIterableOps[A]^, n: Int) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying} = takeRightIterator(underlying.iterator, n) protected val normN = n max 0 override def knownSize = { val size = underlying.knownSize @@ -272,15 +275,15 @@ object View extends IterableFactory[View] { } @SerialVersionUID(3L) - class TakeWhile[A](underlying: SomeIterableOps[A], p: A => Boolean) extends AbstractView[A] { - def iterator: Iterator[A] = underlying.iterator.takeWhile(p) + class TakeWhile[A](underlying: SomeIterableOps[A]^, p: A => Boolean) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying, p} = underlying.iterator.takeWhile(p) override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize override def isEmpty: Boolean = iterator.isEmpty } @SerialVersionUID(3L) - class ScanLeft[+A, +B](underlying: SomeIterableOps[A], z: B, op: (B, A) => B) extends AbstractView[B] { - def iterator: Iterator[B] = underlying.iterator.scanLeft(z)(op) + class ScanLeft[+A, +B](underlying: SomeIterableOps[A]^, z: B, op: (B, A) => B) extends AbstractView[B] { + def iterator: Iterator[B]^{underlying, op} = underlying.iterator.scanLeft(z)(op) override def knownSize: Int = { val size = underlying.knownSize if (size >= 0) size + 1 else -1 @@ -290,32 +293,32 @@ object View extends IterableFactory[View] { /** A view that maps elements of the underlying collection. */ @SerialVersionUID(3L) - class Map[+A, +B](underlying: SomeIterableOps[A], f: A => B) extends AbstractView[B] { - def iterator = underlying.iterator.map(f) + class Map[+A, +B](underlying: SomeIterableOps[A]^, f: A => B) extends AbstractView[B] { + def iterator: Iterator[B]^{underlying, f} = underlying.iterator.map(f) override def knownSize = underlying.knownSize override def isEmpty: Boolean = underlying.isEmpty } /** A view that flatmaps elements of the underlying collection. */ @SerialVersionUID(3L) - class FlatMap[A, B](underlying: SomeIterableOps[A], f: A => IterableOnce[B]) extends AbstractView[B] { - def iterator = underlying.iterator.flatMap(f) + class FlatMap[A, B](underlying: SomeIterableOps[A]^, f: A => IterableOnce[B]^) extends AbstractView[B] { + def iterator: Iterator[B]^{underlying, f} = underlying.iterator.flatMap(f) override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize override def isEmpty: Boolean = iterator.isEmpty } /** A view that collects elements of the underlying collection. */ @SerialVersionUID(3L) - class Collect[+A, B](underlying: SomeIterableOps[A], pf: PartialFunction[A, B]) extends AbstractView[B] { - def iterator = underlying.iterator.collect(pf) + class Collect[+A, B](underlying: SomeIterableOps[A]^, pf: PartialFunction[A, B]^) extends AbstractView[B] { + def iterator: Iterator[B]^{underlying, pf} = underlying.iterator.collect(pf) } /** A view that concatenates elements of the prefix collection or iterator with the elements * of the suffix collection or iterator. */ @SerialVersionUID(3L) - class Concat[A](prefix: SomeIterableOps[A], suffix: SomeIterableOps[A]) extends AbstractView[A] { - def iterator = prefix.iterator ++ suffix.iterator + class Concat[A](prefix: SomeIterableOps[A]^, suffix: SomeIterableOps[A]^) extends AbstractView[A] { + def iterator: Iterator[A]^{prefix, suffix} = prefix.iterator ++ suffix.iterator override def knownSize = { val prefixSize = prefix.knownSize if (prefixSize >= 0) { @@ -332,8 +335,8 @@ object View extends IterableFactory[View] { * of another collection. */ @SerialVersionUID(3L) - class Zip[A, B](underlying: SomeIterableOps[A], other: Iterable[B]) extends AbstractView[(A, B)] { - def iterator = underlying.iterator.zip(other) + class Zip[A, B](underlying: SomeIterableOps[A]^, other: Iterable[B]^) extends AbstractView[(A, B)] { + def iterator: Iterator[(A, B)]^{underlying, other} = underlying.iterator.zip(other) override def knownSize = { val s1 = underlying.knownSize if (s1 == 0) 0 else { @@ -349,8 +352,8 @@ object View extends IterableFactory[View] { * placeholder elements are used to extend the shorter collection to the length of the longer. */ @SerialVersionUID(3L) - class ZipAll[A, B](underlying: SomeIterableOps[A], other: Iterable[B], thisElem: A, thatElem: B) extends AbstractView[(A, B)] { - def iterator = underlying.iterator.zipAll(other, thisElem, thatElem) + class ZipAll[A, B](underlying: SomeIterableOps[A]^, other: Iterable[B]^, thisElem: A, thatElem: B) extends AbstractView[(A, B)] { + def iterator: Iterator[(A, B)]^{underlying, other} = underlying.iterator.zipAll(other, thisElem, thatElem) override def knownSize = { val s1 = underlying.knownSize if(s1 == -1) -1 else { @@ -363,8 +366,10 @@ object View extends IterableFactory[View] { /** A view that appends an element to its elements */ @SerialVersionUID(3L) - class Appended[+A](underlying: SomeIterableOps[A], elem: A) extends AbstractView[A] { - def iterator: Iterator[A] = new Concat(underlying, new View.Single(elem)).iterator + class Appended[+A](underlying: SomeIterableOps[A]^, elem: A) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying} = + val ct = new Concat(underlying, new View.Single(elem)) + ct.iterator // CC TODO breakout into `ct` needed, otherwise "cannot establish a reference" error override def knownSize: Int = { val size = underlying.knownSize if (size >= 0) size + 1 else -1 @@ -374,8 +379,10 @@ object View extends IterableFactory[View] { /** A view that prepends an element to its elements */ @SerialVersionUID(3L) - class Prepended[+A](elem: A, underlying: SomeIterableOps[A]) extends AbstractView[A] { - def iterator: Iterator[A] = new Concat(new View.Single(elem), underlying).iterator + class Prepended[+A](elem: A, underlying: SomeIterableOps[A]^) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying} = + val ct = new Concat(new View.Single(elem), underlying) + ct.iterator // CC TODO breakout into `ct` needed, otherwise "cannot establish a reference" error override def knownSize: Int = { val size = underlying.knownSize if (size >= 0) size + 1 else -1 @@ -384,8 +391,8 @@ object View extends IterableFactory[View] { } @SerialVersionUID(3L) - class Updated[A](underlying: SomeIterableOps[A], index: Int, elem: A) extends AbstractView[A] { - def iterator: Iterator[A] = new AbstractIterator[A] { + class Updated[A](underlying: SomeIterableOps[A]^, index: Int, elem: A) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying} = new AbstractIterator[A] { private[this] val it = underlying.iterator private[this] var i = 0 def next(): A = { @@ -403,28 +410,28 @@ object View extends IterableFactory[View] { } @SerialVersionUID(3L) - private[collection] class Patched[A](underlying: SomeIterableOps[A], from: Int, other: IterableOnce[A], replaced: Int) extends AbstractView[A] { + private[collection] class Patched[A](underlying: SomeIterableOps[A]^, from: Int, other: IterableOnce[A]^, replaced: Int) extends AbstractView[A] { // we may be unable to traverse `other` more than once, so we need to cache it if that's the case - private val _other: Iterable[A] = other match { + private val _other: Iterable[A]^{other} = other match { case other: Iterable[A] => other case other => LazyList.from(other) } - def iterator: Iterator[A] = underlying.iterator.patch(from, _other.iterator, replaced) + def iterator: Iterator[A]^{underlying, other} = underlying.iterator.patch(from, _other.iterator, replaced) override def knownSize: Int = if (underlying.knownSize == 0 && _other.knownSize == 0) 0 else super.knownSize override def isEmpty: Boolean = if (knownSize == 0) true else iterator.isEmpty } @SerialVersionUID(3L) - class ZipWithIndex[A](underlying: SomeIterableOps[A]) extends AbstractView[(A, Int)] { - def iterator: Iterator[(A, Int)] = underlying.iterator.zipWithIndex + class ZipWithIndex[A](underlying: SomeIterableOps[A]^) extends AbstractView[(A, Int)] { + def iterator: Iterator[(A, Int)]^{underlying} = underlying.iterator.zipWithIndex override def knownSize: Int = underlying.knownSize override def isEmpty: Boolean = underlying.isEmpty } @SerialVersionUID(3L) - class PadTo[A](underlying: SomeIterableOps[A], len: Int, elem: A) extends AbstractView[A] { - def iterator: Iterator[A] = underlying.iterator.padTo(len, elem) + class PadTo[A](underlying: SomeIterableOps[A]^, len: Int, elem: A) extends AbstractView[A] { + def iterator: Iterator[A]^{underlying} = underlying.iterator.padTo(len, elem) override def knownSize: Int = { val size = underlying.knownSize @@ -433,7 +440,7 @@ object View extends IterableFactory[View] { override def isEmpty: Boolean = underlying.isEmpty && len <= 0 } - private[collection] def takeRightIterator[A](it: Iterator[A], n: Int): Iterator[A] = { + private[collection] def takeRightIterator[A](it: Iterator[A]^, n: Int): Iterator[A]^{it} = { val k = it.knownSize if(k == 0 || n <= 0) Iterator.empty else if(n == Int.MaxValue) it @@ -441,22 +448,23 @@ object View extends IterableFactory[View] { else new TakeRightIterator[A](it, n) } - private final class TakeRightIterator[A](private[this] var underlying: Iterator[A], maxlen: Int) extends AbstractIterator[A] { + private final class TakeRightIterator[A](underlying: Iterator[A]^, maxlen: Int) extends AbstractIterator[A] { + private[this] var current: Iterator[A @uncheckedCaptures]^{underlying} = underlying private[this] var len: Int = -1 private[this] var pos: Int = 0 private[this] var buf: ArrayBuffer[AnyRef] = _ def init(): Unit = if(buf eq null) { buf = new ArrayBuffer[AnyRef](maxlen min 256) len = 0 - while(underlying.hasNext) { - val n = underlying.next().asInstanceOf[AnyRef] + while(current.hasNext) { + val n = current.next().asInstanceOf[AnyRef] if(pos >= buf.length) buf.addOne(n) else buf(pos) = n pos += 1 if(pos == maxlen) pos = 0 len += 1 } - underlying = null + current = null if(len > maxlen) len = maxlen pos = pos - len if(pos < 0) pos += maxlen @@ -477,7 +485,7 @@ object View extends IterableFactory[View] { x } } - override def drop(n: Int): Iterator[A] = { + override def drop(n: Int): Iterator[A]^{this} = { init() if (n > 0) { len = (len - n) max 0 @@ -487,7 +495,7 @@ object View extends IterableFactory[View] { } } - private[collection] def dropRightIterator[A](it: Iterator[A], n: Int): Iterator[A] = { + private[collection] def dropRightIterator[A](it: Iterator[A]^, n: Int): Iterator[A]^{it} = { if(n <= 0) it else { val k = it.knownSize @@ -496,7 +504,7 @@ object View extends IterableFactory[View] { } } - private final class DropRightIterator[A](private[this] var underlying: Iterator[A], maxlen: Int) extends AbstractIterator[A] { + private final class DropRightIterator[A](underlying: Iterator[A]^, maxlen: Int) extends AbstractIterator[A] { private[this] var len: Int = -1 // known size or -1 if the end of `underlying` has not been seen yet private[this] var pos: Int = 0 private[this] var buf: ArrayBuffer[AnyRef] = _ diff --git a/tests/pos-special/stdlib/collection/WithFilter.scala b/tests/pos-special/stdlib/collection/WithFilter.scala index 4699abbef5a7..0f3830e9fe25 100644 --- a/tests/pos-special/stdlib/collection/WithFilter.scala +++ b/tests/pos-special/stdlib/collection/WithFilter.scala @@ -11,6 +11,7 @@ */ package scala.collection +import language.experimental.captureChecking /** A template trait that contains just the `map`, `flatMap`, `foreach` and `withFilter` methods * of trait `Iterable`. @@ -22,6 +23,7 @@ package scala.collection */ @SerialVersionUID(3L) abstract class WithFilter[+A, +CC[_]] extends Serializable { + this: WithFilter[A, CC]^ => /** Builds a new collection by applying a function to all elements of the * `filtered` outer $coll. @@ -32,7 +34,7 @@ abstract class WithFilter[+A, +CC[_]] extends Serializable { * the given function `f` to each element of the filtered outer $coll * and collecting the results. */ - def map[B](f: A => B): CC[B] + def map[B](f: A => B): CC[B]^{this, f} /** Builds a new collection by applying a function to all elements of the * `filtered` outer $coll containing this `WithFilter` instance that satisfy @@ -44,7 +46,7 @@ abstract class WithFilter[+A, +CC[_]] extends Serializable { * of the filtered outer $coll and * concatenating the results. */ - def flatMap[B](f: A => IterableOnce[B]): CC[B] + def flatMap[B](f: A => IterableOnce[B]^): CC[B]^{this, f} /** Applies a function `f` to all elements of the `filtered` outer $coll. * @@ -65,6 +67,6 @@ abstract class WithFilter[+A, +CC[_]] extends Serializable { * All these operations apply to those elements of this $coll which * also satisfy both `p` and `q` predicates. */ - def withFilter(q: A => Boolean): WithFilter[A, CC] + def withFilter(q: A => Boolean): WithFilter[A, CC]^{this, q} } diff --git a/tests/pos-special/stdlib/collection/concurrent/Map.scala b/tests/pos-special/stdlib/collection/concurrent/Map.scala index c2b996b93102..d985dad2edc5 100644 --- a/tests/pos-special/stdlib/collection/concurrent/Map.scala +++ b/tests/pos-special/stdlib/collection/concurrent/Map.scala @@ -13,6 +13,7 @@ package scala package collection.concurrent +import language.experimental.captureChecking import scala.annotation.tailrec /** A template trait for mutable maps that allow concurrent access. diff --git a/tests/pos-special/stdlib/collection/concurrent/TrieMap.scala b/tests/pos-special/stdlib/collection/concurrent/TrieMap.scala index e4aa8c8c52a7..0824ecc44519 100644 --- a/tests/pos-special/stdlib/collection/concurrent/TrieMap.scala +++ b/tests/pos-special/stdlib/collection/concurrent/TrieMap.scala @@ -23,8 +23,10 @@ import scala.collection.immutable.{List, Nil} import scala.collection.mutable.GrowableBuilder import scala.util.Try import scala.util.hashing.Hashing +import language.experimental.captureChecking +import caps.unsafe.unsafeAssumePure -private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen, equiv: Equiv[K]) extends INodeBase[K, V](g) { +private[collection] final class INode[sealed K, sealed V](bn: MainNode[K, V], g: Gen, equiv: Equiv[K]) extends INodeBase[K, V](g) { import INodeBase._ WRITE(bn) @@ -427,7 +429,7 @@ private[concurrent] object INode { final val KEY_ABSENT = new AnyRef final val KEY_PRESENT_OR_ABSENT = new AnyRef - def newRootNode[K, V](equiv: Equiv[K]) = { + def newRootNode[sealed K, sealed V](equiv: Equiv[K]) = { val gen = new Gen val cn = new CNode[K, V](0, new Array(0), gen) new INode[K, V](cn, gen, equiv) @@ -435,7 +437,7 @@ private[concurrent] object INode { } -private[concurrent] final class FailedNode[K, V](p: MainNode[K, V]) extends MainNode[K, V] { +private[concurrent] final class FailedNode[sealed K, sealed V](p: MainNode[K, V]) extends MainNode[K, V] { WRITE_PREV(p) def string(lev: Int) = throw new UnsupportedOperationException @@ -448,12 +450,12 @@ private[concurrent] final class FailedNode[K, V](p: MainNode[K, V]) extends Main } -private[concurrent] trait KVNode[K, V] { +private[concurrent] trait KVNode[sealed K, sealed V] { def kvPair: (K, V) } -private[collection] final class SNode[K, V](final val k: K, final val v: V, final val hc: Int) +private[collection] final class SNode[sealed K, sealed V](final val k: K, final val v: V, final val hc: Int) extends BasicNode with KVNode[K, V] { def copy = new SNode(k, v, hc) def copyTombed = new TNode(k, v, hc) @@ -463,7 +465,7 @@ private[collection] final class SNode[K, V](final val k: K, final val v: V, fina } // Tomb Node, used to ensure proper ordering during removals -private[collection] final class TNode[K, V](final val k: K, final val v: V, final val hc: Int) +private[collection] final class TNode[sealed K, sealed V](final val k: K, final val v: V, final val hc: Int) extends MainNode[K, V] with KVNode[K, V] { def copy = new TNode(k, v, hc) def copyTombed = new TNode(k, v, hc) @@ -475,7 +477,7 @@ private[collection] final class TNode[K, V](final val k: K, final val v: V, fina } // List Node, leaf node that handles hash collisions -private[collection] final class LNode[K, V](val entries: List[(K, V)], equiv: Equiv[K]) +private[collection] final class LNode[sealed K, sealed V](val entries: List[(K, V)], equiv: Equiv[K]) extends MainNode[K, V] { def this(k: K, v: V, equiv: Equiv[K]) = this((k -> v) :: Nil, equiv) @@ -517,7 +519,7 @@ private[collection] final class LNode[K, V](val entries: List[(K, V)], equiv: Eq } // Ctrie Node, contains bitmap and array of references to branch nodes -private[collection] final class CNode[K, V](val bitmap: Int, val array: Array[BasicNode], val gen: Gen) extends CNodeBase[K, V] { +private[collection] final class CNode[sealed K, sealed V](val bitmap: Int, val array: Array[BasicNode], val gen: Gen) extends CNodeBase[K, V] { // this should only be called from within read-only snapshots def cachedSize(ct: AnyRef): Int = { val currsz = READ_SIZE() @@ -653,7 +655,7 @@ private[collection] final class CNode[K, V](val bitmap: Int, val array: Array[Ba private[concurrent] object CNode { - def dual[K, V](x: SNode[K, V], xhc: Int, y: SNode[K, V], yhc: Int, lev: Int, gen: Gen, equiv: Equiv[K]): MainNode[K, V] = if (lev < 35) { + def dual[sealed K, sealed V](x: SNode[K, V], xhc: Int, y: SNode[K, V], yhc: Int, lev: Int, gen: Gen, equiv: Equiv[K]): MainNode[K, V] = if (lev < 35) { val xidx = (xhc >>> lev) & 0x1f val yidx = (yhc >>> lev) & 0x1f val bmp = (1 << xidx) | (1 << yidx) @@ -688,7 +690,7 @@ private[concurrent] case class RDCSS_Descriptor[K, V](old: INode[K, V], expected * For details, see: [[http://lampwww.epfl.ch/~prokopec/ctries-snapshot.pdf]] */ @SerialVersionUID(-5212455458703321708L) -final class TrieMap[K, V] private (r: AnyRef, rtupd: AtomicReferenceFieldUpdater[TrieMap[K, V], AnyRef], hashf: Hashing[K], ef: Equiv[K]) +final class TrieMap[sealed K, sealed V] private (r: AnyRef, rtupd: AtomicReferenceFieldUpdater[TrieMap[K, V], AnyRef], hashf: Hashing[K], ef: Equiv[K]) extends scala.collection.mutable.AbstractMap[K, V] with scala.collection.concurrent.Map[K, V] with scala.collection.mutable.MapOps[K, V, TrieMap, TrieMap[K, V]] @@ -1017,10 +1019,10 @@ final class TrieMap[K, V] private (r: AnyRef, rtupd: AtomicReferenceFieldUpdater override def view: MapView[K, V] = if (nonReadOnly) readOnlySnapshot().view else super.view @deprecated("Use .view.filterKeys(f). A future version will include a strict version of this method (for now, .view.filterKeys(p).toMap).", "2.13.0") - override def filterKeys(p: K => Boolean): collection.MapView[K, V] = view.filterKeys(p) + override def filterKeys(p: K => Boolean): collection.MapView[K, V]^{p} = view.filterKeys(p) @deprecated("Use .view.mapValues(f). A future version will include a strict version of this method (for now, .view.mapValues(f).toMap).", "2.13.0") - override def mapValues[W](f: V => W): collection.MapView[K, W] = view.mapValues(f) + override def mapValues[W](f: V => W): collection.MapView[K, W]^{f} = view.mapValues(f) // END extra overrides /////////////////////////////////////////////////////////////////// @@ -1041,11 +1043,11 @@ final class TrieMap[K, V] private (r: AnyRef, rtupd: AtomicReferenceFieldUpdater @SerialVersionUID(3L) object TrieMap extends MapFactory[TrieMap] { - def empty[K, V]: TrieMap[K, V] = new TrieMap[K, V] + def empty[sealed K, sealed V]: TrieMap[K, V] = new TrieMap[K, V] - def from[K, V](it: IterableOnce[(K, V)]): TrieMap[K, V] = new TrieMap[K, V]() ++= it + def from[sealed K, sealed V](it: IterableOnce[(K, V)]^): TrieMap[K, V] = new TrieMap[K, V]() ++= it - def newBuilder[K, V]: mutable.GrowableBuilder[(K, V), TrieMap[K, V]] = new GrowableBuilder(empty[K, V]) + def newBuilder[sealed K, sealed V]: mutable.GrowableBuilder[(K, V), TrieMap[K, V]] = new GrowableBuilder(empty[K, V]) @transient val inodeupdater: AtomicReferenceFieldUpdater[INodeBase[_, _], MainNode[_, _]] = AtomicReferenceFieldUpdater.newUpdater(classOf[INodeBase[_, _]], classOf[MainNode[_, _]], "mainnode") @@ -1069,7 +1071,7 @@ object TrieMap extends MapFactory[TrieMap] { } // non-final as an extension point for parallel collections -private[collection] class TrieMapIterator[K, V](var level: Int, private var ct: TrieMap[K, V], mustInit: Boolean = true) extends AbstractIterator[(K, V)] { +private[collection] class TrieMapIterator[sealed K, sealed V](var level: Int, private var ct: TrieMap[K, V], mustInit: Boolean = true) extends AbstractIterator[(K, V)] { private val stack = new Array[Array[BasicNode]](7) private val stackpos = new Array[Int](7) private var depth = -1 @@ -1182,7 +1184,10 @@ private[collection] class TrieMapIterator[K, V](var level: Int, private var ct: stack(d) = arr1 stackpos(d) = -1 val it = newIterator(level + 1, ct, _mustInit = false) - it.stack(0) = arr2 + val xss: Array[Array[BasicNode]] = it.stack.asInstanceOf + // !!! cc split into separate xss and asInstanceOf needed because cc gets confused with + // two-dimensinal invariant arrays + xss(0) = arr2 it.stackpos(0) = -1 it.depth = 0 it.advance() // <-- fix it diff --git a/tests/pos-special/stdlib/collection/convert/AsJavaConverters.scala b/tests/pos-special/stdlib/collection/convert/AsJavaConverters.scala index 3d155337aa93..bfae792c5107 100644 --- a/tests/pos-special/stdlib/collection/convert/AsJavaConverters.scala +++ b/tests/pos-special/stdlib/collection/convert/AsJavaConverters.scala @@ -18,6 +18,7 @@ import java.util.{concurrent => juc} import java.{lang => jl, util => ju} import scala.{unchecked => uc} +import language.experimental.captureChecking /** Defines converter methods from Scala to Java collections. * These methods are available through the [[scala.jdk.javaapi.CollectionConverters]] object. diff --git a/tests/pos-special/stdlib/collection/convert/AsJavaExtensions.scala b/tests/pos-special/stdlib/collection/convert/AsJavaExtensions.scala index 16b15c513a17..14268f7aa165 100644 --- a/tests/pos-special/stdlib/collection/convert/AsJavaExtensions.scala +++ b/tests/pos-special/stdlib/collection/convert/AsJavaExtensions.scala @@ -16,6 +16,7 @@ package convert import java.util.{concurrent => juc} import java.{lang => jl, util => ju} +import language.experimental.captureChecking /** Defines `asJava` extension methods, available through [[scala.jdk.CollectionConverters]]. */ trait AsJavaExtensions { diff --git a/tests/pos-special/stdlib/collection/convert/AsScalaConverters.scala b/tests/pos-special/stdlib/collection/convert/AsScalaConverters.scala index 30a28ae38147..6cc02b13bb06 100644 --- a/tests/pos-special/stdlib/collection/convert/AsScalaConverters.scala +++ b/tests/pos-special/stdlib/collection/convert/AsScalaConverters.scala @@ -18,6 +18,7 @@ import java.util.{concurrent => juc} import java.{lang => jl, util => ju} import scala.{unchecked => uc} +import language.experimental.captureChecking /** Defines converter methods from Java to Scala collections. * These methods are available through the [[scala.jdk.javaapi.CollectionConverters]] object. diff --git a/tests/pos-special/stdlib/collection/convert/AsScalaExtensions.scala b/tests/pos-special/stdlib/collection/convert/AsScalaExtensions.scala index 39347dde903b..d60bfc7f60a1 100644 --- a/tests/pos-special/stdlib/collection/convert/AsScalaExtensions.scala +++ b/tests/pos-special/stdlib/collection/convert/AsScalaExtensions.scala @@ -16,6 +16,7 @@ package convert import java.util.{concurrent => juc} import java.{lang => jl, util => ju} +import language.experimental.captureChecking /** Defines `asScala` extension methods, available through [[scala.jdk.CollectionConverters]]. */ trait AsScalaExtensions { diff --git a/tests/pos-special/stdlib/collection/convert/ImplicitConversions.scala b/tests/pos-special/stdlib/collection/convert/ImplicitConversions.scala index 05d63f9fdeee..1bc284462ff1 100644 --- a/tests/pos-special/stdlib/collection/convert/ImplicitConversions.scala +++ b/tests/pos-special/stdlib/collection/convert/ImplicitConversions.scala @@ -19,6 +19,7 @@ import java.{lang => jl, util => ju} import scala.collection.JavaConverters._ import scala.language.implicitConversions +import language.experimental.captureChecking /** Defines implicit converter methods from Java to Scala collections. */ @deprecated("Use `scala.jdk.CollectionConverters` instead", "2.13.0") diff --git a/tests/pos-special/stdlib/collection/convert/JavaCollectionWrappers.scala b/tests/pos-special/stdlib/collection/convert/JavaCollectionWrappers.scala index 29c3dcbac5db..e826bdeb23db 100644 --- a/tests/pos-special/stdlib/collection/convert/JavaCollectionWrappers.scala +++ b/tests/pos-special/stdlib/collection/convert/JavaCollectionWrappers.scala @@ -22,6 +22,8 @@ import scala.jdk.CollectionConverters._ import scala.util.Try import scala.util.chaining._ import scala.util.control.ControlThrowable +import language.experimental.captureChecking +import annotation.unchecked.uncheckedCaptures /** Wrappers for exposing Scala collections as Java collections and vice-versa */ @SerialVersionUID(3L) @@ -127,7 +129,7 @@ private[collection] object JavaCollectionWrappers extends Serializable { def prepend(elem: A) = { underlying.subList(0, 0) add elem; this } def addOne(elem: A): this.type = { underlying add elem; this } def insert(idx: Int,elem: A): Unit = underlying.subList(0, idx).add(elem) - def insertAll(i: Int, elems: IterableOnce[A]) = { + def insertAll(i: Int, elems: IterableOnce[A]^) = { val ins = underlying.subList(0, i) elems.iterator.foreach(ins.add(_)) } @@ -136,7 +138,7 @@ private[collection] object JavaCollectionWrappers extends Serializable { // Note: Clone cannot just call underlying.clone because in Java, only specific collections // expose clone methods. Generically, they're protected. override def clone(): JListWrapper[A] = new JListWrapper(new ju.ArrayList[A](underlying)) - def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A], replaced: Int): this.type = { + def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A]^, replaced: Int): this.type = { remove(from, replaced) insertAll(from, patch) this @@ -254,7 +256,7 @@ private[collection] object JavaCollectionWrappers extends Serializable { def getKey = k def getValue = v def setValue(v1 : V) = self.put(k, v1) - + // It's important that this implementation conform to the contract // specified in the javadocs of java.util.Map.Entry.hashCode // @@ -358,7 +360,7 @@ private[collection] object JavaCollectionWrappers extends Serializable { val result = underlying.put(k, v) if (present) Some(result) else None } else { - var result: Option[V] = None + var result: Option[V @uncheckedCaptures] = None def recompute(k0: K, v0: V): V = v.tap(_ => if (v0 != null) result = Some(v0) else if (underlying.containsKey(k0)) result = Some(null.asInstanceOf[V]) @@ -384,7 +386,7 @@ private[collection] object JavaCollectionWrappers extends Serializable { // support Some(null) if currently bound to null override def remove(k: K): Option[V] = { - var result: Option[V] = None + var result: Option[V @uncheckedCaptures] = None def recompute(k0: K, v0: V): V = { if (v0 != null) result = Some(v0) else if (underlying.containsKey(k0)) result = Some(null.asInstanceOf[V]) diff --git a/tests/pos-special/stdlib/collection/convert/StreamExtensions.scala b/tests/pos-special/stdlib/collection/convert/StreamExtensions.scala index cdeea62fb5ed..ddda95707881 100644 --- a/tests/pos-special/stdlib/collection/convert/StreamExtensions.scala +++ b/tests/pos-special/stdlib/collection/convert/StreamExtensions.scala @@ -22,6 +22,7 @@ import scala.collection._ import scala.collection.convert.StreamExtensions.{AccumulatorFactoryInfo, StreamShape, StreamUnboxer} import scala.jdk.CollectionConverters._ import scala.jdk._ +import language.experimental.captureChecking /** Defines extension methods to create Java Streams for Scala collections, available through * [[scala.jdk.javaapi.StreamConverters]]. diff --git a/tests/pos-special/stdlib/collection/convert/impl/ArrayStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/ArrayStepper.scala index 845ecb4a606d..ba51c7a5a353 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/ArrayStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/ArrayStepper.scala @@ -14,6 +14,7 @@ package scala.collection.convert package impl import scala.collection._ +// import language.experimental.captureChecking // TODO enable private[collection] class ObjectArrayStepper[A <: Object](underlying: Array[A], _i0: Int, _iN: Int) extends IndexedStepperBase[AnyStepper[A], ObjectArrayStepper[A]](_i0, _iN) diff --git a/tests/pos-special/stdlib/collection/convert/impl/BinaryTreeStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/BinaryTreeStepper.scala index 7c795aea5391..8b2f604b0977 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/BinaryTreeStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/BinaryTreeStepper.scala @@ -18,6 +18,7 @@ import java.util.Spliterator import annotation.tailrec import scala.collection.Stepper.EfficientSplit import scala.collection._ +// import language.experimental.captureChecking // TODO enable private[collection] object BinaryTreeStepper { @@ -125,7 +126,7 @@ extends EfficientSplit { if (!hasStep || index < 0) null else { val root = stack(0).asInstanceOf[T] - val leftStack = + val leftStack = if (index > 0) java.util.Arrays.copyOfRange(stack, 1, index+1) else BinaryTreeStepper.emptyStack val leftIndex = index - 1 diff --git a/tests/pos-special/stdlib/collection/convert/impl/BitSetStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/BitSetStepper.scala index 574e7fd50f1c..16801089c39f 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/BitSetStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/BitSetStepper.scala @@ -15,11 +15,12 @@ package impl import scala.collection.Stepper.EfficientSplit import scala.collection.{BitSetOps, IntStepper, Stepper} +// import language.experimental.captureChecking // TODO enable private[collection] final class BitSetStepper( - private var underlying: BitSetOps[_], - private var cache0: Long, private var cache1: Long, + private var underlying: BitSetOps[_], + private var cache0: Long, private var cache1: Long, _i0: Int, _iN: Int, private var cacheIndex: Int ) @@ -47,7 +48,7 @@ with IntStepper { findNext() } } - else if (underlying eq null) { + else if (underlying eq null) { i0 = iN found = false found @@ -96,7 +97,7 @@ with IntStepper { else scanLong(bits, from + 1) def nextStep(): Int = - if (found || findNext()) { + if (found || findNext()) { found = false val ans = i0 i0 += 1 diff --git a/tests/pos-special/stdlib/collection/convert/impl/ChampStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/ChampStepper.scala index 466e6c440f45..12fb471ea768 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/ChampStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/ChampStepper.scala @@ -16,6 +16,7 @@ package impl import scala.collection.Stepper.EfficientSplit import scala.collection._ import scala.collection.immutable.Node +// import language.experimental.captureChecking // TODO enable /** A stepper that is a slightly elaborated version of the ChampBaseIterator; * the main difference is that it knows when it should stop instead of running diff --git a/tests/pos-special/stdlib/collection/convert/impl/InOrderStepperBase.scala b/tests/pos-special/stdlib/collection/convert/impl/InOrderStepperBase.scala index 2d1f88d02930..7140c7d673d0 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/InOrderStepperBase.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/InOrderStepperBase.scala @@ -16,6 +16,7 @@ package impl import java.util.Spliterator import scala.collection.Stepper.EfficientSplit +// import language.experimental.captureChecking // TODO enable /** Abstracts all the generic operations of stepping over a collection * that has an indexable ordering but may have gaps. diff --git a/tests/pos-special/stdlib/collection/convert/impl/IndexedSeqStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/IndexedSeqStepper.scala index 136ac8d2dcc3..1e2983fde50d 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/IndexedSeqStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/IndexedSeqStepper.scala @@ -14,6 +14,7 @@ package scala.collection.convert package impl import scala.collection._ +// import language.experimental.captureChecking // TODO enable private[collection] class AnyIndexedSeqStepper[A](underlying: collection.IndexedSeqOps[A, AnyConstr, _], _i0: Int, _iN: Int) extends IndexedStepperBase[AnyStepper[A], AnyIndexedSeqStepper[A]](_i0, _iN) diff --git a/tests/pos-special/stdlib/collection/convert/impl/IndexedStepperBase.scala b/tests/pos-special/stdlib/collection/convert/impl/IndexedStepperBase.scala index 4670ccc56bfc..cae3809ab077 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/IndexedStepperBase.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/IndexedStepperBase.scala @@ -16,6 +16,7 @@ package impl import java.util.Spliterator import scala.collection.Stepper.EfficientSplit +// import language.experimental.captureChecking // TODO enable /** Abstracts all the generic operations of stepping over an indexable collection */ private[convert] abstract class IndexedStepperBase[Sub >: Null, Semi <: Sub](protected var i0: Int, protected var iN: Int) diff --git a/tests/pos-special/stdlib/collection/convert/impl/IteratorStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/IteratorStepper.scala index 68b318c04c9c..393e988959eb 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/IteratorStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/IteratorStepper.scala @@ -17,6 +17,7 @@ import java.util.Spliterator import scala.collection.{AnyStepper, DoubleStepper, IntStepper, LongStepper, Stepper} import scala.jdk.{AnyAccumulator, DoubleAccumulator, IntAccumulator, LongAccumulator} +// import language.experimental.captureChecking // TODO enable private[collection] class AnyIteratorStepper[A](_underlying: Iterator[A]) extends IteratorStepperBase[A, AnyStepper[A], AnyIteratorStepper[A]](_underlying) diff --git a/tests/pos-special/stdlib/collection/convert/impl/NumericRangeStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/NumericRangeStepper.scala index 89e17bbf467c..7c122f901839 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/NumericRangeStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/NumericRangeStepper.scala @@ -15,6 +15,7 @@ package impl import scala.collection.{AnyStepper, IntStepper, LongStepper, Stepper} import scala.collection.immutable.NumericRange +// import language.experimental.captureChecking // TODO enable private[collection] class AnyNumericRangeStepper[A](underlying: NumericRange[A], _i0: Int, _iN: Int) extends IndexedStepperBase[AnyStepper[A], AnyNumericRangeStepper[A]](_i0, _iN) diff --git a/tests/pos-special/stdlib/collection/convert/impl/RangeStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/RangeStepper.scala index 282ddb4aa2ad..50ab623a014e 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/RangeStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/RangeStepper.scala @@ -14,6 +14,7 @@ package scala.collection.convert package impl import scala.collection.{IntStepper, Stepper} +// import language.experimental.captureChecking // TODO enable /** Implements Stepper on an integer Range. You don't actually need the Range to do this, * so only the relevant parts are included. Because the arguments are protected, they are @@ -27,7 +28,7 @@ with IntStepper { val ans = myNext myNext += myStep i0 += 1 - ans + ans } else Stepper.throwNSEE() protected def semiclone(half: Int): RangeStepper = new RangeStepper(myNext, myStep, i0, half) diff --git a/tests/pos-special/stdlib/collection/convert/impl/StringStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/StringStepper.scala index 8990f462b4fd..fe127b857c45 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/StringStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/StringStepper.scala @@ -18,6 +18,7 @@ import java.util.Spliterator import scala.collection.Stepper.EfficientSplit import scala.collection.{IntStepper, Stepper} +// import language.experimental.captureChecking // TODO enable /** Implements `Stepper` on a `String` where you step through chars packed into `Int`. */ diff --git a/tests/pos-special/stdlib/collection/convert/impl/TableStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/TableStepper.scala index cac041a5237b..6329d83bc2a0 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/TableStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/TableStepper.scala @@ -15,6 +15,7 @@ package impl import scala.collection.Stepper.EfficientSplit import scala.collection._ +// import language.experimental.captureChecking // TODO enable private[collection] abstract class TableStepperBase[A, I >: Null <: AnyRef, Sub >: Null, Semi <: Sub with TableStepperBase[A, I, _, _]]( protected var maxLength: Int, protected val table: Array[I], protected var i0: Int, protected val iN: Int diff --git a/tests/pos-special/stdlib/collection/convert/impl/VectorStepper.scala b/tests/pos-special/stdlib/collection/convert/impl/VectorStepper.scala index 332ec65d85fd..504e0dac63ea 100644 --- a/tests/pos-special/stdlib/collection/convert/impl/VectorStepper.scala +++ b/tests/pos-special/stdlib/collection/convert/impl/VectorStepper.scala @@ -14,6 +14,7 @@ package scala.collection.convert package impl import scala.collection._ +// import language.experimental.captureChecking // TODO enable private[convert] abstract class VectorStepperBase[Sub >: Null, Semi <: Sub]( _i0: Int, @@ -91,7 +92,7 @@ with DoubleStepper { index1 = 32 i0 = half ans - } + } } private[collection] class IntVectorStepper(_i0: Int, _iN: Int, _displayN: Int, _trunk: Array[AnyRef]) @@ -109,7 +110,7 @@ with IntStepper { index1 = 32 i0 = half ans - } + } } private[collection] class LongVectorStepper(_i0: Int, _iN: Int, _displayN: Int, _trunk: Array[AnyRef]) @@ -127,5 +128,5 @@ with LongStepper { index1 = 32 i0 = half ans - } + } } diff --git a/tests/pos-special/stdlib/collection/generic/BitOperations.scala b/tests/pos-special/stdlib/collection/generic/BitOperations.scala index 4c64dec9dc1f..f76619a004fa 100644 --- a/tests/pos-special/stdlib/collection/generic/BitOperations.scala +++ b/tests/pos-special/stdlib/collection/generic/BitOperations.scala @@ -12,6 +12,7 @@ package scala.collection package generic +import language.experimental.captureChecking /** Some bit operations. diff --git a/tests/pos-special/stdlib/collection/generic/DefaultSerializationProxy.scala b/tests/pos-special/stdlib/collection/generic/DefaultSerializationProxy.scala index 69b4b3d96e61..7eba9433b8d5 100644 --- a/tests/pos-special/stdlib/collection/generic/DefaultSerializationProxy.scala +++ b/tests/pos-special/stdlib/collection/generic/DefaultSerializationProxy.scala @@ -16,6 +16,8 @@ import java.io.{ObjectInputStream, ObjectOutputStream} import scala.collection.{Factory, Iterable} import scala.collection.mutable.Builder +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** The default serialization proxy for collection implementations. * @@ -27,7 +29,8 @@ import scala.collection.mutable.Builder @SerialVersionUID(3L) final class DefaultSerializationProxy[A](factory: Factory[A, Any], @transient private[this] val coll: Iterable[A]) extends Serializable { - @transient protected var builder: Builder[A, Any] = _ + @transient protected var builder: Builder[A @uncheckedCaptures, Any] = _ + // @uncheckedCaptures OK since builder is used only locally when reading objects private[this] def writeObject(out: ObjectOutputStream): Unit = { out.defaultWriteObject() diff --git a/tests/pos-special/stdlib/collection/generic/IsIterable.scala b/tests/pos-special/stdlib/collection/generic/IsIterable.scala index bf2eab6bb2a6..c309299b615b 100644 --- a/tests/pos-special/stdlib/collection/generic/IsIterable.scala +++ b/tests/pos-special/stdlib/collection/generic/IsIterable.scala @@ -12,6 +12,7 @@ package scala.collection package generic +import language.experimental.captureChecking /** A trait which can be used to avoid code duplication when defining extension * methods that should be applicable both to existing Scala collections (i.e., diff --git a/tests/pos-special/stdlib/collection/generic/IsIterableOnce.scala b/tests/pos-special/stdlib/collection/generic/IsIterableOnce.scala index 7d7293037bd4..2836ca2bb520 100644 --- a/tests/pos-special/stdlib/collection/generic/IsIterableOnce.scala +++ b/tests/pos-special/stdlib/collection/generic/IsIterableOnce.scala @@ -13,6 +13,7 @@ package scala package collection package generic +import language.experimental.captureChecking /** Type class witnessing that a collection representation type `Repr` has * elements of type `A` and has a conversion to `IterableOnce[A]`. diff --git a/tests/pos-special/stdlib/collection/generic/IsMap.scala b/tests/pos-special/stdlib/collection/generic/IsMap.scala index 19f75cf7bced..ad7254d2dd61 100644 --- a/tests/pos-special/stdlib/collection/generic/IsMap.scala +++ b/tests/pos-special/stdlib/collection/generic/IsMap.scala @@ -15,6 +15,7 @@ package generic import IsMap.Tupled import scala.collection.immutable.{IntMap, LongMap} +import language.experimental.captureChecking /** * Type class witnessing that a collection type `Repr` diff --git a/tests/pos-special/stdlib/collection/generic/IsSeq.scala b/tests/pos-special/stdlib/collection/generic/IsSeq.scala index 69ea27d087d1..8ad344c4d4fc 100644 --- a/tests/pos-special/stdlib/collection/generic/IsSeq.scala +++ b/tests/pos-special/stdlib/collection/generic/IsSeq.scala @@ -14,6 +14,9 @@ package scala.collection package generic import scala.reflect.ClassTag +import language.experimental.captureChecking +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** Type class witnessing that a collection representation type `Repr` has * elements of type `A` and has a conversion to `SeqOps[A, Iterable, C]`, for @@ -51,11 +54,24 @@ object IsSeq { implicit def seqOpsIsSeq[CC0[X] <: SeqOps[X, Iterable, CC0[X]], A0]: IsSeq[CC0[A0]] { type A = A0; type C = CC0[A0] } = seqOpsIsSeqVal.asInstanceOf[IsSeq[CC0[A0]] { type A = A0; type C = CC0[A0] }] - implicit def seqViewIsSeq[CC0[X] <: SeqView[X], A0]: IsSeq[CC0[A0]] { type A = A0; type C = View[A0] } = - new IsSeq[CC0[A0]] { + /** !!! Under cc, views are not Seqs and can't use SeqOps. + * So this should be renamed to seqViewIsIterable + */ + implicit def seqViewIsSeq[CC0[X] <: SeqView[X], A0]: IsIterable[CC0[A0]] { type A = A0; type C = View[A0] } = + new IsIterable[CC0[A0]] { type A = A0 type C = View[A] - def apply(coll: CC0[A0]): SeqOps[A0, View, View[A0]] = coll + def apply(coll: CC0[A0]): IterableOps[A0, View, View[A0]] = coll + } + + /** !!! Under cc, views are not Seqs and can't use SeqOps. + * So this should be renamed to stringViewIsIterable + */ + implicit val stringViewIsSeq: IsIterable[StringView] { type A = Char; type C = View[Char] } = + new IsIterable[StringView] { + type A = Char + type C = View[Char] + def apply(coll: StringView): IterableOps[Char, View, View[Char]] = coll } implicit val stringIsSeq: IsSeq[String] { type A = Char; type C = String } = @@ -68,22 +84,15 @@ object IsSeq { def apply(i: Int): Char = s.charAt(i) def toIterable: Iterable[Char] = new immutable.WrappedString(s) protected[this] def coll: String = s - protected[this] def fromSpecific(coll: IterableOnce[Char]): String = coll.iterator.mkString - def iterableFactory: IterableFactory[immutable.ArraySeq] = immutable.ArraySeq.untagged + protected[this] def fromSpecific(coll: IterableOnce[Char]^): String = coll.iterator.mkString + def iterableFactory: FreeSeqFactory[immutable.ArraySeq] = immutable.ArraySeq.untagged override def empty: String = "" protected[this] def newSpecificBuilder: mutable.Builder[Char, String] = new StringBuilder def iterator: Iterator[Char] = s.iterator } } - implicit val stringViewIsSeq: IsSeq[StringView] { type A = Char; type C = View[Char] } = - new IsSeq[StringView] { - type A = Char - type C = View[Char] - def apply(coll: StringView): SeqOps[Char, View, View[Char]] = coll - } - - implicit def arrayIsSeq[A0 : ClassTag]: IsSeq[Array[A0]] { type A = A0; type C = Array[A0] } = + implicit def arrayIsSeq[sealed A0 : ClassTag]: IsSeq[Array[A0]] { type A = A0; type C = Array[A0] } = new IsSeq[Array[A0]] { type A = A0 type C = Array[A0] @@ -91,10 +100,10 @@ object IsSeq { new SeqOps[A, mutable.ArraySeq, Array[A]] { def apply(i: Int): A = a(i) def length: Int = a.length - def toIterable: Iterable[A] = mutable.ArraySeq.make(a) + def toIterable: Iterable[A] = mutable.ArraySeq.make[A @uncheckedCaptures](a) protected def coll: Array[A] = a - protected def fromSpecific(coll: IterableOnce[A]): Array[A] = Array.from(coll) - def iterableFactory: IterableFactory[mutable.ArraySeq] = mutable.ArraySeq.untagged + protected def fromSpecific(coll: IterableOnce[A]^): Array[A] = Array.from(coll) + def iterableFactory: FreeSeqFactory[mutable.ArraySeq] = mutable.ArraySeq.untagged override def empty: Array[A] = Array.empty[A] protected def newSpecificBuilder: mutable.Builder[A, Array[A]] = Array.newBuilder def iterator: Iterator[A] = a.iterator diff --git a/tests/pos-special/stdlib/collection/generic/Subtractable.scala b/tests/pos-special/stdlib/collection/generic/Subtractable.scala index 223997f4e972..2c0967dbaf4b 100644 --- a/tests/pos-special/stdlib/collection/generic/Subtractable.scala +++ b/tests/pos-special/stdlib/collection/generic/Subtractable.scala @@ -13,6 +13,7 @@ package scala package collection package generic +import language.experimental.captureChecking /** This trait represents collection-like objects that can be reduced * using a '+' operator. It defines variants of `-` and `--` diff --git a/tests/pos-special/stdlib/collection/generic/package.scala b/tests/pos-special/stdlib/collection/generic/package.scala index 0c16aa04dc98..0ba67c1bf76e 100644 --- a/tests/pos-special/stdlib/collection/generic/package.scala +++ b/tests/pos-special/stdlib/collection/generic/package.scala @@ -11,6 +11,7 @@ */ package scala.collection +import language.experimental.captureChecking package object generic { diff --git a/tests/pos-special/stdlib/collection/immutable/ArraySeq.scala b/tests/pos-special/stdlib/collection/immutable/ArraySeq.scala index 978c63034f4a..3a221fc76b6c 100644 --- a/tests/pos-special/stdlib/collection/immutable/ArraySeq.scala +++ b/tests/pos-special/stdlib/collection/immutable/ArraySeq.scala @@ -23,6 +23,8 @@ import scala.reflect.ClassTag import scala.runtime.ScalaRunTime import scala.util.Sorting import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** * An immutable array. @@ -38,7 +40,8 @@ sealed abstract class ArraySeq[+A] with IndexedSeqOps[A, ArraySeq, ArraySeq[A]] with StrictOptimizedSeqOps[A, ArraySeq, ArraySeq[A]] with EvidenceIterableFactoryDefaults[A, ArraySeq, ClassTag] - with Serializable { + with Serializable + with Pure { /** The tag of the element type. This does not have to be equal to the element type of this ArraySeq. A primitive * ArraySeq can be backed by an array of boxed values and a reference ArraySeq can be backed by an array of a supertype @@ -53,8 +56,10 @@ sealed abstract class ArraySeq[+A] * array of a supertype or subtype of the element type. */ def unsafeArray: Array[_] + def unsafeArrayAsAnyArray = unsafeArray.asInstanceOf[Array[Any]] + protected def evidenceIterableFactory: ArraySeq.type = ArraySeq - protected def iterableEvidence: ClassTag[A @uncheckedVariance] = elemTag.asInstanceOf[ClassTag[A]] + protected def iterableEvidence: ClassTag[A @uncheckedVariance @uncheckedCaptures] = elemTag.asInstanceOf[ClassTag[A]] def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit @@ -79,10 +84,10 @@ sealed abstract class ArraySeq[+A] } override def prepended[B >: A](elem: B): ArraySeq[B] = - ArraySeq.unsafeWrapArray(unsafeArray.prepended[Any](elem)).asInstanceOf[ArraySeq[B]] + ArraySeq.unsafeWrapArray(unsafeArrayAsAnyArray.prepended(elem)).asInstanceOf[ArraySeq[B]] override def appended[B >: A](elem: B): ArraySeq[B] = - ArraySeq.unsafeWrapArray(unsafeArray.appended[Any](elem)).asInstanceOf[ArraySeq[B]] + ArraySeq.unsafeWrapArray(unsafeArrayAsAnyArray.appended[Any](elem)).asInstanceOf[ArraySeq[B]] /** Fast concatenation of two [[ArraySeq]]s. * @@ -104,8 +109,8 @@ sealed abstract class ArraySeq[+A] null else if (thisIsObj) { // A and B are objects - val ax = this.unsafeArray.asInstanceOf[Array[A]] - val ay = that.unsafeArray.asInstanceOf[Array[B]] + val ax = this.unsafeArray.asInstanceOf[Array[A @uncheckedCaptures]] + val ay = that.unsafeArray.asInstanceOf[Array[B @uncheckedCaptures]] val len = ax.length + ay.length val a = new Array[AnyRef](len) System.arraycopy(ax, 0, a, 0, ax.length) @@ -113,8 +118,8 @@ sealed abstract class ArraySeq[+A] ArraySeq.unsafeWrapArray(a).asInstanceOf[ArraySeq[B]] } else { // A is a primative and B = A. Use this instance's protected ClassTag. - val ax = this.unsafeArray.asInstanceOf[Array[A]] - val ay = that.unsafeArray.asInstanceOf[Array[A]] + val ax = this.unsafeArray.asInstanceOf[Array[A @uncheckedCaptures]] + val ay = that.unsafeArray.asInstanceOf[Array[A @uncheckedCaptures]] val len = ax.length + ay.length val a = iterableEvidence.newArray(len) System.arraycopy(ax, 0, a, 0, ax.length) @@ -124,7 +129,7 @@ sealed abstract class ArraySeq[+A] } } - override def appendedAll[B >: A](suffix: collection.IterableOnce[B]): ArraySeq[B] = { + override def appendedAll[B >: A](suffix: collection.IterableOnce[B]^): ArraySeq[B] = { def genericResult = { val k = suffix.knownSize if (k == 0) this @@ -147,7 +152,7 @@ sealed abstract class ArraySeq[+A] } } - override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): ArraySeq[B] = { + override def prependedAll[B >: A](prefix: collection.IterableOnce[B]^): ArraySeq[B] = { def genericResult = { val k = prefix.knownSize if (k == 0) this @@ -171,7 +176,7 @@ sealed abstract class ArraySeq[+A] } } - override def zip[B](that: collection.IterableOnce[B]): ArraySeq[(A, B)] = + override def zip[B](that: collection.IterableOnce[B]^): ArraySeq[(A, B)] = that match { case bs: ArraySeq[B] => ArraySeq.tabulate(length min bs.length) { i => @@ -181,35 +186,37 @@ sealed abstract class ArraySeq[+A] strictOptimizedZip[B, ArraySeq[(A, B)]](that, iterableFactory.newBuilder) } + private inline def ops[A](xs: Array[A @uncheckedCaptures]): ArrayOps[A] = new ArrayOps[A @uncheckedCaptures](xs) + override def take(n: Int): ArraySeq[A] = if (unsafeArray.length <= n) this else - ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).take(n)).asInstanceOf[ArraySeq[A]] + ArraySeq.unsafeWrapArray(ops(unsafeArrayAsAnyArray).take(n)).asInstanceOf[ArraySeq[A]] override def takeRight(n: Int): ArraySeq[A] = if (unsafeArray.length <= n) this else - ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).takeRight(n)).asInstanceOf[ArraySeq[A]] + ArraySeq.unsafeWrapArray(ops(unsafeArrayAsAnyArray).takeRight(n)).asInstanceOf[ArraySeq[A]] override def drop(n: Int): ArraySeq[A] = if (n <= 0) this else - ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).drop(n)).asInstanceOf[ArraySeq[A]] + ArraySeq.unsafeWrapArray(ops(unsafeArrayAsAnyArray).drop(n)).asInstanceOf[ArraySeq[A]] override def dropRight(n: Int): ArraySeq[A] = if (n <= 0) this else - ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).dropRight(n)).asInstanceOf[ArraySeq[A]] + ArraySeq.unsafeWrapArray(ops(unsafeArrayAsAnyArray).dropRight(n)).asInstanceOf[ArraySeq[A]] override def slice(from: Int, until: Int): ArraySeq[A] = if (from <= 0 && unsafeArray.length <= until) this else - ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).slice(from, until)).asInstanceOf[ArraySeq[A]] + ArraySeq.unsafeWrapArray(ops(unsafeArrayAsAnyArray).slice(from, until)).asInstanceOf[ArraySeq[A]] override def foldLeft[B](z: B)(f: (B, A) => B): B = { // For ArraySeqs with sizes of [100, 1000, 10000] this is [1.3, 1.8, 1.8]x as fast @@ -239,13 +246,13 @@ sealed abstract class ArraySeq[+A] b } - override def tail: ArraySeq[A] = ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).tail).asInstanceOf[ArraySeq[A]] + override def tail: ArraySeq[A] = ArraySeq.unsafeWrapArray(ops(unsafeArrayAsAnyArray).tail).asInstanceOf[ArraySeq[A]] - override def reverse: ArraySeq[A] = ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).reverse).asInstanceOf[ArraySeq[A]] + override def reverse: ArraySeq[A] = ArraySeq.unsafeWrapArray(ops(unsafeArrayAsAnyArray).reverse).asInstanceOf[ArraySeq[A]] override protected[this] def className = "ArraySeq" - override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = { + override def copyToArray[sealed B >: A](xs: Array[B], start: Int, len: Int): Int = { val copied = IterableOnce.elemsToCopyToArray(length, xs.length, start, len) if(copied > 0) { Array.copy(unsafeArray, 0, xs, start, copied) @@ -277,18 +284,18 @@ object ArraySeq extends StrictOptimizedClassTagSeqFactory[ArraySeq] { self => def empty[A : ClassTag]: ArraySeq[A] = emptyImpl - def from[A](it: scala.collection.IterableOnce[A])(implicit tag: ClassTag[A]): ArraySeq[A] = it match { + def from[A](it: scala.collection.IterableOnce[A]^)(implicit tag: ClassTag[A]): ArraySeq[A] = it match { case as: ArraySeq[A] => as case _ => unsafeWrapArray(Array.from[A](it)) } def newBuilder[A : ClassTag]: Builder[A, ArraySeq[A]] = - ArrayBuffer.newBuilder[A].mapResult(b => unsafeWrapArray[A](b.toArray)) + ArrayBuffer.newBuilder[A @uncheckedCaptures].mapResult(b => unsafeWrapArray[A](b.toArray)) override def fill[A : ClassTag](n: Int)(elem: => A): ArraySeq[A] = tabulate(n)(_ => elem) override def tabulate[A : ClassTag](n: Int)(f: Int => A): ArraySeq[A] = { - val elements = Array.ofDim[A](scala.math.max(n, 0)) + val elements = Array.ofDim[A @uncheckedCaptures](scala.math.max(n, 0)) var i = 0 while (i < n) { ScalaRunTime.array_update(elements, i, f(i)) @@ -309,7 +316,7 @@ object ArraySeq extends StrictOptimizedClassTagSeqFactory[ArraySeq] { self => * `ArraySeq.unsafeWrapArray(a.asInstanceOf[Array[Int]])` does not work, it throws a * `ClassCastException` at runtime. */ - def unsafeWrapArray[T](x: Array[T]): ArraySeq[T] = ((x: @unchecked) match { + def unsafeWrapArray[T](x: Array[T @uncheckedCaptures]): ArraySeq[T] = ((x: @unchecked) match { case null => null case x: Array[AnyRef] => new ofRef[AnyRef](x) case x: Array[Int] => new ofInt(x) diff --git a/tests/pos-special/stdlib/collection/immutable/BitSet.scala b/tests/pos-special/stdlib/collection/immutable/BitSet.scala index 9461264850a9..9c2bfdad54d0 100644 --- a/tests/pos-special/stdlib/collection/immutable/BitSet.scala +++ b/tests/pos-special/stdlib/collection/immutable/BitSet.scala @@ -17,6 +17,7 @@ package immutable import BitSetOps.{LogWL, updateArray} import mutable.Builder import scala.annotation.{implicitNotFound, nowarn} +import language.experimental.captureChecking /** A class for immutable bitsets. * $bitsetinfo @@ -37,7 +38,7 @@ sealed abstract class BitSet override def unsorted: Set[Int] = this - override protected def fromSpecific(coll: IterableOnce[Int]): BitSet = bitSetFactory.fromSpecific(coll) + override protected def fromSpecific(coll: IterableOnce[Int]^): BitSet = bitSetFactory.fromSpecific(coll) override protected def newSpecificBuilder: Builder[Int, BitSet] = bitSetFactory.newBuilder override def empty: BitSet = bitSetFactory.empty @@ -94,7 +95,7 @@ sealed abstract class BitSet @SerialVersionUID(3L) object BitSet extends SpecificIterableFactory[Int, BitSet] { - def fromSpecific(it: scala.collection.IterableOnce[Int]): BitSet = + def fromSpecific(it: scala.collection.IterableOnce[Int]^): BitSet = it match { case bs: BitSet => bs case _ => (newBuilder ++= it).result() diff --git a/tests/pos-special/stdlib/collection/immutable/ChampCommon.scala b/tests/pos-special/stdlib/collection/immutable/ChampCommon.scala index 711332567b0f..fc9bcb022874 100644 --- a/tests/pos-special/stdlib/collection/immutable/ChampCommon.scala +++ b/tests/pos-special/stdlib/collection/immutable/ChampCommon.scala @@ -16,6 +16,7 @@ package scala.collection.immutable import java.lang.Integer.bitCount import java.lang.Math.ceil import java.lang.System.arraycopy +import language.experimental.captureChecking private[collection] object Node { final val HashCodeLength = 32 @@ -112,7 +113,7 @@ private[immutable] abstract class ChampBaseIterator[T <: Node[T]] { // ChampBaseReverseIterator and in convert.impl.ChampStepperBase. // If you change this code, check those also in case they also // need to be modified. - + protected var currentValueCursor: Int = 0 protected var currentValueLength: Int = 0 protected var currentValueNode: T = _ diff --git a/tests/pos-special/stdlib/collection/immutable/HashMap.scala b/tests/pos-special/stdlib/collection/immutable/HashMap.scala index 2e8378c4d810..c364924db3a3 100644 --- a/tests/pos-special/stdlib/collection/immutable/HashMap.scala +++ b/tests/pos-special/stdlib/collection/immutable/HashMap.scala @@ -25,6 +25,8 @@ import scala.collection.{Iterator, MapFactory, MapFactoryDefaults, Stepper, Step import scala.runtime.AbstractFunction2 import scala.runtime.Statics.releaseFence import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** This class implements immutable maps using a Compressed Hash-Array Mapped Prefix-tree. * See paper https://michael.steindorfer.name/publications/oopsla15.pdf for more details. @@ -161,7 +163,7 @@ final class HashMap[K, +V] private[immutable] (private[immutable] val rootNode: newHashMapOrThis(rootNode.removed(key, keyUnimprovedHash, improve(keyUnimprovedHash), 0)) } - override def concat[V1 >: V](that: scala.IterableOnce[(K, V1)]): HashMap[K, V1] = that match { + override def concat[V1 >: V](that: scala.IterableOnce[(K, V1)]^): HashMap[K, V1] = that match { case hm: HashMap[K, V1] => if (isEmpty) hm else { @@ -384,7 +386,7 @@ final class HashMap[K, +V] private[immutable] (private[immutable] val rootNode: else new HashMap(newRootNode) } - override def removedAll(keys: IterableOnce[K]): HashMap[K, V] = { + override def removedAll(keys: IterableOnce[K]^): HashMap[K, V] = { if (isEmpty) { this } else { @@ -1766,7 +1768,7 @@ private final class BitmapIndexedMapNode[K, +V]( } else { mapOfNewNodes |= bitpos if (newNodes eq null) { - newNodes = mutable.Queue.empty + newNodes = mutable.Queue.empty[MapNode[K, V] @uncheckedCaptures] } newNodes += newSubNode } @@ -1851,7 +1853,7 @@ private final class BitmapIndexedMapNode[K, +V]( private final class HashCollisionMapNode[K, +V ]( val originalHash: Int, val hash: Int, - var content: Vector[(K, V @uV)] + var content: Vector[(K, V @uV) @uncheckedCaptures] ) extends MapNode[K, V] { import Node._ @@ -2155,7 +2157,7 @@ private final class MapKeyValueTupleReverseIterator[K, V](rootNode: MapNode[K, V private final class MapKeyValueTupleHashIterator[K, V](rootNode: MapNode[K, V]) extends ChampBaseReverseIterator[MapNode[K, V]](rootNode) with Iterator[Any] { private[this] var hash = 0 - private[this] var value: V = _ + private[this] var value: V @uncheckedCaptures = _ override def hashCode(): Int = MurmurHash3.tuple2Hash(hash, value.##, MurmurHash3.productSeed) def next() = { if (!hasNext) @@ -2202,7 +2204,7 @@ object HashMap extends MapFactory[HashMap] { def empty[K, V]: HashMap[K, V] = EmptyMap.asInstanceOf[HashMap[K, V]] - def from[K, V](source: collection.IterableOnce[(K, V)]): HashMap[K, V] = + def from[K, V](source: collection.IterableOnce[(K, V)]^): HashMap[K, V] = source match { case hs: HashMap[K, V] => hs case _ => (newBuilder[K, V] ++= source).result() @@ -2227,12 +2229,12 @@ private[immutable] final class HashMapBuilder[K, V] extends ReusableBuilder[(K, /** The last given out HashMap as a return value of `result()`, if any, otherwise null. * Indicates that on next add, the elements should be copied to an identical structure, before continuing * mutations. */ - private var aliased: HashMap[K, V] = _ + private var aliased: HashMap[K, V] @uncheckedCaptures = _ private def isAliased: Boolean = aliased != null /** The root node of the partially build hashmap */ - private var rootNode: BitmapIndexedMapNode[K, V] = newEmptyRootNode + private var rootNode: BitmapIndexedMapNode[K, V] @uncheckedCaptures = newEmptyRootNode private[immutable] def getOrElse[V0 >: V](key: K, value: V0): V0 = if (rootNode.size == 0) value @@ -2366,7 +2368,7 @@ private[immutable] final class HashMapBuilder[K, V] extends ReusableBuilder[(K, this } - override def addAll(xs: IterableOnce[(K, V)]): this.type = { + override def addAll(xs: IterableOnce[(K, V)]^): this.type = { ensureUnaliased() xs match { case hm: HashMap[K, V] => @@ -2383,7 +2385,7 @@ private[immutable] final class HashMapBuilder[K, V] extends ReusableBuilder[(K, ) currentValueCursor += 1 } - } + }.asInstanceOf // !!! cc gets confused with representation of capture sets in invariant position case hm: collection.mutable.HashMap[K, V] => val iter = hm.nodeIterator while (iter.hasNext) { diff --git a/tests/pos-special/stdlib/collection/immutable/HashSet.scala b/tests/pos-special/stdlib/collection/immutable/HashSet.scala index 459fcf1682aa..38f394a7005f 100644 --- a/tests/pos-special/stdlib/collection/immutable/HashSet.scala +++ b/tests/pos-special/stdlib/collection/immutable/HashSet.scala @@ -23,6 +23,8 @@ import scala.collection.generic.DefaultSerializable import scala.collection.mutable.ReusableBuilder import scala.runtime.Statics.releaseFence import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** This class implements immutable sets using a Compressed Hash-Array Mapped Prefix-tree. * See paper https://michael.steindorfer.name/publications/oopsla15.pdf for more details. @@ -1152,7 +1154,7 @@ private final class BitmapIndexedSetNode[A]( } else { mapOfNewNodes |= bitpos if (newNodes eq null) { - newNodes = mutable.Queue.empty + newNodes = mutable.Queue.empty[SetNode[A] @uncheckedCaptures] } newNodes += newSubNode } @@ -1160,7 +1162,7 @@ private final class BitmapIndexedSetNode[A]( newDataMap |= bitpos nodeMigrateToDataTargetMap |= bitpos if (nodesToMigrateToData eq null) { - nodesToMigrateToData = mutable.Queue.empty + nodesToMigrateToData = mutable.Queue.empty[SetNode[A] @uncheckedCaptures] } nodesToMigrateToData += newSubNode } @@ -1267,7 +1269,7 @@ private final class BitmapIndexedSetNode[A]( } else { mapOfNewNodes |= bitpos if (newNodes eq null) { - newNodes = mutable.Queue.empty + newNodes = mutable.Queue.empty[SetNode[A] @uncheckedCaptures] } newNodes += newSubNode } @@ -1275,7 +1277,7 @@ private final class BitmapIndexedSetNode[A]( newDataMap |= bitpos nodeMigrateToDataTargetMap |= bitpos if (nodesToMigrateToData eq null) { - nodesToMigrateToData = mutable.Queue.empty + nodesToMigrateToData = mutable.Queue.empty[SetNode[A] @uncheckedCaptures] } nodesToMigrateToData += newSubNode } @@ -1740,7 +1742,7 @@ private final class BitmapIndexedSetNode[A]( } } -private final class HashCollisionSetNode[A](val originalHash: Int, val hash: Int, var content: Vector[A]) extends SetNode[A] { +private final class HashCollisionSetNode[A](val originalHash: Int, val hash: Int, var content: Vector[A] @uncheckedCaptures) extends SetNode[A] { import Node._ @@ -1944,7 +1946,7 @@ object HashSet extends IterableFactory[HashSet] { def empty[A]: HashSet[A] = EmptySet.asInstanceOf[HashSet[A]] - def from[A](source: collection.IterableOnce[A]): HashSet[A] = + def from[A](source: collection.IterableOnce[A]^): HashSet[A] = source match { case hs: HashSet[A] => hs case _ if source.knownSize == 0 => empty[A] @@ -1969,12 +1971,12 @@ private[collection] final class HashSetBuilder[A] extends ReusableBuilder[A, Has /** The last given out HashSet as a return value of `result()`, if any, otherwise null. * Indicates that on next add, the elements should be copied to an identical structure, before continuing * mutations. */ - private var aliased: HashSet[A] = _ + private var aliased: HashSet[A] @uncheckedCaptures = _ private def isAliased: Boolean = aliased != null /** The root node of the partially build hashmap */ - private var rootNode: BitmapIndexedSetNode[A] = newEmptyRootNode + private var rootNode: BitmapIndexedSetNode[A] @uncheckedCaptures = newEmptyRootNode /** Inserts element `elem` into array `as` at index `ix`, shifting right the trailing elems */ private def insertElement(as: Array[Int], ix: Int, elem: Int): Array[Int] = { @@ -2084,7 +2086,7 @@ private[collection] final class HashSetBuilder[A] extends ReusableBuilder[A, Has this } - override def addAll(xs: IterableOnce[A]) = { + override def addAll(xs: IterableOnce[A]^) = { ensureUnaliased() xs match { case hm: HashSet[A] => @@ -2100,7 +2102,7 @@ private[collection] final class HashSetBuilder[A] extends ReusableBuilder[A, Has ) currentValueCursor += 1 } - } + }.asInstanceOf // !!! cc gets confused with representation of capture sets in invariant position case other => val it = other.iterator while(it.hasNext) addOne(it.next()) diff --git a/tests/pos-special/stdlib/collection/immutable/IntMap.scala b/tests/pos-special/stdlib/collection/immutable/IntMap.scala index 240821b11460..d7077845b845 100644 --- a/tests/pos-special/stdlib/collection/immutable/IntMap.scala +++ b/tests/pos-special/stdlib/collection/immutable/IntMap.scala @@ -18,6 +18,8 @@ import scala.collection.mutable.{Builder, ImmutableBuilder} import scala.annotation.tailrec import scala.annotation.unchecked.uncheckedVariance import scala.language.implicitConversions +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** Utility class for integer maps. */ @@ -52,7 +54,7 @@ object IntMap { def apply[T](elems: (Int, T)*): IntMap[T] = elems.foldLeft(empty[T])((x, y) => x.updated(y._1, y._2)) - def from[V](coll: IterableOnce[(Int, V)]): IntMap[V] = + def from[V](coll: IterableOnce[(Int, V)]^): IntMap[V] = newBuilder[V].addAll(coll).result() private[immutable] case object Nil extends IntMap[Nothing] { @@ -89,13 +91,13 @@ object IntMap { @SerialVersionUID(3L) private[this] object ToFactory extends Factory[(Int, AnyRef), IntMap[AnyRef]] with Serializable { - def fromSpecific(it: IterableOnce[(Int, AnyRef)]): IntMap[AnyRef] = IntMap.from[AnyRef](it) + def fromSpecific(it: IterableOnce[(Int, AnyRef)]^): IntMap[AnyRef] = IntMap.from[AnyRef](it) def newBuilder: Builder[(Int, AnyRef), IntMap[AnyRef]] = IntMap.newBuilder[AnyRef] } implicit def toBuildFrom[V](factory: IntMap.type): BuildFrom[Any, (Int, V), IntMap[V]] = ToBuildFrom.asInstanceOf[BuildFrom[Any, (Int, V), IntMap[V]]] private[this] object ToBuildFrom extends BuildFrom[Any, (Int, AnyRef), IntMap[AnyRef]] { - def fromSpecific(from: Any)(it: IterableOnce[(Int, AnyRef)]) = IntMap.from(it) + def fromSpecific(from: Any)(it: IterableOnce[(Int, AnyRef)]^) = IntMap.from(it) def newBuilder(from: Any) = IntMap.newBuilder[AnyRef] } @@ -180,9 +182,9 @@ sealed abstract class IntMap[+T] extends AbstractMap[Int, T] with StrictOptimizedMapOps[Int, T, Map, IntMap[T]] with Serializable { - override protected def fromSpecific(coll: scala.collection.IterableOnce[(Int, T) @uncheckedVariance]): IntMap[T] = + override protected def fromSpecific(coll: scala.collection.IterableOnce[(Int, T) @uncheckedVariance]^): IntMap[T] = intMapFrom[T](coll) - protected def intMapFrom[V2](coll: scala.collection.IterableOnce[(Int, V2)]): IntMap[V2] = { + protected def intMapFrom[V2](coll: scala.collection.IterableOnce[(Int, V2)]^): IntMap[V2] = { val b = IntMap.newBuilder[V2] b.sizeHint(coll) b.addAll(coll) @@ -196,7 +198,7 @@ sealed abstract class IntMap[+T] extends AbstractMap[Int, T] override def empty: IntMap[T] = IntMap.Nil override def toList = { - val buffer = new scala.collection.mutable.ListBuffer[(Int, T)] + val buffer = new scala.collection.mutable.ListBuffer[(Int, T) @uncheckedCaptures] foreach(buffer += _) buffer.toList } @@ -327,10 +329,10 @@ sealed abstract class IntMap[+T] extends AbstractMap[Int, T] def flatMap[V2](f: ((Int, T)) => IterableOnce[(Int, V2)]): IntMap[V2] = intMapFrom(new View.FlatMap(this, f)) - override def concat[V1 >: T](that: collection.IterableOnce[(Int, V1)]): IntMap[V1] = + override def concat[V1 >: T](that: collection.IterableOnce[(Int, V1)]^): IntMap[V1] = super.concat(that).asInstanceOf[IntMap[V1]] // Already has correct type but not declared as such - override def ++ [V1 >: T](that: collection.IterableOnce[(Int, V1)]): IntMap[V1] = concat(that) + override def ++ [V1 >: T](that: collection.IterableOnce[(Int, V1)]^): IntMap[V1] = concat(that) def collect[V2](pf: PartialFunction[(Int, T), (Int, V2)]): IntMap[V2] = strictOptimizedCollect(IntMap.newBuilder[V2], pf) diff --git a/tests/pos-special/stdlib/collection/immutable/Iterable.scala b/tests/pos-special/stdlib/collection/immutable/Iterable.scala index d4199ab3ab14..c4f9900eea8b 100644 --- a/tests/pos-special/stdlib/collection/immutable/Iterable.scala +++ b/tests/pos-special/stdlib/collection/immutable/Iterable.scala @@ -13,6 +13,7 @@ package scala.collection.immutable import scala.collection.{IterableFactory, IterableFactoryDefaults} +import language.experimental.captureChecking /** A trait for collections that are guaranteed immutable. * @@ -24,13 +25,14 @@ import scala.collection.{IterableFactory, IterableFactoryDefaults} trait Iterable[+A] extends collection.Iterable[A] with collection.IterableOps[A, Iterable, Iterable[A]] with IterableFactoryDefaults[A, Iterable] { + this: Iterable[A]^ => override def iterableFactory: IterableFactory[Iterable] = Iterable } @SerialVersionUID(3L) object Iterable extends IterableFactory.Delegate[Iterable](List) { - override def from[E](it: IterableOnce[E]): Iterable[E] = it match { + override def from[E](it: IterableOnce[E]^): Iterable[E]^{it} = it match { case iterable: Iterable[E] => iterable case _ => super.from(it) } diff --git a/tests/pos-special/stdlib/collection/immutable/LazyList.scala b/tests/pos-special/stdlib/collection/immutable/LazyListIterable.scala similarity index 66% rename from tests/pos-special/stdlib/collection/immutable/LazyList.scala rename to tests/pos-special/stdlib/collection/immutable/LazyListIterable.scala index 8b7ad26dc5ae..5684130b6048 100644 --- a/tests/pos-special/stdlib/collection/immutable/LazyList.scala +++ b/tests/pos-special/stdlib/collection/immutable/LazyListIterable.scala @@ -22,21 +22,29 @@ import scala.collection.generic.SerializeEnd import scala.collection.mutable.{Builder, ReusableBuilder, StringBuilder} import scala.language.implicitConversions import scala.runtime.Statics +import language.experimental.captureChecking +import annotation.unchecked.uncheckedCaptures /** This class implements an immutable linked list. We call it "lazy" * because it computes its elements only when they are needed. * + * The class extends Iterable; it is a replacement for LazyList, which + * which implemented Seq. The reason is that under capture checking, we + * assume that all Seqs are strict, and LazyList broke that assumption. + * As a consequence, we declare LazyList is deprecated and unsafe for + * capture checking, and replace it by the current class, LazyListIterable. + * * Elements are memoized; that is, the value of each element is computed at most once. * * Elements are computed in-order and are never skipped. In other words, * accessing the tail causes the head to be computed first. * - * How lazy is a `LazyList`? When you have a value of type `LazyList`, you + * How lazy is a `LazyListIterable`? When you have a value of type `LazyListIterable`, you * don't know yet whether the list is empty or not. If you learn that it is non-empty, * then you also know that the head has been computed. But the tail is itself - * a `LazyList`, whose emptiness-or-not might remain undetermined. + * a `LazyListIterable`, whose emptiness-or-not might remain undetermined. * - * A `LazyList` may be infinite. For example, `LazyList.from(0)` contains + * A `LazyListIterable` may be infinite. For example, `LazyListIterable.from(0)` contains * all of the natural numbers 0, 1, 2, and so on. For infinite sequences, * some methods (such as `count`, `sum`, `max` or `min`) will not terminate. * @@ -45,7 +53,7 @@ import scala.runtime.Statics * {{{ * import scala.math.BigInt * object Main extends App { - * val fibs: LazyList[BigInt] = + * val fibs: LazyListIterable[BigInt] = * BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map{ n => n._1 + n._2 } * fibs.take(5).foreach(println) * } @@ -65,7 +73,7 @@ import scala.runtime.Statics * {{{ * import scala.math.BigInt * object Main extends App { - * val fibs: LazyList[BigInt] = + * val fibs: LazyListIterable[BigInt] = * BigInt(0) #:: BigInt(1) #:: * fibs.zip(fibs.tail).map{ n => * println(s"Adding \${n._1} and \${n._2}") @@ -98,22 +106,22 @@ import scala.runtime.Statics * }}} * * Note that the definition of `fibs` uses `val` not `def`. The memoization of the - * `LazyList` requires us to have somewhere to store the information and a `val` + * `LazyListIterable` requires us to have somewhere to store the information and a `val` * allows us to do that. * - * Further remarks about the semantics of `LazyList`: + * Further remarks about the semantics of `LazyListIterable`: * - * - Though the `LazyList` changes as it is accessed, this does not + * - Though the `LazyListIterable` changes as it is accessed, this does not * contradict its immutability. Once the values are memoized they do * not change. Values that have yet to be memoized still "exist", they * simply haven't been computed yet. * * - One must be cautious of memoization; it can eat up memory if you're not - * careful. That's because memoization of the `LazyList` creates a structure much like + * careful. That's because memoization of the `LazyListIterable` creates a structure much like * [[scala.collection.immutable.List]]. As long as something is holding on to * the head, the head holds on to the tail, and so on recursively. * If, on the other hand, there is nothing holding on to the head (e.g. if we used - * `def` to define the `LazyList`) then once it is no longer being used directly, + * `def` to define the `LazyListIterable`) then once it is no longer being used directly, * it disappears. * * - Note that some operations, including [[drop]], [[dropWhile]], @@ -133,30 +141,30 @@ import scala.runtime.Statics * } * } * - * // Our first LazyList definition will be a val definition - * val lazylist1: LazyList[Int] = { - * def loop(v: Int): LazyList[Int] = v #:: loop(v + 1) + * // Our first LazyListIterable definition will be a val definition + * val lazylist1: LazyListIterable[Int] = { + * def loop(v: Int): LazyListIterable[Int] = v #:: loop(v + 1) * loop(0) * } * * // Because lazylist1 is a val, everything that the iterator produces is held - * // by virtue of the fact that the head of the LazyList is held in lazylist1 + * // by virtue of the fact that the head of the LazyListIterable is held in lazylist1 * val it1 = lazylist1.iterator * loop("Iterator1: ", it1.next(), it1) * - * // We can redefine this LazyList such that all we have is the Iterator left - * // and allow the LazyList to be garbage collected as required. Using a def - * // to provide the LazyList ensures that no val is holding onto the head as + * // We can redefine this LazyListIterable such that all we have is the Iterator left + * // and allow the LazyListIterable to be garbage collected as required. Using a def + * // to provide the LazyListIterable ensures that no val is holding onto the head as * // is the case with lazylist1 - * def lazylist2: LazyList[Int] = { - * def loop(v: Int): LazyList[Int] = v #:: loop(v + 1) + * def lazylist2: LazyListIterable[Int] = { + * def loop(v: Int): LazyListIterable[Int] = v #:: loop(v + 1) * loop(0) * } * val it2 = lazylist2.iterator * loop("Iterator2: ", it2.next(), it2) * - * // And, of course, we don't actually need a LazyList at all for such a simple - * // problem. There's no reason to use a LazyList if you don't actually need + * // And, of course, we don't actually need a LazyListIterable at all for such a simple + * // problem. There's no reason to use a LazyListIterable if you don't actually need * // one. * val it3 = new Iterator[Int] { * var i = -1 @@ -167,7 +175,7 @@ import scala.runtime.Statics * }}} * * - In the `fibs` example earlier, the fact that `tail` works at all is of interest. - * `fibs` has an initial `(0, 1, LazyList(...))`, so `tail` is deterministic. + * `fibs` has an initial `(0, 1, LazyListIterable(...))`, so `tail` is deterministic. * If we defined `fibs` such that only `0` were concretely known, then the act * of determining `tail` would require the evaluation of `tail`, so the * computation would be unable to progress, as in this code: @@ -175,7 +183,7 @@ import scala.runtime.Statics * // The first time we try to access the tail we're going to need more * // information which will require us to recurse, which will require us to * // recurse, which... - * lazy val sov: LazyList[Vector[Int]] = Vector(0) #:: sov.zip(sov.tail).map { n => n._1 ++ n._2 } + * lazy val sov: LazyListIterable[Vector[Int]] = Vector(0) #:: sov.zip(sov.tail).map { n => n._1 ++ n._2 } * }}} * * The definition of `fibs` above creates a larger number of objects than @@ -184,8 +192,8 @@ import scala.runtime.Statics * fact that it has a more direct route to the numbers themselves: * * {{{ - * lazy val fib: LazyList[Int] = { - * def loop(h: Int, n: Int): LazyList[Int] = h #:: loop(n, h + n) + * lazy val fib: LazyListIterable[Int] = { + * def loop(h: Int, n: Int): LazyListIterable[Int] = h #:: loop(n, h + n) * loop(1, 1) * } * }}} @@ -196,8 +204,8 @@ import scala.runtime.Statics * the tails content is deferred until the tails empty status, head or tail is * evaluated. * - * Delaying the evaluation of whether a LazyList is empty or not until it's needed - * allows LazyList to not eagerly evaluate any elements on a call to `filter`. + * Delaying the evaluation of whether a LazyListIterable is empty or not until it's needed + * allows LazyListIterable to not eagerly evaluate any elements on a call to `filter`. * * Only when it's further evaluated (which may be never!) any of the elements gets * forced. @@ -205,24 +213,24 @@ import scala.runtime.Statics * for example: * * {{{ - * def tailWithSideEffect: LazyList[Nothing] = { - * println("getting empty LazyList") - * LazyList.empty + * def tailWithSideEffect: LazyListIterable[Nothing] = { + * println("getting empty LazyListIterable") + * LazyListIterable.empty * } * - * val emptyTail = tailWithSideEffect // prints "getting empty LazyList" + * val emptyTail = tailWithSideEffect // prints "getting empty LazyListIterable" * * val suspended = 1 #:: tailWithSideEffect // doesn't print anything * val tail = suspended.tail // although the tail is evaluated, *still* nothing is yet printed * val filtered = tail.filter(_ => false) // still nothing is printed - * filtered.isEmpty // prints "getting empty LazyList" + * filtered.isEmpty // prints "getting empty LazyListIterable" * }}} * * @tparam A the type of the elements contained in this lazy list. * * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html#lazylists "Scala's Collection Library overview"]] * section on `LazyLists` for more information. - * @define Coll `LazyList` + * @define Coll `LazyListIterable` * @define coll lazy list * @define orderDependent * @define orderDependentFold @@ -237,23 +245,24 @@ import scala.runtime.Statics * @define evaluatesAllElements This method evaluates all elements of the collection. */ @SerialVersionUID(3L) -final class LazyList[+A] private(private[this] var lazyState: () => LazyList.State[A]) - extends AbstractSeq[A] - with LinearSeq[A] - with LinearSeqOps[A, LazyList, LazyList[A]] - with IterableFactoryDefaults[A, LazyList] +final class LazyListIterable[+A] private(private[this] var lazyState: () => LazyListIterable.State[A]^) + extends AbstractIterable[A] + with Iterable[A] + with IterableOps[A, LazyListIterable, LazyListIterable[A]] + with IterableFactoryDefaults[A, LazyListIterable] with Serializable { - import LazyList._ + this: LazyListIterable[A]^ => + import LazyListIterable._ @volatile private[this] var stateEvaluated: Boolean = false @inline private def stateDefined: Boolean = stateEvaluated private[this] var midEvaluation = false - private lazy val state: State[A] = { + private lazy val state: State[A]^ = { // if it's already mid-evaluation, we're stuck in an infinite // self-referential loop (also it's empty) if (midEvaluation) { - throw new RuntimeException("self-referential LazyList or a derivation thereof has no more elements") + throw new RuntimeException("self-referential LazyListIterable or a derivation thereof has no more elements") } midEvaluation = true val res = try lazyState() finally midEvaluation = false @@ -264,7 +273,7 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta res } - override def iterableFactory: SeqFactory[LazyList] = LazyList + override def iterableFactory: IterableFactory[LazyListIterable] = LazyListIterable override def isEmpty: Boolean = state eq State.Empty @@ -276,7 +285,7 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta override def head: A = state.head - override def tail: LazyList[A] = state.tail + override def tail: LazyListIterable[A]^{this} = state.tail @inline private[this] def knownIsEmpty: Boolean = stateEvaluated && (isEmpty: @inline) @inline private def knownNonEmpty: Boolean = stateEvaluated && !(isEmpty: @inline) @@ -287,13 +296,13 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * elements of the cycle are evaluated. For example: * * {{{ - * val ring: LazyList[Int] = 1 #:: 2 #:: 3 #:: ring + * val ring: LazyListIterable[Int] = 1 #:: 2 #:: 3 #:: ring * ring.force * ring.toString * * // prints * // - * // LazyList(1, 2, 3, ...) + * // LazyListIterable(1, 2, 3, ...) * }}} * * This method will *not* terminate for non-cyclic infinite-sized collections. @@ -302,7 +311,7 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta */ def force: this.type = { // Use standard 2x 1x iterator trick for cycle detection ("those" is slow one) - var these, those: LazyList[A] = this + var these, those: LazyListIterable[A]^{this} = this if (!these.isEmpty) { these = these.tail } @@ -322,7 +331,7 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * The iterator returned by this method preserves laziness; elements are * only evaluated individually as needed. */ - override def iterator: Iterator[A] = + override def iterator: Iterator[A]^{this} = if (knownIsEmpty) Iterator.empty else new LazyIterator(this) @@ -332,9 +341,9 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * @param f The treatment to apply to each element. * @note Overridden here as final to trigger tail-call optimization, which * replaces 'this' with 'tail' at each iteration. This is absolutely - * necessary for allowing the GC to collect the underlying LazyList as elements + * necessary for allowing the GC to collect the underlying LazyListIterable as elements * are consumed. - * @note This function will force the realization of the entire LazyList + * @note This function will force the realization of the entire LazyListIterable * unless the `f` throws an exception. */ @tailrec @@ -345,12 +354,12 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta } } - /** LazyList specialization of foldLeft which allows GC to collect along the + /** LazyListIterable specialization of foldLeft which allows GC to collect along the * way. * * @tparam B The type of value being accumulated. * @param z The initial value seeded into the function `op`. - * @param op The operation to perform on successive elements of the `LazyList`. + * @param op The operation to perform on successive elements of the `LazyListIterable`. * @return The accumulated value from successive applications of `op`. */ @tailrec @@ -359,10 +368,10 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta else tail.foldLeft(op(z, head))(op) // State.Empty doesn't use the SerializationProxy - protected[this] def writeReplace(): AnyRef = - if (knownNonEmpty) new LazyList.SerializationProxy[A](this) else this + protected[this] def writeReplace(): AnyRef^{this} = + if (knownNonEmpty) new LazyListIterable.SerializationProxy[A](this) else this - override protected[this] def className = "LazyList" + override protected[this] def className = "LazyListIterable" /** The lazy list resulting from the concatenation of this lazy list with the argument lazy list. * @@ -373,10 +382,10 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * @param suffix The collection that gets appended to this lazy list * @return The lazy list containing elements of this lazy list and the iterable object. */ - def lazyAppendedAll[B >: A](suffix: => collection.IterableOnce[B]): LazyList[B] = + def lazyAppendedAll[B >: A](suffix: => collection.IterableOnce[B]^): LazyListIterable[B]^{this, suffix} = newLL { if (isEmpty) suffix match { - case lazyList: LazyList[B] => lazyList.state // don't recompute the LazyList + case lazyList: LazyListIterable[B] => lazyList.state // don't recompute the LazyListIterable case coll if coll.knownSize == 0 => State.Empty case coll => stateFromIterator(coll.iterator) } @@ -389,8 +398,8 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $appendStackSafety */ - override def appendedAll[B >: A](suffix: IterableOnce[B]): LazyList[B] = - if (knownIsEmpty) LazyList.from(suffix) + def appendedAll[B >: A](suffix: IterableOnce[B]^): LazyListIterable[B]^{this, suffix} = + if (knownIsEmpty) LazyListIterable.from(suffix) else lazyAppendedAll(suffix) /** @inheritdoc @@ -399,19 +408,19 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $appendStackSafety */ - override def appended[B >: A](elem: B): LazyList[B] = - if (knownIsEmpty) newLL(sCons(elem, LazyList.empty)) + def appended[B >: A](elem: B): LazyListIterable[B]^{this} = + if (knownIsEmpty) newLL(sCons(elem, LazyListIterable.empty)) else lazyAppendedAll(Iterator.single(elem)) /** @inheritdoc * * $preservesLaziness */ - override def scanLeft[B](z: B)(op: (B, A) => B): LazyList[B] = - if (knownIsEmpty) newLL(sCons(z, LazyList.empty)) + override def scanLeft[B](z: B)(op: (B, A) => B): LazyListIterable[B]^{this, op} = + if (knownIsEmpty) newLL(sCons(z, LazyListIterable.empty)) else newLL(scanLeftState(z)(op)) - private def scanLeftState[B](z: B)(op: (B, A) => B): State[B] = + private def scanLeftState[B](z: B)(op: (B, A) => B): State[B]^{this, op} = sCons( z, newLL { @@ -420,18 +429,18 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta } ) - /** LazyList specialization of reduceLeft which allows GC to collect + /** LazyListIterable specialization of reduceLeft which allows GC to collect * along the way. * * @tparam B The type of value being accumulated. - * @param f The operation to perform on successive elements of the `LazyList`. + * @param f The operation to perform on successive elements of the `LazyListIterable`. * @return The accumulated value from successive applications of `f`. */ override def reduceLeft[B >: A](f: (B, A) => B): B = { if (this.isEmpty) throw new UnsupportedOperationException("empty.reduceLeft") else { var reducedRes: B = this.head - var left: LazyList[A] = this.tail + var left: LazyListIterable[A]^{this} = this.tail while (!left.isEmpty) { reducedRes = f(reducedRes, left.head) left = left.tail @@ -444,13 +453,13 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $preservesLaziness */ - override def partition(p: A => Boolean): (LazyList[A], LazyList[A]) = (filter(p), filterNot(p)) + override def partition(p: A => Boolean): (LazyListIterable[A]^{this, p}, LazyListIterable[A]^{this, p}) = (filter(p), filterNot(p)) /** @inheritdoc * * $preservesLaziness */ - override def partitionMap[A1, A2](f: A => Either[A1, A2]): (LazyList[A1], LazyList[A2]) = { + override def partitionMap[A1, A2](f: A => Either[A1, A2]): (LazyListIterable[A1]^{this, f}, LazyListIterable[A2]^{this, f}) = { val (left, right) = map(f).partition(_.isLeft) (left.map(_.asInstanceOf[Left[A1, _]].value), right.map(_.asInstanceOf[Right[_, A2]].value)) } @@ -459,17 +468,17 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $preservesLaziness */ - override def filter(pred: A => Boolean): LazyList[A] = - if (knownIsEmpty) LazyList.empty - else LazyList.filterImpl(this, pred, isFlipped = false) + override def filter(pred: A => Boolean): LazyListIterable[A]^{this, pred} = + if (knownIsEmpty) LazyListIterable.empty + else LazyListIterable.filterImpl(this, pred, isFlipped = false) /** @inheritdoc * * $preservesLaziness */ - override def filterNot(pred: A => Boolean): LazyList[A] = - if (knownIsEmpty) LazyList.empty - else LazyList.filterImpl(this, pred, isFlipped = true) + override def filterNot(pred: A => Boolean): LazyListIterable[A]^{this, pred} = + if (knownIsEmpty) LazyListIterable.empty + else LazyListIterable.filterImpl(this, pred, isFlipped = true) /** A `collection.WithFilter` which allows GC of the head of lazy list during processing. * @@ -479,21 +488,21 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * The `collection.WithFilter` returned by this method preserves laziness; elements are * only evaluated individually as needed. */ - override def withFilter(p: A => Boolean): collection.WithFilter[A, LazyList] = - new LazyList.WithFilter(coll, p) + override def withFilter(p: A => Boolean): collection.WithFilter[A, LazyListIterable]^{this, p} = + new LazyListIterable.WithFilter(coll, p) /** @inheritdoc * * $preservesLaziness */ - override def prepended[B >: A](elem: B): LazyList[B] = newLL(sCons(elem, this)) + def prepended[B >: A](elem: B): LazyListIterable[B] = newLL(sCons(elem, this)) /** @inheritdoc * * $preservesLaziness */ - override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): LazyList[B] = - if (knownIsEmpty) LazyList.from(prefix) + def prependedAll[B >: A](prefix: collection.IterableOnce[B]^): LazyListIterable[B]^{this, prefix} = + if (knownIsEmpty) LazyListIterable.from(prefix) else if (prefix.knownSize == 0) this else newLL(stateFromIteratorConcatSuffix(prefix.iterator)(state)) @@ -501,17 +510,17 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $preservesLaziness */ - override def map[B](f: A => B): LazyList[B] = - if (knownIsEmpty) LazyList.empty + override def map[B](f: A => B): LazyListIterable[B]^{this, f} = + if (knownIsEmpty) LazyListIterable.empty else (mapImpl(f): @inline) /** @inheritdoc * * $preservesLaziness */ - override def tapEach[U](f: A => U): LazyList[A] = map { a => f(a); a } + override def tapEach[U](f: A => U): LazyListIterable[A]^{this, f} = map { a => f(a); a } - private def mapImpl[B](f: A => B): LazyList[B] = + private def mapImpl[B](f: A => B): LazyListIterable[B]^{this, f} = newLL { if (isEmpty) State.Empty else sCons(f(head), tail.mapImpl(f)) @@ -521,9 +530,9 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $preservesLaziness */ - override def collect[B](pf: PartialFunction[A, B]): LazyList[B] = - if (knownIsEmpty) LazyList.empty - else LazyList.collectImpl(this, pf) + override def collect[B](pf: PartialFunction[A, B]^): LazyListIterable[B]^{this, pf} = + if (knownIsEmpty) LazyListIterable.empty + else LazyListIterable.collectImpl(this, pf) /** @inheritdoc * @@ -534,7 +543,7 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta override def collectFirst[B](pf: PartialFunction[A, B]): Option[B] = if (isEmpty) None else { - val res = pf.applyOrElse(head, LazyList.anyToMarker.asInstanceOf[A => B]) + val res = pf.applyOrElse(head, LazyListIterable.anyToMarker.asInstanceOf[A => B]) if (res.asInstanceOf[AnyRef] eq Statics.pfMarker) tail.collectFirst(pf) else Some(res) } @@ -559,25 +568,25 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta */ // optimisations are not for speed, but for functionality // see tickets #153, #498, #2147, and corresponding tests in run/ (as well as run/stream_flatmap_odds.scala) - override def flatMap[B](f: A => IterableOnce[B]): LazyList[B] = - if (knownIsEmpty) LazyList.empty - else LazyList.flatMapImpl(this, f) + override def flatMap[B](f: A => IterableOnce[B]^): LazyListIterable[B]^{this, f} = + if (knownIsEmpty) LazyListIterable.empty + else LazyListIterable.flatMapImpl(this, f) /** @inheritdoc * * $preservesLaziness */ - override def flatten[B](implicit asIterable: A => IterableOnce[B]): LazyList[B] = flatMap(asIterable) + override def flatten[B](implicit asIterable: A -> IterableOnce[B]): LazyListIterable[B]^{this} = flatMap(asIterable) /** @inheritdoc * * $preservesLaziness */ - override def zip[B](that: collection.IterableOnce[B]): LazyList[(A, B)] = - if (this.knownIsEmpty || that.knownSize == 0) LazyList.empty + override def zip[B](that: collection.IterableOnce[B]^): LazyListIterable[(A, B)]^{this, that} = + if (this.knownIsEmpty || that.knownSize == 0) LazyListIterable.empty else newLL(zipState(that.iterator)) - private def zipState[B](it: Iterator[B]): State[(A, B)] = + private def zipState[B](it: Iterator[B]^): State[(A, B)]^{this, it} = if (this.isEmpty || !it.hasNext) State.Empty else sCons((head, it.next()), newLL { tail zipState it }) @@ -585,29 +594,29 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $preservesLaziness */ - override def zipWithIndex: LazyList[(A, Int)] = this zip LazyList.from(0) + override def zipWithIndex: LazyListIterable[(A, Int)]^{this} = this zip LazyListIterable.from(0) /** @inheritdoc * * $preservesLaziness */ - override def zipAll[A1 >: A, B](that: collection.Iterable[B], thisElem: A1, thatElem: B): LazyList[(A1, B)] = { + override def zipAll[A1 >: A, B](that: collection.Iterable[B]^, thisElem: A1, thatElem: B): LazyListIterable[(A1, B)]^{this, that} = { if (this.knownIsEmpty) { - if (that.knownSize == 0) LazyList.empty - else LazyList.continually(thisElem) zip that + if (that.knownSize == 0) LazyListIterable.empty + else LazyListIterable.continually(thisElem) zip that } else { - if (that.knownSize == 0) zip(LazyList.continually(thatElem)) + if (that.knownSize == 0) zip(LazyListIterable.continually(thatElem)) else newLL(zipAllState(that.iterator, thisElem, thatElem)) } } - private def zipAllState[A1 >: A, B](it: Iterator[B], thisElem: A1, thatElem: B): State[(A1, B)] = { + private def zipAllState[A1 >: A, B](it: Iterator[B]^, thisElem: A1, thatElem: B): State[(A1, B)]^{this, it} = { if (it.hasNext) { - if (this.isEmpty) sCons((thisElem, it.next()), newLL { LazyList.continually(thisElem) zipState it }) + if (this.isEmpty) sCons((thisElem, it.next()), newLL { LazyListIterable.continually(thisElem) zipState it }) else sCons((this.head, it.next()), newLL { this.tail.zipAllState(it, thisElem, thatElem) }) } else { if (this.isEmpty) State.Empty - else sCons((this.head, thatElem), this.tail zip LazyList.continually(thatElem)) + else sCons((this.head, thatElem), this.tail zip LazyListIterable.continually(thatElem)) } } @@ -620,21 +629,21 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * only evaluated individually as needed. */ // just in case it can be meaningfully overridden at some point - override def lazyZip[B](that: collection.Iterable[B]): LazyZip2[A, B, LazyList.this.type] = + override def lazyZip[B](that: collection.Iterable[B]^): LazyZip2[A, B, LazyListIterable.this.type]^{this, that} = super.lazyZip(that) /** @inheritdoc * * $preservesLaziness */ - override def unzip[A1, A2](implicit asPair: A => (A1, A2)): (LazyList[A1], LazyList[A2]) = + override def unzip[A1, A2](implicit asPair: A -> (A1, A2)): (LazyListIterable[A1]^{this}, LazyListIterable[A2]^{this}) = (map(asPair(_)._1), map(asPair(_)._2)) /** @inheritdoc * * $preservesLaziness */ - override def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3)): (LazyList[A1], LazyList[A2], LazyList[A3]) = + override def unzip3[A1, A2, A3](implicit asTriple: A -> (A1, A2, A3)): (LazyListIterable[A1]^{this}, LazyListIterable[A2]^{this}, LazyListIterable[A3]^{this}) = (map(asTriple(_)._1), map(asTriple(_)._2), map(asTriple(_)._3)) /** @inheritdoc @@ -642,27 +651,27 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * $initiallyLazy * Additionally, it preserves laziness for all except the first `n` elements. */ - override def drop(n: Int): LazyList[A] = + override def drop(n: Int): LazyListIterable[A]^{this} = if (n <= 0) this - else if (knownIsEmpty) LazyList.empty - else LazyList.dropImpl(this, n) + else if (knownIsEmpty) LazyListIterable.empty + else LazyListIterable.dropImpl(this, n) /** @inheritdoc * * $initiallyLazy * Additionally, it preserves laziness for all elements after the predicate returns `false`. */ - override def dropWhile(p: A => Boolean): LazyList[A] = - if (knownIsEmpty) LazyList.empty - else LazyList.dropWhileImpl(this, p) + override def dropWhile(p: A => Boolean): LazyListIterable[A]^{this, p} = + if (knownIsEmpty) LazyListIterable.empty + else LazyListIterable.dropWhileImpl(this, p) /** @inheritdoc * * $initiallyLazy */ - override def dropRight(n: Int): LazyList[A] = { + override def dropRight(n: Int): LazyListIterable[A]^{this} = { if (n <= 0) this - else if (knownIsEmpty) LazyList.empty + else if (knownIsEmpty) LazyListIterable.empty else newLL { var scout = this var remaining = n @@ -675,7 +684,7 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta } } - private def dropRightState(scout: LazyList[_]): State[A] = + private def dropRightState(scout: LazyListIterable[_]^): State[A]^{this, scout} = if (scout.isEmpty) State.Empty else sCons(head, newLL(tail.dropRightState(scout.tail))) @@ -683,12 +692,12 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $preservesLaziness */ - override def take(n: Int): LazyList[A] = - if (knownIsEmpty) LazyList.empty + override def take(n: Int): LazyListIterable[A] = + if (knownIsEmpty) LazyListIterable.empty else (takeImpl(n): @inline) - private def takeImpl(n: Int): LazyList[A] = { - if (n <= 0) LazyList.empty + private def takeImpl(n: Int): LazyListIterable[A] = { + if (n <= 0) LazyListIterable.empty else newLL { if (isEmpty) State.Empty else sCons(head, tail.takeImpl(n - 1)) @@ -699,11 +708,11 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $preservesLaziness */ - override def takeWhile(p: A => Boolean): LazyList[A] = - if (knownIsEmpty) LazyList.empty + override def takeWhile(p: A => Boolean): LazyListIterable[A]^{this, p} = + if (knownIsEmpty) LazyListIterable.empty else (takeWhileImpl(p): @inline) - private def takeWhileImpl(p: A => Boolean): LazyList[A] = + private def takeWhileImpl(p: A => Boolean): LazyListIterable[A]^{this, p} = newLL { if (isEmpty || !p(head)) State.Empty else sCons(head, tail.takeWhileImpl(p)) @@ -713,45 +722,29 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $initiallyLazy */ - override def takeRight(n: Int): LazyList[A] = - if (n <= 0 || knownIsEmpty) LazyList.empty - else LazyList.takeRightImpl(this, n) + override def takeRight(n: Int): LazyListIterable[A]^{this} = + if (n <= 0 || knownIsEmpty) LazyListIterable.empty + else LazyListIterable.takeRightImpl(this, n) /** @inheritdoc * * $initiallyLazy * Additionally, it preserves laziness for all but the first `from` elements. */ - override def slice(from: Int, until: Int): LazyList[A] = take(until).drop(from) + override def slice(from: Int, until: Int): LazyListIterable[A]^{this} = take(until).drop(from) /** @inheritdoc * * $evaluatesAllElements */ - override def reverse: LazyList[A] = reverseOnto(LazyList.empty) + def reverse: LazyListIterable[A] = reverseOnto(LazyListIterable.empty) - // need contravariant type B to make the compiler happy - still returns LazyList[A] + // need contravariant type B to make the compiler happy - still returns LazyListIterable[A] @tailrec - private def reverseOnto[B >: A](tl: LazyList[B]): LazyList[B] = + private def reverseOnto[B >: A](tl: LazyListIterable[B]): LazyListIterable[B] = if (isEmpty) tl else tail.reverseOnto(newLL(sCons(head, tl))) - /** @inheritdoc - * - * $preservesLaziness - */ - override def diff[B >: A](that: collection.Seq[B]): LazyList[A] = - if (knownIsEmpty) LazyList.empty - else super.diff(that) - - /** @inheritdoc - * - * $preservesLaziness - */ - override def intersect[B >: A](that: collection.Seq[B]): LazyList[A] = - if (knownIsEmpty) LazyList.empty - else super.intersect(that) - @tailrec private def lengthGt(len: Int): Boolean = if (len < 0) true @@ -763,7 +756,7 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * The iterator returned by this method mostly preserves laziness; * a single element ahead of the iterator is evaluated. */ - override def grouped(size: Int): Iterator[LazyList[A]] = { + override def grouped(size: Int): Iterator[LazyListIterable[A]] = { require(size > 0, "size must be positive, but was " + size) slidingImpl(size = size, step = size) } @@ -773,12 +766,12 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * The iterator returned by this method mostly preserves laziness; * `size - step max 1` elements ahead of the iterator are evaluated. */ - override def sliding(size: Int, step: Int): Iterator[LazyList[A]] = { + override def sliding(size: Int, step: Int): Iterator[LazyListIterable[A]] = { require(size > 0 && step > 0, s"size=$size and step=$step, but both must be positive") slidingImpl(size = size, step = step) } - @inline private def slidingImpl(size: Int, step: Int): Iterator[LazyList[A]] = + @inline private def slidingImpl(size: Int, step: Int): Iterator[LazyListIterable[A]] = if (knownIsEmpty) Iterator.empty else new SlidingIterator[A](this, size = size, step = step) @@ -786,10 +779,10 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $preservesLaziness */ - override def padTo[B >: A](len: Int, elem: B): LazyList[B] = { + def padTo[B >: A](len: Int, elem: B): LazyListIterable[B]^{this} = { if (len <= 0) this else newLL { - if (isEmpty) LazyList.fill(len)(elem).state + if (isEmpty) LazyListIterable.fill(len)(elem).state else sCons(head, tail.padTo(len - 1, elem)) } } @@ -798,13 +791,13 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * $preservesLaziness */ - override def patch[B >: A](from: Int, other: IterableOnce[B], replaced: Int): LazyList[B] = - if (knownIsEmpty) LazyList from other + def patch[B >: A](from: Int, other: IterableOnce[B]^, replaced: Int): LazyListIterable[B]^{this, other} = + if (knownIsEmpty) LazyListIterable from other else patchImpl(from, other, replaced) - private def patchImpl[B >: A](from: Int, other: IterableOnce[B], replaced: Int): LazyList[B] = + private def patchImpl[B >: A](from: Int, other: IterableOnce[B]^, replaced: Int): LazyListIterable[B]^{this, other} = newLL { - if (from <= 0) stateFromIteratorConcatSuffix(other.iterator)(LazyList.dropImpl(this, replaced).state) + if (from <= 0) stateFromIteratorConcatSuffix(other.iterator)(LazyListIterable.dropImpl(this, replaced).state) else if (isEmpty) stateFromIterator(other.iterator) else sCons(head, tail.patchImpl(from - 1, other, replaced)) } @@ -814,17 +807,17 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * $evaluatesAllElements */ // overridden just in case a lazy implementation is developed at some point - override def transpose[B](implicit asIterable: A => collection.Iterable[B]): LazyList[LazyList[B]] = super.transpose + override def transpose[B](implicit asIterable: A -> collection.Iterable[B]): LazyListIterable[LazyListIterable[B]]^{this} = super.transpose /** @inheritdoc * * $preservesLaziness */ - override def updated[B >: A](index: Int, elem: B): LazyList[B] = + def updated[B >: A](index: Int, elem: B): LazyListIterable[B]^{this} = if (index < 0) throw new IndexOutOfBoundsException(s"$index") else updatedImpl(index, elem, index) - private def updatedImpl[B >: A](index: Int, elem: B, startIndex: Int): LazyList[B] = { + private def updatedImpl[B >: A](index: Int, elem: B, startIndex: Int): LazyListIterable[B]^{this} = { newLL { if (index <= 0) sCons(elem, tail) else if (tail.isEmpty) throw new IndexOutOfBoundsException(startIndex.toString) @@ -859,9 +852,9 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta else if (!isEmpty) { b.append(head) var cursor = this - @inline def appendCursorElement(): Unit = b.append(sep).append(cursor.head) + inline def appendCursorElement(): Unit = b.append(sep).append(cursor.head) var scout = tail - @inline def scoutNonEmpty: Boolean = scout.stateDefined && !scout.isEmpty + inline def scoutNonEmpty: Boolean = scout.stateDefined && !scout.isEmpty if ((cursor ne scout) && (!scout.stateDefined || (cursor.state ne scout.state))) { cursor = scout if (scoutNonEmpty) { @@ -883,7 +876,7 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta // if cursor (eq scout) has state defined, it is empty; else unknown state if (!cursor.stateDefined) b.append(sep).append("") } else { - @inline def same(a: LazyList[A], b: LazyList[A]): Boolean = (a eq b) || (a.state eq b.state) + @inline def same(a: LazyListIterable[A]^, b: LazyListIterable[A]^): Boolean = (a eq b) || (a.state eq b.state) // Cycle. // If we have a prefix of length P followed by a cycle of length C, // the scout will be at position (P%C) in the cycle when the cursor @@ -926,9 +919,9 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta * * Examples: * - * - `"LazyList(4, <not computed>)"`, a non-empty lazy list ; - * - `"LazyList(1, 2, 3, <not computed>)"`, a lazy list with at least three elements ; - * - `"LazyList(1, 2, 3, <cycle>)"`, an infinite lazy list that contains + * - `"LazyListIterable(4, <not computed>)"`, a non-empty lazy list ; + * - `"LazyListIterable(1, 2, 3, <not computed>)"`, a lazy list with at least three elements ; + * - `"LazyListIterable(1, 2, 3, <cycle>)"`, an infinite lazy list that contains * a cycle at the fourth element. */ override def toString(): String = addStringNoForce(new JStringBuilder(className), "(", ", ", ")").toString @@ -963,48 +956,49 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta /** * $factoryInfo * @define coll lazy list - * @define Coll `LazyList` + * @define Coll `LazyListIterable` */ @SerialVersionUID(3L) -object LazyList extends SeqFactory[LazyList] { +object LazyListIterable extends IterableFactory[LazyListIterable] { // Eagerly evaluate cached empty instance private[this] val _empty = newLL(State.Empty).force private sealed trait State[+A] extends Serializable { + this: State[A]^ => def head: A - def tail: LazyList[A] + def tail: LazyListIterable[A]^ } private object State { @SerialVersionUID(3L) object Empty extends State[Nothing] { def head: Nothing = throw new NoSuchElementException("head of empty lazy list") - def tail: LazyList[Nothing] = throw new UnsupportedOperationException("tail of empty lazy list") + def tail: LazyListIterable[Nothing] = throw new UnsupportedOperationException("tail of empty lazy list") } @SerialVersionUID(3L) - final class Cons[A](val head: A, val tail: LazyList[A]) extends State[A] + final class Cons[A](val head: A, val tail: LazyListIterable[A]^) extends State[A] } - /** Creates a new LazyList. */ - @inline private def newLL[A](state: => State[A]): LazyList[A] = new LazyList[A](() => state) + /** Creates a new LazyListIterable. */ + @inline private def newLL[A](state: => State[A]^): LazyListIterable[A]^{state} = new LazyListIterable[A](() => state) /** Creates a new State.Cons. */ - @inline private def sCons[A](hd: A, tl: LazyList[A]): State[A] = new State.Cons[A](hd, tl) + @inline private def sCons[A](hd: A, tl: LazyListIterable[A]^): State[A]^{tl} = new State.Cons[A](hd, tl) private val anyToMarker: Any => Any = _ => Statics.pfMarker /* All of the following `Impl` methods are carefully written so as not to - * leak the beginning of the `LazyList`. They copy the initial `LazyList` (`ll`) into + * leak the beginning of the `LazyListIterable`. They copy the initial `LazyListIterable` (`ll`) into * `var rest`, which gets closed over as a `scala.runtime.ObjectRef`, thus not permanently - * leaking the head of the `LazyList`. Additionally, the methods are written so that, should - * an exception be thrown by the evaluation of the `LazyList` or any supplied function, they + * leaking the head of the `LazyListIterable`. Additionally, the methods are written so that, should + * an exception be thrown by the evaluation of the `LazyListIterable` or any supplied function, they * can continue their execution where they left off. */ - private def filterImpl[A](ll: LazyList[A], p: A => Boolean, isFlipped: Boolean): LazyList[A] = { + private def filterImpl[A](ll: LazyListIterable[A]^, p: A => Boolean, isFlipped: Boolean): LazyListIterable[A]^{ll, p} = { // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD - var restRef = ll // val restRef = new ObjectRef(ll) + var restRef: LazyListIterable[A @uncheckedCaptures]^{cap[filterImpl]} = ll // restRef is captured by closure arg to newLL, so A is not recognized as parametric newLL { var elem: A = null.asInstanceOf[A] var found = false @@ -1019,9 +1013,9 @@ object LazyList extends SeqFactory[LazyList] { } } - private def collectImpl[A, B](ll: LazyList[A], pf: PartialFunction[A, B]): LazyList[B] = { + private def collectImpl[A, B](ll: LazyListIterable[A]^, pf: PartialFunction[A, B]^): LazyListIterable[B]^{ll, pf} = { // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD - var restRef = ll // val restRef = new ObjectRef(ll) + var restRef: LazyListIterable[A @uncheckedCaptures]^{cap[collectImpl]} = ll // restRef is captured by closure arg to newLL, so A is not recognized as parametric newLL { val marker = Statics.pfMarker val toMarker = anyToMarker.asInstanceOf[A => B] // safe because Function1 is erased @@ -1038,11 +1032,11 @@ object LazyList extends SeqFactory[LazyList] { } } - private def flatMapImpl[A, B](ll: LazyList[A], f: A => IterableOnce[B]): LazyList[B] = { + private def flatMapImpl[A, B](ll: LazyListIterable[A]^, f: A => IterableOnce[B]^): LazyListIterable[B]^{ll, f} = { // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD - var restRef = ll // val restRef = new ObjectRef(ll) + var restRef: LazyListIterable[A @uncheckedCaptures]^{cap[flatMapImpl]} = ll // restRef is captured by closure arg to newLL, so A is not recognized as parametric newLL { - var it: Iterator[B] = null + var it: Iterator[B @uncheckedCaptures]^{ll, f} = null var itHasNext = false var rest = restRef // var rest = restRef.elem while (!itHasNext && !rest.isEmpty) { @@ -1062,9 +1056,9 @@ object LazyList extends SeqFactory[LazyList] { } } - private def dropImpl[A](ll: LazyList[A], n: Int): LazyList[A] = { + private def dropImpl[A](ll: LazyListIterable[A]^, n: Int): LazyListIterable[A]^{ll} = { // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD - var restRef = ll // val restRef = new ObjectRef(ll) + var restRef: LazyListIterable[A @uncheckedCaptures]^{cap[dropImpl]} = ll // restRef is captured by closure arg to newLL, so A is not recognized as parametric var iRef = n // val iRef = new IntRef(n) newLL { var rest = restRef // var rest = restRef.elem @@ -1079,9 +1073,9 @@ object LazyList extends SeqFactory[LazyList] { } } - private def dropWhileImpl[A](ll: LazyList[A], p: A => Boolean): LazyList[A] = { + private def dropWhileImpl[A](ll: LazyListIterable[A]^, p: A => Boolean): LazyListIterable[A]^{ll, p} = { // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD - var restRef = ll // val restRef = new ObjectRef(ll) + var restRef: LazyListIterable[A @uncheckedCaptures]^{cap[dropWhileImpl]} = ll // restRef is captured by closure arg to newLL, so A is not recognized as parametric newLL { var rest = restRef // var rest = restRef.elem while (!rest.isEmpty && p(rest.head)) { @@ -1092,10 +1086,10 @@ object LazyList extends SeqFactory[LazyList] { } } - private def takeRightImpl[A](ll: LazyList[A], n: Int): LazyList[A] = { + private def takeRightImpl[A](ll: LazyListIterable[A]^, n: Int): LazyListIterable[A]^{ll} = { // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD - var restRef = ll // val restRef = new ObjectRef(ll) - var scoutRef = ll // val scoutRef = new ObjectRef(ll) + var restRef: LazyListIterable[A @uncheckedCaptures]^{cap[takeRightImpl]} = ll // restRef is captured by closure arg to newLL, so A is not recognized as parametric + var scoutRef: LazyListIterable[A @uncheckedCaptures]^{cap[takeRightImpl]} = ll // same situation var remainingRef = n // val remainingRef = new IntRef(n) newLL { var scout = scoutRef // var scout = scoutRef.elem @@ -1120,117 +1114,115 @@ object LazyList extends SeqFactory[LazyList] { } } - /** An alternative way of building and matching lazy lists using LazyList.cons(hd, tl). + /** An alternative way of building and matching lazy lists using LazyListIterable.cons(hd, tl). */ object cons { /** A lazy list consisting of a given first element and remaining elements * @param hd The first element of the result lazy list * @param tl The remaining elements of the result lazy list */ - def apply[A](hd: => A, tl: => LazyList[A]): LazyList[A] = newLL(sCons(hd, newLL(tl.state))) + def apply[A](hd: => A, tl: => LazyListIterable[A]^): LazyListIterable[A]^{hd, tl} = newLL(sCons(hd, newLL(tl.state))) /** Maps a lazy list to its head and tail */ - def unapply[A](xs: LazyList[A]): Option[(A, LazyList[A])] = #::.unapply(xs) + def unapply[A](xs: LazyListIterable[A]^): Option[(A, LazyListIterable[A]^{xs})] = #::.unapply(xs) } - implicit def toDeferrer[A](l: => LazyList[A]): Deferrer[A] = new Deferrer[A](() => l) - - final class Deferrer[A] private[LazyList] (private val l: () => LazyList[A]) extends AnyVal { - /** Construct a LazyList consisting of a given first element followed by elements - * from another LazyList. + extension [A](l: => LazyListIterable[A]) + /** Construct a LazyListIterable consisting of a given first element followed by elements + * from another LazyListIterable. */ - def #:: [B >: A](elem: => B): LazyList[B] = newLL(sCons(elem, newLL(l().state))) - /** Construct a LazyList consisting of the concatenation of the given LazyList and - * another LazyList. + def #:: [B >: A](elem: => B): LazyListIterable[B]^{elem, l} = newLL(sCons(elem, newLL(l.state))) + + /** Construct a LazyListIterable consisting of the concatenation of the given LazyListIterable and + * another LazyListIterable. */ - def #:::[B >: A](prefix: LazyList[B]): LazyList[B] = prefix lazyAppendedAll l() - } + def #:::[B >: A](prefix: LazyListIterable[B]^): LazyListIterable[B]^{prefix, l} = prefix lazyAppendedAll l object #:: { - def unapply[A](s: LazyList[A]): Option[(A, LazyList[A])] = + def unapply[A](s: LazyListIterable[A]^): Option[(A, LazyListIterable[A]^{s})] = if (!s.isEmpty) Some((s.head, s.tail)) else None } - def from[A](coll: collection.IterableOnce[A]): LazyList[A] = coll match { - case lazyList: LazyList[A] => lazyList + def from[A](coll: collection.IterableOnce[A]^): LazyListIterable[A]^{coll} = coll match { + case lazyList: LazyListIterable[A] => lazyList case _ if coll.knownSize == 0 => empty[A] case _ => newLL(stateFromIterator(coll.iterator)) } - def empty[A]: LazyList[A] = _empty + def empty[A]: LazyListIterable[A] = _empty /** Creates a State from an Iterator, with another State appended after the Iterator * is empty. */ - private def stateFromIteratorConcatSuffix[A](it: Iterator[A])(suffix: => State[A]): State[A] = + private def stateFromIteratorConcatSuffix[A](it: Iterator[A]^)(suffix: => State[A]^): State[A]^{it, suffix} = if (it.hasNext) sCons(it.next(), newLL(stateFromIteratorConcatSuffix(it)(suffix))) else suffix /** Creates a State from an IterableOnce. */ - private def stateFromIterator[A](it: Iterator[A]): State[A] = + private def stateFromIterator[A](it: Iterator[A]^): State[A]^{it} = if (it.hasNext) sCons(it.next(), newLL(stateFromIterator(it))) else State.Empty - override def concat[A](xss: collection.Iterable[A]*): LazyList[A] = + override def concat[A](xss: collection.Iterable[A]*): LazyListIterable[A] = if (xss.knownSize == 0) empty else newLL(concatIterator(xss.iterator)) - private def concatIterator[A](it: Iterator[collection.Iterable[A]]): State[A] = + private def concatIterator[A](it: Iterator[collection.Iterable[A]]^): State[A]^{it} = if (!it.hasNext) State.Empty else stateFromIteratorConcatSuffix(it.next().iterator)(concatIterator(it)) - /** An infinite LazyList that repeatedly applies a given function to a start value. + /** An infinite LazyListIterable that repeatedly applies a given function to a start value. * - * @param start the start value of the LazyList + * @param start the start value of the LazyListIterable * @param f the function that's repeatedly applied - * @return the LazyList returning the infinite sequence of values `start, f(start), f(f(start)), ...` + * @return the LazyListIterable returning the infinite sequence of values `start, f(start), f(f(start)), ...` */ - def iterate[A](start: => A)(f: A => A): LazyList[A] = + def iterate[A](start: => A)(f: A => A): LazyListIterable[A]^{start, f} = newLL { val head = start sCons(head, iterate(f(head))(f)) } /** - * Create an infinite LazyList starting at `start` and incrementing by + * Create an infinite LazyListIterable starting at `start` and incrementing by * step `step`. * - * @param start the start value of the LazyList - * @param step the increment value of the LazyList - * @return the LazyList starting at value `start`. + * @param start the start value of the LazyListIterable + * @param step the increment value of the LazyListIterable + * @return the LazyListIterable starting at value `start`. */ - def from(start: Int, step: Int): LazyList[Int] = + def from(start: Int, step: Int): LazyListIterable[Int] = newLL(sCons(start, from(start + step, step))) /** - * Create an infinite LazyList starting at `start` and incrementing by `1`. + * Create an infinite LazyListIterable starting at `start` and incrementing by `1`. * - * @param start the start value of the LazyList - * @return the LazyList starting at value `start`. + * @param start the start value of the LazyListIterable + * @return the LazyListIterable starting at value `start`. */ - def from(start: Int): LazyList[Int] = from(start, 1) + def from(start: Int): LazyListIterable[Int] = from(start, 1) /** - * Create an infinite LazyList containing the given element expression (which + * Create an infinite LazyListIterable containing the given element expression (which * is computed for each occurrence). * - * @param elem the element composing the resulting LazyList - * @return the LazyList containing an infinite number of elem + * @param elem the element composing the resulting LazyListIterable + * @return the LazyListIterable containing an infinite number of elem */ - def continually[A](elem: => A): LazyList[A] = newLL(sCons(elem, continually(elem))) + def continually[A](elem: => A): LazyListIterable[A]^{elem} = newLL(sCons(elem, continually(elem))) - override def fill[A](n: Int)(elem: => A): LazyList[A] = + override def fill[A](n: Int)(elem: => A): LazyListIterable[A]^{elem} = if (n > 0) newLL(sCons(elem, fill(n - 1)(elem))) else empty - override def tabulate[A](n: Int)(f: Int => A): LazyList[A] = { - def at(index: Int): LazyList[A] = + override def tabulate[A](n: Int)(f: Int => A): LazyListIterable[A]^{f} = { + def at(index: Int): LazyListIterable[A]^{f} = if (index < n) newLL(sCons(f(index), at(index + 1))) else empty at(0) } // significantly simpler than the iterator returned by Iterator.unfold - override def unfold[A, S](init: S)(f: S => Option[(A, S)]): LazyList[A] = + override def unfold[A, S](init: S)(f: S => Option[(A, S)]): LazyListIterable[A]^{f} = newLL { f(init) match { case Some((elem, state)) => sCons(elem, unfold(state)(f)) @@ -1244,9 +1236,9 @@ object LazyList extends SeqFactory[LazyList] { * @tparam A the type of the ${coll}’s elements * @return A builder for $Coll objects. */ - def newBuilder[A]: Builder[A, LazyList[A]] = new LazyBuilder[A] + def newBuilder[A]: Builder[A, LazyListIterable[A]] = new LazyBuilder[A] - private class LazyIterator[+A](private[this] var lazyList: LazyList[A]) extends AbstractIterator[A] { + private class LazyIterator[+A](private[this] var lazyList: LazyListIterable[A]^) extends AbstractIterator[A] { override def hasNext: Boolean = !lazyList.isEmpty override def next(): A = @@ -1258,8 +1250,9 @@ object LazyList extends SeqFactory[LazyList] { } } - private class SlidingIterator[A](private[this] var lazyList: LazyList[A], size: Int, step: Int) - extends AbstractIterator[LazyList[A]] { + private class SlidingIterator[A](private[this] var lazyList: LazyListIterable[A]^, size: Int, step: Int) + extends AbstractIterator[LazyListIterable[A]] { + this: SlidingIterator[A]^ => private val minLen = size - step max 0 private var first = true @@ -1267,7 +1260,7 @@ object LazyList extends SeqFactory[LazyList] { if (first) !lazyList.isEmpty else lazyList.lengthGt(minLen) - def next(): LazyList[A] = { + def next(): LazyListIterable[A] = { if (!hasNext) Iterator.empty.next() else { first = false @@ -1278,20 +1271,21 @@ object LazyList extends SeqFactory[LazyList] { } } - private final class WithFilter[A] private[LazyList](lazyList: LazyList[A], p: A => Boolean) - extends collection.WithFilter[A, LazyList] { + private final class WithFilter[A] private[LazyListIterable](lazyList: LazyListIterable[A]^, p: A => Boolean) + extends collection.WithFilter[A, LazyListIterable] { + this: WithFilter[A]^ => private[this] val filtered = lazyList.filter(p) - def map[B](f: A => B): LazyList[B] = filtered.map(f) - def flatMap[B](f: A => IterableOnce[B]): LazyList[B] = filtered.flatMap(f) + def map[B](f: A => B): LazyListIterable[B]^{this, f} = filtered.map(f) + def flatMap[B](f: A => IterableOnce[B]^): LazyListIterable[B]^{this, f} = filtered.flatMap(f) def foreach[U](f: A => U): Unit = filtered.foreach(f) - def withFilter(q: A => Boolean): collection.WithFilter[A, LazyList] = new WithFilter(filtered, q) + def withFilter(q: A => Boolean): collection.WithFilter[A, LazyListIterable]^{this, q} = new WithFilter(filtered, q) } - private final class LazyBuilder[A] extends ReusableBuilder[A, LazyList[A]] { + private final class LazyBuilder[A] extends ReusableBuilder[A, LazyListIterable[A]] { import LazyBuilder._ - private[this] var next: DeferredState[A] = _ - private[this] var list: LazyList[A] = _ + private[this] var next: DeferredState[A @uncheckedCaptures] = _ + private[this] var list: LazyListIterable[A @uncheckedCaptures] = _ clear() @@ -1301,7 +1295,7 @@ object LazyList extends SeqFactory[LazyList] { next = deferred } - override def result(): LazyList[A] = { + override def result(): LazyListIterable[A] = { next init State.Empty list } @@ -1314,10 +1308,10 @@ object LazyList extends SeqFactory[LazyList] { } // lazy implementation which doesn't evaluate the collection being added - override def addAll(xs: IterableOnce[A]): this.type = { + override def addAll(xs: IterableOnce[A]^): this.type = { if (xs.knownSize != 0) { val deferred = new DeferredState[A] - next init stateFromIteratorConcatSuffix(xs.iterator)(deferred.eval()) + next.init(stateFromIteratorConcatSuffix(xs.iterator)(deferred.eval())) next = deferred } this @@ -1326,16 +1320,17 @@ object LazyList extends SeqFactory[LazyList] { private object LazyBuilder { final class DeferredState[A] { - private[this] var _state: () => State[A] = _ + this: DeferredState[A]^ => + private[this] var _state: (() => State[A]^) @uncheckedCaptures = _ - def eval(): State[A] = { + def eval(): State[A]^ = { val state = _state if (state == null) throw new IllegalStateException("uninitialized") state() } // racy - def init(state: => State[A]): Unit = { + def init(state: => State[A]^): Unit = { if (_state != null) throw new IllegalStateException("already initialized") _state = () => state } @@ -1348,7 +1343,7 @@ object LazyList extends SeqFactory[LazyList] { * of long evaluated lazy lists without exhausting the stack through recursive serialization of cons cells. */ @SerialVersionUID(3L) - final class SerializationProxy[A](@transient protected var coll: LazyList[A]) extends Serializable { + final class SerializationProxy[A](@transient protected var coll: LazyListIterable[A]^) extends Serializable { private[this] def writeObject(out: ObjectOutputStream): Unit = { out.defaultWriteObject() @@ -1363,15 +1358,15 @@ object LazyList extends SeqFactory[LazyList] { private[this] def readObject(in: ObjectInputStream): Unit = { in.defaultReadObject() - val init = new mutable.ListBuffer[A] + val init = new mutable.ListBuffer[A @uncheckedCaptures] var initRead = false while (!initRead) in.readObject match { case SerializeEnd => initRead = true case a => init += a.asInstanceOf[A] } - val tail = in.readObject().asInstanceOf[LazyList[A]] + val tail = in.readObject().asInstanceOf[LazyListIterable[A]] // scala/scala#10118: caution that no code path can evaluate `tail.state` - // before the resulting LazyList is returned + // before the resulting LazyListIterable is returned val it = init.toList.iterator coll = newLL(stateFromIteratorConcatSuffix(it)(tail.state)) } diff --git a/tests/pos-special/stdlib/collection/immutable/List.scala b/tests/pos-special/stdlib/collection/immutable/List.scala index 5358922752fb..6a305f4ebdec 100644 --- a/tests/pos-special/stdlib/collection/immutable/List.scala +++ b/tests/pos-special/stdlib/collection/immutable/List.scala @@ -14,11 +14,12 @@ package scala package collection package immutable -import scala.annotation.unchecked.uncheckedVariance +import scala.annotation.unchecked.{uncheckedVariance, uncheckedCaptures} import scala.annotation.tailrec import mutable.{Builder, ListBuffer} import scala.collection.generic.DefaultSerializable import scala.runtime.Statics.releaseFence +import language.experimental.captureChecking /** A class for immutable linked lists representing ordered collections * of elements of type `A`. @@ -143,7 +144,7 @@ sealed abstract class List[+A] override def prepended[B >: A](elem: B): List[B] = elem :: this - override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): List[B] = prefix match { + override def prependedAll[B >: A](prefix: collection.IterableOnce[B]^): List[B] = prefix match { case xs: List[B] => xs ::: this case _ if prefix.knownSize == 0 => this case b: ListBuffer[B] if this.isEmpty => b.toList @@ -165,7 +166,7 @@ sealed abstract class List[+A] } // When calling appendAll with another list `suffix`, avoid copying `suffix` - override def appendedAll[B >: A](suffix: collection.IterableOnce[B]): List[B] = suffix match { + override def appendedAll[B >: A](suffix: collection.IterableOnce[B]^): List[B] = suffix match { case xs: List[B] => this ::: xs case _ => super.appendedAll(suffix) } @@ -214,7 +215,7 @@ sealed abstract class List[+A] // dropRight is inherited from LinearSeq override def splitAt(n: Int): (List[A], List[A]) = { - val b = new ListBuffer[A] + val b = new ListBuffer[A @uncheckedCaptures] var i = 0 var these = this while (!these.isEmpty && i < n) { @@ -257,7 +258,7 @@ sealed abstract class List[+A] } } - final override def collect[B](pf: PartialFunction[A, B]): List[B] = { + final override def collect[B](pf: PartialFunction[A, B]^): List[B] = { if (this eq Nil) Nil else { var rest = this var h: ::[B] = null @@ -285,7 +286,7 @@ sealed abstract class List[+A] } } - final override def flatMap[B](f: A => IterableOnce[B]): List[B] = { + final override def flatMap[B](f: A => IterableOnce[B]^): List[B] = { var rest = this var h: ::[B] = null var t: ::[B] = null @@ -306,7 +307,7 @@ sealed abstract class List[+A] } @inline final override def takeWhile(p: A => Boolean): List[A] = { - val b = new ListBuffer[A] + val b = new ListBuffer[A @uncheckedCaptures] var these = this while (!these.isEmpty && p(these.head)) { b += these.head @@ -316,7 +317,7 @@ sealed abstract class List[+A] } @inline final override def span(p: A => Boolean): (List[A], List[A]) = { - val b = new ListBuffer[A] + val b = new ListBuffer[A @uncheckedCaptures] var these = this while (!these.isEmpty && p(these.head)) { b += these.head @@ -651,7 +652,7 @@ sealed abstract class List[+A] // Internal code that mutates `next` _must_ call `Statics.releaseFence()` if either immediately, or // before a newly-allocated, thread-local :: instance is aliased (e.g. in ListBuffer.toList) -final case class :: [+A](override val head: A, private[scala] var next: List[A @uncheckedVariance]) // sound because `next` is used only locally +final case class :: [+A](override val head: A, private[scala] var next: List[A @uncheckedVariance @uncheckedCaptures]) // sound because `next` is used only locally extends List[A] { releaseFence() override def headOption: Some[A] = Some(head) @@ -666,7 +667,7 @@ case object Nil extends List[Nothing] { override def init: Nothing = throw new UnsupportedOperationException("init of empty list") override def knownSize: Int = 0 override def iterator: Iterator[Nothing] = Iterator.empty - override def unzip[A1, A2](implicit asPair: Nothing => (A1, A2)): (List[A1], List[A2]) = EmptyUnzip + override def unzip[A1, A2](implicit asPair: Nothing -> (A1, A2)): (List[A1], List[A2]) = EmptyUnzip @transient private[this] val EmptyUnzip = (Nil, Nil) @@ -681,9 +682,9 @@ case object Nil extends List[Nothing] { object List extends StrictOptimizedSeqFactory[List] { private val TupleOfNil = (Nil, Nil) - def from[B](coll: collection.IterableOnce[B]): List[B] = Nil.prependedAll(coll) + def from[B](coll: collection.IterableOnce[B]^): List[B] = Nil.prependedAll(coll) - def newBuilder[A]: Builder[A, List[A]] = new ListBuffer() + def newBuilder[A]: Builder[A, List[A]] = new ListBuffer[A @uncheckedCaptures]() def empty[A]: List[A] = Nil diff --git a/tests/pos-special/stdlib/collection/immutable/ListMap.scala b/tests/pos-special/stdlib/collection/immutable/ListMap.scala index 4a2b8dbd807c..c5000d785144 100644 --- a/tests/pos-special/stdlib/collection/immutable/ListMap.scala +++ b/tests/pos-special/stdlib/collection/immutable/ListMap.scala @@ -19,6 +19,8 @@ import scala.collection.mutable.ReusableBuilder import scala.collection.generic.DefaultSerializable import scala.runtime.Statics.releaseFence import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** * This class implements immutable maps using a list-based data structure. List map iterators and @@ -131,8 +133,8 @@ object ListMap extends MapFactory[ListMap] { */ private[immutable] final class Node[K, V]( override private[immutable] val key: K, - private[immutable] var _value: V, - private[immutable] var _init: ListMap[K, V] + private[immutable] var _value: V @uncheckedCaptures, + private[immutable] var _init: ListMap[K, V] @uncheckedCaptures ) extends ListMap[K, V] { releaseFence() @@ -239,7 +241,7 @@ object ListMap extends MapFactory[ListMap] { private object EmptyListMap extends ListMap[Any, Nothing] - def from[K, V](it: collection.IterableOnce[(K, V)]): ListMap[K, V] = + def from[K, V](it: collection.IterableOnce[(K, V)]^): ListMap[K, V] = it match { case lm: ListMap[K, V] => lm case lhm: collection.mutable.LinkedHashMap[K, V] => @@ -285,7 +287,7 @@ object ListMap extends MapFactory[ListMap] { */ private[immutable] final class ListMapBuilder[K, V] extends mutable.ReusableBuilder[(K, V), ListMap[K, V]] { private[this] var isAliased: Boolean = false - private[this] var underlying: ListMap[K, V] = ListMap.empty + private[this] var underlying: ListMap[K, V] @uncheckedCaptures = ListMap.empty override def clear(): Unit = { underlying = ListMap.empty @@ -322,7 +324,7 @@ private[immutable] final class ListMapBuilder[K, V] extends mutable.ReusableBuil } this } - override def addAll(xs: IterableOnce[(K, V)]): this.type = { + override def addAll(xs: IterableOnce[(K, V)]^): this.type = { if (isAliased) { super.addAll(xs) } else if (underlying.nonEmpty) { diff --git a/tests/pos-special/stdlib/collection/immutable/ListSet.scala b/tests/pos-special/stdlib/collection/immutable/ListSet.scala index e2ab0de858da..719abd78e1e6 100644 --- a/tests/pos-special/stdlib/collection/immutable/ListSet.scala +++ b/tests/pos-special/stdlib/collection/immutable/ListSet.scala @@ -17,6 +17,8 @@ package immutable import mutable.{Builder, ImmutableBuilder} import scala.annotation.tailrec import scala.collection.generic.DefaultSerializable +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** * This class implements immutable sets using a list-based data structure. List set iterators and @@ -117,7 +119,7 @@ sealed class ListSet[A] @SerialVersionUID(3L) object ListSet extends IterableFactory[ListSet] { - def from[E](it: scala.collection.IterableOnce[E]): ListSet[E] = + def from[E](it: scala.collection.IterableOnce[E]^): ListSet[E] = it match { case ls: ListSet[E] => ls case _ if it.knownSize == 0 => empty[E] diff --git a/tests/pos-special/stdlib/collection/immutable/LongMap.scala b/tests/pos-special/stdlib/collection/immutable/LongMap.scala index c418dc7616ac..4abf433273f2 100644 --- a/tests/pos-special/stdlib/collection/immutable/LongMap.scala +++ b/tests/pos-special/stdlib/collection/immutable/LongMap.scala @@ -20,6 +20,8 @@ import scala.collection.mutable.{Builder, ImmutableBuilder, ListBuffer} import scala.annotation.tailrec import scala.annotation.unchecked.uncheckedVariance import scala.language.implicitConversions +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** Utility class for long maps. */ @@ -52,7 +54,7 @@ object LongMap { def apply[T](elems: (Long, T)*): LongMap[T] = elems.foldLeft(empty[T])((x, y) => x.updated(y._1, y._2)) - def from[V](coll: IterableOnce[(Long, V)]): LongMap[V] = + def from[V](coll: IterableOnce[(Long, V)]^): LongMap[V] = newBuilder[V].addAll(coll).result() def newBuilder[V]: Builder[(Long, V), LongMap[V]] = @@ -86,13 +88,13 @@ object LongMap { @SerialVersionUID(3L) private[this] object ToFactory extends Factory[(Long, AnyRef), LongMap[AnyRef]] with Serializable { - def fromSpecific(it: IterableOnce[(Long, AnyRef)]): LongMap[AnyRef] = LongMap.from[AnyRef](it) + def fromSpecific(it: IterableOnce[(Long, AnyRef)]^): LongMap[AnyRef] = LongMap.from[AnyRef](it) def newBuilder: Builder[(Long, AnyRef), LongMap[AnyRef]] = LongMap.newBuilder[AnyRef] } implicit def toBuildFrom[V](factory: LongMap.type): BuildFrom[Any, (Long, V), LongMap[V]] = ToBuildFrom.asInstanceOf[BuildFrom[Any, (Long, V), LongMap[V]]] private[this] object ToBuildFrom extends BuildFrom[Any, (Long, AnyRef), LongMap[AnyRef]] { - def fromSpecific(from: Any)(it: IterableOnce[(Long, AnyRef)]) = LongMap.from(it) + def fromSpecific(from: Any)(it: IterableOnce[(Long, AnyRef)]^) = LongMap.from(it) def newBuilder(from: Any) = LongMap.newBuilder[AnyRef] } @@ -176,7 +178,7 @@ sealed abstract class LongMap[+T] extends AbstractMap[Long, T] with StrictOptimizedMapOps[Long, T, Map, LongMap[T]] with Serializable { - override protected def fromSpecific(coll: scala.collection.IterableOnce[(Long, T)] @uncheckedVariance): LongMap[T] = { + override protected def fromSpecific(coll: scala.collection.IterableOnce[(Long, T) @uncheckedVariance]^): LongMap[T] = { //TODO should this be the default implementation of this method in StrictOptimizedIterableOps? val b = newSpecificBuilder b.sizeHint(coll) @@ -191,7 +193,7 @@ sealed abstract class LongMap[+T] extends AbstractMap[Long, T] override def empty: LongMap[T] = LongMap.Nil override def toList = { - val buffer = new ListBuffer[(Long, T)] + val buffer = new ListBuffer[(Long, T) @uncheckedCaptures] foreach(buffer += _) buffer.toList } @@ -478,10 +480,10 @@ sealed abstract class LongMap[+T] extends AbstractMap[Long, T] def flatMap[V2](f: ((Long, T)) => IterableOnce[(Long, V2)]): LongMap[V2] = LongMap.from(new View.FlatMap(coll, f)) - override def concat[V1 >: T](that: scala.collection.IterableOnce[(Long, V1)]): LongMap[V1] = + override def concat[V1 >: T](that: scala.collection.IterableOnce[(Long, V1)]^): LongMap[V1] = super.concat(that).asInstanceOf[LongMap[V1]] // Already has correct type but not declared as such - override def ++ [V1 >: T](that: scala.collection.IterableOnce[(Long, V1)]): LongMap[V1] = concat(that) + override def ++ [V1 >: T](that: scala.collection.IterableOnce[(Long, V1)]^): LongMap[V1] = concat(that) def collect[V2](pf: PartialFunction[(Long, T), (Long, V2)]): LongMap[V2] = strictOptimizedCollect(LongMap.newBuilder[V2], pf) diff --git a/tests/pos-special/stdlib/collection/immutable/Map.scala b/tests/pos-special/stdlib/collection/immutable/Map.scala index 9d334893b8cc..6daad829bf55 100644 --- a/tests/pos-special/stdlib/collection/immutable/Map.scala +++ b/tests/pos-special/stdlib/collection/immutable/Map.scala @@ -18,6 +18,8 @@ import scala.annotation.unchecked.uncheckedVariance import scala.collection.generic.DefaultSerializable import scala.collection.immutable.Map.Map4 import scala.collection.mutable.{Builder, ReusableBuilder} +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** Base type of immutable Maps */ trait Map[K, +V] @@ -39,7 +41,7 @@ trait Map[K, +V] * @param d the function mapping keys to values, used for non-present keys * @return a wrapper of the map with a default value */ - def withDefault[V1 >: V](d: K => V1): Map[K, V1] = new Map.WithDefault[K, V1](this, d) + def withDefault[V1 >: V](d: K -> V1): Map[K, V1] = new Map.WithDefault[K, V1](this, d) /** The same map with a given default value. * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc. @@ -86,10 +88,10 @@ trait MapOps[K, +V, +CC[X, +Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C] * @return a new $coll that contains all elements of the current $coll * except one less occurrence of each of the elements of `elems`. */ - def removedAll(keys: IterableOnce[K]): C = keys.iterator.foldLeft[C](coll)(_ - _) + def removedAll(keys: IterableOnce[K]^): C = keys.iterator.foldLeft[C](coll)(_ - _) /** Alias for `removedAll` */ - @`inline` final override def -- (keys: IterableOnce[K]): C = removedAll(keys) + @`inline` final override def -- (keys: IterableOnce[K]^): C = removedAll(keys) /** Creates a new map obtained by updating this map with a given key/value pair. * @param key the key @@ -153,7 +155,7 @@ trait StrictOptimizedMapOps[K, +V, +CC[X, +Y] <: MapOps[X, Y, CC, _], +C <: MapO with collection.StrictOptimizedMapOps[K, V, CC, C] with StrictOptimizedIterableOps[(K, V), Iterable, C] { - override def concat [V1 >: V](that: collection.IterableOnce[(K, V1)]): CC[K, V1] = { + override def concat [V1 >: V](that: collection.IterableOnce[(K, V1)]^): CC[K, V1] = { var result: CC[K, V1] = coll val it = that.iterator while (it.hasNext) result = result + it.next() @@ -171,7 +173,7 @@ trait StrictOptimizedMapOps[K, +V, +CC[X, +Y] <: MapOps[X, Y, CC, _], +C <: MapO object Map extends MapFactory[Map] { @SerialVersionUID(3L) - class WithDefault[K, +V](val underlying: Map[K, V], val defaultValue: K => V) + class WithDefault[K, +V](val underlying: Map[K, V], val defaultValue: K -> V) extends AbstractMap[K, V] with MapOps[K, V, Map, WithDefault[K, V]] with Serializable { @@ -187,7 +189,7 @@ object Map extends MapFactory[Map] { override def mapFactory: MapFactory[Map] = underlying.mapFactory - override def concat [V2 >: V](xs: collection.IterableOnce[(K, V2)]): WithDefault[K, V2] = + override def concat [V2 >: V](xs: collection.IterableOnce[(K, V2)]^): WithDefault[K, V2] = new WithDefault(underlying.concat(xs), defaultValue) def removed(key: K): WithDefault[K, V] = new WithDefault[K, V](underlying.removed(key), defaultValue) @@ -197,7 +199,7 @@ object Map extends MapFactory[Map] { override def empty: WithDefault[K, V] = new WithDefault[K, V](underlying.empty, defaultValue) - override protected def fromSpecific(coll: collection.IterableOnce[(K, V)] @uncheckedVariance): WithDefault[K, V] = + override protected def fromSpecific(coll: collection.IterableOnce[(K, V) @uncheckedVariance]^): WithDefault[K, V] = new WithDefault[K, V](mapFactory.from(coll), defaultValue) override protected def newSpecificBuilder: Builder[(K, V), WithDefault[K, V]] @uncheckedVariance = @@ -206,7 +208,7 @@ object Map extends MapFactory[Map] { def empty[K, V]: Map[K, V] = EmptyMap.asInstanceOf[Map[K, V]] - def from[K, V](it: collection.IterableOnce[(K, V)]): Map[K, V] = + def from[K, V](it: collection.IterableOnce[(K, V)]^): Map[K, V] = it match { case it: Iterable[_] if it.isEmpty => empty[K, V] case m: Map[K, V] => m @@ -229,7 +231,7 @@ object Map extends MapFactory[Map] { override def valuesIterator: Iterator[Nothing] = Iterator.empty def updated [V1] (key: Any, value: V1): Map[Any, V1] = new Map1(key, value) def removed(key: Any): Map[Any, Nothing] = this - override def concat[V2 >: Nothing](suffix: IterableOnce[(Any, V2)]): Map[Any, V2] = suffix match { + override def concat[V2 >: Nothing](suffix: IterableOnce[(Any, V2)]^): Map[Any, V2] = suffix match { case m: immutable.Map[Any, V2] => m case _ => super.concat(suffix) } @@ -313,7 +315,7 @@ object Map extends MapFactory[Map] { override protected def nextResult(k: K, v: V): V = v } - private abstract class Map2Iterator[A] extends AbstractIterator[A] { + private abstract class Map2Iterator[A] extends AbstractIterator[A], Pure { private[this] var i = 0 override def hasNext: Boolean = i < 2 override def next(): A = { @@ -416,7 +418,7 @@ object Map extends MapFactory[Map] { override protected def nextResult(k: K, v: V): V = v } - private abstract class Map3Iterator[A] extends AbstractIterator[A] { + private abstract class Map3Iterator[A] extends AbstractIterator[A], Pure { private[this] var i = 0 override def hasNext: Boolean = i < 3 override def next(): A = { @@ -536,7 +538,7 @@ object Map extends MapFactory[Map] { override protected def nextResult(k: K, v: V): V = v } - private abstract class Map4Iterator[A] extends AbstractIterator[A] { + private abstract class Map4Iterator[A] extends AbstractIterator[A], Pure { private[this] var i = 0 override def hasNext: Boolean = i < 4 override def next(): A = { @@ -639,9 +641,9 @@ object Map extends MapFactory[Map] { abstract class AbstractMap[K, +V] extends scala.collection.AbstractMap[K, V] with Map[K, V] private[immutable] final class MapBuilderImpl[K, V] extends ReusableBuilder[(K, V), Map[K, V]] { - private[this] var elems: Map[K, V] = Map.empty + private[this] var elems: Map[K, V] @uncheckedCaptures = Map.empty private[this] var switchedToHashMapBuilder: Boolean = false - private[this] var hashMapBuilder: HashMapBuilder[K, V] = _ + private[this] var hashMapBuilder: HashMapBuilder[K, V] @uncheckedCaptures = _ private[immutable] def getOrElse[V0 >: V](key: K, value: V0): V0 = if (hashMapBuilder ne null) hashMapBuilder.getOrElse(key, value) @@ -682,7 +684,7 @@ private[immutable] final class MapBuilderImpl[K, V] extends ReusableBuilder[(K, def addOne(elem: (K, V)) = addOne(elem._1, elem._2) - override def addAll(xs: IterableOnce[(K, V)]): this.type = + override def addAll(xs: IterableOnce[(K, V)]^): this.type = if (switchedToHashMapBuilder) { hashMapBuilder.addAll(xs) this diff --git a/tests/pos-special/stdlib/collection/immutable/NumericRange.scala b/tests/pos-special/stdlib/collection/immutable/NumericRange.scala index d1ee494711a7..f26d9728e5ad 100644 --- a/tests/pos-special/stdlib/collection/immutable/NumericRange.scala +++ b/tests/pos-special/stdlib/collection/immutable/NumericRange.scala @@ -14,6 +14,8 @@ package scala.collection.immutable import scala.collection.Stepper.EfficientSplit import scala.collection.{AbstractIterator, AnyStepper, IterableFactoryDefaults, Iterator, Stepper, StepperShape} +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** `NumericRange` is a more generic version of the * `Range` class which works with arbitrary types. @@ -492,7 +494,7 @@ object NumericRange { import num.mkNumericOps private[this] var _hasNext = !self.isEmpty - private[this] var _next: T = self.start + private[this] var _next: T @uncheckedCaptures = self.start private[this] val lastElement: T = if (_hasNext) self.last else self.start override def knownSize: Int = if (_hasNext) num.toInt((lastElement - _next) / self.step) + 1 else 0 def hasNext: Boolean = _hasNext diff --git a/tests/pos-special/stdlib/collection/immutable/Queue.scala b/tests/pos-special/stdlib/collection/immutable/Queue.scala index 3d0f8206b6a9..929c79ce588a 100644 --- a/tests/pos-special/stdlib/collection/immutable/Queue.scala +++ b/tests/pos-special/stdlib/collection/immutable/Queue.scala @@ -15,6 +15,7 @@ package immutable import scala.collection.generic.DefaultSerializable import scala.collection.mutable.{Builder, ListBuffer} +import language.experimental.captureChecking /** `Queue` objects implement data structures that allow to * insert and retrieve elements in a first-in-first-out (FIFO) manner. @@ -119,7 +120,7 @@ sealed class Queue[+A] protected(protected val in: List[A], protected val out: L override def appended[B >: A](elem: B): Queue[B] = enqueue(elem) - override def appendedAll[B >: A](that: scala.collection.IterableOnce[B]): Queue[B] = { + override def appendedAll[B >: A](that: scala.collection.IterableOnce[B]^): Queue[B] = { val newIn = that match { case that: Queue[B] => that.in ++ (that.out reverse_::: this.in) case that: List[B] => that reverse_::: this.in @@ -200,9 +201,9 @@ sealed class Queue[+A] protected(protected val in: List[A], protected val out: L */ @SerialVersionUID(3L) object Queue extends StrictOptimizedSeqFactory[Queue] { - def newBuilder[A]: Builder[A, Queue[A]] = new ListBuffer[A] mapResult (x => new Queue[A](Nil, x)) + def newBuilder[sealed A]: Builder[A, Queue[A]] = new ListBuffer[A] mapResult (x => new Queue[A](Nil, x)) - def from[A](source: IterableOnce[A]): Queue[A] = source match { + def from[A](source: IterableOnce[A]^): Queue[A] = source match { case q: Queue[A] => q case _ => val list = List.from(source) diff --git a/tests/pos-special/stdlib/collection/immutable/Range.scala b/tests/pos-special/stdlib/collection/immutable/Range.scala index 66a149840488..459591d1a9cb 100644 --- a/tests/pos-special/stdlib/collection/immutable/Range.scala +++ b/tests/pos-special/stdlib/collection/immutable/Range.scala @@ -17,6 +17,7 @@ import scala.collection.Stepper.EfficientSplit import scala.collection.convert.impl.RangeStepper import scala.collection.{AbstractIterator, AnyStepper, IterableFactoryDefaults, Iterator, Stepper, StepperShape} import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking /** The `Range` class represents integer values in range * ''[start;end)'' with non-zero step value `step`. @@ -213,7 +214,7 @@ sealed abstract class Range( private[this] def posOf(i: Int): Int = if (contains(i)) (i - start) / step else -1 - override def sameElements[B >: Int](that: IterableOnce[B]): Boolean = that match { + override def sameElements[B >: Int](that: IterableOnce[B]^): Boolean = that match { case other: Range => (this.length : @annotation.switch) match { case 0 => other.isEmpty @@ -613,7 +614,7 @@ object Range { // As there is no appealing default step size for not-really-integral ranges, // we offer a partially constructed object. - class Partial[T, U](private val f: T => U) extends AnyVal { + class Partial[T, U](private val f: T -> U) extends AnyVal { def by(x: T): U = f(x) override def toString = "Range requires step" } diff --git a/tests/pos-special/stdlib/collection/immutable/RedBlackTree.scala b/tests/pos-special/stdlib/collection/immutable/RedBlackTree.scala index 2e7aa7b472ad..5fbc927d7a21 100644 --- a/tests/pos-special/stdlib/collection/immutable/RedBlackTree.scala +++ b/tests/pos-special/stdlib/collection/immutable/RedBlackTree.scala @@ -17,6 +17,8 @@ package immutable import scala.annotation.meta.{getter, setter} import scala.annotation.tailrec import scala.runtime.Statics.releaseFence +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** An object containing the RedBlack tree implementation used by for `TreeMaps` and `TreeSets`. * @@ -834,10 +836,11 @@ private[collection] object RedBlackTree { * we potentially do so in `startFrom`. */ val maximumHeight = 2 * (32 - Integer.numberOfLeadingZeros(root.count + 2 - 1)) - 2 - new Array[Tree[A, B]](maximumHeight) + new Array[Tree[A, B] @uncheckedCaptures](maximumHeight) } private[this] var index = 0 - protected var lookahead: Tree[A, B] = if (start.isDefined) startFrom(start.get) else findLeftMostOrPopOnEmpty(root) + protected var lookahead: Tree[A, B] @uncheckedCaptures = + if (start.isDefined) startFrom(start.get) else findLeftMostOrPopOnEmpty(root) /** * Find the leftmost subtree whose key is equal to the given key, or if no such thing, diff --git a/tests/pos-special/stdlib/collection/immutable/Seq.scala b/tests/pos-special/stdlib/collection/immutable/Seq.scala index 925fd648c70c..d575c3aaf14a 100644 --- a/tests/pos-special/stdlib/collection/immutable/Seq.scala +++ b/tests/pos-special/stdlib/collection/immutable/Seq.scala @@ -14,6 +14,8 @@ package scala package collection package immutable +import language.experimental.captureChecking + trait Seq[+A] extends Iterable[A] with collection.Seq[A] with SeqOps[A, Seq, Seq[A]] @@ -37,7 +39,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any with collection.SeqOps[A, CC, C] */ @SerialVersionUID(3L) object Seq extends SeqFactory.Delegate[Seq](List) { - override def from[E](it: IterableOnce[E]): Seq[E] = it match { + override def from[E](it: IterableOnce[E]^): Seq[E] = it match { case s: Seq[E] => s case _ => super.from(it) } @@ -57,7 +59,7 @@ trait IndexedSeq[+A] extends Seq[A] } - override def sameElements[B >: A](o: IterableOnce[B]): Boolean = o match { + override def sameElements[B >: A](o: IterableOnce[B]^): Boolean = o match { case that: IndexedSeq[_] => (this eq that) || { val length = this.length @@ -110,7 +112,7 @@ object IndexedSeqDefaults { @SerialVersionUID(3L) object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](Vector) { - override def from[E](it: IterableOnce[E]): IndexedSeq[E] = it match { + override def from[E](it: IterableOnce[E]^): IndexedSeq[E] = it match { case is: IndexedSeq[E] => is case _ => super.from(it) } @@ -141,14 +143,14 @@ trait LinearSeq[+A] @SerialVersionUID(3L) object LinearSeq extends SeqFactory.Delegate[LinearSeq](List) { - override def from[E](it: IterableOnce[E]): LinearSeq[E] = it match { + override def from[E](it: IterableOnce[E]^): LinearSeq[E] = it match { case ls: LinearSeq[E] => ls case _ => super.from(it) } } trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeqOps[A, CC, C]] - extends Any with SeqOps[A, CC, C] + extends AnyRef with SeqOps[A, CC, C] with collection.LinearSeqOps[A, CC, C] /** Explicit instantiation of the `Seq` trait to reduce class file size in subclasses. */ diff --git a/tests/pos-special/stdlib/collection/immutable/SeqMap.scala b/tests/pos-special/stdlib/collection/immutable/SeqMap.scala index aca9e139165e..6c955fd52fc2 100644 --- a/tests/pos-special/stdlib/collection/immutable/SeqMap.scala +++ b/tests/pos-special/stdlib/collection/immutable/SeqMap.scala @@ -15,6 +15,8 @@ package collection package immutable import scala.collection.mutable.{Builder, ReusableBuilder} +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** A base trait for ordered, immutable maps. * @@ -44,7 +46,7 @@ trait SeqMap[K, +V] object SeqMap extends MapFactory[SeqMap] { def empty[K, V]: SeqMap[K, V] = EmptySeqMap.asInstanceOf[SeqMap[K, V]] - def from[K, V](it: collection.IterableOnce[(K, V)]): SeqMap[K, V] = + def from[K, V](it: collection.IterableOnce[(K, V)]^): SeqMap[K, V] = it match { case sm: SeqMap[K, V] => sm case _ => (newBuilder[K, V] ++= it).result() @@ -228,9 +230,9 @@ object SeqMap extends MapFactory[SeqMap] { } private final class SeqMapBuilderImpl[K, V] extends ReusableBuilder[(K, V), SeqMap[K, V]] { - private[this] var elems: SeqMap[K, V] = SeqMap.empty + private[this] var elems: SeqMap[K, V] @uncheckedCaptures = SeqMap.empty private[this] var switchedToVectorMapBuilder: Boolean = false - private[this] var vectorMapBuilder: VectorMapBuilder[K, V] = _ + private[this] var vectorMapBuilder: VectorMapBuilder[K, V] @uncheckedCaptures = _ override def clear(): Unit = { elems = SeqMap.empty @@ -265,7 +267,7 @@ object SeqMap extends MapFactory[SeqMap] { this } - override def addAll(xs: IterableOnce[(K, V)]): this.type = + override def addAll(xs: IterableOnce[(K, V)]^): this.type = if (switchedToVectorMapBuilder) { vectorMapBuilder.addAll(xs) this diff --git a/tests/pos-special/stdlib/collection/immutable/Set.scala b/tests/pos-special/stdlib/collection/immutable/Set.scala index f07eb66991c8..ac92f81b2013 100644 --- a/tests/pos-special/stdlib/collection/immutable/Set.scala +++ b/tests/pos-special/stdlib/collection/immutable/Set.scala @@ -16,6 +16,8 @@ package immutable import scala.collection.immutable.Set.Set4 import scala.collection.mutable.{Builder, ReusableBuilder} +import language.experimental.captureChecking +import annotation.unchecked.uncheckedCaptures /** Base trait for immutable set collections */ trait Set[A] extends Iterable[A] @@ -94,7 +96,7 @@ object Set extends IterableFactory[Set] { def empty[A]: Set[A] = EmptySet.asInstanceOf[Set[A]] - def from[E](it: collection.IterableOnce[E]): Set[E] = + def from[E](it: collection.IterableOnce[E]^): Set[E] = it match { // We want `SortedSet` (and subclasses, such as `BitSet`) to // rebuild themselves to avoid element type widening issues @@ -128,7 +130,7 @@ object Set extends IterableFactory[Set] { private[collection] def emptyInstance: Set[Any] = EmptySet @SerialVersionUID(3L) - private abstract class SetNIterator[A](n: Int) extends AbstractIterator[A] with Serializable { + private abstract class SetNIterator[A](n: Int) extends AbstractIterator[A], Serializable, Pure { private[this] var current = 0 private[this] var remainder = n override def knownSize: Int = remainder @@ -351,9 +353,9 @@ abstract class AbstractSet[A] extends scala.collection.AbstractSet[A] with Set[A * $multipleResults */ private final class SetBuilderImpl[A] extends ReusableBuilder[A, Set[A]] { - private[this] var elems: Set[A] = Set.empty + private[this] var elems: Set[A @uncheckedCaptures] = Set.empty private[this] var switchedToHashSetBuilder: Boolean = false - private[this] var hashSetBuilder: HashSetBuilder[A] = _ + private[this] var hashSetBuilder: HashSetBuilder[A @uncheckedCaptures] = _ override def clear(): Unit = { elems = Set.empty @@ -388,7 +390,7 @@ private final class SetBuilderImpl[A] extends ReusableBuilder[A, Set[A]] { this } - override def addAll(xs: IterableOnce[A]): this.type = + override def addAll(xs: IterableOnce[A]^): this.type = if (switchedToHashSetBuilder) { hashSetBuilder.addAll(xs) this diff --git a/tests/pos-special/stdlib/collection/immutable/SortedMap.scala b/tests/pos-special/stdlib/collection/immutable/SortedMap.scala index 666d8c55bfb0..9587502fd908 100644 --- a/tests/pos-special/stdlib/collection/immutable/SortedMap.scala +++ b/tests/pos-special/stdlib/collection/immutable/SortedMap.scala @@ -16,6 +16,7 @@ package immutable import scala.annotation.unchecked.uncheckedVariance import scala.collection.mutable.Builder +import language.experimental.captureChecking /** An immutable map whose key-value pairs are sorted according to an [[scala.math.Ordering]] on the keys. * @@ -69,7 +70,7 @@ trait SortedMap[K, +V] * @param d the function mapping keys to values, used for non-present keys * @return a wrapper of the map with a default value */ - override def withDefault[V1 >: V](d: K => V1): SortedMap[K, V1] = new SortedMap.WithDefault[K, V1](this, d) + override def withDefault[V1 >: V](d: K -> V1): SortedMap[K, V1] = new SortedMap.WithDefault[K, V1](this, d) /** The same map with a given default value. * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc. @@ -123,7 +124,7 @@ trait StrictOptimizedSortedMapOps[K, +V, +CC[X, +Y] <: Map[X, Y] with SortedMapO with collection.StrictOptimizedSortedMapOps[K, V, CC, C] with StrictOptimizedMapOps[K, V, Map, C] { - override def concat[V2 >: V](xs: collection.IterableOnce[(K, V2)]): CC[K, V2] = { + override def concat[V2 >: V](xs: collection.IterableOnce[(K, V2)]^): CC[K, V2] = { var result: CC[K, V2] = coll val it = xs.iterator while (it.hasNext) result = result + it.next() @@ -134,12 +135,12 @@ trait StrictOptimizedSortedMapOps[K, +V, +CC[X, +Y] <: Map[X, Y] with SortedMapO @SerialVersionUID(3L) object SortedMap extends SortedMapFactory.Delegate[SortedMap](TreeMap) { - override def from[K: Ordering, V](it: IterableOnce[(K, V)]): SortedMap[K, V] = it match { + override def from[K: Ordering, V](it: IterableOnce[(K, V)]^): SortedMap[K, V] = it match { case sm: SortedMap[K, V] if Ordering[K] == sm.ordering => sm case _ => super.from(it) } - final class WithDefault[K, +V](underlying: SortedMap[K, V], defaultValue: K => V) + final class WithDefault[K, +V](underlying: SortedMap[K, V], defaultValue: K -> V) extends Map.WithDefault[K, V](underlying, defaultValue) with SortedMap[K, V] with SortedMapOps[K, V, SortedMap, WithDefault[K, V]] with Serializable { @@ -161,14 +162,14 @@ object SortedMap extends SortedMapFactory.Delegate[SortedMap](TreeMap) { override def updated[V1 >: V](key: K, value: V1): WithDefault[K, V1] = new WithDefault[K, V1](underlying.updated(key, value), defaultValue) - override def concat [V2 >: V](xs: collection.IterableOnce[(K, V2)]): WithDefault[K, V2] = + override def concat [V2 >: V](xs: collection.IterableOnce[(K, V2)]^): WithDefault[K, V2] = new WithDefault( underlying.concat(xs) , defaultValue) override def removed(key: K): WithDefault[K, V] = new WithDefault[K, V](underlying.removed(key), defaultValue) override def empty: WithDefault[K, V] = new WithDefault[K, V](underlying.empty, defaultValue) - override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)] @uncheckedVariance): WithDefault[K, V] = + override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V) @uncheckedVariance]^): WithDefault[K, V] = new WithDefault[K, V](sortedMapFactory.from(coll), defaultValue) override protected def newSpecificBuilder: Builder[(K, V), WithDefault[K, V]] @uncheckedVariance = diff --git a/tests/pos-special/stdlib/collection/immutable/SortedSet.scala b/tests/pos-special/stdlib/collection/immutable/SortedSet.scala index 303e5ea9658c..874abcaecda1 100644 --- a/tests/pos-special/stdlib/collection/immutable/SortedSet.scala +++ b/tests/pos-special/stdlib/collection/immutable/SortedSet.scala @@ -13,6 +13,7 @@ package scala package collection package immutable +import language.experimental.captureChecking /** Base trait for sorted sets */ trait SortedSet[A] @@ -50,7 +51,7 @@ trait StrictOptimizedSortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[ */ @SerialVersionUID(3L) object SortedSet extends SortedIterableFactory.Delegate[SortedSet](TreeSet) { - override def from[E: Ordering](it: IterableOnce[E]): SortedSet[E] = it match { + override def from[E: Ordering](it: IterableOnce[E]^): SortedSet[E] = it match { case ss: SortedSet[E] if Ordering[E] == ss.ordering => ss case _ => super.from(it) } diff --git a/tests/pos-special/stdlib/collection/immutable/Stream.scala b/tests/pos-special/stdlib/collection/immutable/Stream.scala deleted file mode 100644 index ae03641e97dd..000000000000 --- a/tests/pos-special/stdlib/collection/immutable/Stream.scala +++ /dev/null @@ -1,568 +0,0 @@ -/* - * 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 -package collection -package immutable - -import java.io.{ObjectInputStream, ObjectOutputStream} -import java.lang.{StringBuilder => JStringBuilder} - -import scala.annotation.tailrec -import scala.annotation.unchecked.uncheckedVariance -import scala.collection.generic.SerializeEnd -import scala.collection.mutable.{ArrayBuffer, StringBuilder} -import scala.language.implicitConversions -import Stream.cons - -@deprecated("Use LazyList (which is fully lazy) instead of Stream (which has a lazy tail only)", "2.13.0") -@SerialVersionUID(3L) -sealed abstract class Stream[+A] extends AbstractSeq[A] - with LinearSeq[A] - with LinearSeqOps[A, Stream, Stream[A]] - with IterableFactoryDefaults[A, Stream] - with Serializable { - def tail: Stream[A] - - /** Forces evaluation of the whole `Stream` and returns it. - * - * @note Often we use `Stream`s to represent an infinite set or series. If - * that's the case for your particular `Stream` then this function will never - * return and will probably crash the VM with an `OutOfMemory` exception. - * This function will not hang on a finite cycle, however. - * - * @return The fully realized `Stream`. - */ - def force: this.type - - override def iterableFactory: SeqFactory[Stream] = Stream - - override protected[this] def className: String = "Stream" - - /** Apply the given function `f` to each element of this linear sequence - * (while respecting the order of the elements). - * - * @param f The treatment to apply to each element. - * @note Overridden here as final to trigger tail-call optimization, which - * replaces 'this' with 'tail' at each iteration. This is absolutely - * necessary for allowing the GC to collect the underlying Stream as elements - * are consumed. - * @note This function will force the realization of the entire Stream - * unless the `f` throws an exception. - */ - @tailrec - override final def foreach[U](f: A => U): Unit = { - if (!this.isEmpty) { - f(head) - tail.foreach(f) - } - } - - @tailrec - override final def find(p: A => Boolean): Option[A] = { - if(isEmpty) None - else if(p(head)) Some(head) - else tail.find(p) - } - - override def take(n: Int): Stream[A] = { - if (n <= 0 || isEmpty) Stream.empty - else if (n == 1) new Stream.Cons(head, Stream.empty) - else new Stream.Cons(head, tail.take(n - 1)) - } - - /** Stream specialization of foldLeft which allows GC to collect along the - * way. - * - * @tparam B The type of value being accumulated. - * @param z The initial value seeded into the function `op`. - * @param op The operation to perform on successive elements of the `Stream`. - * @return The accumulated value from successive applications of `op`. - */ - @tailrec - override final def foldLeft[B](z: B)(op: (B, A) => B): B = { - if (this.isEmpty) z - else tail.foldLeft(op(z, head))(op) - } - - /** The stream resulting from the concatenation of this stream with the argument stream. - * @param rest The collection that gets appended to this stream - * @return The stream containing elements of this stream and the iterable object. - */ - @deprecated("The `append` operation has been renamed `lazyAppendedAll`", "2.13.0") - @inline final def append[B >: A](rest: => IterableOnce[B]): Stream[B] = lazyAppendedAll(rest) - - protected[this] def writeReplace(): AnyRef = - if(nonEmpty && tailDefined) new Stream.SerializationProxy[A](this) else this - - /** Prints elements of this stream one by one, separated by commas. */ - @deprecated(message = """Use print(stream.force.mkString(", ")) instead""", since = "2.13.0") - @inline def print(): Unit = Console.print(this.force.mkString(", ")) - - /** Prints elements of this stream one by one, separated by `sep`. - * @param sep The separator string printed between consecutive elements. - */ - @deprecated(message = "Use print(stream.force.mkString(sep)) instead", since = "2.13.0") - @inline def print(sep: String): Unit = Console.print(this.force.mkString(sep)) - - /** The stream resulting from the concatenation of this stream with the argument stream. - * - * @param suffix The collection that gets appended to this stream - * @return The stream containing elements of this stream and the iterable object. - */ - def lazyAppendedAll[B >: A](suffix: => collection.IterableOnce[B]): Stream[B] = - if (isEmpty) iterableFactory.from(suffix) else cons[B](head, tail.lazyAppendedAll(suffix)) - - override def scanLeft[B](z: B)(op: (B, A) => B): Stream[B] = - if (isEmpty) z +: iterableFactory.empty - else cons(z, tail.scanLeft(op(z, head))(op)) - - /** Stream specialization of reduceLeft which allows GC to collect - * along the way. - * - * @tparam B The type of value being accumulated. - * @param f The operation to perform on successive elements of the `Stream`. - * @return The accumulated value from successive applications of `f`. - */ - override final def reduceLeft[B >: A](f: (B, A) => B): B = { - if (this.isEmpty) throw new UnsupportedOperationException("empty.reduceLeft") - else { - var reducedRes: B = this.head - var left: Stream[A] = this.tail - while (!left.isEmpty) { - reducedRes = f(reducedRes, left.head) - left = left.tail - } - reducedRes - } - } - - override def partition(p: A => Boolean): (Stream[A], Stream[A]) = (filter(p(_)), filterNot(p(_))) - - override def filter(pred: A => Boolean): Stream[A] = filterImpl(pred, isFlipped = false) - - override def filterNot(pred: A => Boolean): Stream[A] = filterImpl(pred, isFlipped = true) - - private[immutable] def filterImpl(p: A => Boolean, isFlipped: Boolean): Stream[A] = { - // optimization: drop leading prefix of elems for which f returns false - // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise - var rest: Stream[A] = coll - while (rest.nonEmpty && p(rest.head) == isFlipped) rest = rest.tail - // private utility func to avoid `this` on stack (would be needed for the lazy arg) - if (rest.nonEmpty) Stream.filteredTail(rest, p, isFlipped) - else iterableFactory.empty - } - - /** A `collection.WithFilter` which allows GC of the head of stream during processing */ - override final def withFilter(p: A => Boolean): collection.WithFilter[A, Stream] = - Stream.withFilter(coll, p) - - override final def prepended[B >: A](elem: B): Stream[B] = cons(elem, coll) - - override final def map[B](f: A => B): Stream[B] = - if (isEmpty) iterableFactory.empty - else cons(f(head), tail.map(f)) - - @tailrec override final def collect[B](pf: PartialFunction[A, B]): Stream[B] = - if(isEmpty) Stream.empty - else { - var newHead: B = null.asInstanceOf[B] - val runWith = pf.runWith((b: B) => newHead = b) - if(runWith(head)) Stream.collectedTail(newHead, this, pf) - else tail.collect(pf) - } - - @tailrec override final def collectFirst[B](pf: PartialFunction[A, B]): Option[B] = - if(isEmpty) None - else { - var newHead: B = null.asInstanceOf[B] - val runWith = pf.runWith((b: B) => newHead = b) - if(runWith(head)) Some(newHead) - else tail.collectFirst(pf) - } - - // optimisations are not for speed, but for functionality - // see tickets #153, #498, #2147, and corresponding tests in run/ (as well as run/stream_flatmap_odds.scala) - override final def flatMap[B](f: A => IterableOnce[B]): Stream[B] = - if (isEmpty) iterableFactory.empty - else { - // establish !prefix.isEmpty || nonEmptyPrefix.isEmpty - var nonEmptyPrefix: Stream[A] = coll - var prefix = iterableFactory.from(f(nonEmptyPrefix.head)) - while (!nonEmptyPrefix.isEmpty && prefix.isEmpty) { - nonEmptyPrefix = nonEmptyPrefix.tail - if(!nonEmptyPrefix.isEmpty) - prefix = iterableFactory.from(f(nonEmptyPrefix.head)) - } - - if (nonEmptyPrefix.isEmpty) iterableFactory.empty - else prefix.lazyAppendedAll(nonEmptyPrefix.tail.flatMap(f)) - } - - override final def zip[B](that: collection.IterableOnce[B]): Stream[(A, B)] = - if (this.isEmpty || that.isEmpty) iterableFactory.empty - else { - val thatIterable = that match { - case that: collection.Iterable[B] => that - case _ => LazyList.from(that) - } - cons[(A, B)]((this.head, thatIterable.head), this.tail.zip(thatIterable.tail)) - } - - override final def zipWithIndex: Stream[(A, Int)] = this.zip(LazyList.from(0)) - - protected def tailDefined: Boolean - - /** Appends all elements of this $coll to a string builder using start, end, and separator strings. - * The written text begins with the string `start` and ends with the string `end`. - * Inside, the string representations (w.r.t. the method `toString`) - * of all elements of this $coll are separated by the string `sep`. - * - * Undefined elements are represented with `"_"`, an undefined tail is represented with `"<not computed>"`, - * and cycles are represented with `"<cycle>"`. - * - * @param sb the string builder to which elements are appended. - * @param start the starting string. - * @param sep the separator string. - * @param end the ending string. - * @return the string builder `b` to which elements were appended. - */ - override def addString(sb: StringBuilder, start: String, sep: String, end: String): sb.type = { - force - addStringNoForce(sb.underlying, start, sep, end) - sb - } - - private[this] def addStringNoForce(b: JStringBuilder, start: String, sep: String, end: String): JStringBuilder = { - b.append(start) - if (nonEmpty) { - b.append(head) - var cursor = this - def appendCursorElement(): Unit = b.append(sep).append(cursor.head) - if (tailDefined) { // If tailDefined, also !isEmpty - var scout = tail - if (cursor ne scout) { - cursor = scout - if (scout.tailDefined) { - scout = scout.tail - // Use 2x 1x iterator trick for cycle detection; slow iterator can add strings - while ((cursor ne scout) && scout.tailDefined) { - appendCursorElement() - cursor = cursor.tail - scout = scout.tail - if (scout.tailDefined) scout = scout.tail - } - } - } - if (!scout.tailDefined) { // Not a cycle, scout hit an end - while (cursor ne scout) { - appendCursorElement() - cursor = cursor.tail - } - if (cursor.nonEmpty) { - appendCursorElement() - } - } - else { - // Cycle. - // If we have a prefix of length P followed by a cycle of length C, - // the scout will be at position (P%C) in the cycle when the cursor - // enters it at P. They'll then collide when the scout advances another - // C - (P%C) ahead of the cursor. - // If we run the scout P farther, then it will be at the start of - // the cycle: (C - (P%C) + (P%C)) == C == 0. So if another runner - // starts at the beginning of the prefix, they'll collide exactly at - // the start of the loop. - var runner = this - var k = 0 - while (runner ne scout) { - runner = runner.tail - scout = scout.tail - k += 1 - } - // Now runner and scout are at the beginning of the cycle. Advance - // cursor, adding to string, until it hits; then we'll have covered - // everything once. If cursor is already at beginning, we'd better - // advance one first unless runner didn't go anywhere (in which case - // we've already looped once). - if ((cursor eq scout) && (k > 0)) { - appendCursorElement() - cursor = cursor.tail - } - while (cursor ne scout) { - appendCursorElement() - cursor = cursor.tail - } - } - } - if (cursor.nonEmpty) { - // Either undefined or cyclic; we can check with tailDefined - if (!cursor.tailDefined) b.append(sep).append("") - else b.append(sep).append("") - } - } - b.append(end) - } - - /** - * @return a string representation of this collection. Undefined elements are - * represented with `"_"`, an undefined tail is represented with `"<not computed>"`, - * and cycles are represented with `"<cycle>"` - * - * Examples: - * - * - `"Stream(_, <not computed>)"`, a non-empty stream, whose head has not been - * evaluated ; - * - `"Stream(_, 1, _, <not computed>)"`, a stream with at least three elements, - * the second one has been evaluated ; - * - `"Stream(1, 2, 3, <cycle>)"`, an infinite stream that contains - * a cycle at the fourth element. - */ - override def toString = addStringNoForce(new JStringBuilder(className), "(", ", ", ")").toString - - @deprecated("Check .knownSize instead of .hasDefiniteSize for more actionable information (see scaladoc for details)", "2.13.0") - override def hasDefiniteSize: Boolean = isEmpty || { - if (!tailDefined) false - else { - // Two-iterator trick (2x & 1x speed) for cycle detection. - var those = this - var these = tail - while (those ne these) { - if (these.isEmpty) return true - if (!these.tailDefined) return false - these = these.tail - if (these.isEmpty) return true - if (!these.tailDefined) return false - these = these.tail - if (those eq these) return false - those = those.tail - } - false // Cycle detected - } - } -} - -@deprecated("Use LazyList (which is fully lazy) instead of Stream (which has a lazy tail only)", "2.13.0") -@SerialVersionUID(3L) -object Stream extends SeqFactory[Stream] { - - /* !!! #11997 This `object cons` must be defined lexically *before* `class Cons` below. - * Otherwise it prevents Scala.js from building on Windows. - */ - /** An alternative way of building and matching Streams using Stream.cons(hd, tl). - */ - object cons { - /** A stream consisting of a given first element and remaining elements - * @param hd The first element of the result stream - * @param tl The remaining elements of the result stream - */ - def apply[A](hd: A, tl: => Stream[A]): Stream[A] = new Cons(hd, tl) - - /** Maps a stream to its head and tail */ - def unapply[A](xs: Stream[A]): Option[(A, Stream[A])] = #::.unapply(xs) - } - - //@SerialVersionUID(3L) //TODO Putting an annotation on Stream.empty causes a cyclic dependency in unpickling - object Empty extends Stream[Nothing] { - override def isEmpty: Boolean = true - override def head: Nothing = throw new NoSuchElementException("head of empty stream") - override def tail: Stream[Nothing] = throw new UnsupportedOperationException("tail of empty stream") - /** Forces evaluation of the whole `Stream` and returns it. - * - * @note Often we use `Stream`s to represent an infinite set or series. If - * that's the case for your particular `Stream` then this function will never - * return and will probably crash the VM with an `OutOfMemory` exception. - * This function will not hang on a finite cycle, however. - * - * @return The fully realized `Stream`. - */ - def force: this.type = this - override def knownSize: Int = 0 - protected def tailDefined: Boolean = false - } - - @SerialVersionUID(3L) - final class Cons[A](override val head: A, tl: => Stream[A]) extends Stream[A] { - override def isEmpty: Boolean = false - @volatile private[this] var tlVal: Stream[A] = _ - @volatile private[this] var tlGen = () => tl - protected def tailDefined: Boolean = tlGen eq null - override def tail: Stream[A] = { - if (!tailDefined) - synchronized { - if (!tailDefined) { - tlVal = tlGen() - tlGen = null - } - } - tlVal - } - - /** Forces evaluation of the whole `Stream` and returns it. - * - * @note Often we use `Stream`s to represent an infinite set or series. If - * that's the case for your particular `Stream` then this function will never - * return and will probably crash the VM with an `OutOfMemory` exception. - * This function will not hang on a finite cycle, however. - * - * @return The fully realized `Stream`. - */ - def force: this.type = { - // Use standard 2x 1x iterator trick for cycle detection ("those" is slow one) - var these, those: Stream[A] = this - if (!these.isEmpty) these = these.tail - while (those ne these) { - if (these.isEmpty) return this - these = these.tail - if (these.isEmpty) return this - these = these.tail - if (these eq those) return this - those = those.tail - } - this - } - - } - - implicit def toDeferrer[A](l: => Stream[A]): Deferrer[A] = new Deferrer[A](() => l) - - final class Deferrer[A] private[Stream] (private val l: () => Stream[A]) extends AnyVal { - /** Construct a Stream consisting of a given first element followed by elements - * from another Stream. - */ - def #:: [B >: A](elem: B): Stream[B] = new Cons(elem, l()) - /** Construct a Stream consisting of the concatenation of the given Stream and - * another Stream. - */ - def #:::[B >: A](prefix: Stream[B]): Stream[B] = prefix lazyAppendedAll l() - } - - object #:: { - def unapply[A](s: Stream[A]): Option[(A, Stream[A])] = - if (s.nonEmpty) Some((s.head, s.tail)) else None - } - - def from[A](coll: collection.IterableOnce[A]): Stream[A] = coll match { - case coll: Stream[A] => coll - case _ => fromIterator(coll.iterator) - } - - /** - * @return A `Stream[A]` that gets its elements from the given `Iterator`. - * - * @param it Source iterator - * @tparam A type of elements - */ - // Note that the resulting `Stream` will be effectively iterable more than once because - // `Stream` memoizes its elements - def fromIterator[A](it: Iterator[A]): Stream[A] = - if (it.hasNext) { - new Stream.Cons(it.next(), fromIterator(it)) - } else Stream.Empty - - def empty[A]: Stream[A] = Empty - - override def newBuilder[A]: mutable.Builder[A, Stream[A]] = ArrayBuffer.newBuilder[A].mapResult(array => from(array)) - - private[immutable] def withFilter[A](l: Stream[A] @uncheckedVariance, p: A => Boolean): collection.WithFilter[A, Stream] = - new WithFilter[A](l, p) - - private[this] final class WithFilter[A](l: Stream[A] @uncheckedVariance, p: A => Boolean) extends collection.WithFilter[A, Stream] { - private[this] var s = l // set to null to allow GC after filtered - private[this] lazy val filtered: Stream[A] = { val f = s.filter(p); s = null.asInstanceOf[Stream[A]]; f } // don't set to null if throw during filter - def map[B](f: A => B): Stream[B] = filtered.map(f) - def flatMap[B](f: A => IterableOnce[B]): Stream[B] = filtered.flatMap(f) - def foreach[U](f: A => U): Unit = filtered.foreach(f) - def withFilter(q: A => Boolean): collection.WithFilter[A, Stream] = new WithFilter(filtered, q) - } - - /** An infinite Stream that repeatedly applies a given function to a start value. - * - * @param start the start value of the Stream - * @param f the function that's repeatedly applied - * @return the Stream returning the infinite sequence of values `start, f(start), f(f(start)), ...` - */ - def iterate[A](start: A)(f: A => A): Stream[A] = { - cons(start, iterate(f(start))(f)) - } - - /** - * Create an infinite Stream starting at `start` and incrementing by - * step `step`. - * - * @param start the start value of the Stream - * @param step the increment value of the Stream - * @return the Stream starting at value `start`. - */ - def from(start: Int, step: Int): Stream[Int] = - cons(start, from(start + step, step)) - - /** - * Create an infinite Stream starting at `start` and incrementing by `1`. - * - * @param start the start value of the Stream - * @return the Stream starting at value `start`. - */ - def from(start: Int): Stream[Int] = from(start, 1) - - /** - * Create an infinite Stream containing the given element expression (which - * is computed for each occurrence). - * - * @param elem the element composing the resulting Stream - * @return the Stream containing an infinite number of elem - */ - def continually[A](elem: => A): Stream[A] = cons(elem, continually(elem)) - - - private[Stream] def filteredTail[A](stream: Stream[A] @uncheckedVariance, p: A => Boolean, isFlipped: Boolean) = { - cons(stream.head, stream.tail.filterImpl(p, isFlipped)) - } - - private[Stream] def collectedTail[A, B](head: B, stream: Stream[A] @uncheckedVariance, pf: PartialFunction[A, B]) = { - cons(head, stream.tail.collect(pf)) - } - - /** This serialization proxy is used for Streams which start with a sequence of evaluated cons cells. - * The forced sequence is serialized in a compact, sequential format, followed by the unevaluated tail, which uses - * standard Java serialization to store the complete structure of unevaluated thunks. This allows the serialization - * of long evaluated streams without exhausting the stack through recursive serialization of cons cells. - */ - @SerialVersionUID(3L) - class SerializationProxy[A](@transient protected var coll: Stream[A]) extends Serializable { - - private[this] def writeObject(out: ObjectOutputStream): Unit = { - out.defaultWriteObject() - var these = coll - while(these.nonEmpty && these.tailDefined) { - out.writeObject(these.head) - these = these.tail - } - out.writeObject(SerializeEnd) - out.writeObject(these) - } - - private[this] def readObject(in: ObjectInputStream): Unit = { - in.defaultReadObject() - val init = new ArrayBuffer[A] - var initRead = false - while (!initRead) in.readObject match { - case SerializeEnd => initRead = true - case a => init += a.asInstanceOf[A] - } - val tail = in.readObject().asInstanceOf[Stream[A]] - coll = (init ++: tail) - } - - protected[this] def readResolve(): Any = coll - } -} diff --git a/tests/pos-special/stdlib/collection/immutable/StrictOptimizedSeqOps.scala b/tests/pos-special/stdlib/collection/immutable/StrictOptimizedSeqOps.scala index db5192edc36c..b1e4622971fb 100644 --- a/tests/pos-special/stdlib/collection/immutable/StrictOptimizedSeqOps.scala +++ b/tests/pos-special/stdlib/collection/immutable/StrictOptimizedSeqOps.scala @@ -13,6 +13,8 @@ package scala package collection package immutable +import language.experimental.captureChecking +import annotation.unchecked.uncheckedCaptures /** * Trait that overrides operations to take advantage of strict builders. @@ -23,11 +25,11 @@ trait StrictOptimizedSeqOps[+A, +CC[_], +C] with collection.StrictOptimizedSeqOps[A, CC, C] with StrictOptimizedIterableOps[A, CC, C] { - override def distinctBy[B](f: A => B): C = { + override def distinctBy[B](f: A -> B): C = { if (lengthCompare(1) <= 0) coll else { val builder = newSpecificBuilder - val seen = mutable.HashSet.empty[B] + val seen = mutable.HashSet.empty[B @uncheckedCaptures] val it = this.iterator var different = false while (it.hasNext) { @@ -57,7 +59,7 @@ trait StrictOptimizedSeqOps[+A, +CC[_], +C] b.result() } - override def patch[B >: A](from: Int, other: IterableOnce[B], replaced: Int): CC[B] = { + override def patch[B >: A](from: Int, other: IterableOnce[B]^, replaced: Int): CC[B] = { val b = iterableFactory.newBuilder[B] var i = 0 val it = iterator diff --git a/tests/pos-special/stdlib/collection/immutable/TreeMap.scala b/tests/pos-special/stdlib/collection/immutable/TreeMap.scala index a51c7b9e7bf6..ff01ad7806ec 100644 --- a/tests/pos-special/stdlib/collection/immutable/TreeMap.scala +++ b/tests/pos-special/stdlib/collection/immutable/TreeMap.scala @@ -20,6 +20,8 @@ import scala.collection.generic.DefaultSerializable import scala.collection.immutable.{RedBlackTree => RB} import scala.collection.mutable.ReusableBuilder import scala.runtime.AbstractFunction2 +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** An immutable SortedMap whose values are stored in a red-black tree. * @@ -138,7 +140,7 @@ final class TreeMap[K, +V] private (private val tree: RB.Tree[K, V])(implicit va def updated[V1 >: V](key: K, value: V1): TreeMap[K, V1] = newMapOrSelf(RB.update(tree, key, value, overwrite = true)) - override def concat[V1 >: V](that: collection.IterableOnce[(K, V1)]): TreeMap[K, V1] = + override def concat[V1 >: V](that: collection.IterableOnce[(K, V1)]^): TreeMap[K, V1] = newMapOrSelf(that match { case tm: TreeMap[K, V] @unchecked if ordering == tm.ordering => RB.union(tree, tm.tree) @@ -158,7 +160,7 @@ final class TreeMap[K, +V] private (private val tree: RB.Tree[K, V])(implicit va adder.finalTree }) - override def removedAll(keys: IterableOnce[K]): TreeMap[K, V] = keys match { + override def removedAll(keys: IterableOnce[K]^): TreeMap[K, V] = keys match { case ts: TreeSet[K] if ordering == ts.ordering => newMapOrSelf(RB.difference(tree, ts.tree)) case _ => super.removedAll(keys) @@ -269,7 +271,7 @@ final class TreeMap[K, +V] private (private val tree: RB.Tree[K, V])(implicit va private final class Adder[B1 >: V] extends RB.MapHelper[K, B1] with Function1[(K, B1), Unit] { - private var currentMutableTree: RB.Tree[K,B1] = tree0 + private var currentMutableTree: RB.Tree[K,B1] @uncheckedCaptures = tree0 def finalTree = beforePublish(currentMutableTree) override def apply(kv: (K, B1)): Unit = { currentMutableTree = mutableUpd(currentMutableTree, kv._1, kv._2) @@ -299,7 +301,7 @@ object TreeMap extends SortedMapFactory[TreeMap] { def empty[K : Ordering, V]: TreeMap[K, V] = new TreeMap() - def from[K, V](it: IterableOnce[(K, V)])(implicit ordering: Ordering[K]): TreeMap[K, V] = + def from[K, V](it: IterableOnce[(K, V)]^)(implicit ordering: Ordering[K]): TreeMap[K, V] = it match { case tm: TreeMap[K, V] if ordering == tm.ordering => tm case sm: scala.collection.SortedMap[K, V] if ordering == sm.ordering => @@ -320,7 +322,7 @@ object TreeMap extends SortedMapFactory[TreeMap] { extends RB.MapHelper[K, V] with ReusableBuilder[(K, V), TreeMap[K, V]] { type Tree = RB.Tree[K, V] - private var tree:Tree = null + private var tree:Tree @uncheckedCaptures = null def addOne(elem: (K, V)): this.type = { tree = mutableUpd(tree, elem._1, elem._2) @@ -329,7 +331,7 @@ object TreeMap extends SortedMapFactory[TreeMap] { private object adder extends AbstractFunction2[K, V, Unit] { // we cache tree to avoid the outer access to tree // in the hot path (apply) - private[this] var accumulator :Tree = null + private[this] var accumulator: Tree @uncheckedCaptures = null def addForEach(hasForEach: collection.Map[K, V]): Unit = { accumulator = tree hasForEach.foreachEntry(this) @@ -343,7 +345,7 @@ object TreeMap extends SortedMapFactory[TreeMap] { } } - override def addAll(xs: IterableOnce[(K, V)]): this.type = { + override def addAll(xs: IterableOnce[(K, V)]^): this.type = { xs match { // TODO consider writing a mutable-safe union for TreeSet/TreeMap builder ++= // for the moment we have to force immutability before the union diff --git a/tests/pos-special/stdlib/collection/immutable/TreeSeqMap.scala b/tests/pos-special/stdlib/collection/immutable/TreeSeqMap.scala index 80bafb1cf3be..91233669e5ca 100644 --- a/tests/pos-special/stdlib/collection/immutable/TreeSeqMap.scala +++ b/tests/pos-special/stdlib/collection/immutable/TreeSeqMap.scala @@ -15,6 +15,8 @@ package collection package immutable import scala.annotation.tailrec +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** This class implements an immutable map that preserves order using * a hash map for the key to value mapping to provide efficient lookup, @@ -204,7 +206,7 @@ final class TreeSeqMap[K, +V] private ( new TreeSeqMap(ong, mng, ordinal, orderedBy) } else { // Populate with builder otherwise - val bdr = newBuilder[K, V](orderedBy) + val bdr = newBuilder[K @uncheckedCaptures, V @uncheckedCaptures](orderedBy) val iter = ordering.iterator var i = 0 while (i < f) { @@ -222,7 +224,7 @@ final class TreeSeqMap[K, +V] private ( } override def map[K2, V2](f: ((K, V)) => (K2, V2)): TreeSeqMap[K2, V2] = { - val bdr = newBuilder[K2, V2](orderedBy) + val bdr = newBuilder[K2 @uncheckedCaptures, V2 @uncheckedCaptures](orderedBy) val iter = ordering.iterator while (iter.hasNext) { val k = iter.next() @@ -233,8 +235,8 @@ final class TreeSeqMap[K, +V] private ( bdr.result() } - override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): TreeSeqMap[K2, V2] = { - val bdr = newBuilder[K2, V2](orderedBy) + override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]^): TreeSeqMap[K2, V2] = { + val bdr = newBuilder[K2 @uncheckedCaptures, V2 @uncheckedCaptures](orderedBy) val iter = ordering.iterator while (iter.hasNext) { val k = iter.next() @@ -249,7 +251,7 @@ final class TreeSeqMap[K, +V] private ( } override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)]): TreeSeqMap[K2, V2] = { - val bdr = newBuilder[K2, V2](orderedBy) + val bdr = newBuilder[K2 @uncheckedCaptures, V2 @uncheckedCaptures](orderedBy) val iter = ordering.iterator while (iter.hasNext) { val k = iter.next() @@ -259,7 +261,7 @@ final class TreeSeqMap[K, +V] private ( bdr.result() } - override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]): TreeSeqMap[K, V2] = { + override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]^): TreeSeqMap[K, V2] = { var ong: Ordering[K] = ordering var mng: Mapping[K, V2] = mapping var ord = increment(ordinal) @@ -302,7 +304,7 @@ object TreeSeqMap extends MapFactory[TreeSeqMap] { else EmptyByInsertion }.asInstanceOf[TreeSeqMap[K, V]] - def from[K, V](it: collection.IterableOnce[(K, V)]): TreeSeqMap[K, V] = + def from[sealed K, sealed V](it: collection.IterableOnce[(K, V)]^): TreeSeqMap[K, V] = it match { case om: TreeSeqMap[K, V] => om case _ => (newBuilder[K, V] ++= it).result() @@ -310,10 +312,10 @@ object TreeSeqMap extends MapFactory[TreeSeqMap] { @inline private def increment(ord: Int) = if (ord == Int.MaxValue) Int.MinValue else ord + 1 - def newBuilder[K, V]: mutable.Builder[(K, V), TreeSeqMap[K, V]] = newBuilder(OrderBy.Insertion) - def newBuilder[K, V](orderedBy: OrderBy): mutable.Builder[(K, V), TreeSeqMap[K, V]] = new Builder[K, V](orderedBy) + def newBuilder[sealed K, sealed V]: mutable.Builder[(K, V), TreeSeqMap[K, V]] = newBuilder(OrderBy.Insertion) + def newBuilder[sealed K, sealed V](orderedBy: OrderBy): mutable.Builder[(K, V), TreeSeqMap[K, V]] = new Builder[K, V](orderedBy) - final class Builder[K, V](orderedBy: OrderBy) extends mutable.Builder[(K, V), TreeSeqMap[K, V]] { + final class Builder[sealed K, sealed V](orderedBy: OrderBy) extends mutable.Builder[(K, V), TreeSeqMap[K, V]] { private[this] val bdr = new MapBuilderImpl[K, (Int, V)] private[this] var ong = Ordering.empty[K] private[this] var ord = 0 @@ -435,7 +437,7 @@ object TreeSeqMap extends MapFactory[TreeSeqMap] { protected def format(sb: StringBuilder, prefix: String, subPrefix: String): Unit = sb ++= s"${prefix}Tip(${toBinaryString(ord)} -> $value)\n" } - final case class Bin[+T](prefix: Int, mask: Int, left: Ordering[T], var right: Ordering[T] @scala.annotation.unchecked.uncheckedVariance) extends Ordering[T] { + final case class Bin[+T](prefix: Int, mask: Int, left: Ordering[T], var right: Ordering[T @uncheckedCaptures] @scala.annotation.unchecked.uncheckedVariance) extends Ordering[T] { def bin[S](left: Ordering[S], right: Ordering[S]): Ordering[S] = { if ((this.left eq left) && (this.right eq right)) this.asInstanceOf[Bin[S]] else Bin[S](prefix, mask, left, right) @@ -607,7 +609,7 @@ object TreeSeqMap extends MapFactory[TreeSeqMap] { } final def splitAt(n: Int): (Ordering[T], Ordering[T]) = { - var rear = Ordering.empty[T] + var rear: Ordering[T @uncheckedCaptures] = Ordering.empty[T] var i = n (modifyOrRemove { (o, v) => i -= 1 diff --git a/tests/pos-special/stdlib/collection/immutable/TreeSet.scala b/tests/pos-special/stdlib/collection/immutable/TreeSet.scala index f0be91b72acc..c4241b818c38 100644 --- a/tests/pos-special/stdlib/collection/immutable/TreeSet.scala +++ b/tests/pos-special/stdlib/collection/immutable/TreeSet.scala @@ -19,7 +19,8 @@ import scala.collection.generic.DefaultSerializable import scala.collection.mutable.ReusableBuilder import scala.collection.immutable.{RedBlackTree => RB} import scala.runtime.AbstractFunction1 - +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** This class implements immutable sorted sets using a tree. * @@ -239,7 +240,7 @@ object TreeSet extends SortedIterableFactory[TreeSet] { def empty[A: Ordering]: TreeSet[A] = new TreeSet[A] - def from[E](it: scala.collection.IterableOnce[E])(implicit ordering: Ordering[E]): TreeSet[E] = + def from[E](it: scala.collection.IterableOnce[E]^)(implicit ordering: Ordering[E]): TreeSet[E] = it match { case ts: TreeSet[E] if ordering == ts.ordering => ts case ss: scala.collection.SortedSet[E] if ordering == ss.ordering => @@ -262,14 +263,14 @@ object TreeSet extends SortedIterableFactory[TreeSet] { extends RB.SetHelper[A] with ReusableBuilder[A, TreeSet[A]] { type Tree = RB.Tree[A, Any] - private [this] var tree:RB.Tree[A, Any] = null + private [this] var tree:RB.Tree[A @uncheckedCaptures, Any] = null override def addOne(elem: A): this.type = { tree = mutableUpd(tree, elem) this } - override def addAll(xs: IterableOnce[A]): this.type = { + override def addAll(xs: IterableOnce[A]^): this.type = { xs match { // TODO consider writing a mutable-safe union for TreeSet/TreeMap builder ++= // for the moment we have to force immutability before the union diff --git a/tests/pos-special/stdlib/collection/immutable/Vector.scala b/tests/pos-special/stdlib/collection/immutable/Vector.scala index aa3fac5acd69..d9d33add512d 100644 --- a/tests/pos-special/stdlib/collection/immutable/Vector.scala +++ b/tests/pos-special/stdlib/collection/immutable/Vector.scala @@ -24,6 +24,8 @@ import scala.collection.generic.DefaultSerializable import scala.collection.immutable.VectorInline._ import scala.collection.immutable.VectorStatics._ import scala.collection.mutable.ReusableBuilder +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** $factoryInfo @@ -35,7 +37,7 @@ object Vector extends StrictOptimizedSeqFactory[Vector] { def empty[A]: Vector[A] = Vector0 - def from[E](it: collection.IterableOnce[E]): Vector[E] = + def from[E](it: collection.IterableOnce[E]^): Vector[E] = it match { case v: Vector[E] => v case _ => @@ -191,21 +193,21 @@ sealed abstract class Vector[+A] private[immutable] (private[immutable] final va override def updated[B >: A](index: Int, elem: B): Vector[B] = super.updated(index, elem) override def appended[B >: A](elem: B): Vector[B] = super.appended(elem) override def prepended[B >: A](elem: B): Vector[B] = super.prepended(elem) - override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): Vector[B] = { + override def prependedAll[B >: A](prefix: collection.IterableOnce[B]^): Vector[B] = { val k = prefix.knownSize if (k == 0) this else if (k < 0) super.prependedAll(prefix) else prependedAll0(prefix, k) } - override final def appendedAll[B >: A](suffix: collection.IterableOnce[B]): Vector[B] = { + override final def appendedAll[B >: A](suffix: collection.IterableOnce[B]^): Vector[B] = { val k = suffix.knownSize if (k == 0) this else if (k < 0) super.appendedAll(suffix) else appendedAll0(suffix, k) } - protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = { + protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B]^, k: Int): Vector[B] = { // k >= 0, k = prefix.knownSize val tinyAppendLimit = 4 + vectorSliceCount if (k < tinyAppendLimit /*|| k < (this.size >>> Log2ConcatFaster)*/) { @@ -223,11 +225,11 @@ sealed abstract class Vector[+A] private[immutable] (private[immutable] final va } else super.prependedAll(prefix) } - protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B]^, k: Int): Vector[B] = { // k >= 0, k = suffix.knownSize val tinyAppendLimit = 4 + vectorSliceCount if (k < tinyAppendLimit) { - var v: Vector[B] = this + var v: Vector[B @uncheckedCaptures] = this suffix match { case it: Iterable[_] => it.asInstanceOf[Iterable[B]].foreach(x => v = v.appended(x)) case _ => suffix.iterator.foreach(x => v = v.appended(x)) @@ -263,7 +265,7 @@ sealed abstract class Vector[+A] private[immutable] (private[immutable] final va /** Length of all slices up to and including index */ protected[immutable] def vectorSlicePrefixLength(idx: Int): Int - override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = iterator.copyToArray(xs, start, len) + override def copyToArray[sealed B >: A](xs: Array[B], start: Int, len: Int): Int = iterator.copyToArray(xs, start, len) override def toVector: Vector[A] = this @@ -369,10 +371,10 @@ private object Vector0 extends BigVector[Nothing](empty1, empty1, 0) { } } - override protected[this]def prependedAll0[B >: Nothing](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + override protected[this]def prependedAll0[B >: Nothing](prefix: collection.IterableOnce[B]^, k: Int): Vector[B] = Vector.from(prefix) - override protected[this]def appendedAll0[B >: Nothing](suffix: collection.IterableOnce[B], k: Int): Vector[B] = + override protected[this]def appendedAll0[B >: Nothing](suffix: collection.IterableOnce[B]^, k: Int): Vector[B] = Vector.from(suffix) override protected[this] def ioob(index: Int): IndexOutOfBoundsException = @@ -423,13 +425,13 @@ private final class Vector1[+A](_data1: Arr1) extends VectorImpl[A](_data1) { protected[immutable] def vectorSlice(idx: Int): Array[_ <: AnyRef] = prefix1 protected[immutable] def vectorSlicePrefixLength(idx: Int): Int = prefix1.length - override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B]^, k: Int): Vector[B] = prepend1IfSpace(prefix1, prefix) match { case null => super.prependedAll0(prefix, k) case data1b => new Vector1(data1b) } - override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B]^, k: Int): Vector[B] = { val data1b = append1IfSpace(prefix1, suffix) if(data1b ne null) new Vector1(data1b) else super.appendedAll0(suffix, k) @@ -518,7 +520,7 @@ private final class Vector2[+A](_prefix1: Arr1, private[immutable] val len1: Int case 2 => length0 } - override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B]^, k: Int): Vector[B] = prepend1IfSpace(prefix1, prefix) match { case null => super.prependedAll0(prefix, k) case prefix1b => @@ -529,7 +531,7 @@ private final class Vector2[+A](_prefix1: Arr1, private[immutable] val len1: Int ) } - override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B]^, k: Int): Vector[B] = { val suffix1b = append1IfSpace(suffix1, suffix) if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) else super.appendedAll0(suffix, k) @@ -640,7 +642,7 @@ private final class Vector3[+A](_prefix1: Arr1, private[immutable] val len1: Int case 4 => length0 } - override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B]^, k: Int): Vector[B] = prepend1IfSpace(prefix1, prefix) match { case null => super.prependedAll0(prefix, k) case prefix1b => @@ -652,7 +654,7 @@ private final class Vector3[+A](_prefix1: Arr1, private[immutable] val len1: Int ) } - override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B]^, k: Int): Vector[B] = { val suffix1b = append1IfSpace(suffix1, suffix) if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) else super.appendedAll0(suffix, k) @@ -783,7 +785,7 @@ private final class Vector4[+A](_prefix1: Arr1, private[immutable] val len1: Int case 6 => length0 } - override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B]^, k: Int): Vector[B] = prepend1IfSpace(prefix1, prefix) match { case null => super.prependedAll0(prefix, k) case prefix1b => @@ -796,7 +798,7 @@ private final class Vector4[+A](_prefix1: Arr1, private[immutable] val len1: Int ) } - override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B]^, k: Int): Vector[B] = { val suffix1b = append1IfSpace(suffix1, suffix) if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) else super.appendedAll0(suffix, k) @@ -947,7 +949,7 @@ private final class Vector5[+A](_prefix1: Arr1, private[immutable] val len1: Int case 8 => length0 } - override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B]^, k: Int): Vector[B] = prepend1IfSpace(prefix1, prefix) match { case null => super.prependedAll0(prefix, k) case prefix1b => @@ -961,7 +963,7 @@ private final class Vector5[+A](_prefix1: Arr1, private[immutable] val len1: Int ) } - override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B]^, k: Int): Vector[B] = { val suffix1b = append1IfSpace(suffix1, suffix) if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) else super.appendedAll0(suffix, k) @@ -1132,7 +1134,7 @@ private final class Vector6[+A](_prefix1: Arr1, private[immutable] val len1: Int case 10 => length0 } - override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B]^, k: Int): Vector[B] = prepend1IfSpace(prefix1, prefix) match { case null => super.prependedAll0(prefix, k) case prefix1b => @@ -1147,7 +1149,7 @@ private final class Vector6[+A](_prefix1: Arr1, private[immutable] val len1: Int ) } - override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B]^, k: Int): Vector[B] = { val suffix1b = append1IfSpace(suffix1, suffix) if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) else super.appendedAll0(suffix, k) @@ -1814,7 +1816,7 @@ final class VectorBuilder[A] extends ReusableBuilder[A, Vector[A]] { this } - override def addAll(xs: IterableOnce[A]): this.type = xs match { + override def addAll(xs: IterableOnce[A]^): this.type = xs match { case v: Vector[_] => if(len1 == 0 && lenRest == 0 && !prefixIsRightAligned) initFrom(v) else addVector(v.asInstanceOf[Vector[A]]) @@ -2183,7 +2185,7 @@ private object VectorStatics { ac.asInstanceOf[Array[T]] } - final def prepend1IfSpace(prefix1: Arr1, xs: IterableOnce[_]): Arr1 = xs match { + final def prepend1IfSpace(prefix1: Arr1, xs: IterableOnce[_]^): Arr1 = xs match { case it: Iterable[_] => if(it.sizeCompare(WIDTH-prefix1.length) <= 0) { it.size match { @@ -2206,7 +2208,7 @@ private object VectorStatics { } else null } - final def append1IfSpace(suffix1: Arr1, xs: IterableOnce[_]): Arr1 = xs match { + final def append1IfSpace(suffix1: Arr1, xs: IterableOnce[_]^): Arr1 = xs match { case it: Iterable[_] => if(it.sizeCompare(WIDTH-suffix1.length) <= 0) { it.size match { @@ -2391,7 +2393,7 @@ private final class NewVectorIterator[A](v: Vector[A], private[this] var totalLe take(_until) } - override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = { + override def copyToArray[sealed B >: A](xs: Array[B], start: Int, len: Int): Int = { val xsLen = xs.length val total = IterableOnce.elemsToCopyToArray(knownSize, xsLen, start, len) var copied = 0 @@ -2466,7 +2468,7 @@ private class LongVectorStepper(it: NewVectorIterator[Long]) // The following definitions are needed for binary compatibility with ParVector private[collection] class VectorIterator[+A](_startIndex: Int, private[this] var endIndex: Int) extends AbstractIterator[A] { - private[immutable] var it: NewVectorIterator[A @uncheckedVariance] = _ + private[immutable] var it: NewVectorIterator[A @uncheckedVariance @uncheckedCaptures] = _ def hasNext: Boolean = it.hasNext def next(): A = it.next() private[collection] def remainingElementCount: Int = it.size diff --git a/tests/pos-special/stdlib/collection/immutable/VectorMap.scala b/tests/pos-special/stdlib/collection/immutable/VectorMap.scala index cd8cf06c5c68..0860a0b47f28 100644 --- a/tests/pos-special/stdlib/collection/immutable/VectorMap.scala +++ b/tests/pos-special/stdlib/collection/immutable/VectorMap.scala @@ -15,6 +15,8 @@ package collection package immutable import scala.annotation.tailrec +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** This class implements immutable maps using a vector/map-based data structure, which preserves insertion order. * @@ -58,7 +60,7 @@ final class VectorMap[K, +V] private ( } } - override def withDefault[V1 >: V](d: K => V1): Map[K, V1] = + override def withDefault[V1 >: V](d: K -> V1): Map[K, V1] = new Map.WithDefault(this, d) override def withDefaultValue[V1 >: V](d: V1): Map[K, V1] = @@ -229,7 +231,7 @@ object VectorMap extends MapFactory[VectorMap] { def empty[K, V]: VectorMap[K, V] = EmptyMap.asInstanceOf[VectorMap[K, V]] - def from[K, V](it: collection.IterableOnce[(K, V)]): VectorMap[K, V] = + def from[K, V](it: collection.IterableOnce[(K, V)]^): VectorMap[K, V] = it match { case vm: VectorMap[K, V] => vm case _ => (newBuilder[K, V] ++= it).result() @@ -241,7 +243,7 @@ object VectorMap extends MapFactory[VectorMap] { private[immutable] final class VectorMapBuilder[K, V] extends mutable.Builder[(K, V), VectorMap[K, V]] { private[this] val vectorBuilder = new VectorBuilder[K] private[this] val mapBuilder = new MapBuilderImpl[K, (Int, V)] - private[this] var aliased: VectorMap[K, V] = _ + private[this] var aliased: VectorMap[K, V] @uncheckedCaptures = _ // OK since VectorMapBuilder is private override def clear(): Unit = { vectorBuilder.clear() diff --git a/tests/pos-special/stdlib/collection/immutable/WrappedString.scala b/tests/pos-special/stdlib/collection/immutable/WrappedString.scala index f2fdb8e3c32e..47fe769c81ef 100644 --- a/tests/pos-special/stdlib/collection/immutable/WrappedString.scala +++ b/tests/pos-special/stdlib/collection/immutable/WrappedString.scala @@ -17,6 +17,7 @@ import scala.Predef.{wrapString => _, assert} import scala.collection.Stepper.EfficientSplit import scala.collection.convert.impl.CharStringStepper import scala.collection.mutable.{Builder, StringBuilder} +import language.experimental.captureChecking /** * This class serves as a wrapper augmenting `String`s with all the operations @@ -34,11 +35,12 @@ import scala.collection.mutable.{Builder, StringBuilder} @SerialVersionUID(3L) final class WrappedString(private val self: String) extends AbstractSeq[Char] with IndexedSeq[Char] with IndexedSeqOps[Char, IndexedSeq, WrappedString] - with Serializable { + with Serializable + with Pure { def apply(i: Int): Char = self.charAt(i) - override protected def fromSpecific(coll: scala.collection.IterableOnce[Char]): WrappedString = WrappedString.fromSpecific(coll) + override protected def fromSpecific(coll: scala.collection.IterableOnce[Char]^): WrappedString = WrappedString.fromSpecific(coll) override protected def newSpecificBuilder: Builder[Char, WrappedString] = WrappedString.newBuilder override def empty: WrappedString = WrappedString.empty @@ -65,13 +67,13 @@ final class WrappedString(private val self: String) extends AbstractSeq[Char] wi r.asInstanceOf[S with EfficientSplit] } - override def startsWith[B >: Char](that: IterableOnce[B], offset: Int = 0): Boolean = + override def startsWith[B >: Char](that: IterableOnce[B]^, offset: Int = 0): Boolean = that match { case s: WrappedString => self.startsWith(s.self, offset) case _ => super.startsWith(that, offset) } - override def endsWith[B >: Char](that: collection.Iterable[B]): Boolean = + override def endsWith[B >: Char](that: collection.Iterable[B]^): Boolean = that match { case s: WrappedString => self.endsWith(s.self) case _ => super.endsWith(that) @@ -88,7 +90,7 @@ final class WrappedString(private val self: String) extends AbstractSeq[Char] wi case _ => super.lastIndexOf(elem, end) } - override def copyToArray[B >: Char](xs: Array[B], start: Int, len: Int): Int = + override def copyToArray[sealed B >: Char](xs: Array[B], start: Int, len: Int): Int = (xs: Any) match { case chs: Array[Char] => val copied = IterableOnce.elemsToCopyToArray(length, chs.length, start, len) @@ -97,13 +99,13 @@ final class WrappedString(private val self: String) extends AbstractSeq[Char] wi case _ => super.copyToArray(xs, start, len) } - override def appendedAll[B >: Char](suffix: IterableOnce[B]): IndexedSeq[B] = + override def appendedAll[B >: Char](suffix: IterableOnce[B]^): IndexedSeq[B] = suffix match { case s: WrappedString => new WrappedString(self concat s.self) case _ => super.appendedAll(suffix) } - override def sameElements[B >: Char](o: IterableOnce[B]) = o match { + override def sameElements[B >: Char](o: IterableOnce[B]^) = o match { case s: WrappedString => self == s.self case _ => super.sameElements(o) } @@ -123,7 +125,7 @@ final class WrappedString(private val self: String) extends AbstractSeq[Char] wi */ @SerialVersionUID(3L) object WrappedString extends SpecificIterableFactory[Char, WrappedString] { - def fromSpecific(it: IterableOnce[Char]): WrappedString = { + def fromSpecific(it: IterableOnce[Char]^): WrappedString = { val b = newBuilder val s = it.knownSize if(s >= 0) b.sizeHint(s) diff --git a/tests/pos-special/stdlib/collection/immutable/package.scala b/tests/pos-special/stdlib/collection/immutable/package.scala index 8458429727e8..985ef22859be 100644 --- a/tests/pos-special/stdlib/collection/immutable/package.scala +++ b/tests/pos-special/stdlib/collection/immutable/package.scala @@ -11,7 +11,7 @@ */ package scala.collection - +import language.experimental.captureChecking package object immutable { type StringOps = scala.collection.StringOps diff --git a/tests/pos-special/stdlib/collection/mutable/AnyRefMap.scala b/tests/pos-special/stdlib/collection/mutable/AnyRefMap.scala index c02a10770696..a6413649e219 100644 --- a/tests/pos-special/stdlib/collection/mutable/AnyRefMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/AnyRefMap.scala @@ -17,6 +17,8 @@ package mutable import scala.annotation.nowarn import scala.collection.generic.DefaultSerializationProxy import scala.language.implicitConversions +import language.experimental.captureChecking + /** This class implements mutable maps with `AnyRef` keys based on a hash table with open addressing. * @@ -41,7 +43,7 @@ import scala.language.implicitConversions * rapidly as 2^30^ is approached. * */ -class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initialBufferSize: Int, initBlank: Boolean) +class AnyRefMap[K <: AnyRef, sealed V] private[collection] (defaultEntry: K -> V, initialBufferSize: Int, initBlank: Boolean) extends AbstractMap[K, V] with MapOps[K, V, Map, AnyRefMap[K, V]] with StrictOptimizedIterableOps[(K, V), Iterable, AnyRefMap[K, V]] @@ -51,7 +53,7 @@ class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initi def this() = this(AnyRefMap.exceptionDefault, 16, true) /** Creates a new `AnyRefMap` that returns default values according to a supplied key-value mapping. */ - def this(defaultEntry: K => V) = this(defaultEntry, 16, true) + def this(defaultEntry: K -> V) = this(defaultEntry, 16, true) /** Creates a new `AnyRefMap` with an initial buffer of specified size. * @@ -61,7 +63,7 @@ class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initi def this(initialBufferSize: Int) = this(AnyRefMap.exceptionDefault, initialBufferSize, true) /** Creates a new `AnyRefMap` with specified default values and initial buffer size. */ - def this(defaultEntry: K => V, initialBufferSize: Int) = this(defaultEntry, initialBufferSize, true) + def this(defaultEntry: K -> V, initialBufferSize: Int) = this(defaultEntry, initialBufferSize, true) private[this] var mask = 0 private[this] var _size = 0 @@ -87,7 +89,7 @@ class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initi mask = m; _size = sz; _vacant = vc; _hashes = hz; _keys = kz; _values = vz } - override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)]): AnyRefMap[K,V] = { + override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)]^): AnyRefMap[K,V] = { var sz = coll.knownSize if(sz < 0) sz = 4 val arm = new AnyRefMap[K, V](sz * 2) @@ -393,24 +395,24 @@ class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initi } @deprecated("Consider requiring an immutable Map or fall back to Map.concat", "2.13.0") - override def + [V1 >: V](kv: (K, V1)): AnyRefMap[K, V1] = AnyRefMap.from(new View.Appended(this, kv)) + override def + [sealed V1 >: V](kv: (K, V1)): AnyRefMap[K, V1] = AnyRefMap.from(new View.Appended(this, kv)) @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0") - override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): AnyRefMap[K, V1] = { + override def + [sealed V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): AnyRefMap[K, V1] = { val m = this + elem1 + elem2 if(elems.isEmpty) m else m.concat(elems) } - override def concat[V2 >: V](xs: scala.collection.IterableOnce[(K, V2)]): AnyRefMap[K, V2] = { + override def concat[sealed V2 >: V](xs: scala.collection.IterableOnce[(K, V2)]^): AnyRefMap[K, V2] = { val arm = clone().asInstanceOf[AnyRefMap[K, V2]] xs.iterator.foreach(kv => arm += kv) arm } - override def ++[V2 >: V](xs: scala.collection.IterableOnce[(K, V2)]): AnyRefMap[K, V2] = concat(xs) + override def ++[sealed V2 >: V](xs: scala.collection.IterableOnce[(K, V2)]^): AnyRefMap[K, V2] = concat(xs) @deprecated("Use m.clone().addOne(k,v) instead of m.updated(k, v)", "2.13.0") - override def updated[V1 >: V](key: K, value: V1): AnyRefMap[K, V1] = + override def updated[sealed V1 >: V](key: K, value: V1): AnyRefMap[K, V1] = clone().asInstanceOf[AnyRefMap[K, V1]].addOne(key, value) private[this] def foreachElement[A,B](elems: Array[AnyRef], f: A => B): Unit = { @@ -435,7 +437,7 @@ class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initi * Unlike `mapValues`, this method generates a new * collection immediately. */ - def mapValuesNow[V1](f: V => V1): AnyRefMap[K, V1] = { + def mapValuesNow[sealed V1](f: V => V1): AnyRefMap[K, V1] = { val arm = new AnyRefMap[K,V1](AnyRefMap.exceptionDefault, 1, false) val hz = java.util.Arrays.copyOf(_hashes, _hashes.length) val kz = java.util.Arrays.copyOf(_keys, _keys.length) @@ -476,11 +478,11 @@ class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initi } // The implicit dummy parameter is necessary to distinguish these methods from the base methods they overload (not override) - def map[K2 <: AnyRef, V2](f: ((K, V)) => (K2, V2))(implicit dummy: DummyImplicit): AnyRefMap[K2, V2] = + def map[K2 <: AnyRef, sealed V2](f: ((K, V)) => (K2, V2))(implicit dummy: DummyImplicit): AnyRefMap[K2, V2] = AnyRefMap.from(new View.Map(this, f)) - def flatMap[K2 <: AnyRef, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit dummy: DummyImplicit): AnyRefMap[K2, V2] = + def flatMap[K2 <: AnyRef, sealed V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit dummy: DummyImplicit): AnyRefMap[K2, V2] = AnyRefMap.from(new View.FlatMap(this, f)) - def collect[K2 <: AnyRef, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit dummy: DummyImplicit): AnyRefMap[K2, V2] = + def collect[K2 <: AnyRef, sealed V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit dummy: DummyImplicit): AnyRefMap[K2, V2] = strictOptimizedCollect(AnyRefMap.newBuilder[K2, V2], pf) override def clear(): Unit = { @@ -504,7 +506,7 @@ object AnyRefMap { private final val VacantBit = 0x40000000 private final val MissVacant = 0xC0000000 - private class ExceptionDefault extends (Any => Nothing) with Serializable { + private class ExceptionDefault extends (Any -> Nothing) with Serializable { def apply(k: Any): Nothing = throw new NoSuchElementException(if (k == null) "(null)" else k.toString) } private val exceptionDefault = new ExceptionDefault @@ -513,7 +515,7 @@ object AnyRefMap { * * This builder can be reused to create multiple instances. */ - final class AnyRefMapBuilder[K <: AnyRef, V] extends ReusableBuilder[(K, V), AnyRefMap[K, V]] { + final class AnyRefMapBuilder[K <: AnyRef, sealed V] extends ReusableBuilder[(K, V), AnyRefMap[K, V]] { private[collection] var elems: AnyRefMap[K, V] = new AnyRefMap[K, V] def addOne(entry: (K, V)): this.type = { elems += entry @@ -525,11 +527,11 @@ object AnyRefMap { } /** Creates a new `AnyRefMap` with zero or more key/value pairs. */ - def apply[K <: AnyRef, V](elems: (K, V)*): AnyRefMap[K, V] = buildFromIterableOnce(elems) + def apply[K <: AnyRef, sealed V](elems: (K, V)*): AnyRefMap[K, V] = buildFromIterableOnce(elems) - def newBuilder[K <: AnyRef, V]: ReusableBuilder[(K, V), AnyRefMap[K, V]] = new AnyRefMapBuilder[K, V] + def newBuilder[K <: AnyRef, sealed V]: ReusableBuilder[(K, V), AnyRefMap[K, V]] = new AnyRefMapBuilder[K, V] - private def buildFromIterableOnce[K <: AnyRef, V](elems: IterableOnce[(K, V)]): AnyRefMap[K, V] = { + private def buildFromIterableOnce[K <: AnyRef, sealed V](elems: IterableOnce[(K, V)]^): AnyRefMap[K, V] = { var sz = elems.knownSize if(sz < 0) sz = 4 val arm = new AnyRefMap[K, V](sz * 2) @@ -539,10 +541,10 @@ object AnyRefMap { } /** Creates a new empty `AnyRefMap`. */ - def empty[K <: AnyRef, V]: AnyRefMap[K, V] = new AnyRefMap[K, V] + def empty[K <: AnyRef, sealed V]: AnyRefMap[K, V] = new AnyRefMap[K, V] /** Creates a new empty `AnyRefMap` with the supplied default */ - def withDefault[K <: AnyRef, V](default: K => V): AnyRefMap[K, V] = new AnyRefMap[K, V](default) + def withDefault[K <: AnyRef, sealed V](default: K -> V): AnyRefMap[K, V] = new AnyRefMap[K, V](default) /** Creates a new `AnyRefMap` from an existing source collection. A source collection * which is already an `AnyRefMap` gets cloned. @@ -552,7 +554,7 @@ object AnyRefMap { * @tparam V the type of the values * @return a new `AnyRefMap` with the elements of `source` */ - def from[K <: AnyRef, V](source: IterableOnce[(K, V)]): AnyRefMap[K, V] = source match { + def from[K <: AnyRef, sealed V](source: IterableOnce[(K, V)]^): AnyRefMap[K, V] = source match { case source: AnyRefMap[_, _] => source.clone().asInstanceOf[AnyRefMap[K, V]] case _ => buildFromIterableOnce(source) } @@ -560,7 +562,7 @@ object AnyRefMap { /** Creates a new `AnyRefMap` from arrays of keys and values. * Equivalent to but more efficient than `AnyRefMap((keys zip values): _*)`. */ - def fromZip[K <: AnyRef, V](keys: Array[K], values: Array[V]): AnyRefMap[K, V] = { + def fromZip[K <: AnyRef, sealed V](keys: Array[K], values: Array[V]): AnyRefMap[K, V] = { val sz = math.min(keys.length, values.length) val arm = new AnyRefMap[K, V](sz * 2) var i = 0 @@ -572,7 +574,7 @@ object AnyRefMap { /** Creates a new `AnyRefMap` from keys and values. * Equivalent to but more efficient than `AnyRefMap((keys zip values): _*)`. */ - def fromZip[K <: AnyRef, V](keys: Iterable[K], values: Iterable[V]): AnyRefMap[K, V] = { + def fromZip[K <: AnyRef, sealed V](keys: Iterable[K]^, values: Iterable[V]^): AnyRefMap[K, V] = { val sz = math.min(keys.size, values.size) val arm = new AnyRefMap[K, V](sz * 2) val ki = keys.iterator @@ -582,20 +584,20 @@ object AnyRefMap { arm } - implicit def toFactory[K <: AnyRef, V](dummy: AnyRefMap.type): Factory[(K, V), AnyRefMap[K, V]] = ToFactory.asInstanceOf[Factory[(K, V), AnyRefMap[K, V]]] + implicit def toFactory[K <: AnyRef, sealed V](dummy: AnyRefMap.type): Factory[(K, V), AnyRefMap[K, V]] = ToFactory.asInstanceOf[Factory[(K, V), AnyRefMap[K, V]]] @SerialVersionUID(3L) private[this] object ToFactory extends Factory[(AnyRef, AnyRef), AnyRefMap[AnyRef, AnyRef]] with Serializable { - def fromSpecific(it: IterableOnce[(AnyRef, AnyRef)]): AnyRefMap[AnyRef, AnyRef] = AnyRefMap.from[AnyRef, AnyRef](it) + def fromSpecific(it: IterableOnce[(AnyRef, AnyRef)]^): AnyRefMap[AnyRef, AnyRef] = AnyRefMap.from[AnyRef, AnyRef](it) def newBuilder: Builder[(AnyRef, AnyRef), AnyRefMap[AnyRef, AnyRef]] = AnyRefMap.newBuilder[AnyRef, AnyRef] } - implicit def toBuildFrom[K <: AnyRef, V](factory: AnyRefMap.type): BuildFrom[Any, (K, V), AnyRefMap[K, V]] = ToBuildFrom.asInstanceOf[BuildFrom[Any, (K, V), AnyRefMap[K, V]]] + implicit def toBuildFrom[K <: AnyRef, sealed V](factory: AnyRefMap.type): BuildFrom[Any, (K, V), AnyRefMap[K, V]] = ToBuildFrom.asInstanceOf[BuildFrom[Any, (K, V), AnyRefMap[K, V]]] private[this] object ToBuildFrom extends BuildFrom[Any, (AnyRef, AnyRef), AnyRefMap[AnyRef, AnyRef]] { - def fromSpecific(from: Any)(it: IterableOnce[(AnyRef, AnyRef)]) = AnyRefMap.from(it) + def fromSpecific(from: Any)(it: IterableOnce[(AnyRef, AnyRef)]^) = AnyRefMap.from(it) def newBuilder(from: Any) = AnyRefMap.newBuilder[AnyRef, AnyRef] } - implicit def iterableFactory[K <: AnyRef, V]: Factory[(K, V), AnyRefMap[K, V]] = toFactory[K, V](this) - implicit def buildFromAnyRefMap[K <: AnyRef, V]: BuildFrom[AnyRefMap[_, _], (K, V), AnyRefMap[K, V]] = toBuildFrom(this) + implicit def iterableFactory[K <: AnyRef, sealed V]: Factory[(K, V), AnyRefMap[K, V]] = toFactory[K, V](this) + implicit def buildFromAnyRefMap[K <: AnyRef, sealed V]: BuildFrom[AnyRefMap[_, _], (K, V), AnyRefMap[K, V]] = toBuildFrom(this) } diff --git a/tests/pos-special/stdlib/collection/mutable/ArrayBuffer.scala b/tests/pos-special/stdlib/collection/mutable/ArrayBuffer.scala index e3ddeb71ef8e..8fa1e6edd566 100644 --- a/tests/pos-special/stdlib/collection/mutable/ArrayBuffer.scala +++ b/tests/pos-special/stdlib/collection/mutable/ArrayBuffer.scala @@ -20,6 +20,8 @@ import scala.annotation.nowarn import scala.annotation.tailrec import scala.collection.Stepper.EfficientSplit import scala.collection.generic.DefaultSerializable +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** An implementation of the `Buffer` class using an array to * represent the assembled sequence internally. Append, update and random @@ -40,7 +42,7 @@ import scala.collection.generic.DefaultSerializable * @define willNotTerminateInf */ @SerialVersionUID(-1582447879429021880L) -class ArrayBuffer[A] private (initialElements: Array[AnyRef], initialSize: Int) +class ArrayBuffer[sealed A] private (initialElements: Array[AnyRef], initialSize: Int) extends AbstractBuffer[A] with IndexedBuffer[A] with IndexedSeqOps[A, ArrayBuffer, ArrayBuffer[A]] @@ -151,7 +153,7 @@ class ArrayBuffer[A] private (initialElements: Array[AnyRef], initialSize: Int) } // Overridden to use array copying for efficiency where possible. - override def addAll(elems: IterableOnce[A]): this.type = { + override def addAll(elems: IterableOnce[A]^): this.type = { elems match { case elems: ArrayBuffer[_] => val elemsLength = elems.size0 @@ -180,7 +182,7 @@ class ArrayBuffer[A] private (initialElements: Array[AnyRef], initialSize: Int) this } - def insertAll(@deprecatedName("n", "2.13.0") index: Int, elems: IterableOnce[A]): Unit = { + def insertAll(@deprecatedName("n", "2.13.0") index: Int, elems: IterableOnce[A]^): Unit = { checkWithinBounds(index, index) elems match { case elems: collection.Iterable[A] => @@ -234,12 +236,12 @@ class ArrayBuffer[A] private (initialElements: Array[AnyRef], initialSize: Int) @deprecated("Use 'new GrowableBuilder(this).mapResult(f)' instead", "2.13.0") @deprecatedOverriding("ArrayBuffer[A] no longer extends Builder[A, ArrayBuffer[A]]", "2.13.0") - @inline def mapResult[NewTo](f: (ArrayBuffer[A]) => NewTo): Builder[A, NewTo] = new GrowableBuilder[A, ArrayBuffer[A]](this).mapResult(f) + @inline def mapResult[NewTo](f: (ArrayBuffer[A]) => NewTo): Builder[A, NewTo]^{f} = new GrowableBuilder[A, ArrayBuffer[A]](this).mapResult(f) @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""") override protected[this] def stringPrefix = "ArrayBuffer" - override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = { + override def copyToArray[sealed B >: A](xs: Array[B], start: Int, len: Int): Int = { val copied = IterableOnce.elemsToCopyToArray(length, xs.length, start, len) if(copied > 0) { Array.copy(array, 0, xs, start, copied) @@ -256,7 +258,7 @@ class ArrayBuffer[A] private (initialElements: Array[AnyRef], initialSize: Int) override def sortInPlace[B >: A]()(implicit ord: Ordering[B]): this.type = { if (length > 1) { mutationCount += 1 - scala.util.Sorting.stableSort(array.asInstanceOf[Array[B]], 0, length) + scala.util.Sorting.stableSort(array.asInstanceOf[Array[B @uncheckedCaptures]], 0, length) } this } @@ -291,7 +293,7 @@ object ArrayBuffer extends StrictOptimizedSeqFactory[ArrayBuffer] { final val DefaultInitialSize = 16 private[this] val emptyArray = new Array[AnyRef](0) - def from[B](coll: collection.IterableOnce[B]): ArrayBuffer[B] = { + def from[sealed B](coll: collection.IterableOnce[B]^): ArrayBuffer[B] = { val k = coll.knownSize if (k >= 0) { // Avoid reallocation of buffer if length is known @@ -303,12 +305,12 @@ object ArrayBuffer extends StrictOptimizedSeqFactory[ArrayBuffer] { else new ArrayBuffer[B] ++= coll } - def newBuilder[A]: Builder[A, ArrayBuffer[A]] = + def newBuilder[sealed A]: Builder[A, ArrayBuffer[A]] = new GrowableBuilder[A, ArrayBuffer[A]](empty) { override def sizeHint(size: Int): Unit = elems.ensureSize(size) } - def empty[A]: ArrayBuffer[A] = new ArrayBuffer[A]() + def empty[sealed A]: ArrayBuffer[A] = new ArrayBuffer[A]() /** * @param arrayLen the length of the backing array @@ -357,22 +359,23 @@ object ArrayBuffer extends StrictOptimizedSeqFactory[ArrayBuffer] { } // TODO: use `CheckedIndexedSeqView.Id` once we can change the return type of `ArrayBuffer#view` -final class ArrayBufferView[A] private[mutable](underlying: ArrayBuffer[A], mutationCount: () => Int) - extends AbstractIndexedSeqView[A] { +final class ArrayBufferView[sealed A] private[mutable](underlying: ArrayBuffer[A], mutationCount: () -> Int) + extends AbstractIndexedSeqView[A], Pure { + /* Removed since it poses problems for capture checking @deprecated("never intended to be public; call ArrayBuffer#view instead", since = "2.13.7") def this(array: Array[AnyRef], length: Int) = { // this won't actually track mutation, but it would be a pain to have the implementation // check if we have a method to get the current mutation count or not on every method and // change what it does based on that. hopefully no one ever calls this. this({ - val _array = array + val _array: Array[Object] = array val _length = length new ArrayBuffer[A](0) { this.array = _array this.size0 = _length - } + }: ArrayBuffer[A] }, () => 0) - } + }*/ @deprecated("never intended to be public", since = "2.13.7") def array: Array[AnyRef] = underlying.toArray[Any].asInstanceOf[Array[AnyRef]] @@ -392,10 +395,10 @@ final class ArrayBufferView[A] private[mutable](underlying: ArrayBuffer[A], muta override def takeRight(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.TakeRight(this, n)(mutationCount) override def drop(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Drop(this, n)(mutationCount) override def dropRight(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.DropRight(this, n)(mutationCount) - override def map[B](f: A => B): IndexedSeqView[B] = new CheckedIndexedSeqView.Map(this, f)(mutationCount) + override def map[B](f: A => B): IndexedSeqView[B]^{f} = new CheckedIndexedSeqView.Map(this, f)(mutationCount) override def reverse: IndexedSeqView[A] = new CheckedIndexedSeqView.Reverse(this)(mutationCount) override def slice(from: Int, until: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Slice(this, from, until)(mutationCount) - override def tapEach[U](f: A => U): IndexedSeqView[A] = new CheckedIndexedSeqView.Map(this, { (a: A) => f(a); a})(mutationCount) + override def tapEach[U](f: A => U): IndexedSeqView[A]^{f} = new CheckedIndexedSeqView.Map(this, { (a: A) => f(a); a})(mutationCount) override def concat[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount) override def appendedAll[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount) diff --git a/tests/pos-special/stdlib/collection/mutable/ArrayBuilder.scala b/tests/pos-special/stdlib/collection/mutable/ArrayBuilder.scala index 454527bcdebd..0620d3d23061 100644 --- a/tests/pos-special/stdlib/collection/mutable/ArrayBuilder.scala +++ b/tests/pos-special/stdlib/collection/mutable/ArrayBuilder.scala @@ -13,6 +13,7 @@ package scala.collection package mutable +import language.experimental.captureChecking import scala.reflect.ClassTag /** A builder class for arrays. @@ -20,7 +21,7 @@ import scala.reflect.ClassTag * @tparam T the type of the elements for the builder. */ @SerialVersionUID(3L) -sealed abstract class ArrayBuilder[T] +sealed abstract class ArrayBuilder[sealed T] extends ReusableBuilder[T, Array[T]] with Serializable { protected[this] var capacity: Int = 0 @@ -57,7 +58,7 @@ sealed abstract class ArrayBuilder[T] this } - override def addAll(xs: IterableOnce[T]): this.type = { + override def addAll(xs: IterableOnce[T]^): this.type = { val k = xs.knownSize if (k > 0) { ensureSize(this.size + k) @@ -493,7 +494,7 @@ object ArrayBuilder { this } - override def addAll(xs: IterableOnce[Unit]): this.type = { + override def addAll(xs: IterableOnce[Unit]^): this.type = { size += xs.iterator.size this } diff --git a/tests/pos-special/stdlib/collection/mutable/ArrayDeque.scala b/tests/pos-special/stdlib/collection/mutable/ArrayDeque.scala index 205e1607f824..f22aacec65c5 100644 --- a/tests/pos-special/stdlib/collection/mutable/ArrayDeque.scala +++ b/tests/pos-special/stdlib/collection/mutable/ArrayDeque.scala @@ -18,6 +18,7 @@ import scala.annotation.nowarn import scala.collection.Stepper.EfficientSplit import scala.collection.generic.DefaultSerializable import scala.reflect.ClassTag +import language.experimental.captureChecking /** An implementation of a double-ended queue that internally uses a resizable circular buffer. * @@ -36,7 +37,7 @@ import scala.reflect.ClassTag * @define mayNotTerminateInf * @define willNotTerminateInf */ -class ArrayDeque[A] protected ( +class ArrayDeque[sealed A] protected ( protected var array: Array[AnyRef], private[ArrayDeque] var start: Int, private[ArrayDeque] var end: Int @@ -99,7 +100,7 @@ class ArrayDeque[A] protected ( this } - override def prependAll(elems: IterableOnce[A]): this.type = { + override def prependAll(elems: IterableOnce[A]^): this.type = { val it = elems.iterator if (it.nonEmpty) { val n = length @@ -130,7 +131,7 @@ class ArrayDeque[A] protected ( this } - override def addAll(elems: IterableOnce[A]): this.type = { + override def addAll(elems: IterableOnce[A]^): this.type = { elems.knownSize match { case srcLength if srcLength > 0 => ensureSize(srcLength + length) @@ -176,7 +177,7 @@ class ArrayDeque[A] protected ( } } - def insertAll(idx: Int, elems: IterableOnce[A]): Unit = { + def insertAll(idx: Int, elems: IterableOnce[A]^): Unit = { requireBounds(idx, length+1) val n = length if (idx == 0) { @@ -462,7 +463,7 @@ class ArrayDeque[A] protected ( protected def ofArray(array: Array[AnyRef], end: Int): ArrayDeque[A] = new ArrayDeque[A](array, start = 0, end) - override def copyToArray[B >: A](dest: Array[B], destStart: Int, len: Int): Int = { + override def copyToArray[sealed B >: A](dest: Array[B], destStart: Int, len: Int): Int = { val copied = IterableOnce.elemsToCopyToArray(length, dest.length, destStart, len) if (copied > 0) { copySliceToArray(srcStart = 0, dest = dest, destStart = destStart, maxItems = len) @@ -470,7 +471,7 @@ class ArrayDeque[A] protected ( copied } - override def toArray[B >: A: ClassTag]: Array[B] = + override def toArray[sealed B >: A: ClassTag]: Array[B] = copySliceToArray(srcStart = 0, dest = new Array[B](length), destStart = 0, maxItems = length) /** @@ -525,7 +526,7 @@ class ArrayDeque[A] protected ( @SerialVersionUID(3L) object ArrayDeque extends StrictOptimizedSeqFactory[ArrayDeque] { - def from[B](coll: collection.IterableOnce[B]): ArrayDeque[B] = { + def from[sealed B](coll: collection.IterableOnce[B]^): ArrayDeque[B] = { val s = coll.knownSize if (s >= 0) { val array = alloc(s) @@ -535,14 +536,14 @@ object ArrayDeque extends StrictOptimizedSeqFactory[ArrayDeque] { } else new ArrayDeque[B]() ++= coll } - def newBuilder[A]: Builder[A, ArrayDeque[A]] = + def newBuilder[sealed A]: Builder[A, ArrayDeque[A]] = new GrowableBuilder[A, ArrayDeque[A]](empty) { override def sizeHint(size: Int): Unit = { elems.ensureSize(size) } } - def empty[A]: ArrayDeque[A] = new ArrayDeque[A]() + def empty[sealed A]: ArrayDeque[A] = new ArrayDeque[A]() final val DefaultInitialSize = 16 diff --git a/tests/pos-special/stdlib/collection/mutable/ArraySeq.scala b/tests/pos-special/stdlib/collection/mutable/ArraySeq.scala index 74ab6b2107e5..bd3a208a94c0 100644 --- a/tests/pos-special/stdlib/collection/mutable/ArraySeq.scala +++ b/tests/pos-special/stdlib/collection/mutable/ArraySeq.scala @@ -19,6 +19,8 @@ import scala.collection.Stepper.EfficientSplit import scala.collection.convert.impl._ import scala.reflect.ClassTag import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking +import annotation.unchecked.uncheckedCaptures /** * A collection representing `Array[T]`. Unlike `ArrayBuffer` it is always backed by the same @@ -34,23 +36,25 @@ import scala.util.hashing.MurmurHash3 * @define willNotTerminateInf */ @SerialVersionUID(3L) -sealed abstract class ArraySeq[T] +sealed abstract class ArraySeq[sealed T] extends AbstractSeq[T] with IndexedSeq[T] with IndexedSeqOps[T, ArraySeq, ArraySeq[T]] with StrictOptimizedSeqOps[T, ArraySeq, ArraySeq[T]] - with Serializable { + with Serializable + with Pure { override def iterableFactory: scala.collection.SeqFactory[ArraySeq] = ArraySeq.untagged - override protected def fromSpecific(coll: scala.collection.IterableOnce[T]): ArraySeq[T] = { + override protected def fromSpecific(coll: scala.collection.IterableOnce[T]^): ArraySeq[T] = { val b = ArrayBuilder.make(elemTag).asInstanceOf[ArrayBuilder[T]] val s = coll.knownSize if(s > 0) b.sizeHint(s) b ++= coll ArraySeq.make(b.result()) } - override protected def newSpecificBuilder: Builder[T, ArraySeq[T]] = ArraySeq.newBuilder(elemTag).asInstanceOf[Builder[T, ArraySeq[T]]] + override protected def newSpecificBuilder: Builder[T, ArraySeq[T]] = + ArraySeq.newBuilder[T](elemTag.asInstanceOf[ClassTag[T]]).asInstanceOf[Builder[T, ArraySeq[T]]] override def empty: ArraySeq[T] = ArraySeq.empty(elemTag.asInstanceOf[ClassTag[T]]) /** The tag of the element type. This does not have to be equal to the element type of this ArraySeq. A primitive @@ -71,9 +75,9 @@ sealed abstract class ArraySeq[T] override protected[this] def className = "ArraySeq" /** Clones this object, including the underlying Array. */ - override def clone(): ArraySeq[T] = ArraySeq.make(array.clone()).asInstanceOf[ArraySeq[T]] + override def clone(): ArraySeq[T] = ArraySeq.make[T](array.clone().asInstanceOf[Array[T]]) - override def copyToArray[B >: T](xs: Array[B], start: Int, len: Int): Int = { + override def copyToArray[sealed B >: T](xs: Array[B], start: Int, len: Int): Int = { val copied = IterableOnce.elemsToCopyToArray(length, xs.length, start, len) if(copied > 0) { Array.copy(array, 0, xs, start, copied) @@ -89,10 +93,10 @@ sealed abstract class ArraySeq[T] } override def sorted[B >: T](implicit ord: Ordering[B]): ArraySeq[T] = - ArraySeq.make(array.sorted(ord.asInstanceOf[Ordering[Any]])).asInstanceOf[ArraySeq[T]] + ArraySeq.make(array.asInstanceOf[Array[T]].sorted(ord.asInstanceOf[Ordering[Any]])).asInstanceOf[ArraySeq[T]] override def sortInPlace[B >: T]()(implicit ord: Ordering[B]): this.type = { - if (length > 1) scala.util.Sorting.stableSort(array.asInstanceOf[Array[B]]) + if (length > 1) scala.util.Sorting.stableSort(array.asInstanceOf[Array[B @uncheckedCaptures]]) this } } @@ -107,9 +111,9 @@ object ArraySeq extends StrictOptimizedClassTagSeqFactory[ArraySeq] { self => private[this] val EmptyArraySeq = new ofRef[AnyRef](new Array[AnyRef](0)) def empty[T : ClassTag]: ArraySeq[T] = EmptyArraySeq.asInstanceOf[ArraySeq[T]] - def from[A : ClassTag](it: scala.collection.IterableOnce[A]): ArraySeq[A] = make(Array.from[A](it)) + def from[sealed A : ClassTag](it: scala.collection.IterableOnce[A]^): ArraySeq[A] = make(Array.from[A](it)) - def newBuilder[A : ClassTag]: Builder[A, ArraySeq[A]] = ArrayBuilder.make[A].mapResult(make) + def newBuilder[sealed A : ClassTag]: Builder[A, ArraySeq[A]] = ArrayBuilder.make[A].mapResult(make) /** * Wrap an existing `Array` into a `ArraySeq` of the proper primitive specialization type @@ -123,7 +127,7 @@ object ArraySeq extends StrictOptimizedClassTagSeqFactory[ArraySeq] { self => * `ArraySeq.make(a.asInstanceOf[Array[Int]])` does not work, it throws a `ClassCastException` * at runtime. */ - def make[T](x: Array[T]): ArraySeq[T] = ((x.asInstanceOf[Array[_]]: @unchecked) match { + def make[sealed T](x: Array[T]): ArraySeq[T] = ((x.asInstanceOf[Array[_]]: @unchecked) match { case null => null case x: Array[AnyRef] => new ofRef[AnyRef](x) case x: Array[Int] => new ofInt(x) diff --git a/tests/pos-special/stdlib/collection/mutable/BitSet.scala b/tests/pos-special/stdlib/collection/mutable/BitSet.scala index 69ecc122c1f9..dcb8a157389b 100644 --- a/tests/pos-special/stdlib/collection/mutable/BitSet.scala +++ b/tests/pos-special/stdlib/collection/mutable/BitSet.scala @@ -17,6 +17,7 @@ package mutable import scala.collection.immutable.Range import BitSetOps.{LogWL, MaxSize} import scala.annotation.implicitNotFound +import language.experimental.captureChecking /** * A class for mutable bitsets. @@ -47,7 +48,7 @@ class BitSet(protected[collection] final var elems: Array[Long]) def this() = this(0) - override protected def fromSpecific(coll: IterableOnce[Int]): BitSet = bitSetFactory.fromSpecific(coll) + override protected def fromSpecific(coll: IterableOnce[Int]^): BitSet = bitSetFactory.fromSpecific(coll) override protected def newSpecificBuilder: Builder[Int, BitSet] = bitSetFactory.newBuilder override def empty: BitSet = bitSetFactory.empty @@ -187,7 +188,7 @@ class BitSet(protected[collection] final var elems: Array[Long]) override def zip[B](that: IterableOnce[B])(implicit @implicitNotFound(collection.BitSet.zipOrdMsg) ev: Ordering[(Int, B)]): SortedSet[(Int, B)] = super.zip(that) - override def addAll(xs: IterableOnce[Int]): this.type = xs match { + override def addAll(xs: IterableOnce[Int]^): this.type = xs match { case bs: collection.BitSet => this |= bs case range: Range => @@ -260,7 +261,7 @@ class BitSet(protected[collection] final var elems: Array[Long]) super.subsetOf(other) } - override def subtractAll(xs: IterableOnce[Int]): this.type = xs match { + override def subtractAll(xs: IterableOnce[Int]^): this.type = xs match { case bs: collection.BitSet => this &~= bs case other => super.subtractAll(other) } @@ -360,7 +361,7 @@ class BitSet(protected[collection] final var elems: Array[Long]) @SerialVersionUID(3L) object BitSet extends SpecificIterableFactory[Int, BitSet] { - def fromSpecific(it: scala.collection.IterableOnce[Int]): BitSet = Growable.from(empty, it) + def fromSpecific(it: scala.collection.IterableOnce[Int]^): BitSet = Growable.from(empty, it) def empty: BitSet = new BitSet() diff --git a/tests/pos-special/stdlib/collection/mutable/Buffer.scala b/tests/pos-special/stdlib/collection/mutable/Buffer.scala index 847b924735ce..0f472dc9ac82 100644 --- a/tests/pos-special/stdlib/collection/mutable/Buffer.scala +++ b/tests/pos-special/stdlib/collection/mutable/Buffer.scala @@ -14,10 +14,12 @@ package scala.collection package mutable import scala.annotation.nowarn +import language.experimental.captureChecking +import scala.annotation.unchecked.uncheckedCaptures /** A `Buffer` is a growable and shrinkable `Seq`. */ -trait Buffer[A] +trait Buffer[sealed A] extends Seq[A] with SeqOps[A, Buffer, Buffer[A]] with Growable[A] @@ -48,19 +50,19 @@ trait Buffer[A] /** Appends the elements contained in a iterable object to this buffer. * @param xs the iterable object containing the elements to append. */ - @`inline` final def appendAll(xs: IterableOnce[A]): this.type = addAll(xs) + @`inline` final def appendAll(xs: IterableOnce[A]^): this.type = addAll(xs) /** Alias for `prepend` */ @`inline` final def +=: (elem: A): this.type = prepend(elem) - def prependAll(elems: IterableOnce[A]): this.type = { insertAll(0, elems); this } + def prependAll(elems: IterableOnce[A]^): this.type = { insertAll(0, elems); this } @deprecated("Use prependAll instead", "2.13.0") @`inline` final def prepend(elems: A*): this.type = prependAll(elems) /** Alias for `prependAll` */ - @inline final def ++=:(elems: IterableOnce[A]): this.type = prependAll(elems) + @inline final def ++=:(elems: IterableOnce[A]^): this.type = prependAll(elems) /** Inserts a new element at a given index into this buffer. * @@ -81,7 +83,7 @@ trait Buffer[A] * @throws IndexOutOfBoundsException if `idx` is out of bounds. */ @throws[IndexOutOfBoundsException] - def insertAll(idx: Int, elems: IterableOnce[A]): Unit + def insertAll(idx: Int, elems: IterableOnce[A]^): Unit /** Removes the element at a given index position. * @@ -103,7 +105,7 @@ trait Buffer[A] @throws[IndexOutOfBoundsException] @throws[IllegalArgumentException] def remove(idx: Int, count: Int): Unit - + /** Removes a single element from this buffer, at its first occurrence. * If the buffer does not contain that element, it is unchanged. * @@ -132,7 +134,7 @@ trait Buffer[A] @deprecated("use dropRightInPlace instead", since = "2.13.4") def trimEnd(n: Int): Unit = dropRightInPlace(n) - def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A], replaced: Int): this.type + def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A]^, replaced: Int): this.type // +=, ++=, clear inherited from Growable // Per remark of @ichoran, we should preferably not have these: @@ -180,11 +182,11 @@ trait IndexedBuffer[A] extends IndexedSeq[A] override def iterableFactory: SeqFactory[IndexedBuffer] = IndexedBuffer - def flatMapInPlace(f: A => IterableOnce[A]): this.type = { + def flatMapInPlace(f: A => IterableOnce[A]^): this.type = { // There's scope for a better implementation which copies elements in place. var i = 0 val s = size - val newElems = new Array[IterableOnce[A]](s) + val newElems = new Array[(IterableOnce[A]^) @uncheckedCaptures](s) while (i < s) { newElems(i) = f(this(i)); i += 1 } clear() i = 0 @@ -207,7 +209,7 @@ trait IndexedBuffer[A] extends IndexedSeq[A] if (i == j) this else takeInPlace(j) } - def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A], replaced: Int): this.type = { + def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A]^, replaced: Int): this.type = { val replaced0 = math.min(math.max(replaced, 0), length) val i = math.min(math.max(from, 0), length) var j = 0 diff --git a/tests/pos-special/stdlib/collection/mutable/Builder.scala b/tests/pos-special/stdlib/collection/mutable/Builder.scala index 0ecc06dff061..dd57cb75da91 100644 --- a/tests/pos-special/stdlib/collection/mutable/Builder.scala +++ b/tests/pos-special/stdlib/collection/mutable/Builder.scala @@ -12,6 +12,9 @@ package scala.collection.mutable +import language.experimental.captureChecking + + /** Base trait for collection builders. * * After calling `result()` the behavior of a Builder (which is not also a [[scala.collection.mutable.ReusableBuilder]]) @@ -20,7 +23,8 @@ package scala.collection.mutable * * @see [[scala.collection.mutable.ReusableBuilder]] for Builders which can be reused after calling `result()` */ -trait Builder[-A, +To] extends Growable[A] { self => +trait Builder[-A, +To] extends Growable[A] { + self: Builder[A, To]^ => /** Clears the contents of this builder. * After execution of this method the builder will contain no elements. @@ -51,7 +55,7 @@ trait Builder[-A, +To] extends Growable[A] { self => * @param coll the collection which serves as a hint for the result's size. * @param delta a correction to add to the `coll.size` to produce the size hint. */ - final def sizeHint(coll: scala.collection.IterableOnce[_], delta: Int = 0): Unit = { + final def sizeHint(coll: scala.collection.IterableOnce[_]^, delta: Int = 0): Unit = { val s = coll.knownSize if (s != -1) sizeHint(s + delta) } @@ -69,7 +73,7 @@ trait Builder[-A, +To] extends Growable[A] { self => * than collection's size are reduced. */ // should probably be `boundingColl: IterableOnce[_]`, but binary compatibility - final def sizeHintBounded(size: Int, boundingColl: scala.collection.Iterable[_]): Unit = { + final def sizeHintBounded(size: Int, boundingColl: scala.collection.Iterable[_]^): Unit = { val s = boundingColl.knownSize if (s != -1) { sizeHint(scala.math.min(s, size)) @@ -77,10 +81,10 @@ trait Builder[-A, +To] extends Growable[A] { self => } /** A builder resulting from this builder my mapping the result using `f`. */ - def mapResult[NewTo](f: To => NewTo): Builder[A, NewTo] = new Builder[A, NewTo] { + def mapResult[NewTo](f: To => NewTo): Builder[A, NewTo]^{this, f} = new Builder[A, NewTo] { def addOne(x: A): this.type = { self += x; this } def clear(): Unit = self.clear() - override def addAll(xs: IterableOnce[A]): this.type = { self ++= xs; this } + override def addAll(xs: IterableOnce[A]^): this.type = { self ++= xs; this } override def sizeHint(size: Int): Unit = self.sizeHint(size) def result(): NewTo = f(self.result()) override def knownSize: Int = self.knownSize diff --git a/tests/pos-special/stdlib/collection/mutable/CheckedIndexedSeqView.scala b/tests/pos-special/stdlib/collection/mutable/CheckedIndexedSeqView.scala index b9598904375d..152b6cc9ffc7 100644 --- a/tests/pos-special/stdlib/collection/mutable/CheckedIndexedSeqView.scala +++ b/tests/pos-special/stdlib/collection/mutable/CheckedIndexedSeqView.scala @@ -13,34 +13,37 @@ package scala package collection package mutable +import language.experimental.captureChecking private[mutable] trait CheckedIndexedSeqView[+A] extends IndexedSeqView[A] { + this: CheckedIndexedSeqView[A]^ => + protected val mutationCount: () => Int - override def iterator: Iterator[A] = new CheckedIndexedSeqView.CheckedIterator(this, mutationCount()) - override def reverseIterator: Iterator[A] = new CheckedIndexedSeqView.CheckedReverseIterator(this, mutationCount()) - - override def appended[B >: A](elem: B): IndexedSeqView[B] = new CheckedIndexedSeqView.Appended(this, elem)(mutationCount) - override def prepended[B >: A](elem: B): IndexedSeqView[B] = new CheckedIndexedSeqView.Prepended(elem, this)(mutationCount) - override def take(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Take(this, n)(mutationCount) - override def takeRight(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.TakeRight(this, n)(mutationCount) - override def drop(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Drop(this, n)(mutationCount) - override def dropRight(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.DropRight(this, n)(mutationCount) - override def map[B](f: A => B): IndexedSeqView[B] = new CheckedIndexedSeqView.Map(this, f)(mutationCount) - override def reverse: IndexedSeqView[A] = new CheckedIndexedSeqView.Reverse(this)(mutationCount) - override def slice(from: Int, until: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Slice(this, from, until)(mutationCount) - override def tapEach[U](f: A => U): IndexedSeqView[A] = new CheckedIndexedSeqView.Map(this, { (a: A) => f(a); a})(mutationCount) - - override def concat[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount) - override def appendedAll[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount) - override def prependedAll[B >: A](prefix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(prefix, this)(mutationCount) + override def iterator: Iterator[A]^{this} = new CheckedIndexedSeqView.CheckedIterator(this, mutationCount()) + override def reverseIterator: Iterator[A]^{this} = new CheckedIndexedSeqView.CheckedReverseIterator(this, mutationCount()) + + override def appended[B >: A](elem: B): IndexedSeqView[B]^{this} = new CheckedIndexedSeqView.Appended(this, elem)(mutationCount) + override def prepended[B >: A](elem: B): IndexedSeqView[B]^{this} = new CheckedIndexedSeqView.Prepended(elem, this)(mutationCount) + override def take(n: Int): IndexedSeqView[A]^{this} = new CheckedIndexedSeqView.Take(this, n)(mutationCount) + override def takeRight(n: Int): IndexedSeqView[A]^{this} = new CheckedIndexedSeqView.TakeRight(this, n)(mutationCount) + override def drop(n: Int): IndexedSeqView[A]^{this} = new CheckedIndexedSeqView.Drop(this, n)(mutationCount) + override def dropRight(n: Int): IndexedSeqView[A]^{this} = new CheckedIndexedSeqView.DropRight(this, n)(mutationCount) + override def map[B](f: A => B): IndexedSeqView[B]^{this, f} = new CheckedIndexedSeqView.Map(this, f)(mutationCount) + override def reverse: IndexedSeqView[A]^{this} = new CheckedIndexedSeqView.Reverse(this)(mutationCount) + override def slice(from: Int, until: Int): IndexedSeqView[A]^{this} = new CheckedIndexedSeqView.Slice(this, from, until)(mutationCount) + override def tapEach[U](f: A => U): IndexedSeqView[A]^{this, f} = new CheckedIndexedSeqView.Map(this, { (a: A) => f(a); a})(mutationCount) + + override def concat[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B]^{this} = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount) + override def appendedAll[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B]^{this} = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount) + override def prependedAll[B >: A](prefix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B]^{this} = new CheckedIndexedSeqView.Concat(prefix, this)(mutationCount) } private[mutable] object CheckedIndexedSeqView { import IndexedSeqView.SomeIndexedSeqOps @SerialVersionUID(3L) - private[mutable] class CheckedIterator[A](self: IndexedSeqView[A], mutationCount: => Int) + private[mutable] class CheckedIterator[A](self: IndexedSeqView[A]^, mutationCount: => Int) extends IndexedSeqView.IndexedSeqViewIterator[A](self) { private[this] val expectedCount = mutationCount override def hasNext: Boolean = { @@ -50,7 +53,7 @@ private[mutable] object CheckedIndexedSeqView { } @SerialVersionUID(3L) - private[mutable] class CheckedReverseIterator[A](self: IndexedSeqView[A], mutationCount: => Int) + private[mutable] class CheckedReverseIterator[A](self: IndexedSeqView[A]^, mutationCount: => Int) extends IndexedSeqView.IndexedSeqViewReverseIterator[A](self) { private[this] val expectedCount = mutationCount override def hasNext: Boolean = { @@ -60,43 +63,43 @@ private[mutable] object CheckedIndexedSeqView { } @SerialVersionUID(3L) - class Id[+A](underlying: SomeIndexedSeqOps[A])(protected val mutationCount: () => Int) + class Id[+A](underlying: SomeIndexedSeqOps[A]^)(protected val mutationCount: () => Int) extends IndexedSeqView.Id(underlying) with CheckedIndexedSeqView[A] @SerialVersionUID(3L) - class Appended[+A](underlying: SomeIndexedSeqOps[A], elem: A)(protected val mutationCount: () => Int) + class Appended[+A](underlying: SomeIndexedSeqOps[A]^, elem: A)(protected val mutationCount: () => Int) extends IndexedSeqView.Appended(underlying, elem) with CheckedIndexedSeqView[A] @SerialVersionUID(3L) - class Prepended[+A](elem: A, underlying: SomeIndexedSeqOps[A])(protected val mutationCount: () => Int) + class Prepended[+A](elem: A, underlying: SomeIndexedSeqOps[A]^)(protected val mutationCount: () => Int) extends IndexedSeqView.Prepended(elem, underlying) with CheckedIndexedSeqView[A] @SerialVersionUID(3L) - class Concat[A](prefix: SomeIndexedSeqOps[A], suffix: SomeIndexedSeqOps[A])(protected val mutationCount: () => Int) + class Concat[A](prefix: SomeIndexedSeqOps[A]^, suffix: SomeIndexedSeqOps[A]^)(protected val mutationCount: () => Int) extends IndexedSeqView.Concat[A](prefix, suffix) with CheckedIndexedSeqView[A] @SerialVersionUID(3L) - class Take[A](underlying: SomeIndexedSeqOps[A], n: Int)(protected val mutationCount: () => Int) + class Take[A](underlying: SomeIndexedSeqOps[A]^, n: Int)(protected val mutationCount: () => Int) extends IndexedSeqView.Take(underlying, n) with CheckedIndexedSeqView[A] @SerialVersionUID(3L) - class TakeRight[A](underlying: SomeIndexedSeqOps[A], n: Int)(protected val mutationCount: () => Int) + class TakeRight[A](underlying: SomeIndexedSeqOps[A]^, n: Int)(protected val mutationCount: () => Int) extends IndexedSeqView.TakeRight(underlying, n) with CheckedIndexedSeqView[A] @SerialVersionUID(3L) - class Drop[A](underlying: SomeIndexedSeqOps[A], n: Int)(protected val mutationCount: () => Int) + class Drop[A](underlying: SomeIndexedSeqOps[A]^, n: Int)(protected val mutationCount: () => Int) extends IndexedSeqView.Drop[A](underlying, n) with CheckedIndexedSeqView[A] @SerialVersionUID(3L) - class DropRight[A](underlying: SomeIndexedSeqOps[A], n: Int)(protected val mutationCount: () => Int) + class DropRight[A](underlying: SomeIndexedSeqOps[A]^, n: Int)(protected val mutationCount: () => Int) extends IndexedSeqView.DropRight[A](underlying, n) with CheckedIndexedSeqView[A] @SerialVersionUID(3L) - class Map[A, B](underlying: SomeIndexedSeqOps[A], f: A => B)(protected val mutationCount: () => Int) + class Map[A, B](underlying: SomeIndexedSeqOps[A]^, f: A => B)(protected val mutationCount: () => Int) extends IndexedSeqView.Map(underlying, f) with CheckedIndexedSeqView[B] @SerialVersionUID(3L) - class Reverse[A](underlying: SomeIndexedSeqOps[A])(protected val mutationCount: () => Int) + class Reverse[A](underlying: SomeIndexedSeqOps[A]^)(protected val mutationCount: () => Int) extends IndexedSeqView.Reverse[A](underlying) with CheckedIndexedSeqView[A] { override def reverse: IndexedSeqView[A] = underlying match { case x: IndexedSeqView[A] => x @@ -105,7 +108,7 @@ private[mutable] object CheckedIndexedSeqView { } @SerialVersionUID(3L) - class Slice[A](underlying: SomeIndexedSeqOps[A], from: Int, until: Int)(protected val mutationCount: () => Int) + class Slice[A](underlying: SomeIndexedSeqOps[A]^, from: Int, until: Int)(protected val mutationCount: () => Int) extends AbstractIndexedSeqView[A] with CheckedIndexedSeqView[A] { protected val lo = from max 0 protected val hi = (until max 0) min underlying.length diff --git a/tests/pos-special/stdlib/collection/mutable/Cloneable.scala b/tests/pos-special/stdlib/collection/mutable/Cloneable.scala index 940ecf3549ad..39149e98cbf0 100644 --- a/tests/pos-special/stdlib/collection/mutable/Cloneable.scala +++ b/tests/pos-special/stdlib/collection/mutable/Cloneable.scala @@ -11,7 +11,7 @@ */ package scala.collection.mutable - +import language.experimental.captureChecking /** A trait for cloneable collections. * diff --git a/tests/pos-special/stdlib/collection/mutable/CollisionProofHashMap.scala b/tests/pos-special/stdlib/collection/mutable/CollisionProofHashMap.scala index 8542b5b56a01..2b27efb6eac1 100644 --- a/tests/pos-special/stdlib/collection/mutable/CollisionProofHashMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/CollisionProofHashMap.scala @@ -18,6 +18,7 @@ import scala.annotation.{implicitNotFound, tailrec, unused} import scala.annotation.unchecked.uncheckedVariance import scala.collection.generic.DefaultSerializationProxy import scala.runtime.Statics +import language.experimental.captureChecking /** This class implements mutable maps using a hashtable with red-black trees in the buckets for good * worst-case performance on hash collisions. An `Ordering` is required for the element type. Equality @@ -32,7 +33,7 @@ import scala.runtime.Statics * @define mayNotTerminateInf * @define willNotTerminateInf */ -final class CollisionProofHashMap[K, V](initialCapacity: Int, loadFactor: Double)(implicit ordering: Ordering[K]) +final class CollisionProofHashMap[sealed K, sealed V](initialCapacity: Int, loadFactor: Double)(implicit ordering: Ordering[K]) extends AbstractMap[K, V] with MapOps[K, V, Map, CollisionProofHashMap[K, V]] //-- with StrictOptimizedIterableOps[(K, V), Iterable, CollisionProofHashMap[K, V]] @@ -63,7 +64,7 @@ final class CollisionProofHashMap[K, V](initialCapacity: Int, loadFactor: Double @`inline` private[this] final def index(hash: Int) = hash & (table.length - 1) - override protected def fromSpecific(coll: IterableOnce[(K, V)] @uncheckedVariance): CollisionProofHashMap[K, V] @uncheckedVariance = CollisionProofHashMap.from(coll) + override protected def fromSpecific(coll: (IterableOnce[(K, V)]^) @uncheckedVariance): CollisionProofHashMap[K, V] @uncheckedVariance = CollisionProofHashMap.from(coll) override protected def newSpecificBuilder: Builder[(K, V), CollisionProofHashMap[K, V]] @uncheckedVariance = CollisionProofHashMap.newBuilder[K, V] override def empty: CollisionProofHashMap[K, V] = new CollisionProofHashMap[K, V] @@ -173,7 +174,7 @@ final class CollisionProofHashMap[K, V](initialCapacity: Int, loadFactor: Double } } - override def addAll(xs: IterableOnce[(K, V)]): this.type = { + override def addAll(xs: IterableOnce[(K, V)]^): this.type = { val k = xs.knownSize if(k > 0) sizeHint(contentSize + k) super.addAll(xs) @@ -442,13 +443,13 @@ final class CollisionProofHashMap[K, V](initialCapacity: Int, loadFactor: Double (implicit @implicitNotFound(CollisionProofHashMap.ordMsg) ordering: Ordering[K2]): CollisionProofHashMap[K2, V2] = sortedMapFactory.from(new View.Collect(this, pf)) - override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]): CollisionProofHashMap[K, V2] = sortedMapFactory.from(suffix match { + override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]^): CollisionProofHashMap[K, V2] = sortedMapFactory.from(suffix match { case it: Iterable[(K, V2)] => new View.Concat(this, it) case _ => iterator.concat(suffix.iterator) }) /** Alias for `concat` */ - @`inline` override final def ++ [V2 >: V](xs: IterableOnce[(K, V2)]): CollisionProofHashMap[K, V2] = concat(xs) + @`inline` override final def ++ [V2 >: V](xs: IterableOnce[(K, V2)]^): CollisionProofHashMap[K, V2] = concat(xs) @deprecated("Consider requiring an immutable Map or fall back to Map.concat", "2.13.0") override def + [V1 >: V](kv: (K, V1)): CollisionProofHashMap[K, V1] = @@ -743,17 +744,17 @@ final class CollisionProofHashMap[K, V](initialCapacity: Int, loadFactor: Double object CollisionProofHashMap extends SortedMapFactory[CollisionProofHashMap] { private[collection] final val ordMsg = "No implicit Ordering[${K2}] found to build a CollisionProofHashMap[${K2}, ${V2}]. You may want to upcast to a Map[${K}, ${V}] first by calling `unsorted`." - def from[K : Ordering, V](it: scala.collection.IterableOnce[(K, V)]): CollisionProofHashMap[K, V] = { + def from[sealed K : Ordering, sealed V](it: scala.collection.IterableOnce[(K, V)]^): CollisionProofHashMap[K, V] = { val k = it.knownSize val cap = if(k > 0) ((k + 1).toDouble / defaultLoadFactor).toInt else defaultInitialCapacity new CollisionProofHashMap[K, V](cap, defaultLoadFactor) ++= it } - def empty[K : Ordering, V]: CollisionProofHashMap[K, V] = new CollisionProofHashMap[K, V] + def empty[sealed K : Ordering, sealed V]: CollisionProofHashMap[K, V] = new CollisionProofHashMap[K, V] - def newBuilder[K : Ordering, V]: Builder[(K, V), CollisionProofHashMap[K, V]] = newBuilder(defaultInitialCapacity, defaultLoadFactor) + def newBuilder[sealed K : Ordering, sealed V]: Builder[(K, V), CollisionProofHashMap[K, V]] = newBuilder(defaultInitialCapacity, defaultLoadFactor) - def newBuilder[K : Ordering, V](initialCapacity: Int, loadFactor: Double): Builder[(K, V), CollisionProofHashMap[K, V]] = + def newBuilder[sealed K : Ordering, sealed V](initialCapacity: Int, loadFactor: Double): Builder[(K, V), CollisionProofHashMap[K, V]] = new GrowableBuilder[(K, V), CollisionProofHashMap[K, V]](new CollisionProofHashMap[K, V](initialCapacity, loadFactor)) { override def sizeHint(size: Int) = elems.sizeHint(size) } @@ -765,8 +766,8 @@ object CollisionProofHashMap extends SortedMapFactory[CollisionProofHashMap] { final def defaultInitialCapacity: Int = 16 @SerialVersionUID(3L) - private final class DeserializationFactory[K, V](val tableLength: Int, val loadFactor: Double, val ordering: Ordering[K]) extends Factory[(K, V), CollisionProofHashMap[K, V]] with Serializable { - def fromSpecific(it: IterableOnce[(K, V)]): CollisionProofHashMap[K, V] = new CollisionProofHashMap[K, V](tableLength, loadFactor)(ordering) ++= it + private final class DeserializationFactory[sealed K, sealed V](val tableLength: Int, val loadFactor: Double, val ordering: Ordering[K]) extends Factory[(K, V), CollisionProofHashMap[K, V]] with Serializable { + def fromSpecific(it: IterableOnce[(K, V)]^): CollisionProofHashMap[K, V] = new CollisionProofHashMap[K, V](tableLength, loadFactor)(ordering) ++= it def newBuilder: Builder[(K, V), CollisionProofHashMap[K, V]] = CollisionProofHashMap.newBuilder(tableLength, loadFactor)(ordering) } @@ -788,7 +789,7 @@ object CollisionProofHashMap extends SortedMapFactory[CollisionProofHashMap] { /////////////////////////// Red-Black Tree Node - final class RBNode[K, V](var key: K, var hash: Int, var value: V, var red: Boolean, var left: RBNode[K, V], var right: RBNode[K, V], var parent: RBNode[K, V]) extends Node { + final class RBNode[sealed K, sealed V](var key: K, var hash: Int, var value: V, var red: Boolean, var left: RBNode[K, V], var right: RBNode[K, V], var parent: RBNode[K, V]) extends Node { override def toString: String = "RBNode(" + key + ", " + hash + ", " + value + ", " + red + ", " + left + ", " + right + ")" @tailrec def getNode(k: K, h: Int)(implicit ord: Ordering[K]): RBNode[K, V] = { @@ -819,17 +820,17 @@ object CollisionProofHashMap extends SortedMapFactory[CollisionProofHashMap] { } } - @`inline` private def leaf[A, B](key: A, hash: Int, value: B, red: Boolean, parent: RBNode[A, B]): RBNode[A, B] = + @`inline` private def leaf[sealed A, sealed B](key: A, hash: Int, value: B, red: Boolean, parent: RBNode[A, B]): RBNode[A, B] = new RBNode(key, hash, value, red, null, null, parent) - @tailrec private def minNodeNonNull[A, B](node: RBNode[A, B]): RBNode[A, B] = + @tailrec private def minNodeNonNull[sealed A, sealed B](node: RBNode[A, B]): RBNode[A, B] = if (node.left eq null) node else minNodeNonNull(node.left) /** * Returns the node that follows `node` in an in-order tree traversal. If `node` has the maximum key (and is, * therefore, the last node), this method returns `null`. */ - private def successor[A, B](node: RBNode[A, B]): RBNode[A, B] = { + private def successor[sealed A, sealed B](node: RBNode[A, B]): RBNode[A, B] = { if (node.right ne null) minNodeNonNull(node.right) else { var x = node @@ -842,7 +843,7 @@ object CollisionProofHashMap extends SortedMapFactory[CollisionProofHashMap] { } } - private final class RBNodesIterator[A, B](tree: RBNode[A, B])(implicit @unused ord: Ordering[A]) extends AbstractIterator[RBNode[A, B]] { + private final class RBNodesIterator[sealed A, sealed B](tree: RBNode[A, B])(implicit @unused ord: Ordering[A]) extends AbstractIterator[RBNode[A, B]] { private[this] var nextNode: RBNode[A, B] = if(tree eq null) null else minNodeNonNull(tree) def hasNext: Boolean = nextNode ne null @@ -858,7 +859,7 @@ object CollisionProofHashMap extends SortedMapFactory[CollisionProofHashMap] { /////////////////////////// Linked List Node - private final class LLNode[K, V](var key: K, var hash: Int, var value: V, var next: LLNode[K, V]) extends Node { + private final class LLNode[sealed K, sealed V](var key: K, var hash: Int, var value: V, var next: LLNode[K, V]) extends Node { override def toString = s"LLNode($key, $value, $hash) -> $next" private[this] def eq(a: Any, b: Any): Boolean = diff --git a/tests/pos-special/stdlib/collection/mutable/Growable.scala b/tests/pos-special/stdlib/collection/mutable/Growable.scala index 914742b9013a..3b5eabac37bf 100644 --- a/tests/pos-special/stdlib/collection/mutable/Growable.scala +++ b/tests/pos-special/stdlib/collection/mutable/Growable.scala @@ -14,6 +14,8 @@ package scala package collection package mutable +import language.experimental.captureChecking + /** This trait forms part of collections that can be augmented * using a `+=` operator and that can be cleared of all elements using * a `clear` method. @@ -54,7 +56,7 @@ trait Growable[-A] extends Clearable { * @param xs the IterableOnce producing the elements to $add. * @return the $coll itself. */ - def addAll(xs: IterableOnce[A]): this.type = { + def addAll(xs: IterableOnce[A]^): this.type = { if (xs.asInstanceOf[AnyRef] eq this) addAll(Buffer.from(xs)) // avoid mutating under our own iterator else { val it = xs.iterator @@ -66,7 +68,7 @@ trait Growable[-A] extends Clearable { } /** Alias for `addAll` */ - @`inline` final def ++= (xs: IterableOnce[A]): this.type = addAll(xs) + @`inline` final def ++= (xs: IterableOnce[A]^): this.type = addAll(xs) /** @return The number of elements in the collection under construction, if it can be cheaply computed, * -1 otherwise. The default implementation always returns -1. @@ -83,7 +85,7 @@ object Growable { * @tparam A Element type * @return The filled instance */ - def from[A](empty: Growable[A], it: collection.IterableOnce[A]): empty.type = empty ++= it + def from[A](empty: Growable[A], it: collection.IterableOnce[A]^): empty.type = empty ++= it } diff --git a/tests/pos-special/stdlib/collection/mutable/GrowableBuilder.scala b/tests/pos-special/stdlib/collection/mutable/GrowableBuilder.scala index 7e945dffb99e..4d6f989e6f3d 100644 --- a/tests/pos-special/stdlib/collection/mutable/GrowableBuilder.scala +++ b/tests/pos-special/stdlib/collection/mutable/GrowableBuilder.scala @@ -12,7 +12,7 @@ package scala package collection.mutable - +import language.experimental.captureChecking /** The canonical builder for collections that are growable, i.e. that support an * efficient `+=` method which adds an element to the collection. @@ -31,7 +31,7 @@ class GrowableBuilder[Elem, To <: Growable[Elem]](protected val elems: To) def addOne(elem: Elem): this.type = { elems += elem; this } - override def addAll(xs: IterableOnce[Elem]): this.type = { elems.addAll(xs); this } + override def addAll(xs: IterableOnce[Elem]^): this.type = { elems.addAll(xs); this } override def knownSize: Int = elems.knownSize } diff --git a/tests/pos-special/stdlib/collection/mutable/HashMap.scala b/tests/pos-special/stdlib/collection/mutable/HashMap.scala index 7ad3cf3869e8..ab45e7ffc73d 100644 --- a/tests/pos-special/stdlib/collection/mutable/HashMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/HashMap.scala @@ -17,6 +17,7 @@ import scala.annotation.{nowarn, tailrec} import scala.collection.Stepper.EfficientSplit import scala.collection.generic.DefaultSerializationProxy import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking /** This class implements mutable maps using a hashtable. * @@ -32,7 +33,7 @@ import scala.util.hashing.MurmurHash3 * @define willNotTerminateInf */ @deprecatedInheritance("HashMap will be made final; use .withDefault for the common use case of computing a default value", "2.13.0") -class HashMap[K, V](initialCapacity: Int, loadFactor: Double) +class HashMap[sealed K, sealed V](initialCapacity: Int, loadFactor: Double) extends AbstractMap[K, V] with MapOps[K, V, HashMap, HashMap[K, V]] with StrictOptimizedIterableOps[(K, V), Iterable, HashMap[K, V]] @@ -94,7 +95,7 @@ class HashMap[K, V](initialCapacity: Int, loadFactor: Double) if(target > table.length) growTable(target) } - override def addAll(xs: IterableOnce[(K, V)]): this.type = { + override def addAll(xs: IterableOnce[(K, V)]^): this.type = { sizeHint(xs.knownSize) xs match { @@ -182,7 +183,7 @@ class HashMap[K, V](initialCapacity: Int, loadFactor: Double) } } - override def subtractAll(xs: IterableOnce[K]): this.type = { + override def subtractAll(xs: IterableOnce[K]^): this.type = { if (size == 0) { return this } @@ -596,17 +597,17 @@ class HashMap[K, V](initialCapacity: Int, loadFactor: Double) @SerialVersionUID(3L) object HashMap extends MapFactory[HashMap] { - def empty[K, V]: HashMap[K, V] = new HashMap[K, V] + def empty[sealed K, sealed V]: HashMap[K, V] = new HashMap[K, V] - def from[K, V](it: collection.IterableOnce[(K, V)]): HashMap[K, V] = { + def from[sealed K, sealed V](it: collection.IterableOnce[(K, V)]^): HashMap[K, V] = { val k = it.knownSize val cap = if(k > 0) ((k + 1).toDouble / defaultLoadFactor).toInt else defaultInitialCapacity new HashMap[K, V](cap, defaultLoadFactor).addAll(it) } - def newBuilder[K, V]: Builder[(K, V), HashMap[K, V]] = newBuilder(defaultInitialCapacity, defaultLoadFactor) + def newBuilder[sealed K, sealed V]: Builder[(K, V), HashMap[K, V]] = newBuilder(defaultInitialCapacity, defaultLoadFactor) - def newBuilder[K, V](initialCapacity: Int, loadFactor: Double): Builder[(K, V), HashMap[K, V]] = + def newBuilder[sealed K, sealed V](initialCapacity: Int, loadFactor: Double): Builder[(K, V), HashMap[K, V]] = new GrowableBuilder[(K, V), HashMap[K, V]](new HashMap[K, V](initialCapacity, loadFactor)) { override def sizeHint(size: Int) = elems.sizeHint(size) } @@ -618,8 +619,8 @@ object HashMap extends MapFactory[HashMap] { final def defaultInitialCapacity: Int = 16 @SerialVersionUID(3L) - private final class DeserializationFactory[K, V](val tableLength: Int, val loadFactor: Double) extends Factory[(K, V), HashMap[K, V]] with Serializable { - def fromSpecific(it: IterableOnce[(K, V)]): HashMap[K, V] = new HashMap[K, V](tableLength, loadFactor).addAll(it) + private final class DeserializationFactory[sealed K, sealed V](val tableLength: Int, val loadFactor: Double) extends Factory[(K, V), HashMap[K, V]] with Serializable { + def fromSpecific(it: IterableOnce[(K, V)]^): HashMap[K, V] = new HashMap[K, V](tableLength, loadFactor).addAll(it) def newBuilder: Builder[(K, V), HashMap[K, V]] = HashMap.newBuilder(tableLength, loadFactor) } diff --git a/tests/pos-special/stdlib/collection/mutable/HashSet.scala b/tests/pos-special/stdlib/collection/mutable/HashSet.scala index 425721a41626..e8c055ff15ef 100644 --- a/tests/pos-special/stdlib/collection/mutable/HashSet.scala +++ b/tests/pos-special/stdlib/collection/mutable/HashSet.scala @@ -17,6 +17,7 @@ import scala.annotation.tailrec import scala.collection.Stepper.EfficientSplit import scala.collection.generic.DefaultSerializationProxy import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking /** This class implements mutable sets using a hashtable. * @@ -28,7 +29,7 @@ import scala.util.hashing.MurmurHash3 * @define mayNotTerminateInf * @define willNotTerminateInf */ -final class HashSet[A](initialCapacity: Int, loadFactor: Double) +final class HashSet[sealed A](initialCapacity: Int, loadFactor: Double) extends AbstractSet[A] with SetOps[A, HashSet, HashSet[A]] with StrictOptimizedIterableOps[A, HashSet, HashSet[A]] @@ -90,7 +91,7 @@ final class HashSet[A](initialCapacity: Int, loadFactor: Double) addElem(elem, computeHash(elem)) } - override def addAll(xs: IterableOnce[A]): this.type = { + override def addAll(xs: IterableOnce[A]^): this.type = { sizeHint(xs.knownSize) xs match { case hs: immutable.HashSet[A] => @@ -114,7 +115,7 @@ final class HashSet[A](initialCapacity: Int, loadFactor: Double) } } - override def subtractAll(xs: IterableOnce[A]): this.type = { + override def subtractAll(xs: IterableOnce[A]^): this.type = { if (size == 0) { return this } @@ -406,17 +407,17 @@ final class HashSet[A](initialCapacity: Int, loadFactor: Double) @SerialVersionUID(3L) object HashSet extends IterableFactory[HashSet] { - def from[B](it: scala.collection.IterableOnce[B]): HashSet[B] = { + def from[sealed B](it: scala.collection.IterableOnce[B]^): HashSet[B] = { val k = it.knownSize val cap = if(k > 0) ((k + 1).toDouble / defaultLoadFactor).toInt else defaultInitialCapacity new HashSet[B](cap, defaultLoadFactor) ++= it } - def empty[A]: HashSet[A] = new HashSet[A] + def empty[sealed A]: HashSet[A] = new HashSet[A] - def newBuilder[A]: Builder[A, HashSet[A]] = newBuilder(defaultInitialCapacity, defaultLoadFactor) + def newBuilder[sealed A]: Builder[A, HashSet[A]] = newBuilder(defaultInitialCapacity, defaultLoadFactor) - def newBuilder[A](initialCapacity: Int, loadFactor: Double): Builder[A, HashSet[A]] = + def newBuilder[sealed A](initialCapacity: Int, loadFactor: Double): Builder[A, HashSet[A]] = new GrowableBuilder[A, HashSet[A]](new HashSet[A](initialCapacity, loadFactor)) { override def sizeHint(size: Int) = elems.sizeHint(size) } @@ -428,8 +429,8 @@ object HashSet extends IterableFactory[HashSet] { final def defaultInitialCapacity: Int = 16 @SerialVersionUID(3L) - private final class DeserializationFactory[A](val tableLength: Int, val loadFactor: Double) extends Factory[A, HashSet[A]] with Serializable { - def fromSpecific(it: IterableOnce[A]): HashSet[A] = new HashSet[A](tableLength, loadFactor) ++= it + private final class DeserializationFactory[sealed A](val tableLength: Int, val loadFactor: Double) extends Factory[A, HashSet[A]] with Serializable { + def fromSpecific(it: IterableOnce[A]^): HashSet[A] = new HashSet[A](tableLength, loadFactor) ++= it def newBuilder: Builder[A, HashSet[A]] = HashSet.newBuilder(tableLength, loadFactor) } diff --git a/tests/pos-special/stdlib/collection/mutable/HashTable.scala b/tests/pos-special/stdlib/collection/mutable/HashTable.scala index 4153bd532163..a3534e322cf3 100644 --- a/tests/pos-special/stdlib/collection/mutable/HashTable.scala +++ b/tests/pos-special/stdlib/collection/mutable/HashTable.scala @@ -19,6 +19,7 @@ import java.lang.Integer.{numberOfLeadingZeros, rotateRight} import scala.util.hashing.byteswap32 import java.lang.Integer +import language.experimental.captureChecking /** This class can be used to construct data structures that are based * on hashtables. Class `HashTable[A]` implements a hashtable @@ -36,7 +37,7 @@ import java.lang.Integer * @tparam A type of the elements contained in this hash table. */ // Not used in the standard library, but used in scala-parallel-collections -private[collection] trait HashTable[A, B, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashUtils[A] { +private[collection] trait HashTable[sealed A, B, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashUtils[A] { // Replacing Entry type parameter by abstract type member here allows to not expose to public // implementation-specific entry classes such as `DefaultEntry` or `LinkedEntry`. // However, I'm afraid it's too late now for such breaking change. @@ -411,7 +412,7 @@ private[collection] object HashTable { /** Class used internally. */ -private[collection] trait HashEntry[A, E <: HashEntry[A, E]] { +private[collection] trait HashEntry[A, sealed E <: HashEntry[A, E]] { val key: A var next: E = _ } diff --git a/tests/pos-special/stdlib/collection/mutable/ImmutableBuilder.scala b/tests/pos-special/stdlib/collection/mutable/ImmutableBuilder.scala index c801f073fb0d..1af98162e9f3 100644 --- a/tests/pos-special/stdlib/collection/mutable/ImmutableBuilder.scala +++ b/tests/pos-special/stdlib/collection/mutable/ImmutableBuilder.scala @@ -13,6 +13,7 @@ package scala package collection package mutable +import language.experimental.captureChecking /** diff --git a/tests/pos-special/stdlib/collection/mutable/IndexedSeq.scala b/tests/pos-special/stdlib/collection/mutable/IndexedSeq.scala index 24d54905de22..022970b4c56f 100644 --- a/tests/pos-special/stdlib/collection/mutable/IndexedSeq.scala +++ b/tests/pos-special/stdlib/collection/mutable/IndexedSeq.scala @@ -12,6 +12,7 @@ package scala.collection package mutable +import language.experimental.captureChecking trait IndexedSeq[T] extends Seq[T] with scala.collection.IndexedSeq[T] diff --git a/tests/pos-special/stdlib/collection/mutable/Iterable.scala b/tests/pos-special/stdlib/collection/mutable/Iterable.scala index d05aeed88044..bf286157b376 100644 --- a/tests/pos-special/stdlib/collection/mutable/Iterable.scala +++ b/tests/pos-special/stdlib/collection/mutable/Iterable.scala @@ -13,11 +13,13 @@ package scala.collection.mutable import scala.collection.{IterableFactory, IterableFactoryDefaults} +import language.experimental.captureChecking trait Iterable[A] extends collection.Iterable[A] with collection.IterableOps[A, Iterable, Iterable[A]] with IterableFactoryDefaults[A, Iterable] { + this: Iterable[A]^ => override def iterableFactory: IterableFactory[Iterable] = Iterable } @@ -31,4 +33,5 @@ trait Iterable[A] object Iterable extends IterableFactory.Delegate[Iterable](ArrayBuffer) /** Explicit instantiation of the `Iterable` trait to reduce class file size in subclasses. */ -abstract class AbstractIterable[A] extends scala.collection.AbstractIterable[A] with Iterable[A] +abstract class AbstractIterable[A] extends scala.collection.AbstractIterable[A] with Iterable[A]: + this: AbstractIterable[A]^ => diff --git a/tests/pos-special/stdlib/collection/mutable/LinkedHashMap.scala b/tests/pos-special/stdlib/collection/mutable/LinkedHashMap.scala index bc663f1d37d8..a253e8738b26 100644 --- a/tests/pos-special/stdlib/collection/mutable/LinkedHashMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/LinkedHashMap.scala @@ -17,6 +17,7 @@ package mutable import scala.annotation.{nowarn, tailrec} import scala.collection.generic.DefaultSerializable import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking /** This class implements mutable maps using a hashtable. @@ -33,7 +34,7 @@ import scala.util.hashing.MurmurHash3 * @define orderDependentFold */ @deprecatedInheritance("LinkedHashMap will be made final; use .withDefault for the common use case of computing a default value", "2.13.11") -class LinkedHashMap[K, V] +class LinkedHashMap[sealed K, sealed V] extends AbstractMap[K, V] with SeqMap[K, V] with MapOps[K, V, LinkedHashMap, LinkedHashMap[K, V]] @@ -476,20 +477,20 @@ class LinkedHashMap[K, V] @SerialVersionUID(3L) object LinkedHashMap extends MapFactory[LinkedHashMap] { - def empty[K, V] = new LinkedHashMap[K, V] + def empty[sealed K, sealed V] = new LinkedHashMap[K, V] - def from[K, V](it: collection.IterableOnce[(K, V)]) = { + def from[sealed K, sealed V](it: collection.IterableOnce[(K, V)]^) = { val newlhm = empty[K, V] newlhm.sizeHint(it.knownSize) newlhm.addAll(it) newlhm } - def newBuilder[K, V] = new GrowableBuilder(empty[K, V]) + def newBuilder[sealed K, sealed V] = new GrowableBuilder(empty[K, V]) /** Class for the linked hash map entry, used internally. */ - private[mutable] final class LinkedEntry[K, V](val key: K, val hash: Int, var value: V) { + private[mutable] final class LinkedEntry[sealed K, sealed V](val key: K, val hash: Int, var value: V) { var earlier: LinkedEntry[K, V] = null var later: LinkedEntry[K, V] = null var next: LinkedEntry[K, V] = null diff --git a/tests/pos-special/stdlib/collection/mutable/LinkedHashSet.scala b/tests/pos-special/stdlib/collection/mutable/LinkedHashSet.scala index 0c01f8ea79ea..a895034a852c 100644 --- a/tests/pos-special/stdlib/collection/mutable/LinkedHashSet.scala +++ b/tests/pos-special/stdlib/collection/mutable/LinkedHashSet.scala @@ -17,6 +17,7 @@ package mutable import scala.annotation.{nowarn, tailrec} import scala.collection.generic.DefaultSerializable import scala.util.hashing.MurmurHash3 +import language.experimental.captureChecking /** This class implements mutable sets using a hashtable. * The iterator and all traversal methods of this class visit elements in the order they were inserted. @@ -31,7 +32,7 @@ import scala.util.hashing.MurmurHash3 * @define orderDependentFold */ @deprecatedInheritance("LinkedHashSet will be made final", "2.13.11") -class LinkedHashSet[A] +class LinkedHashSet[sealed A] extends AbstractSet[A] with SetOps[A, LinkedHashSet, LinkedHashSet[A]] with StrictOptimizedIterableOps[A, LinkedHashSet, LinkedHashSet[A]] @@ -314,20 +315,20 @@ class LinkedHashSet[A] @SerialVersionUID(3L) object LinkedHashSet extends IterableFactory[LinkedHashSet] { - override def empty[A]: LinkedHashSet[A] = new LinkedHashSet[A] + override def empty[sealed A]: LinkedHashSet[A] = new LinkedHashSet[A] - def from[E](it: collection.IterableOnce[E]) = { + def from[sealed E](it: collection.IterableOnce[E]^) = { val newlhs = empty[E] newlhs.sizeHint(it.knownSize) newlhs.addAll(it) newlhs } - def newBuilder[A] = new GrowableBuilder(empty[A]) + def newBuilder[sealed A] = new GrowableBuilder(empty[A]) /** Class for the linked hash set entry, used internally. */ - private[mutable] final class Entry[A](val key: A, val hash: Int) { + private[mutable] final class Entry[sealed A](val key: A, val hash: Int) { var earlier: Entry[A] = null var later: Entry[A] = null var next: Entry[A] = null diff --git a/tests/pos-special/stdlib/collection/mutable/ListBuffer.scala b/tests/pos-special/stdlib/collection/mutable/ListBuffer.scala index d66525763163..4f607c770130 100644 --- a/tests/pos-special/stdlib/collection/mutable/ListBuffer.scala +++ b/tests/pos-special/stdlib/collection/mutable/ListBuffer.scala @@ -19,6 +19,8 @@ import java.lang.{IllegalArgumentException, IndexOutOfBoundsException} import scala.collection.generic.DefaultSerializable import scala.runtime.Statics.releaseFence +import scala.annotation.unchecked.uncheckedCaptures +import language.experimental.captureChecking /** A `Buffer` implementation backed by a list. It provides constant time * prepend and append. Most other operations are linear. @@ -36,7 +38,7 @@ import scala.runtime.Statics.releaseFence * @define willNotTerminateInf */ @SerialVersionUID(-8428291952499836345L) -class ListBuffer[A] +class ListBuffer[sealed A] extends AbstractBuffer[A] with SeqOps[A, ListBuffer, ListBuffer[A]] with StrictOptimizedSeqOps[A, ListBuffer, ListBuffer[A]] @@ -121,7 +123,7 @@ class ListBuffer[A] } // MUST only be called on fresh instances - private def freshFrom(xs: IterableOnce[A]): this.type = { + private def freshFrom(xs: IterableOnce[A]^): this.type = { val it = xs.iterator if (it.hasNext) { var len = 1 @@ -140,7 +142,7 @@ class ListBuffer[A] this } - override final def addAll(xs: IterableOnce[A]): this.type = { + override final def addAll(xs: IterableOnce[A]^): this.type = { val it = xs.iterator if (it.hasNext) { val fresh = new ListBuffer[A].freshFrom(it) @@ -248,7 +250,7 @@ class ListBuffer[A] } } - def insertAll(idx: Int, elems: IterableOnce[A]): Unit = { + def insertAll(idx: Int, elems: IterableOnce[A]^): Unit = { if (idx < 0 || idx > len) throw new IndexOutOfBoundsException(s"$idx is out of bounds (min 0, max ${len-1})") val it = elems.iterator if (it.hasNext) { @@ -305,7 +307,7 @@ class ListBuffer[A] this } - def flatMapInPlace(f: A => IterableOnce[A]): this.type = { + def flatMapInPlace(f: A => IterableOnce[A]^): this.type = { mutationCount += 1 var src = first var dst: List[A] = null @@ -345,7 +347,7 @@ class ListBuffer[A] this } - def patchInPlace(from: Int, patch: collection.IterableOnce[A], replaced: Int): this.type = { + def patchInPlace(from: Int, patch: collection.IterableOnce[A]^, replaced: Int): this.type = { val _len = len val _from = math.max(from, 0) // normalized val _replaced = math.max(replaced, 0) // normalized @@ -395,9 +397,9 @@ class ListBuffer[A] @SerialVersionUID(3L) object ListBuffer extends StrictOptimizedSeqFactory[ListBuffer] { - def from[A](coll: collection.IterableOnce[A]): ListBuffer[A] = new ListBuffer[A].freshFrom(coll) + def from[sealed A](coll: collection.IterableOnce[A]^): ListBuffer[A] = new ListBuffer[A].freshFrom(coll) - def newBuilder[A]: Builder[A, ListBuffer[A]] = new GrowableBuilder(empty[A]) + def newBuilder[sealed A]: Builder[A, ListBuffer[A]] = new GrowableBuilder(empty[A]) - def empty[A]: ListBuffer[A] = new ListBuffer[A] + def empty[A]: ListBuffer[A] = new ListBuffer[A @uncheckedCaptures] } diff --git a/tests/pos-special/stdlib/collection/mutable/ListMap.scala b/tests/pos-special/stdlib/collection/mutable/ListMap.scala index 7cc5aa227757..8ddbc264e47b 100644 --- a/tests/pos-special/stdlib/collection/mutable/ListMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/ListMap.scala @@ -16,6 +16,7 @@ package mutable import scala.annotation.tailrec import scala.collection.generic.DefaultSerializable import scala.collection.immutable.List +import language.experimental.captureChecking /** A simple mutable map backed by a list, so it preserves insertion order. * @@ -30,7 +31,7 @@ import scala.collection.immutable.List * @define orderDependentFold */ @deprecated("Use an immutable.ListMap assigned to a var instead of mutable.ListMap", "2.13.0") -class ListMap[K, V] +class ListMap[sealed K, sealed V] extends AbstractMap[K, V] with MapOps[K, V, ListMap, ListMap[K, V]] with StrictOptimizedIterableOps[(K, V), Iterable, ListMap[K, V]] @@ -76,7 +77,7 @@ class ListMap[K, V] @SerialVersionUID(3L) @deprecated("Use an immutable.ListMap assigned to a var instead of mutable.ListMap", "2.13.0") object ListMap extends MapFactory[ListMap] { - def empty[K, V]: ListMap[K, V] = new ListMap[K, V] - def from[K, V](it: IterableOnce[(K, V)]): ListMap[K,V] = Growable.from(empty[K, V], it) - def newBuilder[K, V]: Builder[(K, V), ListMap[K,V]] = new GrowableBuilder(empty[K, V]) + def empty[sealed K, sealed V]: ListMap[K, V] = new ListMap[K, V] + def from[sealed K, sealed V](it: IterableOnce[(K, V)]^): ListMap[K,V] = Growable.from(empty[K, V], it) + def newBuilder[sealed K, sealed V]: Builder[(K, V), ListMap[K,V]] = new GrowableBuilder(empty[K, V]) } diff --git a/tests/pos-special/stdlib/collection/mutable/LongMap.scala b/tests/pos-special/stdlib/collection/mutable/LongMap.scala index af34ca4ab8c9..2c757160ec77 100644 --- a/tests/pos-special/stdlib/collection/mutable/LongMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/LongMap.scala @@ -15,6 +15,7 @@ package mutable import scala.collection.generic.DefaultSerializationProxy import scala.language.implicitConversions +import language.experimental.captureChecking /** This class implements mutable maps with `Long` keys based on a hash table with open addressing. * @@ -36,7 +37,7 @@ import scala.language.implicitConversions * rapidly as 2^30 is approached. * */ -final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBufferSize: Int, initBlank: Boolean) +final class LongMap[sealed V] private[collection] (defaultEntry: Long -> V, initialBufferSize: Int, initBlank: Boolean) extends AbstractMap[Long, V] with MapOps[Long, V, Map, LongMap[V]] with StrictOptimizedIterableOps[(Long, V), Iterable, LongMap[V]] @@ -46,7 +47,7 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff def this() = this(LongMap.exceptionDefault, 16, true) // TODO: override clear() with an optimization more tailored for efficiency. - override protected def fromSpecific(coll: scala.collection.IterableOnce[(Long, V)]): LongMap[V] = { + override protected def fromSpecific(coll: scala.collection.IterableOnce[(Long, V)]^): LongMap[V] = { //TODO should this be the default implementation of this method in StrictOptimizedIterableOps? val b = newSpecificBuilder b.sizeHint(coll) @@ -56,7 +57,7 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff override protected def newSpecificBuilder: Builder[(Long, V),LongMap[V]] = new GrowableBuilder(LongMap.empty[V]) /** Creates a new `LongMap` that returns default values according to a supplied key-value mapping. */ - def this(defaultEntry: Long => V) = this(defaultEntry, 16, true) + def this(defaultEntry: Long -> V) = this(defaultEntry, 16, true) /** Creates a new `LongMap` with an initial buffer of specified size. * @@ -66,7 +67,7 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff def this(initialBufferSize: Int) = this(LongMap.exceptionDefault, initialBufferSize, true) /** Creates a new `LongMap` with specified default values and initial buffer size. */ - def this(defaultEntry: Long => V, initialBufferSize: Int) = this(defaultEntry, initialBufferSize, true) + def this(defaultEntry: Long -> V, initialBufferSize: Int) = this(defaultEntry, initialBufferSize, true) private[this] var mask = 0 private[this] var extraKeys: Int = 0 @@ -468,18 +469,18 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff } @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0") - override def + [V1 >: V](elem1: (Long, V1), elem2: (Long, V1), elems: (Long, V1)*): LongMap[V1] = { + override def + [sealed V1 >: V](elem1: (Long, V1), elem2: (Long, V1), elems: (Long, V1)*): LongMap[V1] = { val m = this + elem1 + elem2 if(elems.isEmpty) m else m.concat(elems) } - override def concat[V1 >: V](xs: scala.collection.IterableOnce[(Long, V1)]): LongMap[V1] = { + override def concat[sealed V1 >: V](xs: scala.collection.IterableOnce[(Long, V1)]^): LongMap[V1] = { val lm = clone().asInstanceOf[LongMap[V1]] xs.iterator.foreach(kv => lm += kv) lm } - override def ++ [V1 >: V](xs: scala.collection.IterableOnce[(Long, V1)]): LongMap[V1] = concat(xs) + override def ++ [sealed V1 >: V](xs: scala.collection.IterableOnce[(Long, V1)]^): LongMap[V1] = concat(xs) @deprecated("Use m.clone().addOne(k,v) instead of m.updated(k, v)", "2.13.0") override def updated[V1 >: V](key: Long, value: V1): LongMap[V1] = @@ -519,7 +520,7 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff * Unlike `mapValues`, this method generates a new * collection immediately. */ - def mapValuesNow[V1](f: V => V1): LongMap[V1] = { + def mapValuesNow[sealed V1](f: V => V1): LongMap[V1] = { val zv = if ((extraKeys & 1) == 1) f(zeroValue.asInstanceOf[V]).asInstanceOf[AnyRef] else null val mv = if ((extraKeys & 2) == 2) f(minValue.asInstanceOf[V]).asInstanceOf[AnyRef] else null val lm = new LongMap[V1](LongMap.exceptionDefault, 1, false) @@ -562,11 +563,11 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff this } - def map[V2](f: ((Long, V)) => (Long, V2)): LongMap[V2] = LongMap.from(new View.Map(coll, f)) + def map[sealed V2](f: ((Long, V)) => (Long, V2)): LongMap[V2] = LongMap.from(new View.Map(coll, f)) - def flatMap[V2](f: ((Long, V)) => IterableOnce[(Long, V2)]): LongMap[V2] = LongMap.from(new View.FlatMap(coll, f)) + def flatMap[sealed V2](f: ((Long, V)) => IterableOnce[(Long, V2)]): LongMap[V2] = LongMap.from(new View.FlatMap(coll, f)) - def collect[V2](pf: PartialFunction[(Long, V), (Long, V2)]): LongMap[V2] = + def collect[sealed V2](pf: PartialFunction[(Long, V), (Long, V2)]): LongMap[V2] = strictOptimizedCollect(LongMap.newBuilder[V2], pf) protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(LongMap.toFactory[V](LongMap), this) @@ -580,13 +581,13 @@ object LongMap { private final val VacantBit = 0x40000000 private final val MissVacant = 0xC0000000 - private val exceptionDefault: Long => Nothing = (k: Long) => throw new NoSuchElementException(k.toString) + private val exceptionDefault: Long -> Nothing = (k: Long) => throw new NoSuchElementException(k.toString) /** A builder for instances of `LongMap`. * * This builder can be reused to create multiple instances. */ - final class LongMapBuilder[V] extends ReusableBuilder[(Long, V), LongMap[V]] { + final class LongMapBuilder[sealed V] extends ReusableBuilder[(Long, V), LongMap[V]] { private[collection] var elems: LongMap[V] = new LongMap[V] override def addOne(entry: (Long, V)): this.type = { elems += entry @@ -598,9 +599,9 @@ object LongMap { } /** Creates a new `LongMap` with zero or more key/value pairs. */ - def apply[V](elems: (Long, V)*): LongMap[V] = buildFromIterableOnce(elems) + def apply[sealed V](elems: (Long, V)*): LongMap[V] = buildFromIterableOnce(elems) - private def buildFromIterableOnce[V](elems: IterableOnce[(Long, V)]): LongMap[V] = { + private def buildFromIterableOnce[sealed V](elems: IterableOnce[(Long, V)]^): LongMap[V] = { var sz = elems.knownSize if(sz < 0) sz = 4 val lm = new LongMap[V](sz * 2) @@ -610,10 +611,10 @@ object LongMap { } /** Creates a new empty `LongMap`. */ - def empty[V]: LongMap[V] = new LongMap[V] + def empty[sealed V]: LongMap[V] = new LongMap[V] /** Creates a new empty `LongMap` with the supplied default */ - def withDefault[V](default: Long => V): LongMap[V] = new LongMap[V](default) + def withDefault[sealed V](default: Long -> V): LongMap[V] = new LongMap[V](default) /** Creates a new `LongMap` from an existing source collection. A source collection * which is already a `LongMap` gets cloned. @@ -622,17 +623,17 @@ object LongMap { * @tparam A the type of the collection’s elements * @return a new `LongMap` with the elements of `source` */ - def from[V](source: IterableOnce[(Long, V)]): LongMap[V] = source match { + def from[sealed V](source: IterableOnce[(Long, V)]^): LongMap[V] = source match { case source: LongMap[_] => source.clone().asInstanceOf[LongMap[V]] case _ => buildFromIterableOnce(source) } - def newBuilder[V]: ReusableBuilder[(Long, V), LongMap[V]] = new LongMapBuilder[V] + def newBuilder[sealed V]: ReusableBuilder[(Long, V), LongMap[V]] = new LongMapBuilder[V] /** Creates a new `LongMap` from arrays of keys and values. * Equivalent to but more efficient than `LongMap((keys zip values): _*)`. */ - def fromZip[V](keys: Array[Long], values: Array[V]): LongMap[V] = { + def fromZip[sealed V](keys: Array[Long], values: Array[V]): LongMap[V] = { val sz = math.min(keys.length, values.length) val lm = new LongMap[V](sz * 2) var i = 0 @@ -644,7 +645,7 @@ object LongMap { /** Creates a new `LongMap` from keys and values. * Equivalent to but more efficient than `LongMap((keys zip values): _*)`. */ - def fromZip[V](keys: scala.collection.Iterable[Long], values: scala.collection.Iterable[V]): LongMap[V] = { + def fromZip[sealed V](keys: scala.collection.Iterable[Long], values: scala.collection.Iterable[V]): LongMap[V] = { val sz = math.min(keys.size, values.size) val lm = new LongMap[V](sz * 2) val ki = keys.iterator @@ -654,20 +655,20 @@ object LongMap { lm } - implicit def toFactory[V](dummy: LongMap.type): Factory[(Long, V), LongMap[V]] = ToFactory.asInstanceOf[Factory[(Long, V), LongMap[V]]] + implicit def toFactory[sealed V](dummy: LongMap.type): Factory[(Long, V), LongMap[V]] = ToFactory.asInstanceOf[Factory[(Long, V), LongMap[V]]] @SerialVersionUID(3L) private[this] object ToFactory extends Factory[(Long, AnyRef), LongMap[AnyRef]] with Serializable { - def fromSpecific(it: IterableOnce[(Long, AnyRef)]): LongMap[AnyRef] = LongMap.from[AnyRef](it) + def fromSpecific(it: IterableOnce[(Long, AnyRef)]^): LongMap[AnyRef] = LongMap.from[AnyRef](it) def newBuilder: Builder[(Long, AnyRef), LongMap[AnyRef]] = LongMap.newBuilder[AnyRef] } implicit def toBuildFrom[V](factory: LongMap.type): BuildFrom[Any, (Long, V), LongMap[V]] = ToBuildFrom.asInstanceOf[BuildFrom[Any, (Long, V), LongMap[V]]] private object ToBuildFrom extends BuildFrom[Any, (Long, AnyRef), LongMap[AnyRef]] { - def fromSpecific(from: Any)(it: IterableOnce[(Long, AnyRef)]) = LongMap.from(it) + def fromSpecific(from: Any)(it: IterableOnce[(Long, AnyRef)]^) = LongMap.from(it) def newBuilder(from: Any) = LongMap.newBuilder[AnyRef] } - implicit def iterableFactory[V]: Factory[(Long, V), LongMap[V]] = toFactory(this) + implicit def iterableFactory[sealed V]: Factory[(Long, V), LongMap[V]] = toFactory(this) implicit def buildFromLongMap[V]: BuildFrom[LongMap[_], (Long, V), LongMap[V]] = toBuildFrom(this) } diff --git a/tests/pos-special/stdlib/collection/mutable/Map.scala b/tests/pos-special/stdlib/collection/mutable/Map.scala index 610dc01029cc..dab64ddb1f58 100644 --- a/tests/pos-special/stdlib/collection/mutable/Map.scala +++ b/tests/pos-special/stdlib/collection/mutable/Map.scala @@ -14,6 +14,8 @@ package scala package collection package mutable +import language.experimental.captureChecking + /** Base type of mutable Maps */ trait Map[K, V] extends Iterable[(K, V)] @@ -44,7 +46,7 @@ trait Map[K, V] * @param d the function mapping keys to values, used for non-present keys * @return a wrapper of the map with a default value */ - def withDefault(d: K => V): Map[K, V] = new Map.WithDefault[K, V](this, d) + def withDefault(d: K -> V): Map[K, V] = new Map.WithDefault[K, V](this, d) /** The same map with a given default value. * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc. @@ -68,7 +70,8 @@ trait MapOps[K, V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C]] with Cloneable[C] with Builder[(K, V), C] with Growable[(K, V)] - with Shrinkable[K] { + with Shrinkable[K] + with Pure { def result(): C = coll @@ -231,7 +234,7 @@ trait MapOps[K, V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C]] object Map extends MapFactory.Delegate[Map](HashMap) { @SerialVersionUID(3L) - class WithDefault[K, V](val underlying: Map[K, V], val defaultValue: K => V) + class WithDefault[K, V](val underlying: Map[K, V], val defaultValue: K -> V) extends AbstractMap[K, V] with MapOps[K, V, Map, WithDefault[K, V]] with Serializable { @@ -250,12 +253,12 @@ object Map extends MapFactory.Delegate[Map](HashMap) { def addOne(elem: (K, V)): WithDefault.this.type = { underlying.addOne(elem); this } - override def concat[V2 >: V](suffix: collection.IterableOnce[(K, V2)]): Map[K, V2] = + override def concat[V2 >: V](suffix: collection.IterableOnce[(K, V2)]^): Map[K, V2] = underlying.concat(suffix).withDefault(defaultValue) override def empty: WithDefault[K, V] = new WithDefault[K, V](underlying.empty, defaultValue) - override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)]): WithDefault[K, V] = + override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)]^): WithDefault[K, V] = new WithDefault[K, V](mapFactory.from(coll), defaultValue) override protected def newSpecificBuilder: Builder[(K, V), WithDefault[K, V]] = diff --git a/tests/pos-special/stdlib/collection/mutable/MultiMap.scala b/tests/pos-special/stdlib/collection/mutable/MultiMap.scala index 13d7c35e0165..281631c92298 100644 --- a/tests/pos-special/stdlib/collection/mutable/MultiMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/MultiMap.scala @@ -12,6 +12,7 @@ package scala.collection.mutable +import language.experimental.captureChecking /** A trait for mutable maps with multiple values assigned to a key. * @@ -51,7 +52,7 @@ package scala.collection.mutable * @define Coll `MultiMap` */ @deprecated("Use a scala.collection.mutable.MultiDict in the scala-collection-contrib module", "2.13.0") -trait MultiMap[K, V] extends Map[K, Set[V]] { +trait MultiMap[K, sealed V] extends Map[K, Set[V]] { /** Creates a new set. * * Classes that use this trait as a mixin can override this method diff --git a/tests/pos-special/stdlib/collection/mutable/MutationTracker.scala b/tests/pos-special/stdlib/collection/mutable/MutationTracker.scala index e98536d0dad5..3e9b16540031 100644 --- a/tests/pos-special/stdlib/collection/mutable/MutationTracker.scala +++ b/tests/pos-special/stdlib/collection/mutable/MutationTracker.scala @@ -15,6 +15,7 @@ package collection package mutable import java.util.ConcurrentModificationException +import language.experimental.captureChecking /** * Utilities to check that mutations to a client that tracks @@ -66,7 +67,7 @@ private object MutationTracker { * @param mutationCount a by-name provider of the current mutation count * @tparam A the type of the iterator's elements */ - final class CheckedIterator[A](underlying: Iterator[A], mutationCount: => Int) extends AbstractIterator[A] { + final class CheckedIterator[A](underlying: Iterator[A]^, mutationCount: => Int) extends AbstractIterator[A] { private[this] val expectedCount = mutationCount def hasNext: Boolean = { diff --git a/tests/pos-special/stdlib/collection/mutable/OpenHashMap.scala b/tests/pos-special/stdlib/collection/mutable/OpenHashMap.scala index 22e99d4650d1..f1deb25b6a8a 100644 --- a/tests/pos-special/stdlib/collection/mutable/OpenHashMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/OpenHashMap.scala @@ -16,6 +16,7 @@ package mutable import java.lang.Integer.numberOfLeadingZeros import java.util.ConcurrentModificationException import scala.collection.generic.DefaultSerializable +import language.experimental.captureChecking /** * @define Coll `OpenHashMap` @@ -25,10 +26,10 @@ import scala.collection.generic.DefaultSerializable @SerialVersionUID(3L) object OpenHashMap extends MapFactory[OpenHashMap] { - def empty[K, V] = new OpenHashMap[K, V] - def from[K, V](it: IterableOnce[(K, V)]): OpenHashMap[K,V] = empty ++= it + def empty[sealed K, sealed V] = new OpenHashMap[K, V] + def from[sealed K, sealed V](it: IterableOnce[(K, V)]^): OpenHashMap[K,V] = empty ++= it - def newBuilder[K, V]: Builder[(K, V), OpenHashMap[K,V]] = + def newBuilder[sealed K, sealed V]: Builder[(K, V), OpenHashMap[K,V]] = new GrowableBuilder[(K, V), OpenHashMap[K, V]](empty) /** A hash table entry. @@ -38,7 +39,7 @@ object OpenHashMap extends MapFactory[OpenHashMap] { * If its `key` is not the default value of type `Key`, the entry is occupied. * If the entry is occupied, `hash` contains the hash value of `key`. */ - final private class OpenEntry[Key, Value](var key: Key, + final private class OpenEntry[sealed Key, sealed Value](var key: Key, var hash: Int, var value: Option[Value]) @@ -61,7 +62,7 @@ object OpenHashMap extends MapFactory[OpenHashMap] { * @define willNotTerminateInf */ @deprecated("Use HashMap or one of the specialized versions (LongMap, AnyRefMap) instead of OpenHashMap", "2.13.0") -class OpenHashMap[Key, Value](initialSize : Int) +class OpenHashMap[sealed Key, sealed Value](initialSize : Int) extends AbstractMap[Key, Value] with MapOps[Key, Value, OpenHashMap, OpenHashMap[Key, Value]] with StrictOptimizedIterableOps[(Key, Value), Iterable, OpenHashMap[Key, Value]] diff --git a/tests/pos-special/stdlib/collection/mutable/PriorityQueue.scala b/tests/pos-special/stdlib/collection/mutable/PriorityQueue.scala index 5572bdca3cf6..a395fac4a44a 100644 --- a/tests/pos-special/stdlib/collection/mutable/PriorityQueue.scala +++ b/tests/pos-special/stdlib/collection/mutable/PriorityQueue.scala @@ -15,6 +15,7 @@ package mutable import scala.collection.generic.DefaultSerializationProxy import scala.math.Ordering +import language.experimental.captureChecking /** A heap-based priority queue. * @@ -66,7 +67,7 @@ import scala.math.Ordering * @define mayNotTerminateInf * @define willNotTerminateInf */ -sealed class PriorityQueue[A](implicit val ord: Ordering[A]) +sealed class PriorityQueue[sealed A](implicit val ord: Ordering[A]) extends AbstractIterable[A] with Iterable[A] with IterableOps[A, Iterable, PriorityQueue[A]] @@ -77,7 +78,7 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A]) with Serializable { - private class ResizableArrayAccess[A0] extends ArrayBuffer[A0] { + private class ResizableArrayAccess[sealed A0] extends ArrayBuffer[A0] { override def mapInPlace(f: A0 => A0): this.type = { var i = 1 // see "we do not use array(0)" comment below (???) val siz = this.size @@ -106,7 +107,7 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A]) override def isEmpty: Boolean = resarr.p_size0 < 2 // not eligible for EvidenceIterableFactoryDefaults since C != CC[A] (PriorityQueue[A] != Iterable[A]) - override protected def fromSpecific(coll: scala.collection.IterableOnce[A]): PriorityQueue[A] = PriorityQueue.from(coll) + override protected def fromSpecific(coll: scala.collection.IterableOnce[A]^): PriorityQueue[A] = PriorityQueue.from(coll) override protected def newSpecificBuilder: Builder[A, PriorityQueue[A]] = PriorityQueue.newBuilder override def empty: PriorityQueue[A] = PriorityQueue.empty @@ -161,7 +162,7 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A]) this } - override def addAll(xs: IterableOnce[A]): this.type = { + override def addAll(xs: IterableOnce[A]^): this.type = { val from = resarr.p_size0 for (x <- xs.iterator) unsafeAdd(x) heapify(from) @@ -364,7 +365,7 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A]) pq } - override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = { + override def copyToArray[sealed B >: A](xs: Array[B], start: Int, len: Int): Int = { val copied = IterableOnce.elemsToCopyToArray(length, xs.length, start, len) if (copied > 0) { Array.copy(resarr.p_array, 1, xs, start, copied) @@ -383,7 +384,7 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A]) @SerialVersionUID(3L) object PriorityQueue extends SortedIterableFactory[PriorityQueue] { - def newBuilder[A : Ordering]: Builder[A, PriorityQueue[A]] = { + def newBuilder[sealed A : Ordering]: Builder[A, PriorityQueue[A]] = { new Builder[A, PriorityQueue[A]] { val pq = new PriorityQueue[A] def addOne(elem: A): this.type = { pq.unsafeAdd(elem); this } @@ -392,9 +393,9 @@ object PriorityQueue extends SortedIterableFactory[PriorityQueue] { } } - def empty[A : Ordering]: PriorityQueue[A] = new PriorityQueue[A] + def empty[sealed A : Ordering]: PriorityQueue[A] = new PriorityQueue[A] - def from[E : Ordering](it: IterableOnce[E]): PriorityQueue[E] = { + def from[sealed E : Ordering](it: IterableOnce[E]^): PriorityQueue[E] = { val b = newBuilder[E] b ++= it b.result() diff --git a/tests/pos-special/stdlib/collection/mutable/Queue.scala b/tests/pos-special/stdlib/collection/mutable/Queue.scala index 18cce0bd3852..a578b0742009 100644 --- a/tests/pos-special/stdlib/collection/mutable/Queue.scala +++ b/tests/pos-special/stdlib/collection/mutable/Queue.scala @@ -15,6 +15,7 @@ package mutable import scala.annotation.nowarn import scala.collection.generic.DefaultSerializable +import language.experimental.captureChecking /** `Queue` objects implement data structures that allow to @@ -27,7 +28,7 @@ import scala.collection.generic.DefaultSerializable * @define mayNotTerminateInf * @define willNotTerminateInf */ -class Queue[A] protected (array: Array[AnyRef], start: Int, end: Int) +class Queue[sealed A] protected (array: Array[AnyRef], start: Int, end: Int) extends ArrayDeque[A](array, start, end) with IndexedSeqOps[A, Queue, Queue[A]] with StrictOptimizedSeqOps[A, Queue, Queue[A]] @@ -129,10 +130,10 @@ class Queue[A] protected (array: Array[AnyRef], start: Int, end: Int) @SerialVersionUID(3L) object Queue extends StrictOptimizedSeqFactory[Queue] { - def from[A](source: IterableOnce[A]): Queue[A] = empty ++= source + def from[sealed A](source: IterableOnce[A]^): Queue[A] = empty ++= source - def empty[A]: Queue[A] = new Queue + def empty[sealed A]: Queue[A] = new Queue - def newBuilder[A]: Builder[A, Queue[A]] = new GrowableBuilder[A, Queue[A]](empty) + def newBuilder[sealed A]: Builder[A, Queue[A]] = new GrowableBuilder[A, Queue[A]](empty) } diff --git a/tests/pos-special/stdlib/collection/mutable/RedBlackTree.scala b/tests/pos-special/stdlib/collection/mutable/RedBlackTree.scala index 3ac0e1a1f797..1f320f832cdf 100644 --- a/tests/pos-special/stdlib/collection/mutable/RedBlackTree.scala +++ b/tests/pos-special/stdlib/collection/mutable/RedBlackTree.scala @@ -16,6 +16,7 @@ package collection.mutable import scala.annotation.tailrec import collection.{AbstractIterator, Iterator} import java.lang.String +import language.experimental.captureChecking /** * An object containing the red-black tree implementation used by mutable `TreeMaps`. @@ -31,25 +32,25 @@ private[collection] object RedBlackTree { // Therefore, while obtaining the size of the whole tree is O(1), knowing the number of entries inside a range is O(n) // on the size of the range. - final class Tree[A, B](var root: Node[A, B], var size: Int) { + final class Tree[sealed A, sealed B](var root: Node[A, B], var size: Int) { def treeCopy(): Tree[A, B] = new Tree(copyTree(root), size) } - final class Node[A, B](var key: A, var value: B, var red: Boolean, var left: Node[A, B], var right: Node[A, B], var parent: Node[A, B]) { + final class Node[sealed A, sealed B](var key: A, var value: B, var red: Boolean, var left: Node[A, B], var right: Node[A, B], var parent: Node[A, B]) { override def toString: String = "Node(" + key + ", " + value + ", " + red + ", " + left + ", " + right + ")" } object Tree { - def empty[A, B]: Tree[A, B] = new Tree(null, 0) + def empty[sealed A, sealed B]: Tree[A, B] = new Tree(null, 0) } object Node { - @`inline` def apply[A, B](key: A, value: B, red: Boolean, + @`inline` def apply[sealed A, sealed B](key: A, value: B, red: Boolean, left: Node[A, B], right: Node[A, B], parent: Node[A, B]): Node[A, B] = new Node(key, value, red, left, right, parent) - @`inline` def leaf[A, B](key: A, value: B, red: Boolean, parent: Node[A, B]): Node[A, B] = + @`inline` def leaf[sealed A, sealed B](key: A, value: B, red: Boolean, parent: Node[A, B]): Node[A, B] = new Node(key, value, red, null, null, parent) def unapply[A, B](t: Node[A, B]) = Some((t.key, t.value, t.left, t.right, t.parent)) @@ -180,7 +181,7 @@ private[collection] object RedBlackTree { // ---- insertion ---- - def insert[A, B](tree: Tree[A, B], key: A, value: B)(implicit ord: Ordering[A]): Unit = { + def insert[sealed A, sealed B](tree: Tree[A, B], key: A, value: B)(implicit ord: Ordering[A]): Unit = { var y: Node[A, B] = null var x = tree.root var cmp = 1 @@ -476,16 +477,16 @@ private[collection] object RedBlackTree { if (node.right ne null) transformNodeNonNull(node.right, f) } - def iterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[(A, B)] = + def iterator[sealed A: Ordering, sealed B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[(A, B)] = new EntriesIterator(tree, start, end) - def keysIterator[A: Ordering](tree: Tree[A, _], start: Option[A] = None, end: Option[A] = None): Iterator[A] = + def keysIterator[sealed A: Ordering](tree: Tree[A, _], start: Option[A] = None, end: Option[A] = None): Iterator[A] = new KeysIterator(tree, start, end) - def valuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[B] = + def valuesIterator[sealed A: Ordering, sealed B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[B] = new ValuesIterator(tree, start, end) - private[this] abstract class TreeIterator[A, B, R](tree: Tree[A, B], start: Option[A], end: Option[A]) + private[this] abstract class TreeIterator[sealed A, sealed B, R](tree: Tree[A, B], start: Option[A], end: Option[A]) (implicit ord: Ordering[A]) extends AbstractIterator[R] { protected def nextResult(node: Node[A, B]): R @@ -513,19 +514,19 @@ private[collection] object RedBlackTree { setNullIfAfterEnd() } - private[this] final class EntriesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A]) + private[this] final class EntriesIterator[sealed A: Ordering, sealed B](tree: Tree[A, B], start: Option[A], end: Option[A]) extends TreeIterator[A, B, (A, B)](tree, start, end) { def nextResult(node: Node[A, B]) = (node.key, node.value) } - private[this] final class KeysIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A]) + private[this] final class KeysIterator[sealed A: Ordering, sealed B](tree: Tree[A, B], start: Option[A], end: Option[A]) extends TreeIterator[A, B, A](tree, start, end) { def nextResult(node: Node[A, B]) = node.key } - private[this] final class ValuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A]) + private[this] final class ValuesIterator[sealed A: Ordering, sealed B](tree: Tree[A, B], start: Option[A], end: Option[A]) extends TreeIterator[A, B, B](tree, start, end) { def nextResult(node: Node[A, B]) = node.value @@ -603,7 +604,7 @@ private[collection] object RedBlackTree { // building /** Build a Tree suitable for a TreeSet from an ordered sequence of keys */ - def fromOrderedKeys[A](xs: Iterator[A], size: Int): Tree[A, Null] = { + def fromOrderedKeys[sealed A](xs: Iterator[A], size: Int): Tree[A, Null] = { val maxUsedDepth = 32 - Integer.numberOfLeadingZeros(size) // maximum depth of non-leaf nodes def f(level: Int, size: Int): Node[A, Null] = size match { case 0 => null @@ -622,7 +623,7 @@ private[collection] object RedBlackTree { } /** Build a Tree suitable for a TreeMap from an ordered sequence of key/value pairs */ - def fromOrderedEntries[A, B](xs: Iterator[(A, B)], size: Int): Tree[A, B] = { + def fromOrderedEntries[sealed A, sealed B](xs: Iterator[(A, B)], size: Int): Tree[A, B] = { val maxUsedDepth = 32 - Integer.numberOfLeadingZeros(size) // maximum depth of non-leaf nodes def f(level: Int, size: Int): Node[A, B] = size match { case 0 => null @@ -642,7 +643,7 @@ private[collection] object RedBlackTree { new Tree(f(1, size), size) } - def copyTree[A, B](n: Node[A, B]): Node[A, B] = + def copyTree[sealed A, sealed B](n: Node[A, B]): Node[A, B] = if(n eq null) null else { val c = new Node(n.key, n.value, n.red, copyTree(n.left), copyTree(n.right), null) if(c.left != null) c.left.parent = c diff --git a/tests/pos-special/stdlib/collection/mutable/ReusableBuilder.scala b/tests/pos-special/stdlib/collection/mutable/ReusableBuilder.scala index d7d3b6db4f09..246e525e37d9 100644 --- a/tests/pos-special/stdlib/collection/mutable/ReusableBuilder.scala +++ b/tests/pos-special/stdlib/collection/mutable/ReusableBuilder.scala @@ -14,6 +14,7 @@ package scala package collection package mutable +import language.experimental.captureChecking /** `ReusableBuilder` is a marker trait that indicates that a `Builder` * can be reused to build more than one instance of a collection. In diff --git a/tests/pos-special/stdlib/collection/mutable/Seq.scala b/tests/pos-special/stdlib/collection/mutable/Seq.scala index e83d79987208..443eec379c1b 100644 --- a/tests/pos-special/stdlib/collection/mutable/Seq.scala +++ b/tests/pos-special/stdlib/collection/mutable/Seq.scala @@ -13,6 +13,7 @@ package scala.collection.mutable import scala.collection.{IterableFactoryDefaults, SeqFactory} +import language.experimental.captureChecking trait Seq[A] extends Iterable[A] diff --git a/tests/pos-special/stdlib/collection/mutable/SeqMap.scala b/tests/pos-special/stdlib/collection/mutable/SeqMap.scala index 67066f99e07e..5740490223b2 100644 --- a/tests/pos-special/stdlib/collection/mutable/SeqMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/SeqMap.scala @@ -13,6 +13,7 @@ package scala package collection package mutable +import language.experimental.captureChecking /** * A generic trait for ordered mutable maps. Concrete classes have to provide diff --git a/tests/pos-special/stdlib/collection/mutable/Set.scala b/tests/pos-special/stdlib/collection/mutable/Set.scala index 6530e8fedf05..01384e993e89 100644 --- a/tests/pos-special/stdlib/collection/mutable/Set.scala +++ b/tests/pos-special/stdlib/collection/mutable/Set.scala @@ -13,6 +13,7 @@ package scala.collection.mutable import scala.collection.{IterableFactory, IterableFactoryDefaults, IterableOps} +import language.experimental.captureChecking /** Base trait for mutable sets */ trait Set[A] diff --git a/tests/pos-special/stdlib/collection/mutable/Shrinkable.scala b/tests/pos-special/stdlib/collection/mutable/Shrinkable.scala index 006a3b88e49f..de2a24ecf01f 100644 --- a/tests/pos-special/stdlib/collection/mutable/Shrinkable.scala +++ b/tests/pos-special/stdlib/collection/mutable/Shrinkable.scala @@ -14,6 +14,7 @@ package scala package collection.mutable import scala.annotation.tailrec +import language.experimental.captureChecking /** This trait forms part of collections that can be reduced * using a `-=` operator. @@ -52,7 +53,7 @@ trait Shrinkable[-A] { * @param xs the iterator producing the elements to remove. * @return the $coll itself */ - def subtractAll(xs: collection.IterableOnce[A]): this.type = { + def subtractAll(xs: collection.IterableOnce[A]^): this.type = { @tailrec def loop(xs: collection.LinearSeq[A]): Unit = { if (xs.nonEmpty) { subtractOne(xs.head) @@ -74,6 +75,6 @@ trait Shrinkable[-A] { } /** Alias for `subtractAll` */ - @`inline` final def --= (xs: collection.IterableOnce[A]): this.type = subtractAll(xs) + @`inline` final def --= (xs: collection.IterableOnce[A]^): this.type = subtractAll(xs) } diff --git a/tests/pos-special/stdlib/collection/mutable/SortedMap.scala b/tests/pos-special/stdlib/collection/mutable/SortedMap.scala index eb2f0d231b7a..8017177f5720 100644 --- a/tests/pos-special/stdlib/collection/mutable/SortedMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/SortedMap.scala @@ -14,6 +14,7 @@ package scala package collection.mutable import scala.collection.{SortedMapFactory, SortedMapFactoryDefaults} +import language.experimental.captureChecking /** * Base type for mutable sorted map collections @@ -37,7 +38,7 @@ trait SortedMap[K, V] * @param d the function mapping keys to values, used for non-present keys * @return a wrapper of the map with a default value */ - override def withDefault(d: K => V): SortedMap[K, V] = new SortedMap.WithDefault[K, V](this, d) + override def withDefault(d: K -> V): SortedMap[K, V] = new SortedMap.WithDefault[K, V](this, d) /** The same map with a given default value. * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc. @@ -66,7 +67,7 @@ trait SortedMapOps[K, V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], object SortedMap extends SortedMapFactory.Delegate[SortedMap](TreeMap) { @SerialVersionUID(3L) - final class WithDefault[K, V](underlying: SortedMap[K, V], defaultValue: K => V) + final class WithDefault[K, V](underlying: SortedMap[K, V], defaultValue: K -> V) extends Map.WithDefault[K, V](underlying, defaultValue) with SortedMap[K, V] with SortedMapOps[K, V, SortedMap, WithDefault[K, V]] @@ -91,10 +92,10 @@ object SortedMap extends SortedMapFactory.Delegate[SortedMap](TreeMap) { override def empty: WithDefault[K, V] = new WithDefault[K, V](underlying.empty, defaultValue) - override def concat[V2 >: V](suffix: collection.IterableOnce[(K, V2)]): SortedMap[K, V2] = + override def concat[V2 >: V](suffix: collection.IterableOnce[(K, V2)]^): SortedMap[K, V2] = underlying.concat(suffix).withDefault(defaultValue) - override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)]): WithDefault[K, V] = + override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)]^): WithDefault[K, V] = new WithDefault[K, V](sortedMapFactory.from(coll), defaultValue) override protected def newSpecificBuilder: Builder[(K, V), WithDefault[K, V]] = diff --git a/tests/pos-special/stdlib/collection/mutable/SortedSet.scala b/tests/pos-special/stdlib/collection/mutable/SortedSet.scala index 2bcb8dc7845a..e657fb749d7d 100644 --- a/tests/pos-special/stdlib/collection/mutable/SortedSet.scala +++ b/tests/pos-special/stdlib/collection/mutable/SortedSet.scala @@ -13,6 +13,7 @@ package scala package collection package mutable +import language.experimental.captureChecking /** * Base type for mutable sorted set collections diff --git a/tests/pos-special/stdlib/collection/mutable/Stack.scala b/tests/pos-special/stdlib/collection/mutable/Stack.scala index 675666bc805c..4efa9621f374 100644 --- a/tests/pos-special/stdlib/collection/mutable/Stack.scala +++ b/tests/pos-special/stdlib/collection/mutable/Stack.scala @@ -16,6 +16,8 @@ import scala.annotation.{migration, nowarn} import scala.collection.generic.DefaultSerializable import scala.collection.{IterableFactoryDefaults, IterableOnce, SeqFactory, StrictOptimizedSeqFactory, StrictOptimizedSeqOps} +import language.experimental.captureChecking + /** A stack implements a data structure which allows to store and retrieve * objects in a last-in-first-out (LIFO) fashion. * @@ -33,7 +35,7 @@ import scala.collection.{IterableFactoryDefaults, IterableOnce, SeqFactory, Stri * @define willNotTerminateInf */ @migration("Stack is now based on an ArrayDeque instead of a linked list", "2.13.0") -class Stack[A] protected (array: Array[AnyRef], start: Int, end: Int) +class Stack[sealed A] protected (array: Array[AnyRef], start: Int, end: Int) extends ArrayDeque[A](array, start, end) with IndexedSeqOps[A, Stack, Stack[A]] with StrictOptimizedSeqOps[A, Stack, Stack[A]] @@ -133,10 +135,10 @@ class Stack[A] protected (array: Array[AnyRef], start: Int, end: Int) @SerialVersionUID(3L) object Stack extends StrictOptimizedSeqFactory[Stack] { - def from[A](source: IterableOnce[A]): Stack[A] = empty ++= source + def from[sealed A](source: IterableOnce[A]^): Stack[A] = empty ++= source - def empty[A]: Stack[A] = new Stack + def empty[sealed A]: Stack[A] = new Stack - def newBuilder[A]: Builder[A, Stack[A]] = new GrowableBuilder[A, Stack[A]](empty) + def newBuilder[sealed A]: Builder[A, Stack[A]] = new GrowableBuilder[A, Stack[A]](empty) } diff --git a/tests/pos-special/stdlib/collection/mutable/StringBuilder.scala b/tests/pos-special/stdlib/collection/mutable/StringBuilder.scala index 1d8b9563e917..5320fa1dabb0 100644 --- a/tests/pos-special/stdlib/collection/mutable/StringBuilder.scala +++ b/tests/pos-special/stdlib/collection/mutable/StringBuilder.scala @@ -14,6 +14,7 @@ package scala.collection.mutable import scala.collection.{IterableFactoryDefaults, IterableOnce} import scala.collection.immutable.WrappedString +import language.experimental.captureChecking import scala.Predef.{ // unimport char-related implicit conversions to avoid triggering them accidentally genericArrayOps => _, @@ -81,7 +82,7 @@ final class StringBuilder(val underlying: java.lang.StringBuilder) extends Abstr // Methods required to make this an IndexedSeq: def apply(i: Int): Char = underlying.charAt(i) - override protected def fromSpecific(coll: scala.collection.IterableOnce[Char]): StringBuilder = + override protected def fromSpecific(coll: scala.collection.IterableOnce[Char]^): StringBuilder = new StringBuilder() appendAll coll override protected def newSpecificBuilder: Builder[Char, StringBuilder] = @@ -109,7 +110,7 @@ final class StringBuilder(val underlying: java.lang.StringBuilder) extends Abstr override def toString: String = result() - override def toArray[B >: Char](implicit ct: scala.reflect.ClassTag[B]) = + override def toArray[sealed B >: Char](implicit ct: scala.reflect.ClassTag[B]) = ct.runtimeClass match { case java.lang.Character.TYPE => toCharArray.asInstanceOf[Array[B]] case _ => super.toArray @@ -184,7 +185,7 @@ final class StringBuilder(val underlying: java.lang.StringBuilder) extends Abstr * @param xs the characters to be appended. * @return this StringBuilder. */ - def appendAll(xs: IterableOnce[Char]): this.type = { + def appendAll(xs: IterableOnce[Char]^): this.type = { xs match { case x: WrappedString => underlying append x.unwrap case x: ArraySeq.ofChar => underlying append x.array @@ -313,7 +314,7 @@ final class StringBuilder(val underlying: java.lang.StringBuilder) extends Abstr * @return this StringBuilder. * @throws StringIndexOutOfBoundsException if the index is out of bounds. */ - def insertAll(index: Int, xs: IterableOnce[Char]): this.type = + def insertAll(index: Int, xs: IterableOnce[Char]^): this.type = insertAll(index, (ArrayBuilder.make[Char] ++= xs).result()) /** Inserts the given Array[Char] into this sequence at the given index. diff --git a/tests/pos-special/stdlib/collection/mutable/TreeMap.scala b/tests/pos-special/stdlib/collection/mutable/TreeMap.scala index 1af968a08ac3..f714a9ed46c2 100644 --- a/tests/pos-special/stdlib/collection/mutable/TreeMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/TreeMap.scala @@ -17,6 +17,7 @@ package mutable import scala.collection.Stepper.EfficientSplit import scala.collection.generic.DefaultSerializable import scala.collection.mutable.{RedBlackTree => RB} +import language.experimental.captureChecking /** * A mutable sorted map implemented using a mutable red-black tree as underlying data structure. @@ -28,7 +29,7 @@ import scala.collection.mutable.{RedBlackTree => RB} * @define Coll mutable.TreeMap * @define coll mutable tree map */ -sealed class TreeMap[K, V] private (tree: RB.Tree[K, V])(implicit val ordering: Ordering[K]) +sealed class TreeMap[sealed K, sealed V] private (tree: RB.Tree[K, V])(implicit val ordering: Ordering[K]) extends AbstractMap[K, V] with SortedMap[K, V] with SortedMapOps[K, V, TreeMap, TreeMap[K, V]] @@ -247,11 +248,11 @@ sealed class TreeMap[K, V] private (tree: RB.Tree[K, V])(implicit val ordering: @SerialVersionUID(3L) object TreeMap extends SortedMapFactory[TreeMap] { - def from[K : Ordering, V](it: IterableOnce[(K, V)]): TreeMap[K, V] = + def from[sealed K : Ordering, sealed V](it: IterableOnce[(K, V)]^): TreeMap[K, V] = Growable.from(empty[K, V], it) - def empty[K : Ordering, V]: TreeMap[K, V] = new TreeMap[K, V]() + def empty[sealed K : Ordering, sealed V]: TreeMap[K, V] = new TreeMap[K, V]() - def newBuilder[K: Ordering, V]: Builder[(K, V), TreeMap[K, V]] = new GrowableBuilder(empty[K, V]) + def newBuilder[sealed K: Ordering, sealed V]: Builder[(K, V), TreeMap[K, V]] = new GrowableBuilder(empty[K, V]) } diff --git a/tests/pos-special/stdlib/collection/mutable/TreeSet.scala b/tests/pos-special/stdlib/collection/mutable/TreeSet.scala index bed474dc02a3..9ba439bea041 100644 --- a/tests/pos-special/stdlib/collection/mutable/TreeSet.scala +++ b/tests/pos-special/stdlib/collection/mutable/TreeSet.scala @@ -17,6 +17,7 @@ import scala.collection.Stepper.EfficientSplit import scala.collection.generic.DefaultSerializable import scala.collection.mutable.{RedBlackTree => RB} import scala.collection.{SortedIterableFactory, SortedSetFactoryDefaults, Stepper, StepperShape, StrictOptimizedIterableOps, StrictOptimizedSortedSetOps, mutable} +import language.experimental.captureChecking /** * A mutable sorted set implemented using a mutable red-black tree as underlying data structure. @@ -28,7 +29,7 @@ import scala.collection.{SortedIterableFactory, SortedSetFactoryDefaults, Steppe * @define coll mutable tree set */ // Original API designed in part by Lucien Pereira -sealed class TreeSet[A] private (private val tree: RB.Tree[A, Null])(implicit val ordering: Ordering[A]) +sealed class TreeSet[sealed A] private (private val tree: RB.Tree[A, Null])(implicit val ordering: Ordering[A]) extends AbstractSet[A] with SortedSet[A] with SortedSetOps[A, TreeSet, TreeSet[A]] @@ -191,9 +192,9 @@ sealed class TreeSet[A] private (private val tree: RB.Tree[A, Null])(implicit va @SerialVersionUID(3L) object TreeSet extends SortedIterableFactory[TreeSet] { - def empty[A : Ordering]: TreeSet[A] = new TreeSet[A]() + def empty[sealed A : Ordering]: TreeSet[A] = new TreeSet[A]() - def from[E](it: IterableOnce[E])(implicit ordering: Ordering[E]): TreeSet[E] = + def from[sealed E](it: IterableOnce[E]^)(implicit ordering: Ordering[E]): TreeSet[E] = it match { case ts: TreeSet[E] if ordering == ts.ordering => new TreeSet[E](ts.tree.treeCopy()) @@ -209,7 +210,7 @@ object TreeSet extends SortedIterableFactory[TreeSet] { new TreeSet[E](t) } - def newBuilder[A](implicit ordering: Ordering[A]): Builder[A, TreeSet[A]] = new ReusableBuilder[A, TreeSet[A]] { + def newBuilder[sealed A](implicit ordering: Ordering[A]): Builder[A, TreeSet[A]] = new ReusableBuilder[A, TreeSet[A]] { private[this] var tree: RB.Tree[A, Null] = RB.Tree.empty def addOne(elem: A): this.type = { RB.insert(tree, elem, null); this } def result(): TreeSet[A] = new TreeSet[A](tree) diff --git a/tests/pos-special/stdlib/collection/mutable/UnrolledBuffer.scala b/tests/pos-special/stdlib/collection/mutable/UnrolledBuffer.scala index 489f2a1b0387..2015b76a31b8 100644 --- a/tests/pos-special/stdlib/collection/mutable/UnrolledBuffer.scala +++ b/tests/pos-special/stdlib/collection/mutable/UnrolledBuffer.scala @@ -17,6 +17,7 @@ import scala.annotation.tailrec import scala.collection.generic.DefaultSerializable import scala.reflect.ClassTag import scala.collection.immutable.Nil +import language.experimental.captureChecking /** A buffer that stores elements in an unrolled linked list. * @@ -45,7 +46,7 @@ import scala.collection.immutable.Nil * */ @SerialVersionUID(3L) -sealed class UnrolledBuffer[T](implicit val tag: ClassTag[T]) +sealed class UnrolledBuffer[sealed T](implicit val tag: ClassTag[T]) extends AbstractBuffer[T] with Buffer[T] with Seq[T] @@ -190,7 +191,7 @@ sealed class UnrolledBuffer[T](implicit val tag: ClassTag[T]) def insert(idx: Int, elem: T): Unit = insertAll(idx, elem :: Nil) - def insertAll(idx: Int, elems: IterableOnce[T]): Unit = + def insertAll(idx: Int, elems: IterableOnce[T]^): Unit = if (idx >= 0 && idx <= sz) { sz += headptr.insertAll(idx, elems, this) } else throw new IndexOutOfBoundsException(s"$idx is out of bounds (min 0, max ${sz-1})") @@ -202,7 +203,7 @@ sealed class UnrolledBuffer[T](implicit val tag: ClassTag[T]) this } - def patchInPlace(from: Int, patch: collection.IterableOnce[T], replaced: Int): this.type = { + def patchInPlace(from: Int, patch: collection.IterableOnce[T]^, replaced: Int): this.type = { remove(from, replaced) insertAll(from, patch) this @@ -240,11 +241,11 @@ object UnrolledBuffer extends StrictOptimizedClassTagSeqFactory[UnrolledBuffer] val untagged: SeqFactory[UnrolledBuffer] = new ClassTagSeqFactory.AnySeqDelegate(self) - def empty[A : ClassTag]: UnrolledBuffer[A] = new UnrolledBuffer[A] + def empty[sealed A : ClassTag]: UnrolledBuffer[A] = new UnrolledBuffer[A] - def from[A : ClassTag](source: scala.collection.IterableOnce[A]): UnrolledBuffer[A] = newBuilder[A].addAll(source) + def from[sealed A : ClassTag](source: scala.collection.IterableOnce[A]^): UnrolledBuffer[A] = newBuilder[A].addAll(source) - def newBuilder[A : ClassTag]: UnrolledBuffer[A] = new UnrolledBuffer[A] + def newBuilder[sealed A : ClassTag]: UnrolledBuffer[A] = new UnrolledBuffer[A] final val waterline: Int = 50 @@ -257,7 +258,7 @@ object UnrolledBuffer extends StrictOptimizedClassTagSeqFactory[UnrolledBuffer] /** Unrolled buffer node. */ - class Unrolled[T: ClassTag] private[collection] (var size: Int, var array: Array[T], var next: Unrolled[T], val buff: UnrolledBuffer[T] = null) { + class Unrolled[sealed T: ClassTag] private[collection] (var size: Int, var array: Array[T], var next: Unrolled[T], val buff: UnrolledBuffer[T] = null) { private[collection] def this() = this(0, new Array[T](unrolledlength), null, null) private[collection] def this(b: UnrolledBuffer[T]) = this(0, new Array[T](unrolledlength), null, b) @@ -372,7 +373,7 @@ object UnrolledBuffer extends StrictOptimizedClassTagSeqFactory[UnrolledBuffer] if (next eq null) true else false // checks if last node was thrown out } else false - @tailrec final def insertAll(idx: Int, t: scala.collection.IterableOnce[T], buffer: UnrolledBuffer[T]): Int = { + @tailrec final def insertAll(idx: Int, t: scala.collection.IterableOnce[T]^, buffer: UnrolledBuffer[T]): Int = { if (idx < size) { // divide this node at the appropriate position and insert all into head // update new next @@ -436,7 +437,7 @@ object UnrolledBuffer extends StrictOptimizedClassTagSeqFactory[UnrolledBuffer] // This is used by scala.collection.parallel.mutable.UnrolledParArrayCombiner: // Todo -- revisit whether inheritance is the best way to achieve this functionality -private[collection] class DoublingUnrolledBuffer[T](implicit t: ClassTag[T]) extends UnrolledBuffer[T]()(t) { +private[collection] class DoublingUnrolledBuffer[sealed T](implicit t: ClassTag[T]) extends UnrolledBuffer[T]()(t) { override def calcNextLength(sz: Int) = if (sz < 10000) sz * 2 else sz override protected def newUnrolled = new UnrolledBuffer.Unrolled[T](0, new Array[T](4), null, this) } diff --git a/tests/pos-special/stdlib/collection/mutable/WeakHashMap.scala b/tests/pos-special/stdlib/collection/mutable/WeakHashMap.scala index 7286a318e1f9..a9498b7fc69b 100644 --- a/tests/pos-special/stdlib/collection/mutable/WeakHashMap.scala +++ b/tests/pos-special/stdlib/collection/mutable/WeakHashMap.scala @@ -16,6 +16,7 @@ package mutable import scala.annotation.nowarn import scala.collection.convert.JavaCollectionWrappers.{JMapWrapper, JMapWrapperLike} +import language.experimental.captureChecking /** A hash map with references to entries which are weakly reachable. Entries are * removed from this map when the key is no longer (strongly) referenced. This class wraps @@ -33,7 +34,7 @@ import scala.collection.convert.JavaCollectionWrappers.{JMapWrapper, JMapWrapper * @define willNotTerminateInf */ @SerialVersionUID(3L) -class WeakHashMap[K, V] extends JMapWrapper[K, V](new java.util.WeakHashMap) +class WeakHashMap[sealed K, sealed V] extends JMapWrapper[K, V](new java.util.WeakHashMap) with JMapWrapperLike[K, V, WeakHashMap, WeakHashMap[K, V]] with MapFactoryDefaults[K, V, WeakHashMap, Iterable] { override def empty = new WeakHashMap[K, V] @@ -48,8 +49,8 @@ class WeakHashMap[K, V] extends JMapWrapper[K, V](new java.util.WeakHashMap) */ @SerialVersionUID(3L) object WeakHashMap extends MapFactory[WeakHashMap] { - def empty[K, V]: WeakHashMap[K,V] = new WeakHashMap[K, V] - def from[K, V](it: collection.IterableOnce[(K, V)]): WeakHashMap[K,V] = Growable.from(empty[K, V], it) - def newBuilder[K, V]: Builder[(K, V), WeakHashMap[K,V]] = new GrowableBuilder(WeakHashMap.empty[K, V]) + def empty[sealed K, sealed V]: WeakHashMap[K,V] = new WeakHashMap[K, V] + def from[sealed K, sealed V](it: collection.IterableOnce[(K, V)]^): WeakHashMap[K,V] = Growable.from(empty[K, V], it) + def newBuilder[sealed K, sealed V]: Builder[(K, V), WeakHashMap[K,V]] = new GrowableBuilder(WeakHashMap.empty[K, V]) } diff --git a/tests/pos-special/stdlib/collection/mutable/package.scala b/tests/pos-special/stdlib/collection/mutable/package.scala index 4915e8a48b22..d658ca5bc65a 100644 --- a/tests/pos-special/stdlib/collection/mutable/package.scala +++ b/tests/pos-special/stdlib/collection/mutable/package.scala @@ -11,6 +11,7 @@ */ package scala.collection +import language.experimental.captureChecking package object mutable { diff --git a/tests/pos-special/stdlib/collection/package.scala b/tests/pos-special/stdlib/collection/package.scala index 954573ff1ddd..ad4686be1fb2 100644 --- a/tests/pos-special/stdlib/collection/package.scala +++ b/tests/pos-special/stdlib/collection/package.scala @@ -11,6 +11,7 @@ */ package scala +import language.experimental.captureChecking package object collection { @deprecated("Use Iterable instead of Traversable", "2.13.0")