Skip to content

Commit 9f231fb

Browse files
committed
Capture checked versions of Iterator and IterableOnce
1 parent bdd6e9d commit 9f231fb

File tree

6 files changed

+150
-110
lines changed

6 files changed

+150
-110
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
collection/IterableOnce.scala
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
collection/Iterator.scala

tests/pos-custom-args/captures/stdlib/collection/IterableOnce.scala

Lines changed: 65 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import scala.language.implicitConversions
2020
import scala.math.{Numeric, Ordering}
2121
import scala.reflect.ClassTag
2222
import scala.runtime.AbstractFunction2
23+
import language.experimental.captureChecking
2324

2425
/**
2526
* A template trait for collections which can be traversed either once only
@@ -42,8 +43,10 @@ import scala.runtime.AbstractFunction2
4243
* @define coll collection
4344
*/
4445
trait IterableOnce[+A] extends Any {
46+
this: IterableOnce[A]^ =>
47+
4548
/** Iterator can be used only once */
46-
def iterator: Iterator[A]
49+
def iterator: Iterator[A]^{this}
4750

4851
/** Returns a [[scala.collection.Stepper]] for the elements of this collection.
4952
*
@@ -65,9 +68,9 @@ trait IterableOnce[+A] extends Any {
6568
* allow creating parallel streams, whereas bare Steppers can be converted only to sequential
6669
* streams.
6770
*/
68-
def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S = {
71+
def stepper[S <: Stepper[_]^{this}](implicit shape: StepperShape[A, S]): S = {
6972
import convert.impl._
70-
val s = shape.shape match {
73+
val s: Any = shape.shape match {
7174
case StepperShape.IntShape => new IntIteratorStepper (iterator.asInstanceOf[Iterator[Int]])
7275
case StepperShape.LongShape => new LongIteratorStepper (iterator.asInstanceOf[Iterator[Long]])
7376
case StepperShape.DoubleShape => new DoubleIteratorStepper(iterator.asInstanceOf[Iterator[Double]])
@@ -84,7 +87,7 @@ trait IterableOnce[+A] extends Any {
8487

8588
final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) extends AnyVal {
8689
@deprecated("Use .iterator.withFilter(...) instead", "2.13.0")
87-
def withFilter(f: A => Boolean): Iterator[A] = it.iterator.withFilter(f)
90+
def withFilter(f: A => Boolean): Iterator[A]^{f} = it.iterator.withFilter(f)
8891

8992
@deprecated("Use .iterator.reduceLeftOption(...) instead", "2.13.0")
9093
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
102105
def reduceRight(f: (A, A) => A): A = it.iterator.reduceRight(f)
103106

104107
@deprecated("Use .iterator.maxBy(...) instead", "2.13.0")
105-
def maxBy[B](f: A => B)(implicit cmp: Ordering[B]): A = it.iterator.maxBy(f)
108+
def maxBy[B](f: A -> B)(implicit cmp: Ordering[B]): A = it.iterator.maxBy(f)
106109

107110
@deprecated("Use .iterator.reduceLeft(...) instead", "2.13.0")
108111
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
120123
def reduceOption(f: (A, A) => A): Option[A] = it.iterator.reduceOption(f)
121124

122125
@deprecated("Use .iterator.minBy(...) instead", "2.13.0")
123-
def minBy[B](f: A => B)(implicit cmp: Ordering[B]): A = it.iterator.minBy(f)
126+
def minBy[B](f: A -> B)(implicit cmp: Ordering[B]): A = it.iterator.minBy(f)
124127

125128
@deprecated("Use .iterator.size instead", "2.13.0")
126129
def size: Int = it.iterator.size
@@ -132,7 +135,7 @@ final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) ext
132135
def collectFirst[B](f: PartialFunction[A, B]): Option[B] = it.iterator.collectFirst(f)
133136

134137
@deprecated("Use .iterator.filter(...) instead", "2.13.0")
135-
def filter(f: A => Boolean): Iterator[A] = it.iterator.filter(f)
138+
def filter(f: A => Boolean): Iterator[A]^{f} = it.iterator.filter(f)
136139

137140
@deprecated("Use .iterator.exists(...) instead", "2.13.0")
138141
def exists(f: A => Boolean): Boolean = it.iterator.exists(f)
@@ -238,13 +241,13 @@ final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) ext
238241
@`inline` def :\ [B](z: B)(op: (A, B) => B): B = foldRight[B](z)(op)
239242

240243
@deprecated("Use .iterator.map instead or consider requiring an Iterable", "2.13.0")
241-
def map[B](f: A => B): IterableOnce[B] = it match {
244+
def map[B](f: A => B): IterableOnce[B]^{f} = it match {
242245
case it: Iterable[A] => it.map(f)
243246
case _ => it.iterator.map(f)
244247
}
245248

246249
@deprecated("Use .iterator.flatMap instead or consider requiring an Iterable", "2.13.0")
247-
def flatMap[B](f: A => IterableOnce[B]): IterableOnce[B] = it match {
250+
def flatMap[B](f: A => IterableOnce[B]): IterableOnce[B]^{f} = it match {
248251
case it: Iterable[A] => it.flatMap(f)
249252
case _ => it.iterator.flatMap(f)
250253
}
@@ -315,9 +318,11 @@ object IterableOnce {
315318
* @define coll collection
316319
*
317320
*/
318-
trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
321+
trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A]^ =>
319322
/////////////////////////////////////////////////////////////// Abstract methods that must be implemented
320323

324+
import IterableOnceOps.Maximized
325+
321326
/** Produces a $coll containing cumulative results of applying the
322327
* operator going left to right, including the initial value.
323328
*
@@ -329,23 +334,23 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
329334
* @param op the binary operator applied to the intermediate result and the element
330335
* @return collection with intermediate results
331336
*/
332-
def scanLeft[B](z: B)(op: (B, A) => B): CC[B]
337+
def scanLeft[B](z: B)(op: (B, A) => B): CC[B]^{this, op}
333338

334339
/** Selects all elements of this $coll which satisfy a predicate.
335340
*
336341
* @param p the predicate used to test elements.
337342
* @return a new $coll consisting of all elements of this $coll that satisfy the given
338343
* predicate `p`. The order of the elements is preserved.
339344
*/
340-
def filter(p: A => Boolean): C
345+
def filter(p: A => Boolean): C^{this, p}
341346

342347
/** Selects all elements of this $coll which do not satisfy a predicate.
343348
*
344349
* @param pred the predicate used to test elements.
345350
* @return a new $coll consisting of all elements of this $coll that do not satisfy the given
346351
* predicate `pred`. Their order may not be preserved.
347352
*/
348-
def filterNot(pred: A => Boolean): C
353+
def filterNot(p: A => Boolean): C^{this, p}
349354

350355
/** Selects the first ''n'' elements.
351356
* $orderDependent
@@ -354,15 +359,15 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
354359
* or else the whole $coll, if it has less than `n` elements.
355360
* If `n` is negative, returns an empty $coll.
356361
*/
357-
def take(n: Int): C
362+
def take(n: Int): C^{this}
358363

359364
/** Takes longest prefix of elements that satisfy a predicate.
360365
* $orderDependent
361366
* @param p The predicate used to test elements.
362367
* @return the longest prefix of this $coll whose elements all satisfy
363368
* the predicate `p`.
364369
*/
365-
def takeWhile(p: A => Boolean): C
370+
def takeWhile(p: A => Boolean): C^{this, p}
366371

367372
/** Selects all elements except first ''n'' ones.
368373
* $orderDependent
@@ -371,15 +376,15 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
371376
* empty $coll, if this $coll has less than `n` elements.
372377
* If `n` is negative, don't drop any elements.
373378
*/
374-
def drop(n: Int): C
379+
def drop(n: Int): C^{this}
375380

376381
/** Drops longest prefix of elements that satisfy a predicate.
377382
* $orderDependent
378383
* @param p The predicate used to test elements.
379384
* @return the longest suffix of this $coll whose first element
380385
* does not satisfy the predicate `p`.
381386
*/
382-
def dropWhile(p: A => Boolean): C
387+
def dropWhile(p: A => Boolean): C^{this, p}
383388

384389
/** Selects an interval of elements. The returned $coll is made up
385390
* of all elements `x` which satisfy the invariant:
@@ -394,7 +399,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
394399
* index `from` extending up to (but not including) index `until`
395400
* of this $coll.
396401
*/
397-
def slice(from: Int, until: Int): C
402+
def slice(from: Int, until: Int): C^{this}
398403

399404
/** Builds a new $coll by applying a function to all elements of this $coll.
400405
*
@@ -403,7 +408,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
403408
* @return a new $coll resulting from applying the given function
404409
* `f` to each element of this $coll and collecting the results.
405410
*/
406-
def map[B](f: A => B): CC[B]
411+
def map[B](f: A => B): CC[B]^{this, f}
407412

408413
/** Builds a new $coll by applying a function to all elements of this $coll
409414
* and using the elements of the resulting collections.
@@ -436,7 +441,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
436441
* @return a new $coll resulting from applying the given collection-valued function
437442
* `f` to each element of this $coll and concatenating the results.
438443
*/
439-
def flatMap[B](f: A => IterableOnce[B]): CC[B]
444+
def flatMap[B](f: A => IterableOnce[B]): CC[B]^{this, f}
440445

441446
/** Converts this $coll of iterable collections into
442447
* a $coll formed by the elements of these iterable
@@ -464,7 +469,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
464469
* type of this $coll is an `Iterable`.
465470
* @return a new $coll resulting from concatenating all element ${coll}s.
466471
*/
467-
def flatten[B](implicit asIterable: A => IterableOnce[B]): CC[B]
472+
def flatten[B](implicit asIterable: A -> IterableOnce[B]): CC[B]^{this}
468473

469474
/** Builds a new $coll by applying a partial function to all elements of this $coll
470475
* on which the function is defined.
@@ -475,7 +480,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
475480
* `pf` to each element on which it is defined and collecting the results.
476481
* The order of the elements is preserved.
477482
*/
478-
def collect[B](pf: PartialFunction[A, B]): CC[B]
483+
def collect[B](pf: PartialFunction[A, B]^): CC[B]^{this, pf}
479484

480485
/** Zips this $coll with its indices.
481486
*
@@ -484,7 +489,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
484489
* @example
485490
* `List("a", "b", "c").zipWithIndex == List(("a", 0), ("b", 1), ("c", 2))`
486491
*/
487-
def zipWithIndex: CC[(A @uncheckedVariance, Int)]
492+
def zipWithIndex: CC[(A @uncheckedVariance, Int)]^{this}
488493

489494
/** Splits this $coll into a prefix/suffix pair according to a predicate.
490495
*
@@ -497,7 +502,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
497502
* @return a pair consisting of the longest prefix of this $coll whose
498503
* elements all satisfy `p`, and the rest of this $coll.
499504
*/
500-
def span(p: A => Boolean): (C, C)
505+
def span(p: A => Boolean): (C^{this, p}, C^{this, p})
501506

502507
/** Splits this $coll into a prefix/suffix pair at a given position.
503508
*
@@ -509,7 +514,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
509514
* @return a pair of ${coll}s consisting of the first `n`
510515
* elements of this $coll, and the other elements.
511516
*/
512-
def splitAt(n: Int): (C, C) = {
517+
def splitAt(n: Int): (C^{this}, C^{this}) = {
513518
class Spanner extends runtime.AbstractFunction1[A, Boolean] {
514519
var i = 0
515520
def apply(a: A) = i < n && { i += 1 ; true }
@@ -527,7 +532,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
527532
* @tparam U the return type of f
528533
* @return The same logical collection as this
529534
*/
530-
def tapEach[U](f: A => U): C
535+
def tapEach[U](f: A => U): C^{this, f}
531536

532537
/////////////////////////////////////////////////////////////// Concrete methods based on iterator
533538

@@ -802,7 +807,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
802807
case _ => Some(reduceLeft(op))
803808
}
804809
private final def reduceLeftOptionIterator[B >: A](op: (B, A) => B): Option[B] = reduceOptionIterator[A, B](iterator)(op)
805-
private final def reduceOptionIterator[X >: A, B >: X](it: Iterator[X])(op: (B, X) => B): Option[B] = {
810+
private final def reduceOptionIterator[X >: A, B >: X](it: Iterator[X]^)(op: (B, X) => B): Option[B] = {
806811
if (it.hasNext) {
807812
var acc: B = it.next()
808813
while (it.hasNext)
@@ -1041,35 +1046,12 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
10411046
* @return the first element of this $coll with the largest value measured by function f
10421047
* with respect to the ordering `cmp`.
10431048
*/
1044-
def maxBy[B](f: A => B)(implicit ord: Ordering[B]): A =
1049+
def maxBy[B](f: A -> B)(implicit ord: Ordering[B]): A =
10451050
knownSize match {
10461051
case 0 => throw new UnsupportedOperationException("empty.maxBy")
10471052
case _ => foldLeft(new Maximized[A, B]("maxBy")(f)(ord.gt))((m, a) => m(m, a)).result
10481053
}
10491054

1050-
private class Maximized[X, B](descriptor: String)(f: X => B)(cmp: (B, B) => Boolean) extends AbstractFunction2[Maximized[X, B], X, Maximized[X, B]] {
1051-
var maxElem: X = null.asInstanceOf[X]
1052-
var maxF: B = null.asInstanceOf[B]
1053-
var nonEmpty = false
1054-
def toOption: Option[X] = if (nonEmpty) Some(maxElem) else None
1055-
def result: X = if (nonEmpty) maxElem else throw new UnsupportedOperationException(s"empty.$descriptor")
1056-
def apply(m: Maximized[X, B], a: X): Maximized[X, B] =
1057-
if (m.nonEmpty) {
1058-
val fa = f(a)
1059-
if (cmp(fa, maxF)) {
1060-
maxF = fa
1061-
maxElem = a
1062-
}
1063-
m
1064-
}
1065-
else {
1066-
m.nonEmpty = true
1067-
m.maxElem = a
1068-
m.maxF = f(a)
1069-
m
1070-
}
1071-
}
1072-
10731055
/** Finds the first element which yields the largest value measured by function f.
10741056
*
10751057
* $willNotTerminateInf
@@ -1080,7 +1062,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
10801062
* @return an option value containing the first element of this $coll with the
10811063
* largest value measured by function f with respect to the ordering `cmp`.
10821064
*/
1083-
def maxByOption[B](f: A => B)(implicit ord: Ordering[B]): Option[A] =
1065+
def maxByOption[B](f: A -> B)(implicit ord: Ordering[B]): Option[A] =
10841066
knownSize match {
10851067
case 0 => None
10861068
case _ => foldLeft(new Maximized[A, B]("maxBy")(f)(ord.gt))((m, a) => m(m, a)).toOption
@@ -1097,7 +1079,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
10971079
* @return the first element of this $coll with the smallest value measured by function f
10981080
* with respect to the ordering `cmp`.
10991081
*/
1100-
def minBy[B](f: A => B)(implicit ord: Ordering[B]): A =
1082+
def minBy[B](f: A -> B)(implicit ord: Ordering[B]): A =
11011083
knownSize match {
11021084
case 0 => throw new UnsupportedOperationException("empty.minBy")
11031085
case _ => foldLeft(new Maximized[A, B]("minBy")(f)(ord.lt))((m, a) => m(m, a)).result
@@ -1114,7 +1096,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
11141096
* with the smallest value measured by function f
11151097
* with respect to the ordering `cmp`.
11161098
*/
1117-
def minByOption[B](f: A => B)(implicit ord: Ordering[B]): Option[A] =
1099+
def minByOption[B](f: A -> B)(implicit ord: Ordering[B]): Option[A] =
11181100
knownSize match {
11191101
case 0 => None
11201102
case _ => foldLeft(new Maximized[A, B]("minBy")(f)(ord.lt))((m, a) => m(m, a)).toOption
@@ -1310,7 +1292,7 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
13101292
def to[C1](factory: Factory[A, C1]): C1 = factory.fromSpecific(this)
13111293

13121294
@deprecated("Use .iterator instead of .toIterator", "2.13.0")
1313-
@`inline` final def toIterator: Iterator[A] = iterator
1295+
@`inline` final def toIterator: Iterator[A]^{this} = iterator
13141296

13151297
def toList: immutable.List[A] = immutable.List.from(this)
13161298

@@ -1352,3 +1334,31 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
13521334
xs
13531335
}
13541336
}
1337+
1338+
object IterableOnceOps:
1339+
1340+
// Moved out of trait IterableOnceOps to here, since universal traits cannot
1341+
// have nested classes in Scala 3
1342+
private class Maximized[X, B](descriptor: String)(f: X -> B)(cmp: (B, B) -> Boolean) extends AbstractFunction2[Maximized[X, B], X, Maximized[X, B]] {
1343+
var maxElem: X = null.asInstanceOf[X]
1344+
var maxF: B = null.asInstanceOf[B]
1345+
var nonEmpty = false
1346+
def toOption: Option[X] = if (nonEmpty) Some(maxElem) else None
1347+
def result: X = if (nonEmpty) maxElem else throw new UnsupportedOperationException(s"empty.$descriptor")
1348+
def apply(m: Maximized[X, B], a: X): Maximized[X, B] =
1349+
if (m.nonEmpty) {
1350+
val fa = f(a)
1351+
if (cmp(fa, maxF)) {
1352+
maxF = fa
1353+
maxElem = a
1354+
}
1355+
m
1356+
}
1357+
else {
1358+
m.nonEmpty = true
1359+
m.maxElem = a
1360+
m.maxF = f(a)
1361+
m
1362+
}
1363+
}
1364+
end IterableOnceOps

0 commit comments

Comments
 (0)