Skip to content

Commit 1fdfa9d

Browse files
committed
Correctly implement specialized MutableEntrySet.remove KT-41278
1 parent d22b149 commit 1fdfa9d

File tree

3 files changed

+41
-15
lines changed

3 files changed

+41
-15
lines changed

core/commonMain/src/implementations/immutableMap/PersistentHashMapBuilderContentViews.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ internal abstract class AbstractMapBuilderEntries<E : Map.Entry<K, V>, K, V> : A
1313
return containsEntry(element)
1414
}
1515
abstract fun containsEntry(element: Map.Entry<K, V>): Boolean
16+
17+
final override fun remove(element: E): Boolean {
18+
// TODO: Eliminate this check after KT-30016 gets fixed.
19+
if ((element as? Any?) !is Map.Entry<*, *>) return false
20+
return removeEntry(element)
21+
}
22+
abstract fun removeEntry(element: Map.Entry<K, V>): Boolean
1623
}
1724

1825
internal class PersistentHashMapBuilderEntries<K, V>(private val builder: PersistentHashMapBuilder<K, V>)
@@ -29,9 +36,7 @@ internal class PersistentHashMapBuilderEntries<K, V>(private val builder: Persis
2936
return PersistentHashMapBuilderEntriesIterator(builder)
3037
}
3138

32-
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
33-
// TODO: Eliminate this check after KT-30016 gets fixed.
34-
if ((element as Any?) !is Map.Entry<*, *>) return false
39+
override fun removeEntry(element: Map.Entry<K, V>): Boolean {
3540
return builder.remove(element.key, element.value)
3641
}
3742

core/commonMain/src/implementations/persistentOrderedMap/PersistentOrderedMapBuilderContentViews.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ internal class PersistentOrderedMapBuilderEntries<K, V>(private val builder: Per
2121
return PersistentOrderedMapBuilderEntriesIterator(builder)
2222
}
2323

24-
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
25-
// TODO: Eliminate this check after KT-30016 gets fixed.
26-
if ((element as Any?) !is Map.Entry<*, *>) return false
24+
override fun removeEntry(element: Map.Entry<K, V>): Boolean {
2725
return builder.remove(element.key, element.value)
2826
}
2927

core/commonTest/src/contract/map/KT41278Test.kt

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import kotlin.test.assertTrue
1414

1515
class KT41278Test {
1616
// Based on https://youtrack.jetbrains.com/issue/KT-42428.
17-
private fun doTest(map: Map<String, Int>, key: String, value: Int, createEntry: (String, Int) -> Map.Entry<String, Int>) {
17+
private fun doContainsTest(map: Map<String, Int>, key: String, value: Int, createEntry: (String, Int) -> Map.Entry<String, Int>) {
1818
assertTrue(map.keys.contains(key))
1919
assertEquals(value, map[key])
2020
// This one requires special efforts to make it work this way.
@@ -28,14 +28,28 @@ class KT41278Test {
2828
assertFalse(map.entries.contains("not an entry" as Any?))
2929
}
3030

31+
private fun doRemoveTest(map: MutableMap<String, Int>, key: String, value: Int, createEntry: (String, Int) -> Map.Entry<String, Int>) {
32+
assertTrue(map.keys.contains(key))
33+
assertEquals(value, map[key])
34+
// This one requires special efforts to make it work this way.
35+
// map.entries can in fact be `MutableSet<MutableMap.MutableEntry>`,
36+
// which [remove] method takes [MutableEntry], so the compiler may generate special bridge
37+
// returning false for values that aren't [MutableEntry].
38+
assertTrue(map.entries.toMutableSet().remove(createEntry(key, value)))
39+
assertTrue(map.entries.remove(createEntry(key, value)))
40+
}
41+
3142
@Test
3243
fun persistentOrderedMap() {
3344
val mapLetterToIndex = ('a'..'z').mapIndexed { i, c -> "$c" to i }.fold(persistentMapOf<String, Int>()) { map, pair ->
3445
map.put(pair.first, pair.second)
3546
}
3647

37-
doTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
38-
doTest(mapLetterToIndex, "h", 7, ::TestMutableMapEntry)
48+
doContainsTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
49+
doContainsTest(mapLetterToIndex, "h", 7, ::TestMutableMapEntry)
50+
51+
doRemoveTest(mapLetterToIndex.builder(), "h", 7, ::TestMapEntry)
52+
doRemoveTest(mapLetterToIndex.builder(), "h", 7, ::TestMutableMapEntry)
3953
}
4054

4155
@Test
@@ -44,24 +58,33 @@ class KT41278Test {
4458
map.put(pair.first, pair.second)
4559
}
4660

47-
doTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
48-
doTest(mapLetterToIndex, "h", 7, ::TestMutableMapEntry)
61+
doContainsTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
62+
doContainsTest(mapLetterToIndex, "h", 7, ::TestMutableMapEntry)
63+
64+
doRemoveTest(mapLetterToIndex.builder(), "h", 7, ::TestMapEntry)
65+
doRemoveTest(mapLetterToIndex.builder(), "h", 7, ::TestMutableMapEntry)
4966
}
5067

5168
@Test
5269
fun persistentOrderedMapBuilder() {
5370
val mapLetterToIndex = persistentMapOf<String, Int>().builder().apply { putAll(('a'..'z').mapIndexed { i, c -> "$c" to i }) }
5471

55-
doTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
56-
doTest(mapLetterToIndex, "h", 7, ::TestMutableMapEntry)
72+
doContainsTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
73+
doContainsTest(mapLetterToIndex, "h", 7, ::TestMutableMapEntry)
74+
75+
doRemoveTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
76+
doRemoveTest(mapLetterToIndex, "b", 1, ::TestMutableMapEntry)
5777
}
5878

5979
@Test
6080
fun persistentHashMapBuilder() {
6181
val mapLetterToIndex = persistentHashMapOf<String, Int>().builder().apply { putAll(('a'..'z').mapIndexed { i, c -> "$c" to i }) }
6282

63-
doTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
64-
doTest(mapLetterToIndex, "h", 7, ::TestMutableMapEntry)
83+
doContainsTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
84+
doContainsTest(mapLetterToIndex, "h", 7, ::TestMutableMapEntry)
85+
86+
doRemoveTest(mapLetterToIndex, "h", 7, ::TestMapEntry)
87+
doRemoveTest(mapLetterToIndex, "b", 1, ::TestMutableMapEntry)
6588
}
6689
}
6790

0 commit comments

Comments
 (0)