diff --git a/compat/src/main/scala-2.11/scala/collection/compat/package.scala b/compat/src/main/scala-2.11/scala/collection/compat/package.scala index bf713e54..8cdd3c38 100644 --- a/compat/src/main/scala-2.11/scala/collection/compat/package.scala +++ b/compat/src/main/scala-2.11/scala/collection/compat/package.scala @@ -21,6 +21,17 @@ package object compat extends compat.PackageShared { implicit ordering: Ordering[A]): CanBuildFrom[Any, A, CC[A]] = CompatImpl.simpleCBF(fact.newBuilder[A]) + // CanBuildFrom instances for `IterableView[(K, V), Map[K, V]]` that preserve + // the strict type of the view to be `Map` instead of `Iterable` + // Instances produced by this method are used to chain `filterKeys` after `mapValues` + implicit def canBuildFromIterableViewMapLike[K, V, L, W, CC[X, Y] <: Map[X, Y]]: CanBuildFrom[IterableView[(K, V), CC[K, V]], (L, W), IterableView[(L, W), CC[L, W]]] = + new CanBuildFrom[IterableView[(K, V), CC[K, V]], (L, W), IterableView[(L, W), CC[L, W]]] { + // `CanBuildFrom` parameters are used as type constraints, they are not used + // at run-time, hence the dummy builder implementations + def apply(from: IterableView[(K, V), CC[K, V]]) = new TraversableView.NoBuilder + def apply() = new TraversableView.NoBuilder + } + implicit def toTraversableLikeExtensionMethods[Repr](self: Repr)( implicit traversable: IsTraversableLike[Repr]) : TraversableLikeExtensionMethods[traversable.A, Repr] = diff --git a/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala b/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala index 785fbcf4..62f6d728 100644 --- a/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala +++ b/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala @@ -354,7 +354,15 @@ class MapViewExtensionMethods[K, V, C <: scala.collection.Map[K, V]]( implicit bf: CanBuildFrom[IterableView[(K, V), C], (K, W), That]): That = self.map[(K, W), That] { case (k, v) => (k, f(v)) } - def filterKeys[That](p: K => Boolean)( - implicit bf: CanBuildFrom[IterableView[(K, V), C], (K, V), That]): That = - self.collect[(K, V), That] { case (k, v) if p(k) => (k, v) } + // TODO: Replace the current implementation of `mapValues` with this + // after major version bump when bincompat can be broken. + // At the same time, remove `canBuildFromIterableViewMapLike` + /* + def mapValues[W](f: V => W): IterableView[(K, W), C] = + // the implementation of `self.map` also casts the result + self.map({ case (k, v) => (k, f(v)) }).asInstanceOf[IterableView[(K, W), C]] + */ + + def filterKeys(p: K => Boolean): IterableView[(K, V), C] = + self.filter { case (k, _) => p(k) } } diff --git a/compat/src/main/scala-2.12/scala/collection/compat/package.scala b/compat/src/main/scala-2.12/scala/collection/compat/package.scala index c73d66a6..012532d4 100644 --- a/compat/src/main/scala-2.12/scala/collection/compat/package.scala +++ b/compat/src/main/scala-2.12/scala/collection/compat/package.scala @@ -32,6 +32,17 @@ package object compat extends compat.PackageShared { implicit ordering: Ordering[A]): CanBuildFrom[Any, A, CC[A]] = CompatImpl.simpleCBF(fact.newBuilder[A]) + // CanBuildFrom instances for `IterableView[(K, V), Map[K, V]]` that preserve + // the strict type of the view to be `Map` instead of `Iterable` + // Instances produced by this method are used to chain `filterKeys` after `mapValues` + implicit def canBuildFromIterableViewMapLike[K, V, L, W, CC[X, Y] <: Map[X, Y]]: CanBuildFrom[IterableView[(K, V), CC[K, V]], (L, W), IterableView[(L, W), CC[L, W]]] = + new CanBuildFrom[IterableView[(K, V), CC[K, V]], (L, W), IterableView[(L, W), CC[L, W]]] { + // `CanBuildFrom` parameters are used as type constraints, they are not used + // at run-time, hence the dummy builder implementations + def apply(from: IterableView[(K, V), CC[K, V]]) = new TraversableView.NoBuilder + def apply() = new TraversableView.NoBuilder + } + implicit def toTraversableLikeExtensionMethods[Repr](self: Repr)( implicit traversable: IsTraversableLike[Repr]) : TraversableLikeExtensionMethods[traversable.A, Repr] = diff --git a/compat/src/test/scala/test/scala/collection/ViewTest.scala b/compat/src/test/scala/test/scala/collection/ViewTest.scala index 7c150fc4..fd28ce23 100644 --- a/compat/src/test/scala/test/scala/collection/ViewTest.scala +++ b/compat/src/test/scala/test/scala/collection/ViewTest.scala @@ -35,4 +35,11 @@ class ViewTest { assertEquals(oldStyle.toMap, newStyle.toMap) } + @Test + def filterKeysMapValues(): Unit = { + val m = Map("a" -> 1, "b" -> 2, "c" -> 3) + assertEquals(Map(), m.view.filterKeys(_.length > 1).mapValues(_ + 1).toMap) + assertEquals(Map(), m.view.mapValues(_ + 1).filterKeys(_.length > 1).toMap) + } + }