Skip to content

Commit 963a7ed

Browse files
committed
Remove multi-parameter, vararg variant of + and -
Ref scala/scala-dev#496 Ref scala/scala3#4311 (comment) Using the `compileTimeError` annotation, this removes the multi-parameter, vararg variants of `+` and `-` operators from the collections, and instructs the users to migrate to `++` and `--` instead. This is part of an effort to remove the ambiguity between tuple literal and parameter list when in an infixed operator notation.
1 parent 782d431 commit 963a7ed

14 files changed

+81
-49
lines changed

src/library/scala/collection/Map.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package scala
1414
package collection
1515

16+
import scala.annotation.compileTimeError
1617
import scala.annotation.unchecked.uncheckedVariance
1718
import scala.collection.generic.DefaultSerializable
1819
import scala.collection.mutable.StringBuilder
@@ -62,7 +63,7 @@ trait Map[K, +V]
6263
// These two methods are not in MapOps so that MapView is not forced to implement them
6364
@deprecated("Use - or remove on an immutable Map", "2.13.0")
6465
def - (key: K): Map[K, V]
65-
@deprecated("Use -- or removeAll on an immutable Map", "2.13.0")
66+
@compileTimeError("use -- or removeAll on an immutable Map instead")
6667
def - (key1: K, key2: K, keys: K*): Map[K, V]
6768

6869
@deprecatedOverriding("Compatibility override", since="2.13.0")
@@ -301,9 +302,8 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
301302
def + [V1 >: V](kv: (K, V1)): CC[K, V1] =
302303
mapFactory.from(new View.Appended(toIterable, kv))
303304

304-
@deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
305-
def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] =
306-
mapFactory.from(new View.Concat(new View.Appended(new View.Appended(toIterable, elem1), elem2), elems))
305+
@compileTimeError("use ++ with an explicit collection argument instead")
306+
def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = ???
307307

308308
@deprecated("Consider requiring an immutable Map.", "2.13.0")
309309
@`inline` def -- (keys: IterableOnce[K]): C = {

src/library/scala/collection/Set.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package scala
1414
package collection
1515

16+
import scala.annotation.compileTimeError
1617
import scala.language.higherKinds
1718
import scala.util.hashing.MurmurHash3
1819
import java.lang.String
@@ -174,8 +175,8 @@ trait SetOps[A, +CC[_], +C <: SetOps[A, CC, C]]
174175
@deprecated("Consider requiring an immutable Set or fall back to Set.diff", "2.13.0")
175176
def - (elem: A): C = diff(Set(elem))
176177

177-
@deprecated("Use &- with an explicit collection argument instead of - with varargs", "2.13.0")
178-
def - (elem1: A, elem2: A, elems: A*): C = diff(elems.toSet + elem1 + elem2)
178+
@compileTimeError("use &- with an explicit collection argument instead")
179+
def - (elem1: A, elem2: A, elems: A*): C = ???
179180

180181
// The implicit dummy parameter is necessary to avoid erased signature clashes
181182
// between this `concat` and the polymorphic one defined in `IterableOps`.
@@ -202,8 +203,8 @@ trait SetOps[A, +CC[_], +C <: SetOps[A, CC, C]]
202203
@deprecated("Consider requiring an immutable Set or fall back to Set.union", "2.13.0")
203204
def + (elem: A): C = fromSpecific(new View.Appended(toIterable, elem))
204205

205-
@deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
206-
def + (elem1: A, elem2: A, elems: A*): C = fromSpecific(new View.Concat(new View.Appended(new View.Appended(toIterable, elem1), elem2), elems))
206+
@compileTimeError("use ++ with an explicit collection argument instead")
207+
def + (elem1: A, elem2: A, elems: A*): C = ???
207208

208209
/** Alias for `concat` */
209210
@`inline` final def ++ (that: collection.IterableOnce[A])(implicit dummy: DummyImplicit): C = concat(that)

src/library/scala/collection/SortedMap.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
package scala
1414
package collection
1515

16-
import scala.annotation.implicitNotFound
16+
import scala.annotation.{ compileTimeError, implicitNotFound }
1717
import scala.collection.immutable.TreeMap
1818
import scala.language.higherKinds
1919
import scala.annotation.unchecked.uncheckedVariance
@@ -189,8 +189,8 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _],
189189
@deprecated("Consider requiring an immutable Map or fall back to Map.concat", "2.13.0")
190190
override def + [V1 >: V](kv: (K, V1)): CC[K, V1] = sortedMapFactory.from(new View.Appended(toIterable, kv))
191191

