From 511c908ba9761ce1d766b4b2100f17f68bbcb1d2 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Tue, 24 Sep 2013 17:24:02 +0400 Subject: [PATCH] Generating stub methods for read-only collection. --- .../codegen/ImplementationBodyCodegen.java | 24 ++++++++++---- .../box/builtinStubMethods/Collection.kt | 32 +++++++++++++++++++ .../BlackBoxCodegenTestGenerated.java | 5 +++ 3 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 compiler/testData/codegen/box/builtinStubMethods/Collection.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index a4635245f75..371ac4b8b0f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -469,13 +469,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { List result = Lists.newArrayList(); KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); - if (isSubclass(descriptor, builtIns.getList())) { - TypeParameterDescriptor listTypeParameter = builtIns.getList().getTypeConstructor().getParameters().get(0); - TypeSubstitutor deepSubstitutor = SubstitutionUtils.buildDeepSubstitutor(descriptor.getDefaultType()); - TypeProjection substitute = deepSubstitutor.substitute(new TypeProjection(listTypeParameter.getDefaultType())); - assert substitute != null : "Couldn't substitute: " + descriptor; - ClassifierDescriptor classifier = substitute.getType().getConstructor().getDeclarationDescriptor(); - assert classifier != null : "No classifier: " + substitute.getType(); + if (isSubclass(descriptor, builtIns.getCollection())) { + ClassifierDescriptor classifier = getSubstituteForTypeParameterOf(builtIns.getCollection()); if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("add"), builtIns.getBoolean(), classifier) == null) { @@ -505,6 +500,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("clear"), builtIns.getUnit()) == null){ result.add("clear()V"); } + } + + if (isSubclass(descriptor, builtIns.getList())) { + ClassifierDescriptor classifier = getSubstituteForTypeParameterOf(builtIns.getList()); if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("set"), classifier, builtIns.getInt(), classifier) == null) { @@ -532,6 +531,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return result; } + @NotNull + private ClassifierDescriptor getSubstituteForTypeParameterOf(@NotNull ClassDescriptor trait) { + TypeParameterDescriptor listTypeParameter = trait.getTypeConstructor().getParameters().get(0); + TypeSubstitutor deepSubstitutor = SubstitutionUtils.buildDeepSubstitutor(descriptor.getDefaultType()); + TypeProjection substitute = deepSubstitutor.substitute(new TypeProjection(listTypeParameter.getDefaultType())); + assert substitute != null : "Couldn't substitute: " + descriptor; + ClassifierDescriptor classifier = substitute.getType().getConstructor().getDeclarationDescriptor(); + assert classifier != null : "No classifier: " + substitute.getType(); + return classifier; + } + private void generateBuiltinMethodStubs() { for (String signature : getBuiltinMethodStubSignatures()) { diff --git a/compiler/testData/codegen/box/builtinStubMethods/Collection.kt b/compiler/testData/codegen/box/builtinStubMethods/Collection.kt new file mode 100644 index 00000000000..9435170e886 --- /dev/null +++ b/compiler/testData/codegen/box/builtinStubMethods/Collection.kt @@ -0,0 +1,32 @@ +class MyCollection: Collection { + override fun size(): Int = 0 + override fun isEmpty(): Boolean = true + override fun contains(o: Any?): Boolean = false + override fun iterator(): Iterator = throw UnsupportedOperationException() + override fun toArray(): Array = throw UnsupportedOperationException() + override fun toArray(a: Array): Array = throw UnsupportedOperationException() + override fun containsAll(c: Collection): Boolean = false + override fun hashCode(): Int = 0 + override fun equals(other: Any?): Boolean = false +} + +fun expectUoe(block: () -> Any) { + try { + block() + throw AssertionError() + } catch (e: UnsupportedOperationException) { + } +} + +fun box(): String { + val collection = MyCollection() as MutableCollection + + expectUoe { collection.add("") } + expectUoe { collection.remove("") } + expectUoe { collection.addAll(collection) } + expectUoe { collection.removeAll(collection) } + expectUoe { collection.retainAll(collection) } + expectUoe { collection.clear() } + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index f335b8f210e..f7bfde2cf6e 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -424,6 +424,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box/builtinStubMethods"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("Collection.kt") + public void testCollection() throws Exception { + doTest("compiler/testData/codegen/box/builtinStubMethods/Collection.kt"); + } + @TestMetadata("Iterator.kt") public void testIterator() throws Exception { doTest("compiler/testData/codegen/box/builtinStubMethods/Iterator.kt");