From 6cb0e5151ca7764e1132469471f096dc530200ce Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 30 Sep 2015 18:23:26 +0300 Subject: [PATCH] KT-9377 Support is-checks for read-only collections Intrinsics for is/as/as? with mutable Kotlin collections and related types. --- .../kotlin/codegen/ExpressionCodegen.java | 16 +- .../codegen/inline/ReifiedTypeInliner.kt | 43 ++- .../kotlin/codegen/intrinsics/CheckCast.kt | 87 ++++++ .../kotlin/codegen/intrinsics/InstanceOf.kt | 72 +++++ .../box/builtinStubMethods/Collection.kt | 9 +- .../box/builtinStubMethods/Iterator.kt | 2 +- .../builtinStubMethods/IteratorWithRemove.kt | 2 +- .../codegen/box/builtinStubMethods/List.kt | 2 +- .../box/builtinStubMethods/ListIterator.kt | 2 +- .../ListWithAllImplementations.kt | 2 +- .../ListWithAllInheritedImplementations.kt | 2 +- .../codegen/box/builtinStubMethods/Map.kt | 5 +- .../box/builtinStubMethods/MapEntry.kt | 2 +- .../MapEntryWithSetValue.kt | 2 +- .../MapWithAllImplementations.kt | 5 +- .../box/builtinStubMethods/SubstitutedList.kt | 2 +- .../box/builtinStubMethods/abstractMember.kt | 2 +- .../delegationToArrayList.kt | 4 +- .../implementationInTrait.kt | 2 +- .../inheritedImplementations.kt | 2 +- .../manyTypeParametersWithUpperBounds.kt | 2 +- .../nonTrivialSubstitution.kt | 2 +- .../nonTrivialUpperBound.kt | 2 +- .../boxWithStdlib/casts/asWithMutable.kt | 126 ++++++++ .../boxWithStdlib/casts/isWithMutable.kt | 106 +++++++ .../casts/reifiedAsWithMutable.kt | 128 +++++++++ .../casts/reifiedIsWithMutable.kt | 109 +++++++ .../casts/reifiedSafeAsWithMutable.kt | 139 +++++++++ .../boxWithStdlib/casts/safeAsWithMutable.kt | 133 +++++++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 36 +++ .../src/kotlin/jvm/internal/Intrinsics.java | 271 +++++++++++++++++- .../org/jetbrains/kotlin/utils/SmartSet.kt | 22 +- 32 files changed, 1291 insertions(+), 50 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/CheckCast.kt create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/InstanceOf.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/casts/asWithMutable.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/casts/isWithMutable.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/casts/reifiedAsWithMutable.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/casts/reifiedIsWithMutable.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/casts/reifiedSafeAsWithMutable.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/casts/safeAsWithMutable.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index c64ac3368e4..b4238b68f19 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -36,9 +36,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; import org.jetbrains.kotlin.codegen.inline.*; -import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethod; -import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; -import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicPropertyGetter; +import org.jetbrains.kotlin.codegen.intrinsics.*; import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsPackage; import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; import org.jetbrains.kotlin.codegen.state.GenerationState; @@ -3751,7 +3749,7 @@ The "returned" value of try expression with no finally is either the last expres v.mark(ok); } - generateCheckCastInstruction(rightType); + generateCheckCastInstruction(rightType, opToken == JetTokens.AS_SAFE); return Unit.INSTANCE$; } }); @@ -3826,14 +3824,16 @@ The "returned" value of try expression with no finally is either the last expres private void generateInstanceOfInstruction(@NotNull JetType jetType) { Type type = boxType(asmType(jetType)); putReifierMarkerIfTypeIsReifiedParameter(jetType, ReifiedTypeInliner.INSTANCEOF_MARKER_METHOD_NAME); - v.instanceOf(type); + InstanceOf.instanceOf(v, jetType, type); } @NotNull - private StackValue generateCheckCastInstruction(@NotNull JetType jetType) { + private StackValue generateCheckCastInstruction(@NotNull JetType jetType, boolean safeAs) { Type type = boxType(asmType(jetType)); - putReifierMarkerIfTypeIsReifiedParameter(jetType, ReifiedTypeInliner.CHECKCAST_MARKER_METHOD_NAME); - v.checkcast(type); + putReifierMarkerIfTypeIsReifiedParameter(jetType, + safeAs ? ReifiedTypeInliner.SAFE_CHECKCAST_MARKER_METHOD_NAME + : ReifiedTypeInliner.CHECKCAST_MARKER_METHOD_NAME); + CheckCast.checkcast(v, jetType, type, safeAs); return StackValue.onStack(type); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index cd4f46f9fb7..4467c143fba 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -20,6 +20,8 @@ import com.google.common.collect.ImmutableSet import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.codegen.context.MethodContext +import org.jetbrains.kotlin.codegen.intrinsics.CheckCast +import org.jetbrains.kotlin.codegen.intrinsics.InstanceOf import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.jvm.AsmTypes @@ -36,13 +38,15 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame companion object { public val NEW_ARRAY_MARKER_METHOD_NAME: String = "reifyNewArray" public val CHECKCAST_MARKER_METHOD_NAME: String = "reifyCheckcast" + public val SAFE_CHECKCAST_MARKER_METHOD_NAME: String = "reifySafeCheckcast" public val INSTANCEOF_MARKER_METHOD_NAME: String = "reifyInstanceof" public val JAVA_CLASS_MARKER_METHOD_NAME: String = "reifyJavaClass" public val CLASS_LITERAL_MARKER_METHOD_NAME: String = "reifyClassLiteral" public val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME: String = "needClassReification" private val PARAMETRISED_MARKERS = ImmutableSet.of( - NEW_ARRAY_MARKER_METHOD_NAME, CHECKCAST_MARKER_METHOD_NAME, + NEW_ARRAY_MARKER_METHOD_NAME, + CHECKCAST_MARKER_METHOD_NAME, SAFE_CHECKCAST_MARKER_METHOD_NAME, INSTANCEOF_MARKER_METHOD_NAME, JAVA_CLASS_MARKER_METHOD_NAME, CLASS_LITERAL_MARKER_METHOD_NAME ) @@ -134,15 +138,18 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame val asmType = mapping.asmType if (asmType != null) { + val jetType = mapping.type ?: return null + // process* methods return false if marker should be reified further // or it's invalid (may be emitted explicitly in code) // they return true if instruction is reified and marker can be deleted if (when (insn.name) { NEW_ARRAY_MARKER_METHOD_NAME -> processNewArray(insn, asmType) - CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, asmType) - INSTANCEOF_MARKER_METHOD_NAME -> processInstanceof(insn, asmType) + CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, instructions, jetType, asmType, safe = false) + SAFE_CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, instructions, jetType, asmType, safe = true) + INSTANCEOF_MARKER_METHOD_NAME -> processInstanceof(insn, instructions, jetType, asmType) JAVA_CLASS_MARKER_METHOD_NAME -> processJavaClass(insn, asmType) - CLASS_LITERAL_MARKER_METHOD_NAME -> processClassLiteral(insn, asmType, instructions, mapping.type!!) + CLASS_LITERAL_MARKER_METHOD_NAME -> processClassLiteral(insn, instructions, jetType, asmType) else -> false }) { instructions.remove(insn.getPrevious()!!) @@ -159,11 +166,29 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame private fun processNewArray(insn: MethodInsnNode, parameter: Type) = processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY) - private fun processCheckcast(insn: MethodInsnNode, parameter: Type) = - processNextTypeInsn(insn, parameter, Opcodes.CHECKCAST) + private fun processCheckcast(insn: MethodInsnNode, instructions: InsnList, jetType: JetType, asmType: Type, safe: Boolean) = + rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { instanceofInsn: AbstractInsnNode -> + if (instanceofInsn !is TypeInsnNode) return false + CheckCast.checkcast(instanceofInsn, instructions, jetType, asmType, safe) + return true + } - private fun processInstanceof(insn: MethodInsnNode, parameter: Type) = - processNextTypeInsn(insn, parameter, Opcodes.INSTANCEOF) + private fun processInstanceof(insn: MethodInsnNode, instructions: InsnList, jetType: JetType, asmType: Type) = + rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { instanceofInsn: AbstractInsnNode -> + if (instanceofInsn !is TypeInsnNode) return false + InstanceOf.instanceOf(instanceofInsn, instructions, jetType, asmType) + return true + } + + inline private fun rewriteNextTypeInsn( + marker: MethodInsnNode, + expectedNextOpcode: Int, + rewrite: (AbstractInsnNode) -> Boolean + ): Boolean { + val next = marker.next ?: return false + if (next.opcode != expectedNextOpcode) return false + return rewrite(next) + } private fun processNextTypeInsn(insn: MethodInsnNode, parameter: Type, expectedNextOpcode: Int): Boolean { if (insn.getNext()?.getOpcode() != expectedNextOpcode) return false @@ -178,7 +203,7 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame return true } - private fun processClassLiteral(insn: MethodInsnNode, parameter: Type, instructions: InsnList, type: JetType): Boolean { + private fun processClassLiteral(insn: MethodInsnNode, instructions: InsnList, type: JetType, parameter: Type): Boolean { val next = insn.next if (next !is FieldInsnNode || next.opcode != Opcodes.GETSTATIC) return false val descriptor = type.constructor.declarationDescriptor!! diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/CheckCast.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/CheckCast.kt new file mode 100644 index 00000000000..ddba89a0460 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/CheckCast.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.codegen.intrinsics + +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter +import org.jetbrains.org.objectweb.asm.tree.InsnList +import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode +import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode + +object CheckCast { + private val INTRINSICS_CLASS = "kotlin/jvm/internal/Intrinsics" + + private val CHECKCAST_METHOD_NAME = hashMapOf( + "kotlin.MutableIterator" to "asMutableIterator", + "kotlin.MutableIterable" to "asMutableIterable", + "kotlin.MutableCollection" to "asMutableCollection", + "kotlin.MutableList" to "asMutableList", + "kotlin.MutableListIterator" to "asMutableListIterator", + "kotlin.MutableSet" to "asMutableSet", + "kotlin.MutableMap" to "asMutableMap", + "kotlin.MutableMap.MutableEntry" to "asMutableMapEntry" + ) + + private val SAFE_CHECKCAST_METHOD_NAME = hashMapOf( + "kotlin.MutableIterator" to "safeAsMutableIterator", + "kotlin.MutableIterable" to "safeAsMutableIterable", + "kotlin.MutableCollection" to "safeAsMutableCollection", + "kotlin.MutableList" to "safeAsMutableList", + "kotlin.MutableListIterator" to "safeAsMutableListIterator", + "kotlin.MutableSet" to "safeAsMutableSet", + "kotlin.MutableMap" to "safeAsMutableMap", + "kotlin.MutableMap.MutableEntry" to "safeAsMutableMapEntry" + ) + + public @JvmStatic fun checkcast(v: InstructionAdapter, jetType: JetType, boxedAsmType: Type, safe: Boolean) { + val intrinsicMethodName = getCheckcastIntrinsicMethodName(jetType, safe) + if (intrinsicMethodName == null) { + v.checkcast(boxedAsmType) + } + else { + val signature = getCheckcastIntrinsicMethodSignature(boxedAsmType) + v.invokestatic(INTRINSICS_CLASS, intrinsicMethodName, signature, false) + } + } + + public @JvmStatic fun checkcast(checkcastInsn: TypeInsnNode, instructions: InsnList, jetType: JetType, asmType: Type, safe: Boolean) { + val intrinsicMethodName = getCheckcastIntrinsicMethodName(jetType, safe) + if (intrinsicMethodName == null) { + checkcastInsn.desc = asmType.internalName + } + else { + val signature = getCheckcastIntrinsicMethodSignature(asmType) + val invokeNode = MethodInsnNode(Opcodes.INVOKESTATIC, INTRINSICS_CLASS, intrinsicMethodName, signature, false) + instructions.insertBefore(checkcastInsn, invokeNode) + instructions.remove(checkcastInsn) + } + } + + private fun getCheckcastIntrinsicMethodName(jetType: JetType, safe: Boolean): String? { + val classDescriptor = TypeUtils.getClassDescriptor(jetType) ?: return null + val classFqName = DescriptorUtils.getFqName(classDescriptor).asString() + return if (safe) SAFE_CHECKCAST_METHOD_NAME[classFqName] else CHECKCAST_METHOD_NAME[classFqName] + } + + private fun getCheckcastIntrinsicMethodSignature(asmType: Type): String = + "(Ljava/lang/Object;)${asmType.descriptor}" + +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/InstanceOf.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/InstanceOf.kt new file mode 100644 index 00000000000..13391a0e111 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/InstanceOf.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.codegen.intrinsics + +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter +import org.jetbrains.org.objectweb.asm.tree.InsnList +import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode +import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode + +object InstanceOf { + private val INTRINSICS_CLASS = "kotlin/jvm/internal/Intrinsics" + + private val INSTANCEOF_METHOD_SIGNATURE = "(Ljava/lang/Object;)Z" + + private val INSTANCEOF_METHOD_NAME = hashMapOf( + "kotlin.MutableIterator" to "isMutableIterator", + "kotlin.MutableIterable" to "isMutableIterable", + "kotlin.MutableCollection" to "isMutableCollection", + "kotlin.MutableList" to "isMutableList", + "kotlin.MutableListIterator" to "isMutableListIterator", + "kotlin.MutableSet" to "isMutableSet", + "kotlin.MutableMap" to "isMutableMap", + "kotlin.MutableMap.MutableEntry" to "isMutableMapEntry" + ) + + public @JvmStatic fun instanceOf(v: InstructionAdapter, jetType: JetType, boxedAsmType: Type) { + val intrinsicMethodName = getInstanceOfIntrinsicMethodName(jetType) + if (intrinsicMethodName == null) { + v.instanceOf(boxedAsmType) + } + else { + v.invokestatic(INTRINSICS_CLASS, intrinsicMethodName, INSTANCEOF_METHOD_SIGNATURE, false) + } + } + + public @JvmStatic fun instanceOf(instanceofInsn: TypeInsnNode, instructions: InsnList, jetType: JetType, asmType: Type) { + val intrinsicMethodName = getInstanceOfIntrinsicMethodName(jetType) + if (intrinsicMethodName == null) { + instanceofInsn.desc = asmType.internalName + } + else { + val invokeNode = MethodInsnNode(Opcodes.INVOKESTATIC, INTRINSICS_CLASS, intrinsicMethodName, INSTANCEOF_METHOD_SIGNATURE, false) + instructions.insertBefore(instanceofInsn, invokeNode) + instructions.remove(instanceofInsn) + } + } + + private fun getInstanceOfIntrinsicMethodName(jetType: JetType): String? { + val classDescriptor = TypeUtils.getClassDescriptor(jetType) ?: return null + val classFqName = DescriptorUtils.getFqName(classDescriptor).asString() + return INSTANCEOF_METHOD_NAME[classFqName] + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/builtinStubMethods/Collection.kt b/compiler/testData/codegen/box/builtinStubMethods/Collection.kt index 0c0ef7b34ed..27aa6a4e5cd 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/Collection.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/Collection.kt @@ -17,13 +17,14 @@ fun expectUoe(block: () -> Any) { } fun box(): String { - val collection = MyCollection() as MutableCollection + val myCollection = MyCollection() + val collection = myCollection as java.util.Collection expectUoe { collection.add("") } expectUoe { collection.remove("") } - expectUoe { collection.addAll(collection) } - expectUoe { collection.removeAll(collection) } - expectUoe { collection.retainAll(collection) } + expectUoe { collection.addAll(myCollection) } + expectUoe { collection.removeAll(myCollection) } + expectUoe { collection.retainAll(myCollection) } expectUoe { collection.clear() } return "OK" diff --git a/compiler/testData/codegen/box/builtinStubMethods/Iterator.kt b/compiler/testData/codegen/box/builtinStubMethods/Iterator.kt index 4175f9340c5..d021209d54d 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/Iterator.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/Iterator.kt @@ -5,7 +5,7 @@ class MyIterator(val v: T): Iterator { fun box(): String { try { - (MyIterator("") as MutableIterator).remove() + (MyIterator("") as java.util.Iterator).remove() throw AssertionError() } catch (e: UnsupportedOperationException) { return "OK" diff --git a/compiler/testData/codegen/box/builtinStubMethods/IteratorWithRemove.kt b/compiler/testData/codegen/box/builtinStubMethods/IteratorWithRemove.kt index d9167842a6b..86ac00f6384 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/IteratorWithRemove.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/IteratorWithRemove.kt @@ -6,6 +6,6 @@ class MyIterator(val v: T): Iterator { } fun box(): String { - (MyIterator("") as MutableIterator).remove() + (MyIterator("") as java.util.Iterator).remove() return "OK" } diff --git a/compiler/testData/codegen/box/builtinStubMethods/List.kt b/compiler/testData/codegen/box/builtinStubMethods/List.kt index fa231e47b6a..004da9106b2 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/List.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/List.kt @@ -23,7 +23,7 @@ fun expectUoe(block: () -> Any) { } fun box(): String { - val list = MyList() as MutableList + val list = MyList() as java.util.List expectUoe { list.add("") } expectUoe { list.remove("") } diff --git a/compiler/testData/codegen/box/builtinStubMethods/ListIterator.kt b/compiler/testData/codegen/box/builtinStubMethods/ListIterator.kt index c20ffc26ff7..3a3f1fffaa6 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/ListIterator.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/ListIterator.kt @@ -16,7 +16,7 @@ fun expectUoe(block: () -> Any) { } fun box(): String { - val list = MyListIterator() as MutableListIterator + val list = MyListIterator() as java.util.ListIterator expectUoe { list.set("") } expectUoe { list.add("") } diff --git a/compiler/testData/codegen/box/builtinStubMethods/ListWithAllImplementations.kt b/compiler/testData/codegen/box/builtinStubMethods/ListWithAllImplementations.kt index 36721a603b1..26d266a050f 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/ListWithAllImplementations.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/ListWithAllImplementations.kt @@ -26,7 +26,7 @@ class MyList(val v: T): List { } fun box(): String { - val list = MyList("") as MutableList + val list = MyList("") as java.util.List list.add("") list.remove("") diff --git a/compiler/testData/codegen/box/builtinStubMethods/ListWithAllInheritedImplementations.kt b/compiler/testData/codegen/box/builtinStubMethods/ListWithAllInheritedImplementations.kt index f328af84940..9782d0707ef 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/ListWithAllInheritedImplementations.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/ListWithAllInheritedImplementations.kt @@ -28,7 +28,7 @@ class MyList(v: T): Super(v), List { } fun box(): String { - val list = MyList("") as MutableList + val list = MyList("") as java.util.List list.add("") list.remove("") diff --git a/compiler/testData/codegen/box/builtinStubMethods/Map.kt b/compiler/testData/codegen/box/builtinStubMethods/Map.kt index 80c356167df..b5cf8d4bfb8 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/Map.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/Map.kt @@ -18,11 +18,12 @@ fun expectUoe(block: () -> Unit) { } fun box(): String { - val map = MyMap() as MutableMap + val myMap = MyMap() + val map = myMap as java.util.Map expectUoe { map.put("", 1) } expectUoe { map.remove("") } - expectUoe { map.putAll(map) } + expectUoe { map.putAll(myMap) } expectUoe { map.clear() } return "OK" diff --git a/compiler/testData/codegen/box/builtinStubMethods/MapEntry.kt b/compiler/testData/codegen/box/builtinStubMethods/MapEntry.kt index 78eec72e98f..d7ef8b616f7 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/MapEntry.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/MapEntry.kt @@ -7,7 +7,7 @@ class MyMapEntry: Map.Entry { fun box(): String { try { - (MyMapEntry() as MutableMap.MutableEntry).setValue(1) + (MyMapEntry() as java.util.Map.Entry).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 index 0f92c3f466e..b5d8f74eb53 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/MapEntryWithSetValue.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/MapEntryWithSetValue.kt @@ -8,7 +8,7 @@ class MyMapEntry: Map.Entry { } fun box(): String { - (MyMapEntry() as MutableMap.MutableEntry).setValue(1) + (MyMapEntry() as java.util.Map.Entry).setValue(1) return "OK" } diff --git a/compiler/testData/codegen/box/builtinStubMethods/MapWithAllImplementations.kt b/compiler/testData/codegen/box/builtinStubMethods/MapWithAllImplementations.kt index a51a26c5d25..da5c2b4e353 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/MapWithAllImplementations.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/MapWithAllImplementations.kt @@ -15,11 +15,12 @@ class MyMap: Map { } fun box(): String { - val map = MyMap() as MutableMap + val myMap = MyMap() + val map = myMap as java.util.Map map.put("", 1) map.remove("") - map.putAll(map) + map.putAll(myMap) map.clear() return "OK" diff --git a/compiler/testData/codegen/box/builtinStubMethods/SubstitutedList.kt b/compiler/testData/codegen/box/builtinStubMethods/SubstitutedList.kt index 5721cc81df3..ce331e76102 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/SubstitutedList.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/SubstitutedList.kt @@ -23,7 +23,7 @@ fun expectUoe(block: () -> Any) { } fun box(): String { - val list = MyList() as MutableList + val list = MyList() as java.util.List expectUoe { list.add("") } expectUoe { list.remove("") } diff --git a/compiler/testData/codegen/box/builtinStubMethods/abstractMember.kt b/compiler/testData/codegen/box/builtinStubMethods/abstractMember.kt index 40a42011eb3..57c548c337d 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/abstractMember.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/abstractMember.kt @@ -11,7 +11,7 @@ class B(var result: String) : A() { } fun box(): String { - val a = B("Fail") as MutableIterator + val a = B("Fail") as java.util.Iterator a.next() a.hasNext() a.remove() diff --git a/compiler/testData/codegen/box/builtinStubMethods/delegationToArrayList.kt b/compiler/testData/codegen/box/builtinStubMethods/delegationToArrayList.kt index b235c682914..3b4af5144e9 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/delegationToArrayList.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/delegationToArrayList.kt @@ -13,7 +13,7 @@ fun expectUoe(block: () -> Any) { } fun box(): String { - val a = A() as MutableList + val a = A() as java.util.List expectUoe { a.add("") } expectUoe { a.remove("") } expectUoe { a.addAll(a) } @@ -28,7 +28,7 @@ fun box(): String { a.listIterator(0) a.subList(0, 0) - val b = B() as MutableList + val b = B() as java.util.List expectUoe { b.add("") } expectUoe { b.remove("") } expectUoe { b.addAll(b) } diff --git a/compiler/testData/codegen/box/builtinStubMethods/implementationInTrait.kt b/compiler/testData/codegen/box/builtinStubMethods/implementationInTrait.kt index 7baaa46e2f8..a3c41808fce 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/implementationInTrait.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/implementationInTrait.kt @@ -21,7 +21,7 @@ fun box(): String { val a = C() if (!a.add("")) return "Fail 1" if (!(a as Addable).add("")) return "Fail 2" - if (!(a as MutableList).add("")) return "Fail 3" + if (!(a as java.util.List).add("")) return "Fail 3" return "OK" } catch (e: UnsupportedOperationException) { return "Fail: no stub method should be generated" diff --git a/compiler/testData/codegen/box/builtinStubMethods/inheritedImplementations.kt b/compiler/testData/codegen/box/builtinStubMethods/inheritedImplementations.kt index ff5f0de6418..9395f57144d 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/inheritedImplementations.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/inheritedImplementations.kt @@ -13,7 +13,7 @@ class S : Set, SetStringImpl() { } fun box(): String { - val s = S() as MutableSet + val s = S() as java.util.Set s.add("") s.remove("") s.clear() diff --git a/compiler/testData/codegen/box/builtinStubMethods/manyTypeParametersWithUpperBounds.kt b/compiler/testData/codegen/box/builtinStubMethods/manyTypeParametersWithUpperBounds.kt index 31bc1608dbe..39667864f50 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/manyTypeParametersWithUpperBounds.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/manyTypeParametersWithUpperBounds.kt @@ -17,7 +17,7 @@ fun expectUoe(block: () -> Any) { } fun box(): String { - val a = A() as MutableSet + val a = A() as java.util.Set a.iterator() diff --git a/compiler/testData/codegen/box/builtinStubMethods/nonTrivialSubstitution.kt b/compiler/testData/codegen/box/builtinStubMethods/nonTrivialSubstitution.kt index 382a5d9bf5c..f597cce81d8 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/nonTrivialSubstitution.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/nonTrivialSubstitution.kt @@ -9,7 +9,7 @@ class MyCollection : Collection>> { } fun box(): String { - val c = MyCollection() as MutableCollection>> + val c = MyCollection() as java.util.Collection>> try { c.add(ArrayList()) return "Fail" diff --git a/compiler/testData/codegen/box/builtinStubMethods/nonTrivialUpperBound.kt b/compiler/testData/codegen/box/builtinStubMethods/nonTrivialUpperBound.kt index 470eaaaf9e6..d086127b679 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/nonTrivialUpperBound.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/nonTrivialUpperBound.kt @@ -5,7 +5,7 @@ class MyIterator : Iterator { fun box(): String { try { - (MyIterator() as MutableIterator).remove() + (MyIterator() as java.util.Iterator).remove() return "Fail" } catch (e: UnsupportedOperationException) { return "OK" diff --git a/compiler/testData/codegen/boxWithStdlib/casts/asWithMutable.kt b/compiler/testData/codegen/boxWithStdlib/casts/asWithMutable.kt new file mode 100644 index 00000000000..83f18bb984d --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/casts/asWithMutable.kt @@ -0,0 +1,126 @@ +import java.util.* + +class Itr : Iterator by ArrayList().iterator() +class MItr : MutableIterator by ArrayList().iterator() +class LItr : ListIterator by ArrayList().listIterator() +class MLItr : MutableListIterator by ArrayList().listIterator() + +class It : Iterable by ArrayList() +class MIt : MutableIterable by ArrayList() +class C : Collection by ArrayList() +class MC : MutableCollection by ArrayList() +class L : List by ArrayList() +class ML : MutableList by ArrayList() +class S : Set by HashSet() +class MS : MutableSet by HashSet() + +class M : Map by HashMap() +class MM : MutableMap by HashMap() + +class ME : Map.Entry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() +} + +class MME : MutableMap.MutableEntry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() + override fun setValue(value: String): String = throw UnsupportedOperationException() +} + +inline fun asFailsWithCCE(operation: String, block: () -> Unit) { + try { + block() + } + catch (e: java.lang.ClassCastException) { + return + } + catch (e: Throwable) { + throw AssertionError("$operation: should throw ClassCastException, got $e") + } + throw AssertionError("$operation: should throw ClassCastException, no exception thrown") +} + +inline fun asSucceeds(operation: String, block: () -> Unit) { + try { + block() + } + catch (e: Throwable) { + throw AssertionError("$operation: should not throw exceptions, got $e") + } +} + +fun box(): String { + val itr = Itr() as Any + val mitr = MItr() + + asFailsWithCCE("itr as MutableIterator") { itr as MutableIterator<*> } + asSucceeds("mitr as MutableIterator") { mitr as MutableIterator<*> } + + val litr = LItr() as Any + val mlitr = MLItr() + + asFailsWithCCE("litr as MutableIterator") { litr as MutableIterator<*> } + asFailsWithCCE("litr as MutableListIterator") { litr as MutableListIterator<*> } + asSucceeds("mlitr as MutableIterator") { mlitr as MutableIterator<*> } + asSucceeds("mlitr as MutableListIterator") { mlitr as MutableListIterator<*> } + + val it = It() as Any + val mit = MIt() + val arrayList = ArrayList() + + asFailsWithCCE("it as MutableIterable") { it as MutableIterable<*> } + asSucceeds("mit as MutableIterable") { mit as MutableIterable<*> } + asSucceeds("arrayList as MutableIterable") { arrayList as MutableIterable<*> } + + val coll = C() as Any + val mcoll = MC() + + asFailsWithCCE("coll as MutableIterable") { coll as MutableIterable<*> } + asFailsWithCCE("coll as MutableCollection") { coll as MutableCollection<*> } + asSucceeds("mcoll as MutableIterable") { mcoll as MutableIterable<*> } + asSucceeds("mcoll as MutableCollection") { mcoll as MutableCollection<*> } + asSucceeds("arrayList as MutableCollection") { arrayList as MutableCollection<*> } + + val list = L() as Any + val mlist = ML() + + asFailsWithCCE("list as MutableIterable") { list as MutableIterable<*> } + asFailsWithCCE("list as MutableCollection") { list as MutableCollection<*> } + asFailsWithCCE("list as MutableList") { list as MutableList<*> } + asSucceeds("mlist as MutableIterable") { mlist as MutableIterable<*> } + asSucceeds("mlist as MutableCollection") { mlist as MutableCollection<*> } + asSucceeds("mlist as MutableList") { mlist as MutableList<*> } + + val set = S() as Any + val mset = MS() + val hashSet = HashSet() + + asFailsWithCCE("set as MutableIterable") { set as MutableIterable<*> } + asFailsWithCCE("set as MutableCollection") { set as MutableCollection<*> } + asFailsWithCCE("set as MutableSet") { set as MutableSet<*> } + asSucceeds("mset as MutableIterable") { mset as MutableIterable<*> } + asSucceeds("mset as MutableCollection") { mset as MutableCollection<*> } + asSucceeds("mset as MutableSet") { mset as MutableSet<*> } + asSucceeds("hashSet as MutableSet") { hashSet as MutableSet<*> } + + val map = M() as Any + val mmap = MM() + val hashMap = HashMap() + + asFailsWithCCE("map as MutableMap") { map as MutableMap<*, *> } + asSucceeds("mmap as MutableMap") { mmap as MutableMap<*, *> } + + val entry = ME() as Any + val mentry = MME() + + asFailsWithCCE("entry as MutableMap.MutableEntry") { entry as MutableMap.MutableEntry<*, *> } + asSucceeds("mentry as MutableMap.MutableEntry") { mentry as MutableMap.MutableEntry<*, *> } + + hashMap[""] = "" + val hashMapEntry = hashMap.entrySet().first() + + asSucceeds("hashMapEntry as MutableMap.MutableEntry") { hashMapEntry as MutableMap.MutableEntry<*, *> } + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/casts/isWithMutable.kt b/compiler/testData/codegen/boxWithStdlib/casts/isWithMutable.kt new file mode 100644 index 00000000000..a41c5eab7ec --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/casts/isWithMutable.kt @@ -0,0 +1,106 @@ +import java.util.* + +class Itr : Iterator by ArrayList().iterator() +class MItr : MutableIterator by ArrayList().iterator() +class LItr : ListIterator by ArrayList().listIterator() +class MLItr : MutableListIterator by ArrayList().listIterator() + +class It : Iterable by ArrayList() +class MIt : MutableIterable by ArrayList() +class C : Collection by ArrayList() +class MC : MutableCollection by ArrayList() +class L : List by ArrayList() +class ML : MutableList by ArrayList() +class S : Set by HashSet() +class MS : MutableSet by HashSet() + +class M : Map by HashMap() +class MM : MutableMap by HashMap() + +class ME : Map.Entry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() +} + +class MME : MutableMap.MutableEntry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() + override fun setValue(value: String): String = throw UnsupportedOperationException() +} + +fun box(): String { + val itr = Itr() as Any + val mitr = MItr() + + assert(itr !is MutableIterator<*>) { "Itr should satisfy '!is MutableIterator'" } + assert(mitr is MutableIterator<*>) { "MItr should satisfy 'is MutableIterator'" } + + val litr = LItr() as Any + val mlitr = MLItr() + + assert(litr !is MutableIterator<*>) { "LItr should satisfy '!is MutableIterator'" } + assert(litr !is MutableListIterator<*>) { "LItr should satisfy '!is MutableListIterator'" } + assert(mlitr is MutableListIterator<*>) { "MLItr should satisfy 'is MutableListIterator'" } + + val it = It() as Any + val mit = MIt() + val arrayList = ArrayList() + + assert(it !is MutableIterable<*>) { "It should satisfy '!is MutableIterable'" } + assert(mit is MutableIterable<*>) { "MIt should satisfy 'is MutableIterable'" } + assert(arrayList is MutableIterable<*>) { "ArrayList should satisfy 'is MutableIterable'" } + + val coll = C() as Any + val mcoll = MC() + + assert(coll !is MutableCollection<*>) { "C should satisfy '!is MutableCollection'" } + assert(coll !is MutableIterable<*>) { "C should satisfy '!is MutableIterable'" } + assert(mcoll is MutableCollection<*>) { "MC should satisfy 'is MutableCollection'" } + assert(mcoll is MutableIterable<*>) { "MC should satisfy 'is MutableIterable'" } + assert(arrayList is MutableCollection<*>) { "ArrayList should satisfy 'is MutableCollection'" } + + val list = L() as Any + val mlist = ML() + + assert(list !is MutableList<*>) { "L should satisfy '!is MutableList'" } + assert(list !is MutableCollection<*>) { "L should satisfy '!is MutableCollection'" } + assert(list !is MutableIterable<*>) { "L should satisfy '!is MutableIterable'" } + assert(mlist is MutableList<*>) { "ML should satisfy 'is MutableList'" } + assert(mlist is MutableCollection<*>) { "ML should satisfy 'is MutableCollection'" } + assert(mlist is MutableIterable<*>) { "ML should satisfy 'is MutableIterable'" } + assert(arrayList is MutableList<*>) { "ArrayList should satisfy 'is MutableList'" } + + val set = S() as Any + val mset = MS() + val hashSet = HashSet() + + assert(set !is MutableSet<*>) { "S should satisfy '!is MutableSet'" } + assert(set !is MutableCollection<*>) { "S should satisfy '!is MutableCollection'" } + assert(set !is MutableIterable<*>) { "S should satisfy '!is MutableIterable'" } + assert(mset is MutableSet<*>) { "MS should satisfy 'is MutableSet'" } + assert(mset is MutableCollection<*>) { "MS should satisfy 'is MutableCollection'" } + assert(mset is MutableIterable<*>) { "MS should satisfy 'is MutableIterable'" } + assert(hashSet is MutableSet<*>) { "HashSet should satisfy 'is MutableSet'" } + assert(hashSet is MutableCollection<*>) { "HashSet should satisfy 'is MutableCollection'" } + assert(hashSet is MutableIterable<*>) { "HashSet should satisfy 'is MutableIterable'" } + + val map = M() as Any + val mmap = MM() + val hashMap = HashMap() + + assert(map !is MutableMap<*, *>) { "M should satisfy '!is MutableMap'" } + assert(mmap is MutableMap<*, *>) { "MM should satisfy 'is MutableMap'"} + assert(hashMap is MutableMap<*, *>) { "HashMap should satisfy 'is MutableMap'" } + + val entry = ME() as Any + val mentry = MME() + + hashMap[""] = "" + val hashMapEntry = hashMap.entrySet().first() + + assert(entry !is MutableMap.MutableEntry<*, *>) { "ME should satisfy '!is MutableMap.MutableEntry'"} + assert(mentry is MutableMap.MutableEntry<*, *>) { "MME should satisfy 'is MutableMap.MutableEntry'"} + assert(hashMapEntry is MutableMap.MutableEntry<*, *>) { "HashMap.Entry should satisfy 'is MutableMap.MutableEntry'"} + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/casts/reifiedAsWithMutable.kt b/compiler/testData/codegen/boxWithStdlib/casts/reifiedAsWithMutable.kt new file mode 100644 index 00000000000..d34bb166d8e --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/casts/reifiedAsWithMutable.kt @@ -0,0 +1,128 @@ +import java.util.* + +class Itr : Iterator by ArrayList().iterator() +class MItr : MutableIterator by ArrayList().iterator() +class LItr : ListIterator by ArrayList().listIterator() +class MLItr : MutableListIterator by ArrayList().listIterator() + +class It : Iterable by ArrayList() +class MIt : MutableIterable by ArrayList() +class C : Collection by ArrayList() +class MC : MutableCollection by ArrayList() +class L : List by ArrayList() +class ML : MutableList by ArrayList() +class S : Set by HashSet() +class MS : MutableSet by HashSet() + +class M : Map by HashMap() +class MM : MutableMap by HashMap() + +class ME : Map.Entry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() +} + +class MME : MutableMap.MutableEntry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() + override fun setValue(value: String): String = throw UnsupportedOperationException() +} + +inline fun reifiedAsSucceeds(x: Any, operation: String) { + try { + x as T + } + catch (e: Throwable) { + throw AssertionError("$operation: should not throw exceptions, got $e") + } +} + +inline fun reifiedAsFailsWithCCE(x: Any, operation: String) { + try { + x as T + } + catch (e: java.lang.ClassCastException) { + return + } + catch (e: Throwable) { + throw AssertionError("$operation: should throw ClassCastException, got $e") + } + throw AssertionError("$operation: should fail with CCE, no exception thrown") +} + +fun box(): String { + val itr = Itr() as Any + val mitr = MItr() + + reifiedAsFailsWithCCE>(itr, "reifiedAs>(itr)") + reifiedAsSucceeds>(mitr, "reifiedAs>(mitr)") + + val litr = LItr() as Any + val mlitr = MLItr() + + reifiedAsFailsWithCCE>(litr, "reifiedAs>(litr)") + reifiedAsFailsWithCCE>(litr, "reifiedAs>(litr)") + reifiedAsSucceeds>(mlitr, "reifiedAs>(mlitr)") + + val it = It() as Any + val mit = MIt() + val arrayList = ArrayList() + + reifiedAsFailsWithCCE>(it, "reifiedAs>(it)") + reifiedAsSucceeds>(mit, "reifiedAs>(mit)") + reifiedAsSucceeds>(arrayList, "reifiedAs>(arrayList)") + + val coll = C() as Any + val mcoll = MC() + + reifiedAsFailsWithCCE>(coll, "reifiedAs>(coll)") + reifiedAsFailsWithCCE>(coll, "reifiedAs>(coll)") + reifiedAsSucceeds>(mcoll, "reifiedAs>(mcoll)") + reifiedAsSucceeds>(mcoll, "reifiedAs>(mcoll)") + reifiedAsSucceeds>(arrayList, "reifiedAs>(arrayList)") + + val list = L() as Any + val mlist = ML() + + reifiedAsFailsWithCCE>(list, "reifiedAs>(list)") + reifiedAsFailsWithCCE>(list, "reifiedAs>(list)") + reifiedAsFailsWithCCE>(list, "reifiedAs>(list)") + reifiedAsSucceeds>(mlist, "reifiedAs>(mlist)") + reifiedAsSucceeds>(mlist, "reifiedAs>(mlist)") + reifiedAsSucceeds>(mlist, "reifiedAs>(mlist)") + reifiedAsSucceeds>(arrayList, "reifiedAs>(arrayList)") + + val set = S() as Any + val mset = MS() + val hashSet = HashSet() + + reifiedAsFailsWithCCE>(set, "reifiedAs>(set)") + reifiedAsFailsWithCCE>(set, "reifiedAs>(set)") + reifiedAsFailsWithCCE>(set, "reifiedAs>(set)") + reifiedAsSucceeds>(mset, "reifiedAs>(mset)") + reifiedAsSucceeds>(mset, "reifiedAs>(mset)") + reifiedAsSucceeds>(mset, "reifiedAs>(mset)") + reifiedAsSucceeds>(hashSet, "reifiedAs>(hashSet)") + reifiedAsSucceeds>(hashSet, "reifiedAs>(hashSet)") + reifiedAsSucceeds>(hashSet, "reifiedAs>(hashSet)") + + val map = M() as Any + val mmap = MM() + val hashMap = HashMap() + + reifiedAsFailsWithCCE>(map, "reifiedAs>(map)") + reifiedAsSucceeds>(mmap, "reifiedAs>(mmap)") + reifiedAsSucceeds>(hashMap, "reifiedAs>(hashMap)") + + val entry = ME() as Any + val mentry = MME() + + hashMap[""] = "" + val hashMapEntry = hashMap.entrySet().first() + + reifiedAsFailsWithCCE>(entry, "reifiedAs>(entry)") + reifiedAsSucceeds>(mentry, "reifiedAs>(mentry)") + reifiedAsSucceeds>(hashMapEntry, "reifiedAs>(hashMapEntry)") + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/casts/reifiedIsWithMutable.kt b/compiler/testData/codegen/boxWithStdlib/casts/reifiedIsWithMutable.kt new file mode 100644 index 00000000000..a333e4e561a --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/casts/reifiedIsWithMutable.kt @@ -0,0 +1,109 @@ +import java.util.* + +class Itr : Iterator by ArrayList().iterator() +class MItr : MutableIterator by ArrayList().iterator() +class LItr : ListIterator by ArrayList().listIterator() +class MLItr : MutableListIterator by ArrayList().listIterator() + +class It : Iterable by ArrayList() +class MIt : MutableIterable by ArrayList() +class C : Collection by ArrayList() +class MC : MutableCollection by ArrayList() +class L : List by ArrayList() +class ML : MutableList by ArrayList() +class S : Set by HashSet() +class MS : MutableSet by HashSet() + +class M : Map by HashMap() +class MM : MutableMap by HashMap() + +class ME : Map.Entry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() +} + +class MME : MutableMap.MutableEntry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() + override fun setValue(value: String): String = throw UnsupportedOperationException() +} + +inline fun reifiedIs(x: Any): Boolean = x is T +inline fun reifiedIsNot(x: Any): Boolean = x !is T + +fun box(): String { + val itr = Itr() as Any + val mitr = MItr() + + assert(reifiedIsNot>(itr)) { "reifiedIsNot>(itr)" } + assert(reifiedIs>(mitr)) { "reifiedIs>(mitr)" } + + val litr = LItr() as Any + val mlitr = MLItr() + + assert(reifiedIsNot>(litr)) { "reifiedIsNot>(litr)" } + assert(reifiedIsNot>(litr)) { "reifiedIsNot>(litr)" } + assert(reifiedIs>(mlitr)) { "reifiedIs>(mlitr)" } + + val it = It() as Any + val mit = MIt() + val arrayList = ArrayList() + + assert(reifiedIsNot>(it)) { "reifiedIsNot>(it)" } + assert(reifiedIs>(mit)) { "reifiedIs>(mit)" } + assert(reifiedIs>(arrayList)) { "reifiedIs>(arrayList)" } + + val coll = C() as Any + val mcoll = MC() + + assert(reifiedIsNot>(coll)) { "reifiedIsNot>(coll)" } + assert(reifiedIsNot>(coll)) { "reifiedIsNot>(coll)" } + assert(reifiedIs>(mcoll)) { "reifiedIs>(mcoll)" } + assert(reifiedIs>(mcoll)) { "reifiedIs>(mcoll)" } + assert(reifiedIs>(arrayList)) { "reifiedIs>(arrayList)" } + + val list = L() as Any + val mlist = ML() + + assert(reifiedIsNot>(list)) { "reifiedIsNot>(list)" } + assert(reifiedIsNot>(list)) { "reifiedIsNot>(list)" } + assert(reifiedIsNot>(list)) { "reifiedIsNot>(list)" } + assert(reifiedIs>(mlist)) { "reifiedIs>(mlist)" } + assert(reifiedIs>(mlist)) { "reifiedIs>(mlist)" } + assert(reifiedIs>(mlist)) { "reifiedIs>(mlist)" } + assert(reifiedIs>(arrayList)) { "reifiedIs>(arrayList)" } + + val set = S() as Any + val mset = MS() + val hashSet = HashSet() + + assert(reifiedIsNot>(set)) { "reifiedIsNot>(set)" } + assert(reifiedIsNot>(set)) { "reifiedIsNot>(set)" } + assert(reifiedIsNot>(set)) { "reifiedIsNot>(set)" } + assert(reifiedIs>(mset)) { "reifiedIs>(mset)" } + assert(reifiedIs>(mset)) { "reifiedIs>(mset)" } + assert(reifiedIs>(mset)) { "reifiedIs>(mset)" } + assert(reifiedIs>(hashSet)) { "reifiedIs>(hashSet)" } + assert(reifiedIs>(hashSet)) { "reifiedIs>(hashSet)" } + assert(reifiedIs>(hashSet)) { "reifiedIs>(hashSet)" } + + val map = M() as Any + val mmap = MM() + val hashMap = HashMap() + + assert(reifiedIsNot>(map)) { "reifiedIsNot>(map)" } + assert(reifiedIs>(mmap)) { "reifiedIs>(mmap)"} + assert(reifiedIs>(hashMap)) { "reifiedIs>(hashMap)" } + + val entry = ME() as Any + val mentry = MME() + + hashMap[""] = "" + val hashMapEntry = hashMap.entrySet().first() + + assert(reifiedIsNot>(entry)) { "reifiedIsNot>(entry)"} + assert(reifiedIs>(mentry)) { "reifiedIs>(mentry)"} + assert(reifiedIs>(hashMapEntry)) { "reifiedIs>(hashMapEntry)"} + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/casts/reifiedSafeAsWithMutable.kt b/compiler/testData/codegen/boxWithStdlib/casts/reifiedSafeAsWithMutable.kt new file mode 100644 index 00000000000..ce844dfe1ee --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/casts/reifiedSafeAsWithMutable.kt @@ -0,0 +1,139 @@ +import java.util.* + +class Itr : Iterator by ArrayList().iterator() +class MItr : MutableIterator by ArrayList().iterator() +class LItr : ListIterator by ArrayList().listIterator() +class MLItr : MutableListIterator by ArrayList().listIterator() + +class It : Iterable by ArrayList() +class MIt : MutableIterable by ArrayList() +class C : Collection by ArrayList() +class MC : MutableCollection by ArrayList() +class L : List by ArrayList() +class ML : MutableList by ArrayList() +class S : Set by HashSet() +class MS : MutableSet by HashSet() + +class M : Map by HashMap() +class MM : MutableMap by HashMap() + +class ME : Map.Entry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() +} + +class MME : MutableMap.MutableEntry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() + override fun setValue(value: String): String = throw UnsupportedOperationException() +} + +inline fun reifiedSafeAsReturnsNonNull(x: Any?, operation: String) { + val y = try { + x as? T + } + catch (e: Throwable) { + throw AssertionError("$operation: should not throw exceptions, got $e") + } + if (y == null) { + throw AssertionError("$operation: should return non-null, got null") + } +} + +inline fun reifiedSafeAsReturnsNull(x: Any?, operation: String) { + val y = try { + x as? T + } + catch (e: Throwable) { + throw AssertionError("$operation: should not throw exceptions, got $e") + } + if (y != null) { + throw AssertionError("$operation: should return null, got $y") + } +} + +fun box(): String { + val itr = Itr() as Any + val mitr = MItr() + + reifiedSafeAsReturnsNull>(itr, "reifiedSafeAs>(itr)") + reifiedSafeAsReturnsNonNull>(mitr, "reifiedSafeAs>(mitr)") + + val litr = LItr() as Any + val mlitr = MLItr() + + reifiedSafeAsReturnsNull>(litr, "reifiedSafeAs>(litr)") + reifiedSafeAsReturnsNull>(litr, "reifiedSafeAs>(litr)") + reifiedSafeAsReturnsNonNull>(mlitr, "reifiedSafeAs>(mlitr)") + + val it = It() as Any + val mit = MIt() + val arrayList = ArrayList() + + reifiedSafeAsReturnsNull>(it, "reifiedSafeAs>(it)") + reifiedSafeAsReturnsNonNull>(mit, "reifiedSafeAs>(mit)") + reifiedSafeAsReturnsNonNull>(arrayList, "reifiedSafeAs>(arrayList)") + + val coll = C() as Any + val mcoll = MC() + + reifiedSafeAsReturnsNull>(coll, "reifiedSafeAs>(coll)") + reifiedSafeAsReturnsNull>(coll, "reifiedSafeAs>(coll)") + reifiedSafeAsReturnsNonNull>(mcoll, "reifiedSafeAs>(mcoll)") + reifiedSafeAsReturnsNonNull>(mcoll, "reifiedSafeAs>(mcoll)") + reifiedSafeAsReturnsNonNull>(arrayList, "reifiedSafeAs>(arrayList)") + + val list = L() as Any + val mlist = ML() + + reifiedSafeAsReturnsNull>(list, "reifiedSafeAs>(list)") + reifiedSafeAsReturnsNull>(list, "reifiedSafeAs>(list)") + reifiedSafeAsReturnsNull>(list, "reifiedSafeAs>(list)") + reifiedSafeAsReturnsNonNull>(mlist, "reifiedSafeAs>(mlist)") + reifiedSafeAsReturnsNonNull>(mlist, "reifiedSafeAs>(mlist)") + reifiedSafeAsReturnsNonNull>(mlist, "reifiedSafeAs>(mlist)") + reifiedSafeAsReturnsNonNull>(arrayList, "reifiedSafeAs>(arrayList)") + + val set = S() as Any + val mset = MS() + val hashSet = HashSet() + + reifiedSafeAsReturnsNull>(set, "reifiedSafeAs>(set)") + reifiedSafeAsReturnsNull>(set, "reifiedSafeAs>(set)") + reifiedSafeAsReturnsNull>(set, "reifiedSafeAs>(set)") + reifiedSafeAsReturnsNonNull>(mset, "reifiedSafeAs>(mset)") + reifiedSafeAsReturnsNonNull>(mset, "reifiedSafeAs>(mset)") + reifiedSafeAsReturnsNonNull>(mset, "reifiedSafeAs>(mset)") + reifiedSafeAsReturnsNonNull>(hashSet, "reifiedSafeAs>(hashSet)") + reifiedSafeAsReturnsNonNull>(hashSet, "reifiedSafeAs>(hashSet)") + reifiedSafeAsReturnsNonNull>(hashSet, "reifiedSafeAs>(hashSet)") + + val map = M() as Any + val mmap = MM() + val hashMap = HashMap() + + reifiedSafeAsReturnsNull>(map, "reifiedSafeAs>(map)") + reifiedSafeAsReturnsNonNull>(mmap, "reifiedSafeAs>(mmap)") + reifiedSafeAsReturnsNonNull>(hashMap, "reifiedSafeAs>(hashMap)") + + val entry = ME() as Any + val mentry = MME() + + hashMap[""] = "" + val hashMapEntry = hashMap.entrySet().first() + + reifiedSafeAsReturnsNull>(entry, "reifiedSafeAs>(entry)") + reifiedSafeAsReturnsNonNull>(mentry, "reifiedSafeAs>(mentry)") + reifiedSafeAsReturnsNonNull>(hashMapEntry, "reifiedSafeAs>(hashMapEntry)") + + reifiedSafeAsReturnsNull>(null, "reifiedSafeAs>(null)") + reifiedSafeAsReturnsNull>(null, "reifiedSafeAs>(null)") + reifiedSafeAsReturnsNull>(null, "reifiedSafeAs>(null)") + reifiedSafeAsReturnsNull>(null, "reifiedSafeAs>(null)") + reifiedSafeAsReturnsNull>(null, "reifiedSafeAs>(null)") + reifiedSafeAsReturnsNull>(null, "reifiedSafeAs>(null)") + reifiedSafeAsReturnsNull>(null, "reifiedSafeAs>(null)") + reifiedSafeAsReturnsNull>(null, "reifiedSafeAs>(null)") + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/casts/safeAsWithMutable.kt b/compiler/testData/codegen/boxWithStdlib/casts/safeAsWithMutable.kt new file mode 100644 index 00000000000..12c105f47a3 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/casts/safeAsWithMutable.kt @@ -0,0 +1,133 @@ +import java.util.* + +class Itr : Iterator by ArrayList().iterator() +class MItr : MutableIterator by ArrayList().iterator() +class LItr : ListIterator by ArrayList().listIterator() +class MLItr : MutableListIterator by ArrayList().listIterator() + +class It : Iterable by ArrayList() +class MIt : MutableIterable by ArrayList() +class C : Collection by ArrayList() +class MC : MutableCollection by ArrayList() +class L : List by ArrayList() +class ML : MutableList by ArrayList() +class S : Set by HashSet() +class MS : MutableSet by HashSet() + +class M : Map by HashMap() +class MM : MutableMap by HashMap() + +class ME : Map.Entry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() +} + +class MME : MutableMap.MutableEntry { + override fun getKey(): String = throw UnsupportedOperationException() + override fun getValue(): String = throw UnsupportedOperationException() + override fun setValue(value: String): String = throw UnsupportedOperationException() +} + +inline fun safeAsReturnsNull(operation: String, block: () -> Any?) { + try { + val x = block() + assert(x == null) { "$operation: should return null, got $x" } + } + catch (e: Throwable) { + assert(false) { "$operation: should not throw exceptions, got $e" } + } +} + +inline fun safeAsReturnsNonNull(operation: String, block: () -> Any?) { + try { + val x = block() + assert(x != null) { "$operation: should return non-null" } + } + catch (e: Throwable) { + assert(false) { "$operation: should not throw exceptions, got $e" } + } +} + +fun box(): String { + val itr = Itr() as Any + val mitr = MItr() + + safeAsReturnsNull("itr as? MutableIterator") { itr as? MutableIterator<*> } + safeAsReturnsNonNull("mitr as? MutableIterator") { mitr as? MutableIterator<*> } + + val litr = LItr() as Any + val mlitr = MLItr() + + safeAsReturnsNull("litr as? MutableIterator") { litr as? MutableIterator<*> } + safeAsReturnsNull("litr as? MutableListIterator") { litr as? MutableListIterator<*> } + safeAsReturnsNonNull("mlitr as? MutableIterator") { mlitr as? MutableIterator<*> } + safeAsReturnsNonNull("mlitr as? MutableListIterator") { mlitr as? MutableListIterator<*> } + + val it = It() as Any + val mit = MIt() + val arrayList = ArrayList() + + safeAsReturnsNull("it as? MutableIterable") { it as? MutableIterable<*> } + safeAsReturnsNonNull("mit as? MutableIterable") { mit as? MutableIterable<*> } + safeAsReturnsNonNull("arrayList as? MutableIterable") { arrayList as? MutableIterable<*> } + + val coll = C() as Any + val mcoll = MC() + + safeAsReturnsNull("coll as? MutableIterable") { coll as? MutableIterable<*> } + safeAsReturnsNull("coll as? MutableCollection") { coll as? MutableCollection<*> } + safeAsReturnsNonNull("mcoll as? MutableIterable") { mcoll as? MutableIterable<*> } + safeAsReturnsNonNull("mcoll as? MutableCollection") { mcoll as? MutableCollection<*> } + safeAsReturnsNonNull("arrayList as? MutableCollection") { arrayList as? MutableCollection<*> } + + val list = L() as Any + val mlist = ML() + + safeAsReturnsNull("list as? MutableIterable") { list as? MutableIterable<*> } + safeAsReturnsNull("list as? MutableCollection") { list as? MutableCollection<*> } + safeAsReturnsNull("list as? MutableList") { list as? MutableList<*> } + safeAsReturnsNonNull("mlist as? MutableIterable") { mlist as? MutableIterable<*> } + safeAsReturnsNonNull("mlist as? MutableCollection") { mlist as? MutableCollection<*> } + safeAsReturnsNonNull("mlist as? MutableList") { mlist as? MutableList<*> } + + val set = S() as Any + val mset = MS() + val hashSet = HashSet() + + safeAsReturnsNull("set as? MutableIterable") { set as? MutableIterable<*> } + safeAsReturnsNull("set as? MutableCollection") { set as? MutableCollection<*> } + safeAsReturnsNull("set as? MutableSet") { set as? MutableSet<*> } + safeAsReturnsNonNull("mset as? MutableIterable") { mset as? MutableIterable<*> } + safeAsReturnsNonNull("mset as? MutableCollection") { mset as? MutableCollection<*> } + safeAsReturnsNonNull("mset as? MutableSet") { mset as? MutableSet<*> } + safeAsReturnsNonNull("hashSet as? MutableSet") { hashSet as? MutableSet<*> } + + val map = M() as Any + val mmap = MM() + val hashMap = HashMap() + + safeAsReturnsNull("map as? MutableMap") { map as? MutableMap<*, *> } + safeAsReturnsNonNull("mmap as? MutableMap") { mmap as? MutableMap<*, *> } + + val entry = ME() as Any + val mentry = MME() + + safeAsReturnsNull("entry as? MutableMap.MutableEntry") { entry as? MutableMap.MutableEntry<*, *> } + safeAsReturnsNonNull("mentry as? MutableMap.MutableEntry") { mentry as? MutableMap.MutableEntry<*, *> } + + hashMap[""] = "" + val hashMapEntry = hashMap.entrySet().first() + + safeAsReturnsNonNull("hashMapEntry as? MutableMap.MutableEntry") { hashMapEntry as? MutableMap.MutableEntry<*, *> } + + safeAsReturnsNull("null as? MutableIterator") { null as? MutableIterator<*> } + safeAsReturnsNull("null as? MutableListIterator") { null as? MutableListIterator<*> } + safeAsReturnsNull("null as? MutableIterable") { null as? MutableIterable<*> } + safeAsReturnsNull("null as? MutableCollection") { null as? MutableCollection<*> } + safeAsReturnsNull("null as? MutableList") { null as? MutableList<*> } + safeAsReturnsNull("null as? MutableSet") { null as? MutableSet<*> } + safeAsReturnsNull("null as? MutableMap") { null as? MutableMap<*, *> } + safeAsReturnsNull("null as? MutableMap.MutableEntry") { null as? MutableMap.MutableEntry<*, *> } + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 8012c06fa42..c986b3a4b5b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -922,6 +922,42 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("asWithMutable.kt") + public void testAsWithMutable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/casts/asWithMutable.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("isWithMutable.kt") + public void testIsWithMutable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/casts/isWithMutable.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("reifiedAsWithMutable.kt") + public void testReifiedAsWithMutable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/casts/reifiedAsWithMutable.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("reifiedIsWithMutable.kt") + public void testReifiedIsWithMutable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/casts/reifiedIsWithMutable.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("reifiedSafeAsWithMutable.kt") + public void testReifiedSafeAsWithMutable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/casts/reifiedSafeAsWithMutable.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("safeAsWithMutable.kt") + public void testSafeAsWithMutable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/casts/safeAsWithMutable.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("unitAsInt.kt") public void testUnitAsInt() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/casts/unitAsInt.kt"); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java b/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java index ec33fa32a1a..0071f30fda6 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java @@ -19,8 +19,7 @@ package kotlin.jvm.internal; import kotlin.KotlinNullPointerException; import kotlin.UninitializedPropertyAccessException; -import java.util.Arrays; -import java.util.List; +import java.util.*; @SuppressWarnings("unused") public class Intrinsics { @@ -35,6 +34,10 @@ public class Intrinsics { throw sanitizeStackTrace(new KotlinNullPointerException()); } + public static void throwCce(String message) { + throw sanitizeStackTrace(new ClassCastException(message)); + } + public static void throwUninitializedPropertyAccessException(String propertyName) { throw sanitizeStackTrace(new UninitializedPropertyAccessException(propertyName)); } @@ -137,4 +140,268 @@ public class Intrinsics { throwable.setStackTrace(list.toArray(new StackTraceElement[list.size()])); return throwable; } + + public static boolean isMutableIterator(Object obj) { + return (obj instanceof Iterator) && + (!(obj instanceof KMappedMarker) || (obj instanceof KMutableIterator)); + } + + public static Iterator asMutableIterator(Object obj) { + Iterator result = null; + try { + result = (Iterator) obj; + } + catch (ClassCastException e) { + throwCce("argument is not an Iterator"); + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableIterator)) { + throwCce("argument is not a MutableIterator"); + } + return result; + } + + public static Iterator safeAsMutableIterator(Object obj) { + Iterator result; + try { + result = (Iterator) obj; + } + catch (ClassCastException e) { + return null; + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableIterator)) { + return null; + } + return result; + } + + public static boolean isMutableListIterator(Object obj) { + return (obj instanceof ListIterator) && + (!(obj instanceof KMappedMarker) || (obj instanceof KMutableListIterator)); + } + + public static ListIterator asMutableListIterator(Object obj) { + ListIterator result = null; + try { + result = (ListIterator) obj; + } + catch (ClassCastException e) { + throwCce("argument is not a ListIterator"); + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableListIterator)) { + throwCce("argument is not a MutableListIterator"); + } + return result; + } + + public static ListIterator safeAsMutableListIterator(Object obj) { + ListIterator result; + try { + result = (ListIterator) obj; + } + catch (ClassCastException e) { + return null; + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableListIterator)) { + return null; + } + return result; + } + + public static boolean isMutableIterable(Object obj) { + return (obj instanceof Iterable) && + (!(obj instanceof KMappedMarker) || (obj instanceof KMutableIterable)); + } + + public static Iterable asMutableIterable(Object obj) { + Iterable result = null; + try { + result = (Iterable) obj; + } + catch (ClassCastException e) { + throwCce("argument is not an Iterable"); + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableIterable)) { + throwCce("argument is not a MutableIterable"); + } + return result; + } + + public static Iterable safeAsMutableIterable(Object obj) { + Iterable result; + try { + result = (Iterable) obj; + } + catch (ClassCastException e) { + return null; + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableIterable)) { + return null; + } + return result; + } + + public static boolean isMutableCollection(Object obj) { + return (obj instanceof Collection) && + (!(obj instanceof KMappedMarker) || (obj instanceof KMutableCollection)); + } + + public static Collection asMutableCollection(Object obj) { + Collection result = null; + try { + result = (Collection) obj; + } + catch (ClassCastException e) { + throwCce("argument is not a Collection"); + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableCollection)) { + throwCce("argument is not a MutableCollection"); + } + return result; + } + + public static Collection safeAsMutableCollection(Object obj) { + Collection result; + try { + result = (Collection) obj; + } + catch (ClassCastException e) { + return null; + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableCollection)) { + return null; + } + return result; + } + + public static boolean isMutableList(Object obj) { + return (obj instanceof List) && + (!(obj instanceof KMappedMarker) || (obj instanceof KMutableList)); + } + + public static List asMutableList(Object obj) { + List result = null; + try { + result = (List) obj; + } + catch (ClassCastException e) { + throwCce("argument is not a List"); + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableList)) { + throwCce("argument is not a MutableList"); + } + return result; + } + + public static List safeAsMutableList(Object obj) { + List result; + try { + result = (List) obj; + } + catch (ClassCastException e) { + return null; + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableList)) { + return null; + } + return result; + } + + public static boolean isMutableSet(Object obj) { + return (obj instanceof Set) && + (!(obj instanceof KMappedMarker) || (obj instanceof KMutableSet)); + } + + public static Set asMutableSet(Object obj) { + Set result = null; + try { + result = (Set) obj; + } + catch (ClassCastException e) { + throwCce("argument is not a Set"); + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableSet)) { + throwCce("argument is not a MutableSet"); + } + return result; + } + + public static Set safeAsMutableSet(Object obj) { + Set result; + try { + result = (Set) obj; + } + catch (ClassCastException e) { + return null; + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableSet)) { + return null; + } + return result; + } + + public static boolean isMutableMap(Object obj) { + return (obj instanceof Map) && + (!(obj instanceof KMappedMarker) || (obj instanceof KMutableMap)); + } + + public static Map asMutableMap(Object obj) { + Map result = null; + try { + result = (Map) obj; + } + catch (ClassCastException e) { + throwCce("argument is not a Map"); + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableMap)) { + throwCce("argument is not a MutableMap"); + } + return result; + } + + public static Map safeAsMutableMap(Object obj) { + Map result = null; + try { + result = (Map) obj; + } + catch (ClassCastException e) { + return null; + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableMap)) { + return null; + } + return result; + } + + public static boolean isMutableMapEntry(Object obj) { + return (obj instanceof Map.Entry) && + (!(obj instanceof KMappedMarker) || (obj instanceof KMutableMap.Entry)); + } + + public static Map.Entry asMutableMapEntry(Object obj) { + Map.Entry result = null; + try { + result = (Map.Entry) obj; + } + catch (ClassCastException e) { + throwCce("argument is not a Map.Entry"); + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableMap.Entry)) { + throwCce("argument is not a MutableMap.MutableEntry"); + } + return result; + } + + public static Map.Entry safeAsMutableMapEntry(Object obj) { + Map.Entry result = null; + try { + result = (Map.Entry) obj; + } + catch (ClassCastException e) { + return null; + } + if ((obj instanceof KMappedMarker) && !(obj instanceof KMutableMap.Entry)) { + return null; + } + return result; + } } diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/SmartSet.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/SmartSet.kt index b73e0cdad30..5ae11c45876 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/utils/SmartSet.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/SmartSet.kt @@ -42,11 +42,11 @@ class SmartSet private constructor() : AbstractSet() { private var size: Int = 0 override fun iterator(): MutableIterator = when { - size == 0 -> emptySet().iterator() - size == 1 -> SingletonIterator(data as T) - size < ARRAY_THRESHOLD -> (data as Array).iterator() - else -> (data as MutableSet).iterator() - } as MutableIterator + size == 0 -> Collections.emptySet().iterator() + size == 1 -> SingletonIterator(data as T) + size < ARRAY_THRESHOLD -> ArrayIterator(data as Array) + else -> (data as MutableSet).iterator() + } override fun add(e: T): Boolean { when { @@ -87,7 +87,7 @@ class SmartSet private constructor() : AbstractSet() { else -> o in data as Set } - private class SingletonIterator(private val element: T) : Iterator { + private class SingletonIterator(private val element: T) : MutableIterator { private var hasNext = true override fun next(): T = @@ -98,5 +98,15 @@ class SmartSet private constructor() : AbstractSet() { else throw NoSuchElementException() override fun hasNext() = hasNext + + override fun remove() = throw UnsupportedOperationException() + } + + private class ArrayIterator(array: Array) : MutableIterator { + private val arrayIterator = array.iterator() + + override fun hasNext(): Boolean = arrayIterator.hasNext() + override fun next(): T = arrayIterator.next() + override fun remove() = throw UnsupportedOperationException() } }