Skip to content

Commit 2837fdb

Browse files
authored
Merge pull request scala#1 from julienrf/fix-soundness
Be more explicit about usage of unsound language features
2 parents 8e2bd53 + d6e3815 commit 2837fdb

21 files changed

+125
-79
lines changed

build.sbt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// TODO Make it a cross project when Scala.js is released for 2.13.0-M4
22

3-
scalaVersion := "2.13.0-M4-pre-20d3c21"
3+
scalaVersion := "2.13.0-M4"
44

55
organization := "org.scala-lang"
66

src/main/scala/scala/collection/MultiDict.scala

+30-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package scala.collection
22

3+
import annotation.unchecked.uncheckedVariance
4+
import scala.util.hashing.MurmurHash3
5+
36
/**
47
* A multidict is a map that can associate a set of values to a given key.
58
*
@@ -14,7 +17,7 @@ trait MultiDict[K, V]
1417
def multiMapFactory: MapFactory[MultiDictCC] = MultiDict
1518

1619
override protected[this] def fromSpecificIterable(coll: Iterable[(K, V)]): MultiDictCC[K, V] = multiMapFactory.from(coll)
17-
override protected[this] def newSpecificBuilder(): mutable.Builder[(K, V), MultiDictCC[K, V]] = multiMapFactory.newBuilder[K, V]()
20+
override protected[this] def newSpecificBuilder: mutable.Builder[(K, V), MultiDictCC[K, V]] = multiMapFactory.newBuilder[K, V]
1821

1922
def canEqual(that: Any): Boolean = true
2023

@@ -32,15 +35,15 @@ trait MultiDict[K, V]
3235
case _ => false
3336
}
3437

35-
override def hashCode(): Int = Set.unorderedHash(sets, "MultiMap".##)
38+
override def hashCode(): Int = MurmurHash3.unorderedHash(sets, "MultiMap".##)
3639

3740
}
3841

3942

4043
trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
4144
extends IterableOps[(K, V), Iterable, C] {
4245

43-
protected[this] type MultiDictCC[K, V] = CC[K, V]
46+
protected[this] type MultiDictCC[K, V] = CC[K, V] @uncheckedVariance
4447

4548
def multiMapFactory: MapFactory[MultiDictCC]
4649

@@ -58,8 +61,8 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
5861
*/
5962
def sets: Map[K, Set[V]]
6063

61-
def iterator(): Iterator[(K, V)] =
62-
sets.iterator().flatMap { case (k, vs) => vs.view.map(v => (k, v)) }
64+
def iterator: Iterator[(K, V)] =
65+
sets.iterator.flatMap { case (k, vs) => vs.view.map(v => (k, v)) }
6366

