From 23080f78f72cf23df9e8116b15033152effb8adf Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Fri, 22 Jan 2016 07:47:54 +0300 Subject: [PATCH] Map.getOrPut: treat nulls as missing values. --- .../boxWithStdlib/regressions/kt3442.kt | 2 +- .../org/jetbrains/kotlin/utils/collections.kt | 12 ++++++++++++ .../kotlin/idea/core/IterableTypesDetection.kt | 3 ++- .../KotlinMoveTarget.kt | 3 ++- js/js.libraries/src/core/collections.kt | 12 ------------ .../stdlib/src/kotlin/collections/Maps.kt | 18 +----------------- .../stdlib/src/kotlin/collections/MapsJVM.kt | 13 ++----------- libraries/stdlib/test/collections/MapTest.kt | 2 +- 8 files changed, 21 insertions(+), 44 deletions(-) diff --git a/compiler/testData/codegen/boxWithStdlib/regressions/kt3442.kt b/compiler/testData/codegen/boxWithStdlib/regressions/kt3442.kt index 55f3226b19f..0876d42e1b9 100644 --- a/compiler/testData/codegen/boxWithStdlib/regressions/kt3442.kt +++ b/compiler/testData/codegen/boxWithStdlib/regressions/kt3442.kt @@ -2,5 +2,5 @@ fun box(): String { val m = hashMapOf() m.put("b", null) val oldValue = m.getOrPut("b", { "Foo" }) - return if (oldValue == null) "OK" else "fail: $oldValue" + return if (oldValue == "Foo") "OK" else "fail: $oldValue" } diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt index c3fbd2a3518..36f9235fac1 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt @@ -41,6 +41,18 @@ fun Iterable.mapToIndex(): Map { return map } + +public inline fun MutableMap.getOrPutNullable(key: K, defaultValue: () -> V): V { + return if (!containsKey(key)) { + val answer = defaultValue() + put(key, answer) + answer + } + else { + get(key) as V + } +} + inline fun > C.ifEmpty(body: () -> C): C = if (isEmpty()) body() else this inline fun Array.ifEmpty(body: () -> Array): Array = if (isEmpty()) body() else this diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/IterableTypesDetection.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/IterableTypesDetection.kt index 88f5d04201f..c1da3e3d3de 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/IterableTypesDetection.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/IterableTypesDetection.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext import org.jetbrains.kotlin.types.expressions.ForLoopConventionsChecker import org.jetbrains.kotlin.util.isValidOperator +import org.jetbrains.kotlin.utils.getOrPutNullable import java.util.* class IterableTypesDetection( @@ -62,7 +63,7 @@ class IterableTypesDetection( = isIterable(FuzzyType(type, emptyList()), loopVarType) private fun elementType(type: FuzzyType): FuzzyType? { - return cache.getOrPut(type, { elementTypeNoCache(type) }) + return cache.getOrPutNullable(type, { elementTypeNoCache(type) }) } override fun elementType(type: KotlinType): FuzzyType? diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/KotlinMoveTarget.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/KotlinMoveTarget.kt index 89396c5b239..5ecea800b5e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/KotlinMoveTarget.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/KotlinMoveTarget.kt @@ -23,6 +23,7 @@ import com.intellij.psi.PsiManager import com.intellij.refactoring.PackageWrapper import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.utils.getOrPutNullable import java.util.HashMap interface KotlinMoveTarget { @@ -64,7 +65,7 @@ class KotlinMoveTargetForDeferredFile( override fun getOrCreateTargetPsi(originalPsi: PsiElement): PsiFile? { val originalFile = originalPsi.containingFile as? KtFile ?: return null - return createdFiles.getOrPut(originalFile) { createFile(originalFile) } + return createdFiles.getOrPutNullable(originalFile) { createFile(originalFile) } } override fun getTargetPsiIfExists(originalPsi: PsiElement) = null diff --git a/js/js.libraries/src/core/collections.kt b/js/js.libraries/src/core/collections.kt index 32ba6828312..3e8e5b36c97 100644 --- a/js/js.libraries/src/core/collections.kt +++ b/js/js.libraries/src/core/collections.kt @@ -35,15 +35,3 @@ public fun setOf(element: T): Set = hashSetOf(element) * specified value. */ public fun mapOf(pair: Pair): Map = hashMapOf(pair) - - -public inline fun MutableMap.getOrPut(key: K, defaultValue: () -> V): V { - val value = get(key) - return if (value == null && !containsKey(key)) { - val answer = defaultValue() - put(key, answer) - answer - } else { - value as V - } -} \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/collections/Maps.kt b/libraries/stdlib/src/kotlin/collections/Maps.kt index c7754f70fda..a724a46c01d 100644 --- a/libraries/stdlib/src/kotlin/collections/Maps.kt +++ b/libraries/stdlib/src/kotlin/collections/Maps.kt @@ -196,8 +196,7 @@ internal inline fun Map.getOrElseNullable(key: K, defaultValue: () * * @sample test.collections.MapTest.getOrPut */ -@kotlin.jvm.JvmVersion -public inline fun MutableMap.getOrPut(key: K, defaultValue: () -> V): V { +public inline fun MutableMap.getOrPut(key: K, defaultValue: () -> V): V { val value = get(key) return if (value == null) { val answer = defaultValue() @@ -208,21 +207,6 @@ public inline fun MutableMap.getOrPut(key: K, defaultValue: () } } -@kotlin.jvm.JvmName("getOrPutNullable") -@kotlin.jvm.JvmVersion -@Deprecated("This function will change its behavior soon not to distinguish missing keys and keys mapped to nulls.") -@kotlin.internal.LowPriorityInOverloadResolution -public inline fun MutableMap.getOrPut(key: K, defaultValue: () -> V): V { - val value = get(key) - return if (value == null && !containsKey(key)) { - val answer = defaultValue() - put(key, answer) - answer - } else { - value as V - } -} - /** * Returns an [Iterator] over the entries in the [Map]. * diff --git a/libraries/stdlib/src/kotlin/collections/MapsJVM.kt b/libraries/stdlib/src/kotlin/collections/MapsJVM.kt index fc71090b423..53970bccc97 100644 --- a/libraries/stdlib/src/kotlin/collections/MapsJVM.kt +++ b/libraries/stdlib/src/kotlin/collections/MapsJVM.kt @@ -18,15 +18,6 @@ public operator fun MutableMap.set(key: K, value: V): Unit { put(key, value) } -/** - * getOrPut is not supported on [ConcurrentMap] since it cannot be implemented correctly in terms of concurrency. - * Use [concurrentGetOrPut] instead, or cast this to a [MutableMap] if you want to sacrifice the concurrent-safety. - */ -@Deprecated("Use concurrentGetOrPut instead or cast this map to MutableMap.", level = DeprecationLevel.ERROR) -@kotlin.internal.LowPriorityInOverloadResolution -public inline fun ConcurrentMap.getOrPut(key: K, defaultValue: () -> V): Nothing = - throw UnsupportedOperationException("getOrPut is not supported on ConcurrentMap.") - /** * Concurrent getOrPut, that is safe for concurrent maps. * @@ -36,14 +27,14 @@ public inline fun ConcurrentMap.getOrPut(key: K, defaultValue: () - * This method guarantees not to put the value into the map if the key is already there, * but the [defaultValue] function may be invoked even if the key is already in the map. */ -public inline fun ConcurrentMap.getOrPut(key: K, defaultValue: () -> V): V { +public inline fun ConcurrentMap.getOrPut(key: K, defaultValue: () -> V): V { // Do not use computeIfAbsent on JVM8 as it would change locking behavior return this.get(key) ?: defaultValue().let { default -> this.putIfAbsent(key, default) ?: default } } -@Deprecated("Use getOrPut instead", ReplaceWith("getOrPut(key, defaultValue)")) +@Deprecated("Use getOrPut instead", ReplaceWith("getOrPut(key, defaultValue)"), level = DeprecationLevel.ERROR) public inline fun ConcurrentMap.concurrentGetOrPut(key: K, defaultValue: () -> V): V { // Do not use computeIfAbsent on JVM8 as it would change locking behavior return this.get(key) ?: diff --git a/libraries/stdlib/test/collections/MapTest.kt b/libraries/stdlib/test/collections/MapTest.kt index 357f5cb3365..26d87955711 100644 --- a/libraries/stdlib/test/collections/MapTest.kt +++ b/libraries/stdlib/test/collections/MapTest.kt @@ -62,7 +62,7 @@ class MapTest { assertEquals(null, c) val d = empty.getOrPut("") { 1 } - assertEquals(null, d) // soon will change to 1 + assertEquals(1, d) } @test fun sizeAndEmpty() {