Support covariant MutableMap.entries.remove in JS/IR
Workaround for KT-43321 Follow up to KT-41278
This commit is contained in:
committed by
TeamCityServer
parent
666ad1f9d5
commit
ed3542cdf5
@@ -50,6 +50,8 @@ public actual abstract class AbstractMutableMap<K, V> protected actual construct
|
|||||||
internal abstract class AbstractEntrySet<E : Map.Entry<K, V>, K, V> : AbstractMutableSet<E>() {
|
internal abstract class AbstractEntrySet<E : Map.Entry<K, V>, K, V> : AbstractMutableSet<E>() {
|
||||||
final override fun contains(element: E): Boolean = containsEntry(element)
|
final override fun contains(element: E): Boolean = containsEntry(element)
|
||||||
abstract fun containsEntry(element: Map.Entry<K, V>): Boolean
|
abstract fun containsEntry(element: Map.Entry<K, V>): Boolean
|
||||||
|
final override fun remove(element: E): Boolean = removeEntry(element)
|
||||||
|
abstract fun removeEntry(element: Map.Entry<K, V>): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
actual override fun clear() {
|
actual override fun clear() {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public actual open class HashMap<K, V> : AbstractMutableMap<K, V>, MutableMap<K,
|
|||||||
|
|
||||||
override operator fun iterator(): MutableIterator<MutableEntry<K, V>> = internalMap.iterator()
|
override operator fun iterator(): MutableIterator<MutableEntry<K, V>> = internalMap.iterator()
|
||||||
|
|
||||||
override fun remove(element: MutableEntry<K, V>): Boolean {
|
override fun removeEntry(element: Map.Entry<K, V>): Boolean {
|
||||||
if (contains(element)) {
|
if (contains(element)) {
|
||||||
this@HashMap.remove(element.key)
|
this@HashMap.remove(element.key)
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
|
|||||||
|
|
||||||
override operator fun iterator(): MutableIterator<MutableEntry<K, V>> = EntryIterator()
|
override operator fun iterator(): MutableIterator<MutableEntry<K, V>> = EntryIterator()
|
||||||
|
|
||||||
override fun remove(element: MutableEntry<K, V>): Boolean {
|
override fun removeEntry(element: Map.Entry<K, V>): Boolean {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
if (contains(element)) {
|
if (contains(element)) {
|
||||||
this@LinkedHashMap.remove(element.key)
|
this@LinkedHashMap.remove(element.key)
|
||||||
|
|||||||
@@ -420,7 +420,10 @@ class MapTest {
|
|||||||
// which [contains] method takes [MutableEntry], so the compiler may generate special bridge
|
// which [contains] method takes [MutableEntry], so the compiler may generate special bridge
|
||||||
// returning false for values that aren't [MutableEntry] (including [SimpleEntry]).
|
// returning false for values that aren't [MutableEntry] (including [SimpleEntry]).
|
||||||
assertTrue(map.entries.contains(SimpleEntry(key, value)), mapDescription)
|
assertTrue(map.entries.contains(SimpleEntry(key, value)), mapDescription)
|
||||||
assertTrue(map.entries.toSet().contains(SimpleEntry(key, value)), mapDescription)
|
assertTrue(map.entries.toSet().contains(SimpleEntry(key, value)), "$mapDescription: reference")
|
||||||
|
|
||||||
|
assertFalse(map.entries.contains(null as Any?), "$mapDescription: contains null")
|
||||||
|
assertFalse(map.entries.contains("not an entry" as Any?), "$mapDescription: contains not an entry")
|
||||||
}
|
}
|
||||||
|
|
||||||
val mapLetterToIndex = ('a'..'z').mapIndexed { i, c -> "$c" to i }.toMap()
|
val mapLetterToIndex = ('a'..'z').mapIndexed { i, c -> "$c" to i }.toMap()
|
||||||
@@ -436,6 +439,36 @@ class MapTest {
|
|||||||
doTest("built Map", builtMap, "y", 24)
|
doTest("built Map", builtMap, "y", 24)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun entriesCovariantRemove() {
|
||||||
|
fun doTest(implName: String, map: MutableMap<String, Int>, key: String, value: Int) {
|
||||||
|
class SimpleEntry<out K, out V>(override val key: K, override val value: V) : Map.Entry<K, V> {
|
||||||
|
override fun toString(): String = "$key=$value"
|
||||||
|
override fun hashCode(): Int = key.hashCode() xor value.hashCode()
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is Map.Entry<*, *> && key == other.key && value == other.value
|
||||||
|
}
|
||||||
|
|
||||||
|
val mapDescription = "$implName: ${map::class}"
|
||||||
|
|
||||||
|
assertTrue(map.entries.toMutableSet().remove(SimpleEntry(key, value) as Map.Entry<*, *>), "$mapDescription: reference")
|
||||||
|
assertTrue(map.entries.remove(SimpleEntry(key, value) as Map.Entry<*, *>), mapDescription)
|
||||||
|
|
||||||
|
assertFalse(map.entries.remove(null as Any?), "$mapDescription: remove null")
|
||||||
|
assertFalse(map.entries.remove("not an entry" as Any?), "$mapDescription: remove not an entry")
|
||||||
|
}
|
||||||
|
|
||||||
|
val mapLetterToIndex = ('a'..'z').mapIndexed { i, c -> "$c" to i }.toMap()
|
||||||
|
doTest("default mutable", mapLetterToIndex.toMutableMap(), "b", 1)
|
||||||
|
doTest("HashMap", mapLetterToIndex.toMap(HashMap()), "c", 2)
|
||||||
|
doTest("LinkedHashMap", mapLetterToIndex.toMap(LinkedHashMap()), "d", 3)
|
||||||
|
|
||||||
|
val builtMap = buildMap {
|
||||||
|
putAll(mapLetterToIndex)
|
||||||
|
doTest("MapBuilder", this, "z", 25)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun firstNotNullOf() {
|
fun firstNotNullOf() {
|
||||||
val map = mapOf("Alice" to 20, "Tom" to 13, "Bob" to 18)
|
val map = mapOf("Alice" to 20, "Tom" to 13, "Bob" to 18)
|
||||||
|
|||||||
Reference in New Issue
Block a user