192-
@deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
193-
override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = sortedMapFactory.from(new View.Concat(new View.Appended(new View.Appended(toIterable, elem1), elem2), elems))
192+
@compileTimeError("use ++ with an explicit collection argument instead")
193+
override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = ???
194194

195195
// TODO Also override mapValues
196196
}

src/library/scala/collection/StrictOptimizedMapOps.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
package scala.collection
1414

15+
import scala.annotation.compileTimeError
1516
import scala.language.higherKinds
1617

1718
/**
@@ -38,9 +39,6 @@ trait StrictOptimizedMapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C
3839
override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)]): CC[K2, V2] =
3940
strictOptimizedCollect(mapFactory.newBuilder, pf)
4041

41-
@deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
42-
override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = {
43-
val m = ((this + elem1).asInstanceOf[Map[K, V]] + elem2).asInstanceOf[CC[K, V1]]
44-
if(elems.isEmpty) m else m.concat(elems).asInstanceOf[CC[K, V1]]
45-
}
42+
@compileTimeError("use ++ with an explicit collection argument instead")
43+
override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = ???
4644
}

src/library/scala/collection/StrictOptimizedSortedMapOps.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
package scala.collection
1414

15-
import scala.annotation.implicitNotFound
15+
import scala.annotation.{ compileTimeError, implicitNotFound }
1616

1717
/**
1818
* Trait that overrides sorted map operations to take advantage of strict builders.
@@ -38,9 +38,6 @@ trait StrictOptimizedSortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOp
3838
override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
3939
strictOptimizedCollect(sortedMapFactory.newBuilder, pf)
4040

41-
@deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
42-
override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = {
43-
val m = ((this + elem1).asInstanceOf[Map[K, V]] + elem2).asInstanceOf[CC[K, V1]]
44-
if(elems.isEmpty) m else m.concat(elems).asInstanceOf[CC[K, V1]]
45-
}
41+
@compileTimeError("use ++ with an explicit collection argument instead")
42+
override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = ???
4643
}

src/library/scala/collection/generic/Subtractable.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ package collection
1515
package generic
1616

1717
import scala.collection.IterableOnce
18-
18+
import scala.annotation.compileTimeError
1919

2020
/** This trait represents collection-like objects that can be reduced
2121
* using a '+' operator. It defines variants of `-` and `--`
@@ -54,8 +54,8 @@ trait Subtractable[A, +Repr <: Subtractable[A, Repr]] { self =>
5454
* @return a new $coll that contains all elements of the current $coll
5555
* except one less occurrence of each of the given elements.
5656
*/
57-
def -(elem1: A, elem2: A, elems: A*): Repr =
58-
this - elem1 - elem2 -- elems
57+
@compileTimeError("use -- with an explicit collection argument instead")
58+
def -(elem1: A, elem2: A, elems: A*): Repr = ???
5959

6060
/** Creates a new $coll from this $coll by removing all elements of another
6161
* collection.

src/library/scala/collection/immutable/Map.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ package scala
1414
package collection
1515
package immutable
1616

17+
import scala.annotation.compileTimeError
1718
import scala.annotation.unchecked.uncheckedVariance
1819
import scala.collection.generic.DefaultSerializable
1920
import scala.collection.immutable.Map.Map4
@@ -76,8 +77,8 @@ trait MapOps[K, +V, +CC[X, +Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C]
7677
@deprecatedOverriding("This method should be final, but is not due to scala/bug#10853", "2.13.0")
7778
/*@`inline` final*/ def - (key: K): C = removed(key)
7879

79-
@deprecated("Use -- with an explicit collection", "2.13.0")
80-
def - (key1: K, key2: K, keys: K*): C = removed(key1).removed(key2).removedAll(keys)
80+
@compileTimeError("use -- with an explicit collection argument instead")
81+
def - (key1: K, key2: K, keys: K*): C = ???
8182