6467
/**
6568
* @return The set of values associated with the given `key`, or the empty
@@ -133,13 +136,8 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
133136
def concat(that: Iterable[(K, V)]): C =
134137
fromSpecificIterable(new View.Concat(toIterable, that))
135138

136-
override def withFilter(p: ((K, V)) => Boolean): MultiMapWithFilter = new MultiMapWithFilter(p)
137-
138-
class MultiMapWithFilter(p: ((K, V)) => Boolean) extends WithFilter(p) {
139-
def map[L, W](f: ((K, V)) => (L, W)): CC[L, W] = multiMapFromIterable(new View.Map(filtered, f))
140-
def flatMap[L, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = multiMapFromIterable(new View.FlatMap(filtered, f))
141-
override def withFilter(q: ((K, V)) => Boolean): MultiMapWithFilter = new MultiMapWithFilter(kv => p(kv) && q(kv))
142-
}
139+
override def withFilter(p: ((K, V)) => Boolean): MultiDictOps.WithFilter[K, V, IterableCC, CC] =
140+
new MultiDictOps.WithFilter(this, p)
143141

144142
/**
145143
* @return Whether there exists a value associated with the given `key`
@@ -203,4 +201,23 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
203201

204202
}
205203

206-
object MultiDict extends MapFactory.Delegate[MultiDict](immutable.MultiDict)
204+
object MultiDictOps {
205+
206+
class WithFilter[K, V, +IterableCC[_], +CC[X, Y] <: MultiDict[X, Y]](
207+
`this`: MultiDictOps[K, V, CC, _] with IterableOps[(K, V), IterableCC, _],
208+
p: ((K, V)) => Boolean
209+
) extends IterableOps.WithFilter[(K, V), IterableCC](`this`, p) {
210+
211+
def map[L, W](f: ((K, V)) => (L, W)): CC[L, W] =
212+
`this`.multiMapFactory.from(new View.Map(filtered, f))
213+
214+
def flatMap[L, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] =
215+
`this`.multiMapFactory.from(new View.FlatMap(filtered, f))
216+
217+
override def withFilter(q: ((K, V)) => Boolean): WithFilter[K, V, IterableCC, CC] =
218+
new WithFilter[K, V, IterableCC, CC](`this`, (kv: (K, V)) => p(kv) && q(kv))
219+
}
220+
221+
}
222+
223+
object MultiDict extends MapFactory.Delegate[MultiDict](immutable.MultiDict)

src/main/scala/scala/collection/MultiSet.scala

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package scala.collection
22

3+
import scala.util.hashing.MurmurHash3
4+
35
/**
46
* A multiset is a set that can contain multiple occurrences of a same value.
57
*
@@ -26,7 +28,7 @@ trait MultiSet[A]
2628
case _ => false
2729
}
2830

29-
override def hashCode(): Int = collection.Set.unorderedHash(occurrences, "MultiSet".##)
31+
override def hashCode(): Int = MurmurHash3.unorderedHash(occurrences, "MultiSet".##)
3032

3133
}
3234

@@ -45,8 +47,8 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
4547
*/
4648
def occurrences: Map[A, Int]
4749

48-
def iterator(): Iterator[A] =
49-
occurrences.iterator().flatMap { case (elem, n) => new View.Fill(n)(elem) }
50+
def iterator: Iterator[A] =
51+
occurrences.iterator.flatMap { case (elem, n) => new View.Fill(n)(elem) }
5052

5153
/**
5254
* @return The number of occurrences of `elem` in this multiset

src/main/scala/scala/collection/SortedMultiDict.scala

+30-14
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package scala.collection
22

3+
import annotation.unchecked.uncheckedVariance
4+
35
/**
46
* A multidict whose keys are sorted
5-
*
67
* @tparam K the type of keys
78
* @tparam V the type of values
89
*/
@@ -13,14 +14,14 @@ trait SortedMultiDict[K, V]
1314
def unsorted: MultiDict[K, V] = this
1415

1516
override protected[this] def fromSpecificIterable(coll: Iterable[(K, V)]): SortedMultiDictCC[K, V] = sortedMultiMapFactory.from(coll)
16-
override protected[this] def newSpecificBuilder(): mutable.Builder[(K, V), SortedMultiDictCC[K, V]] = sortedMultiMapFactory.newBuilder[K, V]()
17+
override protected[this] def newSpecificBuilder: mutable.Builder[(K, V), SortedMultiDictCC[K, V]] = sortedMultiMapFactory.newBuilder[K, V]
1718
}
1819

1920
trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
2021
extends MultiDictOps[K, V, MultiDict, C]
2122
with SortedOps[K, C] {
2223

23-
protected[this] type SortedMultiDictCC[K, V] = CC[K, V]
24+
protected[this] type SortedMultiDictCC[X, Y] = CC[X, Y] @uncheckedVariance
2425

2526
def sortedMultiMapFactory: SortedMapFactory[SortedMultiDictCC]
2627

@@ -41,23 +42,18 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
4142
def lastKey: K = sets.lastKey
4243

4344
def rangeTo(to: K): C = {
44-
val i = from(to).iterator()
45+
val i = rangeFrom(to).iterator
4546
if (i.isEmpty) return coll
4647
val next = i.next()._1
4748
if (ordering.compare(next, to) == 0)
4849
if (i.isEmpty) coll
49-
else until(i.next()._1)
50+
else rangeUntil(i.next()._1)
5051
else
51-
until(next)
52+
rangeUntil(next)
5253
}
5354

54-
override def withFilter(p: ((K, V)) => Boolean): SortedMultiMapWithFilter = new SortedMultiMapWithFilter(p)
55-
56-
class SortedMultiMapWithFilter(p: ((K, V)) => Boolean) extends MultiMapWithFilter(p) {
57-
def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] = sortedFromIterable(new View.Map(filtered, f))
58-
def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = sortedFromIterable(new View.FlatMap(filtered, f))
59-
override def withFilter(q: ((K, V)) => Boolean): SortedMultiMapWithFilter = new SortedMultiMapWithFilter(kv => p(kv) && q(kv))
60-
}
55+
override def withFilter(p: ((K, V)) => Boolean): SortedMultiDictOps.WithFilter[K, V, IterableCC, MultiDictCC, CC] =
56+
new SortedMultiDictOps.WithFilter[K, V, IterableCC, MultiDictCC, CC](this, p)
6157

