From b4bb08c01366a54f361f1e84222344a4214deb0c Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Wed, 25 Sep 2013 00:11:31 +0400 Subject: [PATCH] Generating stub methods for read-only map and entry. --- .../codegen/ImplementationBodyCodegen.java | 41 +++++++++++++++++-- .../codegen/box/builtinStubMethods/Map.kt | 30 ++++++++++++++ .../box/builtinStubMethods/MapEntry.kt | 15 +++++++ .../MapEntryWithSetValue.kt | 14 +++++++ .../MapWithAllImplementations.kt | 27 ++++++++++++ .../BlackBoxCodegenTestGenerated.java | 20 +++++++++ 6 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/box/builtinStubMethods/Map.kt create mode 100644 compiler/testData/codegen/box/builtinStubMethods/MapEntry.kt create mode 100644 compiler/testData/codegen/box/builtinStubMethods/MapEntryWithSetValue.kt create mode 100644 compiler/testData/codegen/box/builtinStubMethods/MapWithAllImplementations.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 371ac4b8b0f..441a64aacbd 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -470,7 +470,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); if (isSubclass(descriptor, builtIns.getCollection())) { - ClassifierDescriptor classifier = getSubstituteForTypeParameterOf(builtIns.getCollection()); + ClassifierDescriptor classifier = getSubstituteForTypeParameterOf(builtIns.getCollection(), 0); if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("add"), builtIns.getBoolean(), classifier) == null) { @@ -503,7 +503,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } if (isSubclass(descriptor, builtIns.getList())) { - ClassifierDescriptor classifier = getSubstituteForTypeParameterOf(builtIns.getList()); + ClassifierDescriptor classifier = getSubstituteForTypeParameterOf(builtIns.getList(), 0); if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("set"), classifier, builtIns.getInt(), classifier) == null) { @@ -521,6 +521,39 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } + if (isSubclass(descriptor, builtIns.getMap())) { + ClassifierDescriptor keyClassifier = getSubstituteForTypeParameterOf(builtIns.getMap(), 0); + ClassifierDescriptor valueClassifier = getSubstituteForTypeParameterOf(builtIns.getMap(), 1); + + if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("put"), + valueClassifier, keyClassifier, valueClassifier) == null) { + result.add("put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + } + + if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("remove"), + valueClassifier, builtIns.getAny()) == null) { + result.add("remove(Ljava/lang/Object;)Ljava/lang/Object;"); + } + + if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("putAll"), + builtIns.getUnit(), builtIns.getMap()) == null) { + result.add("putAll(Ljava/util/Map;)V"); + } + + if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("clear"), builtIns.getUnit()) == null) { + result.add("clear()V"); + } + } + + if (isSubclass(descriptor, builtIns.getMapEntry())) { + ClassifierDescriptor valueClassifier = getSubstituteForTypeParameterOf(builtIns.getMapEntry(), 1); + + if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("setValue"), + valueClassifier, valueClassifier) == null) { + result.add("setValue(Ljava/lang/Object;)Ljava/lang/Object;"); + } + } + if (isSubclass(descriptor, builtIns.getIterator())) { if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("remove"), builtIns.getUnit()) == null) { @@ -532,8 +565,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } @NotNull - private ClassifierDescriptor getSubstituteForTypeParameterOf(@NotNull ClassDescriptor trait) { - TypeParameterDescriptor listTypeParameter = trait.getTypeConstructor().getParameters().get(0); + private ClassifierDescriptor getSubstituteForTypeParameterOf(@NotNull ClassDescriptor trait, int index) { + TypeParameterDescriptor listTypeParameter = trait.getTypeConstructor().getParameters().get(index); TypeSubstitutor deepSubstitutor = SubstitutionUtils.buildDeepSubstitutor(descriptor.getDefaultType()); TypeProjection substitute = deepSubstitutor.substitute(new TypeProjection(listTypeParameter.getDefaultType())); assert substitute != null : "Couldn't substitute: " + descriptor; diff --git a/compiler/testData/codegen/box/builtinStubMethods/Map.kt b/compiler/testData/codegen/box/builtinStubMethods/Map.kt new file mode 100644 index 00000000000..80c356167df --- /dev/null +++ b/compiler/testData/codegen/box/builtinStubMethods/Map.kt @@ -0,0 +1,30 @@ +class MyMap: Map { + override fun size(): Int = 0 + override fun isEmpty(): Boolean = true + override fun containsKey(key: Any?): Boolean = false + override fun containsValue(value: Any?): Boolean = false + override fun get(key: Any?): V? = null + override fun keySet(): Set = throw UnsupportedOperationException() + override fun values(): Collection = throw UnsupportedOperationException() + override fun entrySet(): Set> = throw UnsupportedOperationException() +} + +fun expectUoe(block: () -> Unit) { + try { + block() + throw AssertionError() + } catch (e: UnsupportedOperationException) { + } +} + +fun box(): String { + val map = MyMap() as MutableMap + + expectUoe { map.put("", 1) } + expectUoe { map.remove("") } + expectUoe { map.putAll(map) } + expectUoe { map.clear() } + + return "OK" +} + diff --git a/compiler/testData/codegen/box/builtinStubMethods/MapEntry.kt b/compiler/testData/codegen/box/builtinStubMethods/MapEntry.kt new file mode 100644 index 00000000000..78eec72e98f --- /dev/null +++ b/compiler/testData/codegen/box/builtinStubMethods/MapEntry.kt @@ -0,0 +1,15 @@ +class MyMapEntry: Map.Entry { + override fun hashCode(): Int = 0 + override fun equals(other: Any?): Boolean = false + override fun getKey(): K = throw UnsupportedOperationException() + override fun getValue(): V = throw UnsupportedOperationException() +} + +fun box(): String { + try { + (MyMapEntry() as MutableMap.MutableEntry).setValue(1) + throw AssertionError() + } catch (e: UnsupportedOperationException) { + return "OK" + } +} diff --git a/compiler/testData/codegen/box/builtinStubMethods/MapEntryWithSetValue.kt b/compiler/testData/codegen/box/builtinStubMethods/MapEntryWithSetValue.kt new file mode 100644 index 00000000000..0f92c3f466e --- /dev/null +++ b/compiler/testData/codegen/box/builtinStubMethods/MapEntryWithSetValue.kt @@ -0,0 +1,14 @@ +class MyMapEntry: Map.Entry { + override fun hashCode(): Int = 0 + override fun equals(other: Any?): Boolean = false + override fun getKey(): K = throw UnsupportedOperationException() + override fun getValue(): V = throw UnsupportedOperationException() + + public fun setValue(value: V): V = value +} + +fun box(): String { + (MyMapEntry() as MutableMap.MutableEntry).setValue(1) + + return "OK" +} diff --git a/compiler/testData/codegen/box/builtinStubMethods/MapWithAllImplementations.kt b/compiler/testData/codegen/box/builtinStubMethods/MapWithAllImplementations.kt new file mode 100644 index 00000000000..a51a26c5d25 --- /dev/null +++ b/compiler/testData/codegen/box/builtinStubMethods/MapWithAllImplementations.kt @@ -0,0 +1,27 @@ +class MyMap: Map { + override fun size(): Int = 0 + override fun isEmpty(): Boolean = true + override fun containsKey(key: Any?): Boolean = false + override fun containsValue(value: Any?): Boolean = false + override fun get(key: Any?): V? = null + override fun keySet(): Set = throw UnsupportedOperationException() + override fun values(): Collection = throw UnsupportedOperationException() + override fun entrySet(): Set> = throw UnsupportedOperationException() + + public fun put(key: K, value: V): V? = null + public fun remove(key: Any?): V? = null + public fun putAll(m: Map) {} + public fun clear() {} +} + +fun box(): String { + val map = MyMap() as MutableMap + + map.put("", 1) + map.remove("") + map.putAll(map) + map.clear() + + return "OK" +} + diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index f7bfde2cf6e..992cc0a9ee9 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -454,6 +454,26 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/builtinStubMethods/ListWithAllInheritedImplementations.kt"); } + @TestMetadata("Map.kt") + public void testMap() throws Exception { + doTest("compiler/testData/codegen/box/builtinStubMethods/Map.kt"); + } + + @TestMetadata("MapEntry.kt") + public void testMapEntry() throws Exception { + doTest("compiler/testData/codegen/box/builtinStubMethods/MapEntry.kt"); + } + + @TestMetadata("MapEntryWithSetValue.kt") + public void testMapEntryWithSetValue() throws Exception { + doTest("compiler/testData/codegen/box/builtinStubMethods/MapEntryWithSetValue.kt"); + } + + @TestMetadata("MapWithAllImplementations.kt") + public void testMapWithAllImplementations() throws Exception { + doTest("compiler/testData/codegen/box/builtinStubMethods/MapWithAllImplementations.kt"); + } + @TestMetadata("SubstitutedList.kt") public void testSubstitutedList() throws Exception { doTest("compiler/testData/codegen/box/builtinStubMethods/SubstitutedList.kt");