Skip to content

Commit

Permalink
Add Map.getOrDefault method as PlatformDependent declaration with ref…
Browse files Browse the repository at this point in the history
…ined signature

- First parameter should have type of K instead of Any
- Special bridge should return second parameter if a key has wrong type
- Special bridge may throw an exception if defaultValue has wrong type

 #KT-13209 Fixed
  • Loading branch information
dzharkov committed Jul 27, 2016
1 parent 169acf2 commit 915e36c
Show file tree
Hide file tree
Showing 15 changed files with 353 additions and 26 deletions.
Expand Up @@ -937,13 +937,19 @@ private static void generateTypeCheckBarrierIfNeeded(
@NotNull Type returnType,
@Nullable Type[] delegateParameterTypes
) {
BuiltinMethodsWithSpecialGenericSignature.DefaultValue defaultValue =
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription typeSafeBarrierDescription =
BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
if (defaultValue == null) return;
if (typeSafeBarrierDescription == null) return;

FunctionDescriptor overriddenBuiltin =
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor);

assert overriddenBuiltin != null : "Overridden built-in method should not be null for " + descriptor;

Label defaultBranch = new Label();

for (int i = 0; i < descriptor.getValueParameters().size(); i++) {
if (!typeSafeBarrierDescription.checkParameter(i)) continue;
boolean isCheckForAny = delegateParameterTypes == null || OBJECT_TYPE.equals(delegateParameterTypes[i]);

KotlinType kotlinType = descriptor.getValueParameters().get(i).getType();
Expand All @@ -967,7 +973,13 @@ private static void generateTypeCheckBarrierIfNeeded(
iv.goTo(afterDefaultBranch);

iv.visitLabel(defaultBranch);
StackValue.constant(defaultValue.getValue(), returnType).put(returnType, iv);

if (typeSafeBarrierDescription.equals(BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT)) {
iv.load(2, returnType);
}
else {
StackValue.constant(typeSafeBarrierDescription.getDefaultValue(), returnType).put(returnType, iv);
}
iv.areturn(returnType);

iv.visitLabel(afterDefaultBranch);
Expand Down
Expand Up @@ -103,6 +103,7 @@ public interface Map</*0*/ K, /*1*/ out V> {
public abstract fun containsKey(/*0*/ key: K): kotlin.Boolean
public abstract fun containsValue(/*0*/ value: @kotlin.UnsafeVariance() V): kotlin.Boolean
public abstract operator fun get(/*0*/ key: K): V?
@kotlin.internal.PlatformDependent() public open fun getOrDefault(/*0*/ key: K, /*1*/ defaultValue: @kotlin.UnsafeVariance() V): V
public abstract fun isEmpty(): kotlin.Boolean

public interface Entry</*0*/ out K, /*1*/ out V> {
Expand Down Expand Up @@ -188,6 +189,7 @@ public interface MutableMap</*0*/ K, /*1*/ V> : kotlin.collections.Map<K, V> {
public abstract override /*1*/ /*fake_override*/ fun containsKey(/*0*/ key: K): kotlin.Boolean
public abstract override /*1*/ /*fake_override*/ fun containsValue(/*0*/ value: V): kotlin.Boolean
public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ key: K): V?
@kotlin.internal.PlatformDependent() public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ key: K, /*1*/ defaultValue: V): V
public abstract override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean
public abstract fun put(/*0*/ key: K, /*1*/ value: V): V?
public abstract fun putAll(/*0*/ from: kotlin.collections.Map<out K, V>): kotlin.Unit
Expand Down
Expand Up @@ -123,7 +123,7 @@ public interface Map</*0*/ K, /*1*/ out V> {
public abstract fun containsValue(/*0*/ value: @kotlin.UnsafeVariance() V): kotlin.Boolean
public open fun forEach(/*0*/ p0: java.util.function.BiConsumer<in K!, in V!>!): kotlin.Unit
public abstract operator fun get(/*0*/ key: K): V?
public open fun getOrDefault(/*0*/ p0: kotlin.Any!, /*1*/ p1: @kotlin.UnsafeVariance() V!): V!
@kotlin.internal.PlatformDependent() public open fun getOrDefault(/*0*/ key: K, /*1*/ defaultValue: @kotlin.UnsafeVariance() V): V
public abstract fun isEmpty(): kotlin.Boolean

public interface Entry</*0*/ out K, /*1*/ out V> {
Expand Down Expand Up @@ -229,7 +229,7 @@ public interface MutableMap</*0*/ K, /*1*/ V> : kotlin.collections.Map<K, V> {
public abstract override /*1*/ /*fake_override*/ fun containsValue(/*0*/ value: V): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun forEach(/*0*/ p0: java.util.function.BiConsumer<in K!, in V!>!): kotlin.Unit
public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ key: K): V?
public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ p0: kotlin.Any!, /*1*/ p1: V!): V!
@kotlin.internal.PlatformDependent() public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ key: K, /*1*/ defaultValue: V): V
public abstract override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean
public open fun merge(/*0*/ p0: K!, /*1*/ p1: V!, /*2*/ p2: java.util.function.BiFunction<in V!, in V!, out V!>!): V!
public abstract fun put(/*0*/ key: K, /*1*/ value: V): V?
Expand Down
@@ -0,0 +1,66 @@
// FULL_JDK
// WITH_RUNTIME

class A : MutableMap<Any, Any?> {
override val entries: MutableSet<MutableMap.MutableEntry<Any, Any?>>
get() = throw UnsupportedOperationException()
override val keys: MutableSet<Any>
get() = throw UnsupportedOperationException()
override val values: MutableCollection<Any?>
get() = throw UnsupportedOperationException()

override fun clear() {
throw UnsupportedOperationException()
}

override fun put(key: Any, value: Any?): Any? {
throw UnsupportedOperationException()
}

override fun putAll(from: Map<out Any, Any?>) {
throw UnsupportedOperationException()
}

override fun remove(key: Any): Any? {
throw UnsupportedOperationException()
}

override val size: Int
get() = throw UnsupportedOperationException()

override fun containsKey(key: Any): Boolean {
throw UnsupportedOperationException()
}

override fun containsValue(value: Any?): Boolean {
throw UnsupportedOperationException()
}

override fun get(key: Any): Any? {
throw UnsupportedOperationException()
}

override fun isEmpty(): Boolean {
throw UnsupportedOperationException()
}

override fun getOrDefault(key: Any, defaultValue: Any?): Any? {
if (key == "abc") return "cde"
return defaultValue
}
}

fun box(): String {
val a = A()
if (a.getOrDefault("abc", "xyz") != "cde") return "fail 1"
if (a.getOrDefault("56", "123") != "123") return "fail 2"

val mm = a as MutableMap<Any?, Any?>
if (mm.getOrDefault("abc", "xyz") != "cde") return "fail 3"
if (mm.getOrDefault("56", 123) != 123) return "fail 4"
if (mm.getOrDefault(1, "456") != "456") return "fail 5"
if (mm.getOrDefault(null, "qwe") != "qwe") return "fail 6"
if (mm.getOrDefault("abc", null) != "cde") return "fail 7"

return "OK"
}
@@ -0,0 +1,74 @@
// FULL_JDK
// WITH_RUNTIME

class A : MutableMap<String, String> {
override val entries: MutableSet<MutableMap.MutableEntry<String, String>>
get() = throw UnsupportedOperationException()
override val keys: MutableSet<String>
get() = throw UnsupportedOperationException()
override val values: MutableCollection<String>
get() = throw UnsupportedOperationException()

override fun clear() {
throw UnsupportedOperationException()
}

override fun put(key: String, value: String): String? {
throw UnsupportedOperationException()
}

override fun putAll(from: Map<out String, String>) {
throw UnsupportedOperationException()
}

override fun remove(key: String): String? {
throw UnsupportedOperationException()
}

override val size: Int
get() = throw UnsupportedOperationException()

override fun containsKey(key: String): Boolean {
throw UnsupportedOperationException()
}

override fun containsValue(value: String): Boolean {
throw UnsupportedOperationException()
}

override fun get(key: String): String? {
throw UnsupportedOperationException()
}

override fun isEmpty(): Boolean {
throw UnsupportedOperationException()
}

override fun getOrDefault(key: String, defaultValue: String): String {
if (key == "abc") return "cde"
return defaultValue
}
}

fun box(): String {
val a = A()
if (a.getOrDefault("abc", "xyz") != "cde") return "fail 1"
if (a.getOrDefault("56", "123") != "123") return "fail 2"

val mm = a as MutableMap<Any?, Any?>
if (mm.getOrDefault("abc", "xyz") != "cde") return "fail 3"
if (mm.getOrDefault("56", "123") != "123") return "fail 4"
if (mm.getOrDefault(1, "456") != "456") return "fail 5"
if (mm.getOrDefault(null, "qwe") != "qwe") return "fail 6"

try {
// This is a known problem, there's no way to implement type-safe bridge/barrier properly:
// 'override fun getOrDefault(key: String, defaultValue: String): String' expects two strings,
// and returning defaultValue if Int was received seems incorrect here
mm.getOrDefault("abc", 123)
return "fail 7"
} catch (e: java.lang.ClassCastException) {
}

return "OK"
}
@@ -0,0 +1,80 @@
// FULL_JDK
// WITH_RUNTIME

class A : MutableMap<Any, Any> {
override val entries: MutableSet<MutableMap.MutableEntry<Any, Any>>
get() = throw UnsupportedOperationException()
override val keys: MutableSet<Any>
get() = throw UnsupportedOperationException()
override val values: MutableCollection<Any>
get() = throw UnsupportedOperationException()

override fun clear() {
throw UnsupportedOperationException()
}

override fun put(key: Any, value: Any): Any? {
throw UnsupportedOperationException()
}

override fun putAll(from: Map<out Any, Any>) {
throw UnsupportedOperationException()
}

override fun remove(key: Any): Any? {
throw UnsupportedOperationException()
}

override val size: Int
get() = throw UnsupportedOperationException()

override fun containsKey(key: Any): Boolean {
throw UnsupportedOperationException()
}

override fun containsValue(value: Any): Boolean {
throw UnsupportedOperationException()
}

override fun get(key: Any): Any? {
throw UnsupportedOperationException()
}

override fun isEmpty(): Boolean {
throw UnsupportedOperationException()
}

override fun getOrDefault(key: Any, defaultValue: Any): Any {
// this condition can not be true because of checkParameterIsNotNull checks in the begin of every method, but it's left here
// to emphasize that we expect these parameters are not null
if (key == null || defaultValue == null) {
throw IllegalArgumentException("fail")
}
if (key == "abc") return "cde"
return defaultValue
}
}

fun box(): String {
val a = A()
if (a.getOrDefault("abc", "xyz") != "cde") return "fail 1"
if (a.getOrDefault("56", "123") != "123") return "fail 2"

val mm = a as MutableMap<Any?, Any?>
if (mm.getOrDefault("abc", "xyz") != "cde") return "fail 3"
if (mm.getOrDefault("56", 123) != 123) return "fail 4"
if (mm.getOrDefault(1, "456") != "456") return "fail 5"
if (mm.getOrDefault(null, "qwe") != "qwe") return "fail 6"

try {
// This is a known problem, there's no way to implement type-safe bridge/barrier properly:
// 'override fun getOrDefault(key: Any, defaultValue: Any): Any' expects two not-nullable values,
// and returning defaultValue if null was received seems incorrect here
mm.getOrDefault("abc", null)
return "fail 7"
} catch (e: java.lang.IllegalArgumentException) {
// Parameter specified as non-null is null
}

return "OK"
}
@@ -0,0 +1,18 @@
abstract class A : Map<Int, String>

fun foo(x: Map<Int, String>, a: A, b: java.util.HashMap<Int, String>) {
x.getOrDefault(1, "")
x.getOrDefault(<!TYPE_MISMATCH!>""<!>, "")
x.getOrDefault(1, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)
x.getOrDefault(<!TYPE_MISMATCH!>""<!>, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)

a.getOrDefault(1, "")
a.getOrDefault(<!TYPE_MISMATCH!>""<!>, "")
a.getOrDefault(1, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)
a.getOrDefault(<!TYPE_MISMATCH!>""<!>, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)

b.getOrDefault(1, "")
b.getOrDefault(<!TYPE_MISMATCH!>""<!>, "")
b.getOrDefault(1, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)
b.getOrDefault(<!TYPE_MISMATCH!>""<!>, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)
}
@@ -0,0 +1,20 @@
package

public fun foo(/*0*/ x: kotlin.collections.Map<kotlin.Int, kotlin.String>, /*1*/ a: A, /*2*/ b: java.util.HashMap<kotlin.Int, kotlin.String>): kotlin.Unit

public abstract class A : kotlin.collections.Map<kotlin.Int, kotlin.String> {
public constructor A()
public abstract override /*1*/ /*fake_override*/ val entries: kotlin.collections.Set<kotlin.collections.Map.Entry<kotlin.Int, kotlin.String>>
public abstract override /*1*/ /*fake_override*/ val keys: kotlin.collections.Set<kotlin.Int>
public abstract override /*1*/ /*fake_override*/ val size: kotlin.Int
public abstract override /*1*/ /*fake_override*/ val values: kotlin.collections.Collection<kotlin.String>
public abstract override /*1*/ /*fake_override*/ fun containsKey(/*0*/ key: kotlin.Int): kotlin.Boolean
public abstract override /*1*/ /*fake_override*/ fun containsValue(/*0*/ value: kotlin.String): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun forEach(/*0*/ p0: java.util.function.BiConsumer<in kotlin.Int!, in kotlin.String!>!): kotlin.Unit
public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ key: kotlin.Int): kotlin.String?
@kotlin.internal.PlatformDependent() public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ key: kotlin.Int, /*1*/ defaultValue: kotlin.String): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
Expand Up @@ -20,7 +20,7 @@ public final class KotlinMap1</*0*/ K, /*1*/ V> : java.util.AbstractMap<K, V> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun forEach(/*0*/ p0: java.util.function.BiConsumer<in K!, in V!>!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun get(/*0*/ key: K!): V?
public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ p0: kotlin.Any!, /*1*/ p1: V!): V!
@kotlin.internal.PlatformDependent() public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ key: K!, /*1*/ defaultValue: V!): V!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun merge(/*0*/ p0: K!, /*1*/ p1: V!, /*2*/ p2: java.util.function.BiFunction<in V!, in V!, out V!>!): V!
Expand Down Expand Up @@ -53,7 +53,7 @@ public final class KotlinMap2 : java.util.AbstractMap<kotlin.String, kotlin.Int>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun forEach(/*0*/ p0: java.util.function.BiConsumer<in kotlin.String!, in kotlin.Int!>!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun get(/*0*/ key: kotlin.String!): kotlin.Int?
public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ p0: kotlin.Any!, /*1*/ p1: kotlin.Int!): kotlin.Int!
@kotlin.internal.PlatformDependent() public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ key: kotlin.String!, /*1*/ defaultValue: kotlin.Int!): kotlin.Int!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun merge(/*0*/ p0: kotlin.String!, /*1*/ p1: kotlin.Int!, /*2*/ p2: java.util.function.BiFunction<in kotlin.Int!, in kotlin.Int!, out kotlin.Int!>!): kotlin.Int!
Expand Down
6 changes: 3 additions & 3 deletions compiler/testData/loadJava8/compiledJava/MapRemove.txt
Expand Up @@ -17,7 +17,7 @@ public open class MapRemove {
public abstract override /*1*/ /*fake_override*/ fun containsValue(/*0*/ value: V!): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun forEach(/*0*/ p0: java.util.function.BiConsumer<in K!, in V!>!): kotlin.Unit
public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ key: K!): V?
public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ p0: kotlin.Any!, /*1*/ p1: V!): V!
@kotlin.internal.PlatformDependent() public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ key: K!, /*1*/ defaultValue: V!): V!
public abstract override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun merge(/*0*/ p0: K!, /*1*/ p1: V!, /*2*/ p2: java.util.function.BiFunction<in V!, in V!, out V!>!): V!
public abstract override /*1*/ /*fake_override*/ fun put(/*0*/ key: K!, /*1*/ value: V!): V?
Expand All @@ -44,7 +44,7 @@ public open class MapRemove {
public abstract override /*1*/ /*fake_override*/ fun containsValue(/*0*/ value: kotlin.Int!): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun forEach(/*0*/ p0: java.util.function.BiConsumer<in kotlin.String!, in kotlin.Int!>!): kotlin.Unit
public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ key: kotlin.String!): kotlin.Int?
public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ p0: kotlin.Any!, /*1*/ p1: kotlin.Int!): kotlin.Int!
@kotlin.internal.PlatformDependent() public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ key: kotlin.String!, /*1*/ defaultValue: kotlin.Int!): kotlin.Int!
public abstract override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun merge(/*0*/ p0: kotlin.String!, /*1*/ p1: kotlin.Int!, /*2*/ p2: java.util.function.BiFunction<in kotlin.Int!, in kotlin.Int!, out kotlin.Int!>!): kotlin.Int!
public abstract override /*1*/ /*fake_override*/ fun put(/*0*/ key: kotlin.String!, /*1*/ value: kotlin.Int!): kotlin.Int?
Expand All @@ -71,7 +71,7 @@ public open class MapRemove {
public abstract override /*1*/ /*fake_override*/ fun containsValue(/*0*/ value: kotlin.Int!): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun forEach(/*0*/ p0: java.util.function.BiConsumer<in kotlin.String!, in kotlin.Int!>!): kotlin.Unit
public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ key: kotlin.String!): kotlin.Int?
public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ p0: kotlin.Any!, /*1*/ p1: kotlin.Int!): kotlin.Int!
@kotlin.internal.PlatformDependent() public open override /*1*/ /*fake_override*/ fun getOrDefault(/*0*/ key: kotlin.String!, /*1*/ defaultValue: kotlin.Int!): kotlin.Int!
public abstract override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun merge(/*0*/ p0: kotlin.String!, /*1*/ p1: kotlin.Int!, /*2*/ p2: java.util.function.BiFunction<in kotlin.Int!, in kotlin.Int!, out kotlin.Int!>!): kotlin.Int!
public abstract override /*1*/ /*fake_override*/ fun put(/*0*/ key: kotlin.String!, /*1*/ value: kotlin.Int!): kotlin.Int?
Expand Down

0 comments on commit 915e36c

Please sign in to comment.