6258
/**
6359
* @return a sorted multidict that contains all the entries of `this` sorted multidict,
@@ -130,4 +126,24 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
130126

131127
}
132128

133-
object SortedMultiDict extends SortedMapFactory.Delegate[SortedMultiDict](immutable.SortedMultiDict)
129+
object SortedMultiDictOps {
130+
131+
class WithFilter[K, V, +IterableCC[_], +MultiDictCC[X, Y] <: MultiDict[X, Y], +CC[X, Y] <: MultiDict[X, Y]](
132+
`this`: SortedMultiDictOps[K, V, CC, _] with MultiDictOps[K, V, MultiDictCC, _] with IterableOps[(K, V), IterableCC, _],
133+
p: ((K, V)) => Boolean
134+
) extends MultiDictOps.WithFilter[K, V, IterableCC, MultiDictCC](`this`, p) {
135+
136+
def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] =
137+
`this`.sortedMultiMapFactory.from(new View.Map(filtered, f))
138+
139+
def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] =
140+
`this`.sortedMultiMapFactory.from(new View.FlatMap(filtered, f))
141+
142+
override def withFilter(q: ((K, V)) => Boolean): WithFilter[K, V, IterableCC, MultiDictCC, CC] =
143+
new WithFilter[K, V, IterableCC, MultiDictCC, CC](`this`, kv => p(kv) && q(kv))
144+
145+
}
146+
147+
}
148+
149+
object SortedMultiDict extends SortedMapFactory.Delegate[SortedMultiDict](immutable.SortedMultiDict)

src/main/scala/scala/collection/SortedMultiSet.scala

+31-20
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ trait SortedMultiSet[A]
1313
def unsorted: MultiSet[A] = this
1414

1515
override protected[this] def fromSpecificIterable(coll: Iterable[A]): SortedIterableCC[A] = sortedIterableFactory.from(coll)
16-
override protected[this] def newSpecificBuilder(): mutable.Builder[A, SortedIterableCC[A]] = sortedIterableFactory.newBuilder[A]()
16+
override protected[this] def newSpecificBuilder: mutable.Builder[A, SortedIterableCC[A]] = sortedIterableFactory.newBuilder[A]
1717

1818
protected[this] def sortedFromIterable[B : Ordering](it: scala.collection.Iterable[B]): SortedIterableCC[B] = sortedIterableFactory.from(it)
1919

@@ -24,7 +24,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
2424
extends MultiSetOps[A, MultiSet, C]
2525
with SortedOps[A, C] {
2626

27-
protected[this] type SortedIterableCC[X] = CC[X]
27+
protected[this] type SortedIterableCC[X] = CC[X] @uncheckedVariance
2828

2929
def sortedIterableFactory: SortedIterableFactory[SortedIterableCC]
3030

@@ -52,31 +52,18 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
5252
def lastKey: A = occurrences.lastKey
5353

5454
def rangeTo(to: A): C = {
55-
val i = from(to).iterator()
55+
val i = rangeFrom(to).iterator
5656
if (i.isEmpty) return coll
5757
val next = i.next()
5858
if (ordering.compare(next, to) == 0)
5959
if (i.isEmpty) coll
60-
else until(i.next())
60+
else rangeUntil(i.next())
6161
else
62-
until(next)
62+
rangeUntil(next)
6363
}
6464

65-
override def withFilter(p: A => Boolean): SortedWithFilter = new SortedWithFilter(p)
66-
67-
/** Specialize `WithFilter` for sorted collections
68-
*
69-
* @define coll sorted collection
70-
*/
71-
class SortedWithFilter(p: A => Boolean) extends WithFilter(p) {
72-
73-
def map[B : Ordering](f: A => B): CC[B] = sortedIterableFactory.from(new View.Map(filtered, f))
74-
75-
def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedIterableFactory.from(new View.FlatMap(filtered, f))
76-
77-
override def withFilter(q: A => Boolean): SortedWithFilter = new SortedWithFilter(a => p(a) && q(a))
78-
79-
}
65+
override def withFilter(p: A => Boolean): SortedMultiSetOps.WithFilter[A, IterableCC, CC] =
66+
new SortedMultiSetOps.WithFilter(this, p)
8067

