Skip to content

Commit 21da127

Browse files
committed
Make BuildFrom capture checked
1 parent 9e11c6a commit 21da127

File tree

2 files changed

+25
-18
lines changed

2 files changed

+25
-18
lines changed

tests/pos-special/stdlib/collection/BuildFrom.scala

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import scala.annotation.implicitNotFound
1616
import scala.collection.mutable.Builder
1717
import scala.collection.immutable.WrappedString
1818
import scala.reflect.ClassTag
19+
import language.experimental.captureChecking
20+
import caps.unsafe.unsafeAssumePure
1921

2022
/** Builds a collection of type `C` from elements of type `A` when a source collection of type `From` is available.
2123
* Implicit instances of `BuildFrom` are available for all collection types.
@@ -26,7 +28,11 @@ import scala.reflect.ClassTag
2628
*/
2729
@implicitNotFound(msg = "Cannot construct a collection of type ${C} with elements of type ${A} based on a collection of type ${From}.")
2830
trait BuildFrom[-From, -A, +C] extends Any { self =>
29-
def fromSpecific(from: From)(it: IterableOnce[A]): C
31+
def fromSpecific(from: From)(it: IterableOnce[A]^): C
32+
// !!! this is wrong, we need two versions of fromSpecific; one mapping
33+
// to C^{it} when C is an Iterable, and one mapping to C when C is a Seq, Map, or Set.
34+
// But that requires a lareg scale refactoring of BuildFrom. The unsafeAssumePure
35+
// calls in this file are needed to sweep that problem under the carpet.
3036

3137
/** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
3238
* 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 =>
3743

3844
/** Partially apply a BuildFrom to a Factory */
3945
def toFactory(from: From): Factory[A, C] = new Factory[A, C] {
40-
def fromSpecific(it: IterableOnce[A]): C = self.fromSpecific(from)(it)
46+
def fromSpecific(it: IterableOnce[A]^): C = self.fromSpecific(from)(it)
4147
def newBuilder: Builder[A, C] = self.newBuilder(from)
4248
}
4349
}
@@ -48,42 +54,42 @@ object BuildFrom extends BuildFromLowPriority1 {
4854
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]] {
4955
//TODO: Reuse a prototype instance
5056
def newBuilder(from: CC[K0, V0]): Builder[(K, V), CC[K, V]] = (from: MapOps[K0, V0, CC, _]).mapFactory.newBuilder[K, V]
51-
def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]): CC[K, V] = (from: MapOps[K0, V0, CC, _]).mapFactory.from(it)
57+
def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]^): CC[K, V] = (from: MapOps[K0, V0, CC, _]).mapFactory.from(it)
5258
}
5359

5460
/** Build the source collection type from a SortedMapOps */
5561
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]] {
5662
def newBuilder(from: CC[K0, V0]): Builder[(K, V), CC[K, V]] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.newBuilder[K, V]
57-
def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]): CC[K, V] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.from(it)
63+
def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]^): CC[K, V] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.from(it)
5864
}
5965

6066
implicit def buildFromBitSet[C <: BitSet with BitSetOps[C]]: BuildFrom[C, Int, C] =
6167
new BuildFrom[C, Int, C] {
62-
def fromSpecific(from: C)(it: IterableOnce[Int]): C = from.bitSetFactory.fromSpecific(it)
68+
def fromSpecific(from: C)(it: IterableOnce[Int]^): C = from.bitSetFactory.fromSpecific(it)
6369
def newBuilder(from: C): Builder[Int, C] = from.bitSetFactory.newBuilder
6470
}
6571

6672
implicit val buildFromString: BuildFrom[String, Char, String] =
6773
new BuildFrom[String, Char, String] {
68-
def fromSpecific(from: String)(it: IterableOnce[Char]): String = Factory.stringFactory.fromSpecific(it)
74+
def fromSpecific(from: String)(it: IterableOnce[Char]^): String = Factory.stringFactory.fromSpecific(it)
6975
def newBuilder(from: String): Builder[Char, String] = Factory.stringFactory.newBuilder
7076
}
7177

7278
implicit val buildFromWrappedString: BuildFrom[WrappedString, Char, WrappedString] =
7379
new BuildFrom[WrappedString, Char, WrappedString] {
74-
def fromSpecific(from: WrappedString)(it: IterableOnce[Char]): WrappedString = WrappedString.fromSpecific(it)
80+
def fromSpecific(from: WrappedString)(it: IterableOnce[Char]^): WrappedString = WrappedString.fromSpecific(it)
7581
def newBuilder(from: WrappedString): mutable.Builder[Char, WrappedString] = WrappedString.newBuilder
7682
}
7783

78-
implicit def buildFromArray[A : ClassTag]: BuildFrom[Array[_], A, Array[A]] =
84+
implicit def buildFromArray[sealed A : ClassTag]: BuildFrom[Array[_], A, Array[A]] =
7985
new BuildFrom[Array[_], A, Array[A]] {
80-
def fromSpecific(from: Array[_])(it: IterableOnce[A]): Array[A] = Factory.arrayFactory[A].fromSpecific(it)
86+
def fromSpecific(from: Array[_])(it: IterableOnce[A]^): Array[A] = Factory.arrayFactory[A].fromSpecific(it)
8187
def newBuilder(from: Array[_]): Builder[A, Array[A]] = Factory.arrayFactory[A].newBuilder
8288
}
8389

