diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java index 910bc70f326..ccc201b48a3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java @@ -66,6 +66,7 @@ public class IntrinsicMethods { namedMethods.put("kotlin.arrays.array", new JavaClassArray()); namedMethods.put("kotlin.jvm.internal.unsafe.monitorEnter", MonitorInstruction.MONITOR_ENTER); namedMethods.put("kotlin.jvm.internal.unsafe.monitorExit", MonitorInstruction.MONITOR_EXIT); + namedMethods.put("kotlin.jvm.isArrayOf", new IsArrayOf()); ImmutableList primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList(); for (Name method : primitiveCastMethods) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IsArrayOf.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IsArrayOf.kt new file mode 100644 index 00000000000..fcf8419528a --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IsArrayOf.kt @@ -0,0 +1,43 @@ +/* + * 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.codegen.Callable +import org.jetbrains.kotlin.codegen.ExpressionCodegen +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.types.Variance + +class IsArrayOf : IntrinsicMethod() { + override fun toCallable(fd: FunctionDescriptor, isSuper: Boolean, resolvedCall: ResolvedCall<*>, codegen: ExpressionCodegen): Callable { + val typeArguments = resolvedCall.typeArguments + assert(typeArguments.size == 1) { "Expected only one type parameter for Any?.isArrayOf(), got: $typeArguments" } + + val typeMapper = codegen.state.typeMapper + val method = typeMapper.mapToCallableMethod(fd, false) + + val builtIns = fd.module.builtIns + val elementType = typeArguments.values().first() + val arrayKtType = builtIns.getArrayType(Variance.INVARIANT, elementType) + val arrayType = typeMapper.mapType(arrayKtType) + + return createIntrinsicCallable(method) { + it.instanceOf(arrayType) + } + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/arrays/kt602.kt b/compiler/testData/codegen/box/arrays/kt602.kt deleted file mode 100644 index dcc72b3108a..00000000000 --- a/compiler/testData/codegen/box/arrays/kt602.kt +++ /dev/null @@ -1,2 +0,0 @@ -fun box() = if(arrayOfNulls(10) is Array) "OK" else "fail" - diff --git a/compiler/testData/codegen/box/controlStructures/forInSmartCastToArray.kt b/compiler/testData/codegen/box/controlStructures/forInSmartCastToArray.kt index c69428486ef..83a919d7e9f 100644 --- a/compiler/testData/codegen/box/controlStructures/forInSmartCastToArray.kt +++ b/compiler/testData/codegen/box/controlStructures/forInSmartCastToArray.kt @@ -1,5 +1,5 @@ -fun f(x: Any?): String { - if (x is Array) { +fun f(x: Any?): Any? { + if (x is Array<*>) { for (i in x) { return i } @@ -10,5 +10,5 @@ fun f(x: Any?): String { fun box(): String { val a = arrayOfNulls(1) as Array a[0] = "OK" - return f(a) + return f(a) as String } diff --git a/compiler/testData/codegen/boxWithStdlib/arrays/kt602.kt b/compiler/testData/codegen/boxWithStdlib/arrays/kt602.kt new file mode 100644 index 00000000000..eb527f81d8a --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/arrays/kt602.kt @@ -0,0 +1,2 @@ +fun box() = if(arrayOfNulls(10).isArrayOf()) "OK" else "fail" + diff --git a/compiler/testData/codegen/boxWithStdlib/arrays/kt7338.kt b/compiler/testData/codegen/boxWithStdlib/arrays/kt7338.kt index 2f893e040de..040fa1dd9b9 100644 --- a/compiler/testData/codegen/boxWithStdlib/arrays/kt7338.kt +++ b/compiler/testData/codegen/boxWithStdlib/arrays/kt7338.kt @@ -1,5 +1,5 @@ fun foo(x : Any): String { - return if(x is Array) x[0] else "fail" + return if(x is Array<*> && x.isArrayOf()) (x as Array)[0] else "fail" } fun box(): String { diff --git a/compiler/testData/codegen/boxWithStdlib/toArray/copyToArray.kt b/compiler/testData/codegen/boxWithStdlib/toArray/copyToArray.kt index 03fd6b08ea4..54b11577942 100644 --- a/compiler/testData/codegen/boxWithStdlib/toArray/copyToArray.kt +++ b/compiler/testData/codegen/boxWithStdlib/toArray/copyToArray.kt @@ -2,7 +2,7 @@ import java.util.Arrays fun box(): String { val array = Arrays.asList(2, 3, 9).toTypedArray() - if (array !is Array) return array.javaClass.toString() + if (!array.isArrayOf()) return array.javaClass.toString() val str = Arrays.toString(array) if (str != "[2, 3, 9]") return str diff --git a/compiler/testData/codegen/box/toArray/toArray.kt b/compiler/testData/codegen/boxWithStdlib/toArray/toArray.kt similarity index 75% rename from compiler/testData/codegen/box/toArray/toArray.kt rename to compiler/testData/codegen/boxWithStdlib/toArray/toArray.kt index ccc23fbf998..ce7010bc6b2 100644 --- a/compiler/testData/codegen/box/toArray/toArray.kt +++ b/compiler/testData/codegen/boxWithStdlib/toArray/toArray.kt @@ -8,8 +8,8 @@ fun box(): String { val array1 = collection.toArray() val array2 = collection.toArray(arrayOfNulls(3) as Array) - if (array1 !is Array) return (array1 as Object).getClass().toString() - if (array2 !is Array) return (array2 as Object).getClass().toString() + if (!array1.isArrayOf()) return (array1 as Object).getClass().toString() + if (!array2.isArrayOf()) return (array2 as Object).getClass().toString() val s1 = Arrays.toString(array1) val s2 = Arrays.toString(array2) diff --git a/compiler/testData/codegen/box/toArray/toArrayAlreadyPresent.kt b/compiler/testData/codegen/boxWithStdlib/toArray/toArrayAlreadyPresent.kt similarity index 84% rename from compiler/testData/codegen/box/toArray/toArrayAlreadyPresent.kt rename to compiler/testData/codegen/boxWithStdlib/toArray/toArrayAlreadyPresent.kt index 4f6591cb979..93be5ffff0f 100644 --- a/compiler/testData/codegen/box/toArray/toArrayAlreadyPresent.kt +++ b/compiler/testData/codegen/boxWithStdlib/toArray/toArrayAlreadyPresent.kt @@ -23,8 +23,8 @@ fun box(): String { val array1 = collection.toArray() val array2 = collection.toArray(arrayOfNulls(3) as Array) - if (array1 !is Array) return (array1 as Object).getClass().toString() - if (array2 !is Array) return (array2 as Object).getClass().toString() + if (!array1.isArrayOf()) return (array1 as Object).getClass().toString() + if (!array2.isArrayOf()) return (array2 as Object).getClass().toString() val s1 = Arrays.toString(array1) val s2 = Arrays.toString(array2) diff --git a/compiler/testData/codegen/bytecodeText/isArrayOf.kt b/compiler/testData/codegen/bytecodeText/isArrayOf.kt new file mode 100644 index 00000000000..3370b6fec7a --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/isArrayOf.kt @@ -0,0 +1,3 @@ +fun f(x: Any): Boolean = x is Array<*> && x.isArrayOf() + +// 2 INSTANCEOF \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsArray.kt b/compiler/testData/diagnostics/tests/cast/IsArray.kt index f5329d82748..5bc070e0377 100644 --- a/compiler/testData/diagnostics/tests/cast/IsArray.kt +++ b/compiler/testData/diagnostics/tests/cast/IsArray.kt @@ -1 +1 @@ -fun f(a: Array) = a is Array +fun f(a: Array) = a.isArrayOf() diff --git a/compiler/testData/diagnostics/tests/cast/IsReified.kt b/compiler/testData/diagnostics/tests/cast/IsReified.kt index 22106795e61..513997f865a 100644 --- a/compiler/testData/diagnostics/tests/cast/IsReified.kt +++ b/compiler/testData/diagnostics/tests/cast/IsReified.kt @@ -1 +1 @@ -fun ff(a: Any) = a is Array \ No newline at end of file +fun ff(a: Any) = a is Array<*> && a.isArrayOf() \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 4c5a7ea27a4..0d3c4c3cf26 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -149,6 +149,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } + @TestMetadata("isArrayOf.kt") + public void testIsArrayOf() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/isArrayOf.kt"); + doTest(fileName); + } + @TestMetadata("javaExtensionPropertyIntrinsic.kt") public void testJavaExtensionPropertyIntrinsic() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/javaExtensionPropertyIntrinsic.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 0723ae6dfd4..c5ed215a3d5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -286,12 +286,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } - @TestMetadata("kt602.kt") - public void testKt602() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/kt602.kt"); - doTest(fileName); - } - @TestMetadata("kt7288.kt") public void testKt7288() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/kt7288.kt"); @@ -7409,27 +7403,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } - @TestMetadata("compiler/testData/codegen/box/toArray") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class ToArray extends AbstractBlackBoxCodegenTest { - public void testAllFilesPresentInToArray() throws Exception { - JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/toArray"), Pattern.compile("^(.+)\\.kt$"), true); - } - - @TestMetadata("toArray.kt") - public void testToArray() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toArray.kt"); - doTest(fileName); - } - - @TestMetadata("toArrayAlreadyPresent.kt") - public void testToArrayAlreadyPresent() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toArrayAlreadyPresent.kt"); - doTest(fileName); - } - } - @TestMetadata("compiler/testData/codegen/box/traits") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index c7f0c494013..7f34114fa2a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -256,6 +256,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("kt602.kt") + public void testKt602() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/arrays/kt602.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("kt7009.kt") public void testKt7009() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/arrays/kt7009.kt"); @@ -4644,6 +4650,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/toArray/returnCopyToArray.kt"); doTestWithStdlib(fileName); } + + @TestMetadata("toArray.kt") + public void testToArray() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/toArray/toArray.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("toArrayAlreadyPresent.kt") + public void testToArrayAlreadyPresent() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/toArray/toArrayAlreadyPresent.kt"); + doTestWithStdlib(fileName); + } } @TestMetadata("compiler/testData/codegen/boxWithStdlib/vararg") diff --git a/idea/testData/checker/infos/SmartCasts.kt b/idea/testData/checker/infos/SmartCasts.kt index 8441d34ec0c..a656974aa85 100644 --- a/idea/testData/checker/infos/SmartCasts.kt +++ b/idea/testData/checker/infos/SmartCasts.kt @@ -227,8 +227,8 @@ fun foo(aa: Any): Int { } fun inForLoop(x: Any?) { - if (x is Array) { - for (i in x) {} + if (x is Array<*>) { + for (i in x) {} } for (i in x) {} } diff --git a/libraries/stdlib/src/kotlin/jvm/IsArrayOf.kt b/libraries/stdlib/src/kotlin/jvm/IsArrayOf.kt new file mode 100644 index 00000000000..f64f7ecd7f1 --- /dev/null +++ b/libraries/stdlib/src/kotlin/jvm/IsArrayOf.kt @@ -0,0 +1,26 @@ +/* + * 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 kotlin.jvm + +import kotlin.jvm.internal.Intrinsic + +/** + * Checks if array can contain element of type [T]. + */ +@Intrinsic("kotlin.jvm.isArrayOf") +public fun Array<*>.isArrayOf(): Boolean = + T::class.java.isAssignableFrom(this.javaClass.componentType) \ No newline at end of file diff --git a/libraries/stdlib/test/collections/CollectionJVMTest.kt b/libraries/stdlib/test/collections/CollectionJVMTest.kt index 89df44678b9..3cb78960275 100644 --- a/libraries/stdlib/test/collections/CollectionJVMTest.kt +++ b/libraries/stdlib/test/collections/CollectionJVMTest.kt @@ -123,7 +123,7 @@ class CollectionJVMTest { assertEquals(2, arr.size()) todo { assertTrue { - arr is Array + arr.isArrayOf() } } } diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index 7179efac19d..131a186d67b 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -403,7 +403,7 @@ class CollectionTest { assertEquals(2, arr.size()) todo { assertTrue { - arr is Array + arr.isArrayOf() } } }