8168
/** Builds a new sorted multiset by applying a function to all elements of this sorted multiset.
8269
*
@@ -169,4 +156,28 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
169156

170157
}
171158

159+
object SortedMultiSetOps {
160+
161+
/** Specialize `WithFilter` for sorted collections
162+
*
163+
* @define coll sorted collection
164+
*/
165+
class WithFilter[A, +IterableCC[_], +CC[X] <: MultiSet[X]](
166+
`this`: SortedMultiSetOps[A, CC, _] with IterableOps[A, IterableCC, _],
167+
p: A => Boolean
168+
) extends IterableOps.WithFilter(`this`, p) {
169+
170+
def map[B : Ordering](f: A => B): CC[B] =
171+
`this`.sortedIterableFactory.from(new View.Map(filtered, f))
172+
173+
def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] =
174+
`this`.sortedIterableFactory.from(new View.FlatMap(filtered, f))
175+
176+
override def withFilter(q: A => Boolean): WithFilter[A, IterableCC, CC] =
177+
new WithFilter[A, IterableCC, CC](`this`, a => p(a) && q(a))
178+
179+
}
180+
181+
}
182+
172183
object SortedMultiSet extends SortedIterableFactory.Delegate(immutable.SortedMultiSet)

src/main/scala/scala/collection/decorators/HasSeqOps.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package scala.collection
22
package decorators
33

4-
import scala.collection.immutable.{ImmutableArray, Range}
4+
import scala.collection.immutable.{ArraySeq, Range}
55

66
/** Type class witnessing that a collection type `C` has
77
* elements of type `A` and has a conversion to `SeqOps[A, _, _]`.
@@ -31,7 +31,7 @@ object HasSeqOps {
3131
implicit def stringHasSeqOps: HasSeqOps[String] { type A = Char } =
3232
new HasSeqOps[String] {
3333
type A = Char
34-
def apply(c: String): SeqOps[Char, AnyConstr, _] = stringToStringOps(c)
34+
def apply(c: String): SeqOps[Char, AnyConstr, _] = c: Seq[Char]
3535
}
3636

3737
// 3. StringView
@@ -45,7 +45,7 @@ object HasSeqOps {
4545
implicit def arrayHasSeqOps[A0]: HasSeqOps[Array[A0]] { type A = A0 } =
4646
new HasSeqOps[Array[A0]] {
4747
type A = A0
48-
def apply(c: Array[A0]): SeqOps[A0, AnyConstr, _] = ImmutableArray.unsafeWrapArray(c)
48+
def apply(c: Array[A0]): SeqOps[A0, AnyConstr, _] = mutable.ArraySeq.make(c)
4949
}
5050

5151
// 5. Range collections

src/main/scala/scala/collection/decorators/IterableDecorator.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class IterableDecorator[C, I <: HasIterableOps[C]](coll: C)(implicit val it: I)
1515
* all the elements have been traversed or earlier if the operator returns `None`
1616
*/
1717
def foldSomeLeft[B](z: B)(op: (B, it.A) => Option[B]): B =
18-
it(coll).iterator().foldSomeLeft(z)(op)
18+
it(coll).iterator.foldSomeLeft(z)(op)
1919