84-
implicit def buildFromView[A, B]: BuildFrom[View[A], B, View[B]] =
90+
implicit def buildFromView[A, sealed B]: BuildFrom[View[A], B, View[B]] =
8591
new BuildFrom[View[A], B, View[B]] {
86-
def fromSpecific(from: View[A])(it: IterableOnce[B]): View[B] = View.from(it)
92+
def fromSpecific(from: View[A])(it: IterableOnce[B]^): View[B] = View.from(it).unsafeAssumePure
8793
def newBuilder(from: View[A]): Builder[B, View[B]] = View.newBuilder
8894
}
8995

@@ -97,12 +103,12 @@ trait BuildFromLowPriority1 extends BuildFromLowPriority2 {
97103
// test in test/junit/scala/collection/BuildFromTest.scala and discussion in https://github.com/scala/scala/pull/10209
98104
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]] {
99105
def newBuilder(from: CC[A0]): Builder[A, CC[A]] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.newBuilder[A]
100-
def fromSpecific(from: CC[A0])(it: IterableOnce[A]): CC[A] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.from(it)
106+
def fromSpecific(from: CC[A0])(it: IterableOnce[A]^): CC[A] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.from(it)
101107
}
102108

103109
implicit def fallbackStringCanBuildFrom[A]: BuildFrom[String, A, immutable.IndexedSeq[A]] =
104110
new BuildFrom[String, A, immutable.IndexedSeq[A]] {
105-
def fromSpecific(from: String)(it: IterableOnce[A]): immutable.IndexedSeq[A] = immutable.IndexedSeq.from(it)
111+
def fromSpecific(from: String)(it: IterableOnce[A]^): immutable.IndexedSeq[A] = immutable.IndexedSeq.from(it)
106112
def newBuilder(from: String): Builder[A, immutable.IndexedSeq[A]] = immutable.IndexedSeq.newBuilder[A]
107113
}
108114
}
@@ -112,11 +118,11 @@ trait BuildFromLowPriority2 {
112118
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]] {
113119
//TODO: Reuse a prototype instance
114120
def newBuilder(from: CC[A0]): Builder[A, CC[A]] = (from: IterableOps[A0, CC, _]).iterableFactory.newBuilder[A]
115-
def fromSpecific(from: CC[A0])(it: IterableOnce[A]): CC[A] = (from: IterableOps[A0, CC, _]).iterableFactory.from(it)
121+
def fromSpecific(from: CC[A0])(it: IterableOnce[A]^): CC[A] = (from: IterableOps[A0, CC, _]).iterableFactory.from(it).unsafeAssumePure
116122
}
117123

118124
implicit def buildFromIterator[A]: BuildFrom[Iterator[_], A, Iterator[A]] = new BuildFrom[Iterator[_], A, Iterator[A]] {
119125
def newBuilder(from: Iterator[_]): mutable.Builder[A, Iterator[A]] = Iterator.newBuilder
120-
def fromSpecific(from: Iterator[_])(it: IterableOnce[A]): Iterator[A] = Iterator.from(it)
126+
def fromSpecific(from: Iterator[_])(it: IterableOnce[A]^): Iterator[A] = Iterator.from(it).unsafeAssumePure
121127
}
122128
}

tests/pos-special/stdlib/collection/Factory.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,8 @@ object IterableFactory {
282282

283283
implicit def toBuildFrom[A, CC[_]](factory: IterableFactory[CC]): BuildFrom[Any, A, CC[A]] =
284284
new BuildFrom[Any, A, CC[A]] {
285-
def fromSpecific(from: Any)(it: IterableOnce[A]^): CC[A]^{it} = factory.from(it)
285+
def fromSpecific(from: Any)(it: IterableOnce[A]^): CC[A] =
286+
factory.from(it).unsafeAssumePure // !!! see remark in BuildFrom why this is necessary
286287
def newBuilder(from: Any) = factory.newBuilder
287288
}
288289

@@ -535,7 +536,7 @@ object EvidenceIterableFactory {
535536

536537
implicit def toBuildFrom[Ev[_], A: Ev, CC[_]](factory: EvidenceIterableFactory[CC, Ev]): BuildFrom[Any, A, CC[A]] = new EvidenceIterableFactoryToBuildFrom(factory)
537538
private class EvidenceIterableFactoryToBuildFrom[Ev[_], A: Ev, CC[_]](factory: EvidenceIterableFactory[CC, Ev]) extends BuildFrom[Any, A, CC[A]] {
538-
def fromSpecific(from: Any)(it: IterableOnce[A]): CC[A] = factory.from[A](it)
539+
def fromSpecific(from: Any)(it: IterableOnce[A]^): CC[A] = factory.from[A](it)
539540
def newBuilder(from: Any): Builder[A, CC[A]] = factory.newBuilder[A]
540541
}
541542

@@ -783,7 +784,7 @@ object SortedMapFactory {
783784

784785
implicit def toBuildFrom[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]): BuildFrom[Any, (K, V), CC[K, V]] = new SortedMapFactoryToBuildFrom(factory)
785786
private class SortedMapFactoryToBuildFrom[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]) extends BuildFrom[Any, (K, V), CC[K, V]] {
786-
def fromSpecific(from: Any)(it: IterableOnce[(K, V)]) = factory.from(it)
787+
def fromSpecific(from: Any)(it: IterableOnce[(K, V)]^) = factory.from(it)
787788
def newBuilder(from: Any) = factory.newBuilder[K, V]
788789
}
789790

0 commit comments

Comments
 (0)