8283
/** Creates a new $coll from this $coll by removing all elements of another
8384
* collection.

src/library/scala/collection/mutable/AnyRefMap.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ package collection
1515
package mutable
1616

1717
import java.io.{ObjectInputStream, ObjectOutputStream}
18-
18+
import scala.annotation.compileTimeError
1919
import scala.collection.generic.DefaultSerializationProxy
2020

2121

@@ -379,11 +379,8 @@ class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initi
379379
@deprecated("Consider requiring an immutable Map or fall back to Map.concat", "2.13.0")
380380
override def + [V1 >: V](kv: (K, V1)): AnyRefMap[K, V1] = AnyRefMap.from(new View.Appended(toIterable, kv))
381381

382-
@deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
383-
override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): AnyRefMap[K, V1] = {
384-
val m = this + elem1 + elem2
385-
if(elems.isEmpty) m else m.concat(elems)
386-
}
382+
@compileTimeError("use ++ with an explicit collection argument instead")
383+
override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): AnyRefMap[K, V1] = ???
387384

388385
override def concat[V2 >: V](xs: scala.collection.IterableOnce[(K, V2)]): AnyRefMap[K, V2] = {
389386
val arm = clone().asInstanceOf[AnyRefMap[K, V2]]

src/library/scala/collection/mutable/Growable.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package collection
1515
package mutable
1616

1717
import scala.collection.IterableOnce
18+
import scala.annotation.compileTimeError
1819

1920
/** This trait forms part of collections that can be augmented
2021
* using a `+=` operator and that can be cleared of all elements using
@@ -48,8 +49,8 @@ trait Growable[-A] extends Clearable {
4849
* @param elems the remaining elements to $add.
4950
* @return the $coll itself
5051
*/
51-
@deprecated("Use `++=` (addAll) instead of varargs `+=`", "2.13.0")
52-
@`inline` final def += (elem1: A, elem2: A, elems: A*): this.type = this += elem1 += elem2 ++= (elems: IterableOnce[A])
52+
@compileTimeError("use `++=` or addAll instead")
53+
@`inline` final def += (elem1: A, elem2: A, elems: A*): this.type = ???
5354

5455
/** ${Add}s all elements produced by an IterableOnce to this $coll.
5556
*

src/library/scala/collection/mutable/LongMap.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ package scala.collection
1414
package mutable
1515

1616
import java.io.{ObjectInputStream, ObjectOutputStream}
17-
17+
import scala.annotation.compileTimeError
1818
import scala.collection.generic.DefaultSerializationProxy
1919

2020

@@ -454,11 +454,8 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff
454454
lm
455455
}
456456

457-
@deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
458-
override def + [V1 >: V](elem1: (Long, V1), elem2: (Long, V1), elems: (Long, V1)*): LongMap[V1] = {
459-
val m = this + elem1 + elem2
460-
if(elems.isEmpty) m else m.concat(elems)
461-
}
457+
@compileTimeError("use ++ with an explicit collection argument instead")
458+
override def +[V1 >: V](elem1: (Long, V1), elem2: (Long, V1), elems: (Long, V1)*): LongMap[V1] = ???
462459

463460
override def concat[V1 >: V](xs: scala.collection.IterableOnce[(Long, V1)]): LongMap[V1] = {
464461
val lm = clone().asInstanceOf[LongMap[V1]]

src/library/scala/collection/mutable/Map.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ package scala
1414
package collection
1515
package mutable
1616

17+
import scala.annotation.compileTimeError
1718
import scala.language.higherKinds
1819

1920
/** Base type of mutable Maps */
@@ -77,9 +78,9 @@ trait MapOps[K, V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C]]
7778
@deprecatedOverriding("This method should be final, but is not due to scala/bug#10853", "2.13.0")
7879
/*final*/ def - (key: K): C = clone() -= key
7980

80-
@deprecated("Use -- or removeAll on an immutable Map", "2.13.0")
81+
@compileTimeError("use -- or removeAll on an immutable Map")
8182
@deprecatedOverriding("This method should be final, but is not due to scala/bug#10853", "2.13.0")
82-
/*final*/ def - (key1: K, key2: K, keys: K*): C = clone() -= key1 -= key2 --= keys
83+
/*final*/ def - (key1: K, key2: K, keys: K*): C = ???
8384