2020
/**
2121
* Right to left fold that can be interrupted before traversing the whole collection.
@@ -29,6 +29,6 @@ class IterableDecorator[C, I <: HasIterableOps[C]](coll: C)(implicit val it: I)
2929
* `f` is applied to the previous result to produce the new result and the fold continues.
3030
*/
3131
def lazyFoldRight[B](z: B)(op: it.A => Either[B, B => B]): B =
32-
it(coll).iterator().lazyFoldRight(z)(op)
32+
it(coll).iterator.lazyFoldRight(z)(op)
3333

3434
}

src/main/scala/scala/collection/decorators/views.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ object View {
77
type SomeIterableOps[+A] = IterableOps[A, AnyConstr, _]
88

99
class Intersperse[A](underlying: SomeIterableOps[A], sep: A) extends View[A] {
10-
def iterator(): Iterator[A] = underlying.iterator().intersperse(sep)
10+
def iterator: Iterator[A] = underlying.iterator.intersperse(sep)
1111

1212
override def knownSize: Int = if (underlying.knownSize > 0) (2 * underlying.knownSize - 1) else underlying.knownSize
1313
}
1414

1515
class IntersperseSurround[A](underlying: SomeIterableOps[A], start: A, sep: A, end: A) extends View[A] {
16-
def iterator(): Iterator[A] = underlying.iterator().intersperse(start, sep, end)
16+
def iterator: Iterator[A] = underlying.iterator.intersperse(start, sep, end)
1717

1818
override def knownSize: Int =
1919
if (underlying.knownSize > 0) (2 * underlying.knownSize + 1)

src/main/scala/scala/collection/immutable/MultiDict.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ object MultiDict extends MapFactory[MultiDict] {
6565
def from[K, V](source: IterableOnce[(K, V)]): MultiDict[K, V] =
6666
source match {
6767
case mm: MultiDict[K, V] => mm
68-
case _ => (newBuilder[K, V]() ++= source).result()
68+
case _ => (newBuilder[K, V] ++= source).result()
6969
}
7070

71-
def newBuilder[K, V](): Builder[(K, V), MultiDict[K, V]] =
71+
def newBuilder[K, V]: Builder[(K, V), MultiDict[K, V]] =
7272
new ImmutableBuilder[(K, V), MultiDict[K, V]](empty[K, V]) {
7373
def addOne(elem: (K, V)): this.type = { elems = elems + elem; this }
7474
}

src/main/scala/scala/collection/immutable/MultiSet.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@ object MultiSet extends IterableFactory[MultiSet] {
7676
def from[A](source: IterableOnce[A]): MultiSet[A] =
7777
source match {
7878
case ms: MultiSet[A] => ms
79-
case _ => (newBuilder[A]() ++= source).result()
79+
case _ => (newBuilder[A] ++= source).result()
8080
}
8181

8282
def empty[A] = new MultiSetImpl[A](Map.empty)
8383

84-
def newBuilder[A](): Builder[A, MultiSet[A]] =
84+
def newBuilder[A]: Builder[A, MultiSet[A]] =
8585
new ImmutableBuilder[A, MultiSet[A]](empty[A]) {
8686
def addOne(elem: A): this.type = { elems = elems + elem; this }
8787
}

src/main/scala/scala/collection/immutable/SortedMultiDict.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ object SortedMultiDict extends SortedMapFactory[SortedMultiDict] {
7070
def from[K: Ordering, V](it: IterableOnce[(K, V)]): SortedMultiDict[K, V] =
7171
it match {
7272
case smm: SortedMultiDict[K, V] => smm
73-
case _ => (newBuilder[K, V]() ++= it).result()
73+
case _ => (newBuilder[K, V] ++= it).result()
7474
}
7575

76-
def newBuilder[K: Ordering, V](): Builder[(K, V), SortedMultiDict[K, V]] =
76+
def newBuilder[K: Ordering, V]: Builder[(K, V), SortedMultiDict[K, V]] =
7777
new ImmutableBuilder[(K, V), SortedMultiDict[K, V]](empty[K, V]) {
7878
def addOne(elem: (K, V)): this.type = { elems = elems + elem; this }
7979
}

0 commit comments

Comments
 (0)