Skip to content

Commit 4c96d59

Browse files
authored
Merge pull request #240 from som-snytt/update/latest
Improvements to the Scala 3 crossbuild
2 parents 64dba0d + 962ea7a commit 4c96d59

13 files changed

+96
-99
lines changed

build.sbt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,23 @@ lazy val collectionContrib = crossProject(JVMPlatform, JSPlatform, NativePlatfor
2020
scalaModuleAutomaticModuleName := Some("scala.collection.contrib"),
2121
Compile / compile / scalacOptions ++= {
2222
CrossVersion.partialVersion(scalaVersion.value) match {
23-
case Some((2, _)) => Seq("-opt-warnings", "-Werror", "-Wconf:origin=scala.collection.IterableOps.toIterable:s")
24-
case _ => Seq("-Xfatal-warnings", "-Wconf:cat=deprecation:s")
23+
case Some((2, _)) => Seq(
24+
"-Wconf:origin=scala.collection.IterableOps.toIterable:s", // internal usage; annotating @nowarn is clutter
25+
"-Werror",
26+
"-Wnonunit-statement",
27+
"-Wopt",
28+
"-opt:inline:<sources>",
29+
"-opt:inline:scala.util.package$chaining$,scala.util.ChainingSyntax,scala.util.ChainingOps$",
30+
"-Wvalue-discard",
31+
"-Xlint",
32+
"-Xsource:3-cross",
33+
)
34+
case _ => Seq(
35+
"-Wconf:cat=deprecation:s", // Scala 3 lacks origin, src arrives in 3.3.4 & 3.5
36+
"-Wconf:id=E175:s",
37+
"-Werror",
38+
"-Wnonunit-statement", // warns on uni-limbed if
39+
)
2540
}
2641
},
2742
Compile / doc / scalacOptions ++= {

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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ trait MultiDict[K, V]
1313
with MultiDictOps[K, V, MultiDict, MultiDict[K, V]]
1414
with Equals {
1515

16-
override protected[this] def className: String = "MultiDict"
16+
override protected def className: String = "MultiDict"
1717

1818
def multiDictFactory: MapFactory[MultiDict] = MultiDict
1919
override protected def fromSpecific(coll: IterableOnce[(K, V)]): MultiDict[K, V] = multiDictFactory.from(coll)
@@ -26,14 +26,11 @@ trait MultiDict[K, V]
2626
override def equals(o: Any): Boolean = o match {
2727
case that: MultiDict[K @unchecked, _] =>
2828
(this eq that) ||
29-
(that canEqual this) &&
30-
(this.size == that.size) && {
31-
try {
32-
sets forall { case (k, vs) => that.sets.get(k).contains(vs) }
33-
} catch {
34-
case _: ClassCastException => false
35-
}
36-
}
29+
that.canEqual(this) &&
30+
this.size == that.size && (
31+
try sets.forall { case (k, vs) => that.sets.get(k).contains(vs) }
32+
catch { case _: ClassCastException => false }
33+
)
3734
case _ => false
3835
}
3936

@@ -205,7 +202,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
205202
object MultiDictOps {
206203

207204
class WithFilter[K, V, +IterableCC[_], +CC[X, Y] <: MultiDict[X, Y]](
208-
`this`: MultiDictOps[K, V, CC, _] with IterableOps[(K, V), IterableCC, _],
205+
`this`: MultiDictOps[K, V, CC, ?] & IterableOps[(K, V), IterableCC, ?],
209206
p: ((K, V)) => Boolean
210207
) extends IterableOps.WithFilter[(K, V), IterableCC](`this`, p) {
211208

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

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ trait MultiSet[A]
1212
with MultiSetOps[A, MultiSet, MultiSet[A]]
1313
with Equals {
1414

15-
override protected[this] def className: String = "MultiSet"
15+
override protected def className: String = "MultiSet"
1616

1717
override def iterableFactory: IterableFactory[MultiSet] = MultiSet
1818
override protected def fromSpecific(coll: IterableOnce[A]): MultiSet[A] = iterableFactory.from(coll)
@@ -24,14 +24,11 @@ trait MultiSet[A]
2424
override def equals(o: Any): Boolean = o match {
2525
case that: MultiSet[A @unchecked] =>
2626
(this eq that) ||
27-
(that canEqual this) &&
28-
(this.size == that.size) && {
29-
try {
30-
occurrences forall { case (elem, n) => that.get(elem) == n }
31-
} catch {
32-
case _: ClassCastException => false
33-
}
34-
}
27+
that.canEqual(this) &&
28+
this.size == that.size && (
29+
try occurrences.forall { case (elem, n) => that.get(elem) == n }
30+
catch { case _: ClassCastException => false }
31+
)
3532
case _ => false
3633
}
3734

@@ -42,10 +39,10 @@ trait MultiSet[A]
4239
trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
4340
extends IterableOps[A, CC, C] {
4441

45-
protected[this] def fromSpecificOccurrences(it: Iterable[(A, Int)]): C =
42+
protected def fromSpecificOccurrences(it: Iterable[(A, Int)]): C =
4643
fromSpecific(it.view.flatMap { case (e, n) => new View.Fill(n)(e) })
4744

48-
protected[this] def fromOccurrences[E](it: Iterable[(E, Int)]): CC[E] =
45+
protected def fromOccurrences[E](it: Iterable[(E, Int)]): CC[E] =
4946
// Note new MultiSet(it.to(Map)) would be more efficient but would also loose duplicates
5047
iterableFactory.from(it.view.flatMap { case (e, n) => new View.Fill(n)(e) })
5148

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
2525

2626
def sortedMultiDictFactory: SortedMapFactory[CC]
2727

28-
protected[this] def sortedFromIterable[L : Ordering, W](it: Iterable[(L, W)]): CC[L, W] = sortedMultiDictFactory.from(it)
29-
protected[this] def sortedFromSets[L : Ordering, W](it: Iterable[(L, Set[W])]): CC[L, W] =
28+
protected def sortedFromIterable[L : Ordering, W](it: Iterable[(L, W)]): CC[L, W] = sortedMultiDictFactory.from(it)
29+
protected def sortedFromSets[L : Ordering, W](it: Iterable[(L, Set[W])]): CC[L, W] =
3030
sortedFromIterable(it.view.flatMap { case (l, ws) => ws.map(w => (l, w)) })
3131

3232
/** `this` sorted multidict upcasted to an unsorted multidict */
@@ -126,7 +126,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
126126
object SortedMultiDictOps {
127127

128128
class WithFilter[K, V, +IterableCC[_], +MultiDictCC[X, Y] <: MultiDict[X, Y], +CC[X, Y] <: MultiDict[X, Y]](
129-
`this`: SortedMultiDictOps[K, V, CC, _] with MultiDictOps[K, V, MultiDictCC, _] with IterableOps[(K, V), IterableCC, _],
129+
`this`: SortedMultiDictOps[K, V, CC, ?] & MultiDictOps[K, V, MultiDictCC, ?] & IterableOps[(K, V), IterableCC, ?],
130130
p: ((K, V)) => Boolean
131131
) extends MultiDictOps.WithFilter[K, V, IterableCC, MultiDictCC](`this`, p) {
132132

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
118118
* is the minimum of the lengths of `this` and `that`
119119
*/
120120
def zip[B](that: Iterable[B])(implicit ev: Ordering[B]): CC[(A @uncheckedVariance, B)] = // sound bcs of VarianceNote
121-
sortedFromIterable(new View.Zip(toIterable, that))(Ordering.Tuple2(ordering, implicitly))
121+
sortedFromIterable(new View.Zip(toIterable, that))(using Ordering.Tuple2(ordering, implicitly))
122122

123123
/**
124124
* @return a new collection resulting from applying the given partial
@@ -147,7 +147,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
147147
// --- Override return type of methods that returned an unsorted MultiSet
148148

149149
override def zipWithIndex: CC[(A, Int)] =
150-
sortedFromIterable(new View.ZipWithIndex(toIterable))(Ordering.Tuple2(ordering, implicitly))
150+
sortedFromIterable(new View.ZipWithIndex(toIterable))(using Ordering.Tuple2(ordering, implicitly))
151151

152152
}
153153

@@ -158,7 +158,7 @@ object SortedMultiSetOps {
158158
* @define coll sorted collection
159159
*/
160160
class WithFilter[A, +IterableCC[_], +CC[X] <: MultiSet[X]](
161-
`this`: SortedMultiSetOps[A, CC, _] with IterableOps[A, IterableCC, _],
161+
`this`: SortedMultiSetOps[A, CC, ?] & IterableOps[A, IterableCC, ?],
162162
p: A => Boolean
163163
) extends IterableOps.WithFilter[A, IterableCC](`this`, p) {
164164

src/main/scala/scala/collection/decorators/BitSetDecorator.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package scala.collection.decorators
22

33
import scala.collection.{BitSet, BitSetOps}
44

5-
class BitSetDecorator[+C <: BitSet with BitSetOps[C]](protected val bs: C) {
5+
class BitSetDecorator[+C <: BitSet & BitSetOps[C]](protected val bs: C) {
66

77
import BitSetDecorator._
88
import BitSetOps._

src/main/scala/scala/collection/decorators/IteratorDecorator.scala

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package scala.collection
22
package decorators
33

44
import scala.annotation.tailrec
5+
import scala.util.chaining.*
56
import scala.util.control.NonFatal
67

78
/** Enriches Iterator with additional methods.
@@ -188,8 +189,8 @@ class IteratorDecorator[A](val `this`: Iterator[A]) extends AnyVal {
188189
*/
189190
def splitBy[K](f: A => K): Iterator[immutable.Seq[A]] =
190191
new AbstractIterator[immutable.Seq[A]] {
191-
private var hd: A = _
192-
private var hdKey: K = _
192+
private var hd: A = null.asInstanceOf[A] // todo uninitialized
193+
private var hdKey: K = null.asInstanceOf[K] // todo uninitialized
193194
private var hdDefined: Boolean = false
194195

195196
override def hasNext: Boolean = hdDefined || `this`.hasNext
@@ -240,32 +241,26 @@ class IteratorDecorator[A](val `this`: Iterator[A]) extends AnyVal {
240241
}
241242

242243
/** Gives elements from the source iterator until the source iterator ends or throws a NonFatal exception.
243-
*
244-
* @param exceptionCaught a callback invoked from `hasNext` when the source iterator throws a NonFatal exception
245-
* @return an iterator that takes items until the wrapped iterator ends or throws a NonFatal exception
246-
* @see scala.util.control.NonFatal
247-
* @note Reuse: $consumesAndProducesIterator
248-
*/
249-
def takeUntilException(exceptionCaught: Throwable => Unit): Iterator[A] = {
244+
*
245+
* @param exceptionCaught a callback invoked from `hasNext` when the source iterator throws a NonFatal exception
246+
* @return an iterator that takes items until the wrapped iterator ends or throws a NonFatal exception
247+
* @see scala.util.control.NonFatal
248+
* @note Reuse: $consumesAndProducesIterator
249+
*/
250+
def takeUntilException(exceptionCaught: Throwable => Unit): Iterator[A] =
250251
new AbstractIterator[A] {
251252
private val wrapped = `this`.buffered
252253

253-
override def hasNext: Boolean = {
254-
try {
255-
val n = wrapped.hasNext
256-
// By already invoking `head` (and therefore also `next` on `this`),
257-
// we are sure that `wrapped.next` will not throw when it is used from
258-
// `next`.
259-
if (n) wrapped.head
260-
n
261-
} catch {
254+
override def hasNext: Boolean =
255+
// By already invoking `head` (and therefore also `next` on `this`),
256+
// we are sure that `wrapped.next` will not throw when it is used from `next`.
257+
try wrapped.hasNext.tap(if(_) wrapped.head)
258+
catch {
262259
case NonFatal(t) =>
263260
exceptionCaught(t)
264261
false
265262
}
266-
}
267263

268264
override def next(): A = wrapped.next()
269265
}
270-
}
271266
}

src/main/scala/scala/collection/decorators/package.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ package object decorators {
1717
implicit def mapDecorator[C](coll: C)(implicit map: IsMap[C]): MapDecorator[C, map.type] =
1818
new MapDecorator(coll)(map)
1919

20-
implicit def bitSetDecorator[C <: BitSet with BitSetOps[C]](bs: C): BitSetDecorator[C] =
20+
implicit def bitSetDecorator[C <: BitSet & BitSetOps[C]](bs: C): BitSetDecorator[C] =
2121
new BitSetDecorator(bs)
2222

2323
implicit def mutableBitSetDecorator(bs: mutable.BitSet): MutableBitSetDecorator =

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package decorators
44
/** Views used by decorators */
55
object View {
66

7-
type SomeIterableOps[+A] = IterableOps[A, AnyConstr, _]
7+
type SomeIterableOps[+A] = IterableOps[A, AnyConstr, ?]
88

99
class Intersperse[A](underlying: SomeIterableOps[A], sep: A) extends View[A] {
1010
def iterator: Iterator[A] = underlying.iterator.intersperse(sep)
@@ -21,4 +21,4 @@ object View {
2121
else underlying.knownSize
2222
}
2323

24-
}
24+
}

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

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ package scala
22
package collection
33
package mutable
44

5-
/**
6-
* A mutable multidict
7-
* @tparam K the type of keys
8-
* @tparam V the type of values
9-
*/
5+
/** A mutable multidict.
6+
* @tparam K the type of keys
7+
* @tparam V the type of values
8+
*/
109
class MultiDict[K, V] private (elems: Map[K, Set[V]])
1110
extends collection.MultiDict[K, V]
1211
with Iterable[(K, V)]
@@ -27,20 +26,18 @@ class MultiDict[K, V] private (elems: Map[K, Set[V]])
2726

2827
def addOne(elem: (K, V)): this.type = {
2928
val (k, v) = elem
30-
elems.updateWith(k) {
31-
case None => Some(Set(v))
32-
case Some(vs) => Some(vs += v)
33-
}
29+
val vs = elems.getOrElseUpdate(k, Set.empty[V])
30+
vs.addOne(v)
3431
this
3532
}
3633

3734
def subtractOne(elem: (K, V)): this.type = {
3835
val (k, v) = elem
39-
elems.updateWith(k) {
36+
elems.get(k) match {
4037
case Some(vs) =>
41-
vs -= v
42-
if (vs.nonEmpty) Some(vs) else None
43-
case None => None
38+
vs.subtractOne(v)
39+
if (vs.isEmpty) elems.subtractOne(k)
40+
case _ =>
4441
}
4542
this
4643
}
@@ -50,7 +47,7 @@ class MultiDict[K, V] private (elems: Map[K, Set[V]])
5047
* @return the collection itself
5148
*/
5249
def removeKey(key: K): this.type = {
53-
elems -= key
50+
elems.subtractOne(key)
5451
this
5552
}
5653

@@ -69,4 +66,4 @@ object MultiDict extends MapFactory[MultiDict] {
6966

7067
def newBuilder[K, V]: Builder[(K, V), MultiDict[K, V]] = new GrowableBuilder[(K, V), MultiDict[K, V]](empty)
7168

72-
}
69+
}

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package scala
22
package collection
33
package mutable
44

5+
import java.util.concurrent.atomic.AtomicInteger
6+
57
/**
68
* A mutable multiset.
79
*/
@@ -19,22 +21,19 @@ trait MultiSet[A]
1921
override def knownSize: Int = super[Growable].knownSize
2022
}
2123

22-
class MultiSetImpl[A] private[mutable] (val elems: Map[A, Int]) extends MultiSet[A] {
24+
class MultiSetImpl[A] private[mutable] (elems: Map[A, AtomicInteger]) extends MultiSet[A] {
2325

24-
def occurrences: collection.Map[A, Int] = elems
26+
def occurrences: collection.Map[A, Int] = elems.map { case (k, v) => (k, v.get) }
2527

2628
def addOne(elem: A): this.type = {
27-
elems.updateWith(elem) {
28-
case None => Some(1)
29-
case Some(n) => Some(n + 1)
30-
}
29+
elems.getOrElseUpdate(elem, new AtomicInteger).getAndIncrement
3130
this
3231
}
3332

3433
def subtractOne(elem: A): this.type = {
35-
elems.updateWith(elem) {
36-
case Some(n) => if (n > 1) Some(n - 1) else None
37-
case None => None
34+
elems.get(elem) match {
35+
case Some(n) => if (n.decrementAndGet <= 0) elems.subtractOne(elem)
36+
case _ =>
3837
}
3938
this
4039
}
@@ -50,4 +49,4 @@ object MultiSet extends IterableFactory[MultiSet] {
5049

5150
def newBuilder[A]: Builder[A, MultiSet[A]] = new GrowableBuilder[A, MultiSet[A]](empty)
5251

53-
}
52+
}

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,18 @@ class SortedMultiDict[K, V] private (elems: SortedMap[K, Set[V]])(implicit val o
3131

3232
def addOne(elem: (K, V)): this.type = {
3333
val (k, v) = elem
34-
elems.updateWith(k) {
35-
case None => Some(Set(v))
36-
case Some(vs) => Some(vs += v)
37-
}
34+
val vs = elems.getOrElseUpdate(k, Set.empty[V])
35+
vs.addOne(v)
3836
this
3937
}
4038

4139
def subtractOne(elem: (K, V)): this.type = {
4240
val (k, v) = elem
43-
elems.updateWith(k) {
41+
elems.get(k) match {
4442
case Some(vs) =>
45-
vs -= v
46-
if (vs.nonEmpty) Some(vs) else None
47-
case None => None
43+
vs.subtractOne(v)
44+
if (vs.isEmpty) elems.subtractOne(k)
45+
case _ =>
4846
}
4947
this
5048
}
@@ -54,7 +52,7 @@ class SortedMultiDict[K, V] private (elems: SortedMap[K, Set[V]])(implicit val o
5452
* @return the collection itself
5553
*/
5654
def removeKey(key: K): this.type = {
57-
elems -= key
55+
elems.subtractOne(key)
5856
this
5957
}
6058

@@ -76,4 +74,4 @@ object SortedMultiDict extends SortedMapFactory[SortedMultiDict] {
7674
def newBuilder[K: Ordering, V]: Builder[(K, V), SortedMultiDict[K, V]] =
7775
new GrowableBuilder[(K, V), SortedMultiDict[K, V]](empty)
7876

79-
}
77+
}

0 commit comments

Comments
 (0)