8485
/** Adds a new key/value pair to this map and optionally returns previously bound value.
8586
* If the map already contains a

src/library/scala/collection/mutable/Shrinkable.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
package scala
1414
package collection.mutable
1515

16-
import scala.annotation.tailrec
16+
import scala.annotation.{ compileTimeError, tailrec }
1717

1818
/** This trait forms part of collections that can be reduced
1919
* using a `-=` operator.
@@ -42,11 +42,8 @@ trait Shrinkable[-A] {
4242
* @param elems the remaining elements to remove.
4343
* @return the $coll itself
4444
*/
45-
def -= (elem1: A, elem2: A, elems: A*): this.type = {
46-
this -= elem1
47-
this -= elem2
48-
this --= elems
49-
}
45+
@compileTimeError("use --= or subtractAll with an explicit collection argument instead")
46+
def -= (elem1: A, elem2: A, elems: A*): this.type = ???
5047

5148
/** Removes all elements produced by an iterator from this $coll.
5249
*
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
collection-removal.scala:4: error: use of method + in trait MapOps is unsupported: use ++ with an explicit collection argument instead
2+
val m1 = scala.collection.Map("foo" -> 1) + (("bar" -> 2), ("baz" -> 3))
3+
^
4+
collection-removal.scala:5: error: use of method - in trait Map is unsupported: use -- or removeAll on an immutable Map instead
5+
val m2 = scala.collection.Map("foo" -> 1) - ("foo", "bar", "baz")
6+
^
7+
collection-removal.scala:7: error: use of method + in trait SortedMapOps is unsupported: use ++ with an explicit collection argument instead
8+
val sm1 = scala.collection.SortedMap("foo" -> 1) + (("bar" -> 2), ("baz" -> 3))
9+
^
10+
collection-removal.scala:9: error: use of method - in trait MapOps is unsupported: use -- with an explicit collection argument instead
11+
val im1 = scala.collection.immutable.Map("foo" -> 1) - ("foo", "bar", "baz")
12+
^
13+
collection-removal.scala:11: error: use of method + in class LongMap is unsupported: use ++ with an explicit collection argument instead
14+
val lm1 = scala.collection.mutable.LongMap(1L -> 1) + ((2L -> 2), (3L -> 3))
15+
^
16+
collection-removal.scala:13: error: use of method - in trait SetOps is unsupported: use &- with an explicit collection argument instead
17+
val s1 = scala.collection.Set(1, 2) - (1, 2, 3)
18+
^
19+
collection-removal.scala:14: error: use of method + in trait SetOps is unsupported: use ++ with an explicit collection argument instead
20+
val s2 = scala.collection.Set(1, 2) + (1, 2, 3)
21+
^
22+
collection-removal.scala:16: error: use of method += in trait Growable is unsupported: use `++=` or addAll instead
23+
val lb1 = scala.collection.mutable.ListBuffer(1) += (1, 2, 3)
24+
^
25+
8 errors found
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// scalac: -deprecation -Xfatal-warnings
2+
3+
object Test1 {
4+
val m1 = scala.collection.Map("foo" -> 1) + (("bar" -> 2), ("baz" -> 3))
5+
val m2 = scala.collection.Map("foo" -> 1) - ("foo", "bar", "baz")
6+
7+
val sm1 = scala.collection.SortedMap("foo" -> 1) + (("bar" -> 2), ("baz" -> 3))
8+
9+
val im1 = scala.collection.immutable.Map("foo" -> 1) - ("foo", "bar", "baz")
10+
11+
val lm1 = scala.collection.mutable.LongMap(1L -> 1) + ((2L -> 2), (3L -> 3))
12+
13+
val s1 = scala.collection.Set(1, 2) - (1, 2, 3)
14+
val s2 = scala.collection.Set(1, 2) + (1, 2, 3)
15+
16+
val lb1 = scala.collection.mutable.ListBuffer(1) += (1, 2, 3)
17+
}

0 commit comments

Comments
 (0)