From 57869d85e8dcdc6ba0609b6802178aa2053889a1 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Mon, 5 Oct 2015 19:04:46 +0300 Subject: [PATCH] Spread should always copy arrays. Introduce a special (package private) utility class ArraysUtilJVM to fix Array.asList() issues. --- .../kotlin/codegen/ExpressionCodegen.java | 14 ++++++++-- .../boxWithStdlib/vararg/spreadCopiesArray.kt | 27 ++++++++++++++++++ .../jetbrains/kotlin/codegen/VarArgTest.java | 3 +- ...lackBoxWithStdlibCodegenTestGenerated.java | 6 ++++ libraries/stdlib/src/generated/_Arrays.kt | 2 +- .../stdlib/src/kotlin/ArraysUtilJVM.java | 28 +++++++++++++++++++ .../src/templates/SpecialJVM.kt | 2 +- 7 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/vararg/spreadCopiesArray.kt create mode 100644 libraries/stdlib/src/kotlin/ArraysUtilJVM.java diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 4d01f77f47f..c0cf99dd548 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2685,14 +2685,24 @@ public class ExpressionCodegen extends JetVisitor implem } if (hasSpread) { + boolean arrayOfReferences = KotlinBuiltIns.isArray(outType); if (size == 1) { - gen(arguments.get(0).getArgumentExpression(), type); + // Arrays.copyOf(array, newLength) + ValueArgument argument = arguments.get(0); + Type arrayType = arrayOfReferences ? Type.getType("[Ljava/lang/Object;") + : Type.getType("[" + elementType.getDescriptor()); + gen(argument.getArgumentExpression(), type); + v.dup(); + v.arraylength(); + v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false); + if (arrayOfReferences) { + v.checkcast(type); + } } else { String owner; String addDescriptor; String toArrayDescriptor; - boolean arrayOfReferences = KotlinBuiltIns.isArray(outType); if (arrayOfReferences) { owner = "kotlin/jvm/internal/SpreadBuilder"; addDescriptor = "(Ljava/lang/Object;)V"; diff --git a/compiler/testData/codegen/boxWithStdlib/vararg/spreadCopiesArray.kt b/compiler/testData/codegen/boxWithStdlib/vararg/spreadCopiesArray.kt new file mode 100644 index 00000000000..674e652e23a --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/vararg/spreadCopiesArray.kt @@ -0,0 +1,27 @@ +import kotlin.test.* + +fun copyArray(vararg data: T): Array = data + +inline fun reifiedCopyArray(vararg data: T): Array = data + +fun copyIntArray(vararg data: Int): IntArray = data + +fun box(): String { + val sarr = arrayOf("OK") + val sarr2 = copyArray(*sarr) + sarr[0] = "Array was not copied" + assertEquals(sarr2[0], "OK", "Failed: Array") + + var rsarr = arrayOf("OK") + var rsarr2 = reifiedCopyArray(*rsarr) + rsarr[0] = "Array was not copied" + assertEquals(rsarr2[0], "OK", "Failed: Array, reified copy") + + val iarr = IntArray(1) + iarr[0] = 1 + val iarr2 = copyIntArray(*iarr) + iarr[0] = 42 + assertEquals(iarr2[0], 1, "Failed: IntArray") + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/VarArgTest.java b/compiler/tests/org/jetbrains/kotlin/codegen/VarArgTest.java index 4f2223f8be6..38fd2481ce0 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/VarArgTest.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/VarArgTest.java @@ -91,7 +91,8 @@ public class VarArgTest extends CodegenTestCase { Method main = generateFunction("test"); String[] args = {"mama", "papa"}; String[] result = (String []) main.invoke(null, new Object[] {args}); - assertTrue(args == result); + assertTrue(args != result); + assertTrue(Arrays.equals(args, result)); } public void testArrayAsVararg2() throws InvocationTargetException, IllegalAccessException { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index b29f8546464..b2d0e24752d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -4651,6 +4651,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/vararg"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("spreadCopiesArray.kt") + public void testSpreadCopiesArray() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/vararg/spreadCopiesArray.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("varargInFunParam.kt") public void testVarargInFunParam() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/vararg/varargInFunParam.kt"); diff --git a/libraries/stdlib/src/generated/_Arrays.kt b/libraries/stdlib/src/generated/_Arrays.kt index 45bcd227875..02c49710f83 100644 --- a/libraries/stdlib/src/generated/_Arrays.kt +++ b/libraries/stdlib/src/generated/_Arrays.kt @@ -10165,7 +10165,7 @@ public fun ShortArray.asSequence(): Sequence { */ @kotlin.jvm.JvmVersion public fun Array.asList(): List { - return Arrays.asList(*this) + return ArraysUtilJVM.asList(this) } /** diff --git a/libraries/stdlib/src/kotlin/ArraysUtilJVM.java b/libraries/stdlib/src/kotlin/ArraysUtilJVM.java new file mode 100644 index 00000000000..0ce62ae9871 --- /dev/null +++ b/libraries/stdlib/src/kotlin/ArraysUtilJVM.java @@ -0,0 +1,28 @@ +/* + * 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; + +import java.util.Arrays; +import java.util.List; + +class ArraysUtilJVM { + static List asList(T[] array) { + return Arrays.asList(array); + } +} + + diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt index 2e251ed0d95..af18f17baa5 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt @@ -221,7 +221,7 @@ fun specialJVM(): List { returns("List") body(ArraysOfObjects) { """ - return Arrays.asList(*this) + return ArraysUtilJVM.asList(this) """ }