JVM IR: allow custom toArray to have any array type
To avoid breaking Java source compatibility. This problem can be fixed later once JVM IR is stabilized. #KT-43111 Fixed
This commit is contained in:
+1
-1
@@ -588,7 +588,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
|
||||
if (!withSuper && !declaration.visibility.isPrivate && !declaration.visibility.isProtected) return true
|
||||
|
||||
// `toArray` is always accessible cause mapped to public functions
|
||||
if (symbolOwner is IrSimpleFunction && (symbolOwner.isNonGenericToArray(context) || symbolOwner.isGenericToArray(context))) {
|
||||
if (symbolOwner is IrSimpleFunction && (symbolOwner.isNonGenericToArray() || symbolOwner.isGenericToArray(context))) {
|
||||
if (symbolOwner.parentAsClass.isCollectionSubClass) {
|
||||
return true
|
||||
}
|
||||
|
||||
+10
-5
@@ -11,8 +11,8 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addDispatchReceiver
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addTypeParameter
|
||||
@@ -75,7 +75,7 @@ private class ToArrayLowering(private val context: JvmBackendContext) : ClassLow
|
||||
}
|
||||
}
|
||||
|
||||
irClass.findOrCreate(indirectCollectionSubClass, { it.isNonGenericToArray(context) }) {
|
||||
irClass.findOrCreate(indirectCollectionSubClass, IrSimpleFunction::isNonGenericToArray) {
|
||||
irClass.addFunction {
|
||||
name = Name.identifier("toArray")
|
||||
origin = JvmLoweredDeclarationOrigin.TO_ARRAY
|
||||
@@ -132,7 +132,12 @@ internal fun IrSimpleFunction.isGenericToArray(context: JvmBackendContext): Bool
|
||||
returnType.isArrayOrNullableArrayOf(context, typeParameters[0].symbol) &&
|
||||
valueParameters[0].type.isArrayOrNullableArrayOf(context, typeParameters[0].symbol)
|
||||
|
||||
// Match `fun toArray(): Array<Any?>`
|
||||
internal fun IrSimpleFunction.isNonGenericToArray(context: JvmBackendContext): Boolean =
|
||||
// Match `fun toArray(): Array<...>`.
|
||||
// It would be more correct to check that the return type is erased to `Object[]`, however the old backend doesn't do that
|
||||
// (see `FunctionDescriptor.isNonGenericToArray` and KT-43111).
|
||||
internal fun IrSimpleFunction.isNonGenericToArray(): Boolean =
|
||||
name.asString() == "toArray" && typeParameters.isEmpty() && valueParameters.isEmpty() &&
|
||||
extensionReceiverParameter == null && returnType.isArrayOrNullableArrayOf(context, context.irBuiltIns.anyClass)
|
||||
extensionReceiverParameter == null && returnType.isArrayOrNullableArray()
|
||||
|
||||
private fun IrType.isArrayOrNullableArray(): Boolean =
|
||||
this is IrSimpleType && (isArray() || isNullableArray())
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// The old backend thinks `toArray(): Array<Int?>` is the same as `toArray(): Array<Any?>`
|
||||
// IGNORE_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: MyListWithCustomToArray.java
|
||||
|
||||
@@ -29,7 +27,7 @@ class MyListSubclass<T>(val list: List<T>): MyListWithCustomToArray<T>() {
|
||||
get() = list.size
|
||||
}
|
||||
|
||||
class MyCollection<T>(val list: List<T>) : Collection<T> by list {
|
||||
class MyCollectionWithCustomIntToArray<T>(val list: List<T>) : Collection<T> by list {
|
||||
fun toArray(): Array<Int?> =
|
||||
arrayOfNulls<Int>(0)
|
||||
}
|
||||
@@ -43,8 +41,13 @@ fun box(): String {
|
||||
list2.toArray().contentToString().let { if (it != "[null]") return "fail 3: $it" }
|
||||
list2.toArray(arrayOfNulls<Int>(1)).contentToString().let { if (it != "[null]") return "fail 4: $it" }
|
||||
|
||||
val list3 = MyCollection(listOf(2, 3, 9)) as java.util.Collection<*>
|
||||
val list3 = MyCollectionWithCustomIntToArray(listOf(2, 3, 9)) as java.util.Collection<*>
|
||||
/*
|
||||
// This fails with AbstractMethodError at the moment because of a bug where the backend doesn't check the array element type
|
||||
// of the return type when looking for an implementation of the non-generic parameterless `toArray`.
|
||||
// See `FunctionDescriptor.isNonGenericToArray`, `IrSimpleFunction.isNonGenericToArray` and KT-43111.
|
||||
list3.toArray().contentToString().let { if (it != "[2, 3, 9]") return "fail 5: $it" }
|
||||
list3.toArray(arrayOfNulls<Int>(0)).contentToString().let { if (it != "[2, 3, 9]") return "fail 6: $it" }
|
||||
*/
|
||||
return "OK"
|
||||
}
|
||||
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
class InternalToArray(d: Collection<Any>): Collection<Any> by d {
|
||||
internal fun toArray(): Array<Int> = null!!
|
||||
}
|
||||
|
||||
class PrivateToArray(d: Collection<Any>): Collection<Any> by d {
|
||||
private fun toArray(): Array<Int> = null!!
|
||||
}
|
||||
|
||||
class PublicToArray(d: Collection<Any>): Collection<Any> by d {
|
||||
public fun toArray(): Array<Int> = null!!
|
||||
}
|
||||
Vendored
+62
@@ -0,0 +1,62 @@
|
||||
@kotlin.Metadata
|
||||
public final class InternalToArray {
|
||||
// source: 'customNonGenericToArray.kt'
|
||||
private synthetic final field $$delegate_0: java.util.Collection
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.util.Collection): void
|
||||
public method add(p0: java.lang.Object): boolean
|
||||
public method addAll(p0: java.util.Collection): boolean
|
||||
public method clear(): void
|
||||
public method contains(@org.jetbrains.annotations.NotNull p0: java.lang.Object): boolean
|
||||
public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
|
||||
public method getSize(): int
|
||||
public method isEmpty(): boolean
|
||||
public @org.jetbrains.annotations.NotNull method iterator(): java.util.Iterator
|
||||
public method remove(p0: java.lang.Object): boolean
|
||||
public method removeAll(p0: java.util.Collection): boolean
|
||||
public method retainAll(p0: java.util.Collection): boolean
|
||||
public bridge final method size(): int
|
||||
public final @org.jetbrains.annotations.NotNull method toArray$test_module(): java.lang.Integer[]
|
||||
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class PrivateToArray {
|
||||
// source: 'customNonGenericToArray.kt'
|
||||
private synthetic final field $$delegate_0: java.util.Collection
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.util.Collection): void
|
||||
public method add(p0: java.lang.Object): boolean
|
||||
public method addAll(p0: java.util.Collection): boolean
|
||||
public method clear(): void
|
||||
public method contains(@org.jetbrains.annotations.NotNull p0: java.lang.Object): boolean
|
||||
public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
|
||||
public method getSize(): int
|
||||
public method isEmpty(): boolean
|
||||
public @org.jetbrains.annotations.NotNull method iterator(): java.util.Iterator
|
||||
public method remove(p0: java.lang.Object): boolean
|
||||
public method removeAll(p0: java.util.Collection): boolean
|
||||
public method retainAll(p0: java.util.Collection): boolean
|
||||
public bridge final method size(): int
|
||||
public final @org.jetbrains.annotations.NotNull method toArray(): java.lang.Integer[]
|
||||
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class PublicToArray {
|
||||
// source: 'customNonGenericToArray.kt'
|
||||
private synthetic final field $$delegate_0: java.util.Collection
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.util.Collection): void
|
||||
public method add(p0: java.lang.Object): boolean
|
||||
public method addAll(p0: java.util.Collection): boolean
|
||||
public method clear(): void
|
||||
public method contains(@org.jetbrains.annotations.NotNull p0: java.lang.Object): boolean
|
||||
public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
|
||||
public method getSize(): int
|
||||
public method isEmpty(): boolean
|
||||
public @org.jetbrains.annotations.NotNull method iterator(): java.util.Iterator
|
||||
public method remove(p0: java.lang.Object): boolean
|
||||
public method removeAll(p0: java.util.Collection): boolean
|
||||
public method retainAll(p0: java.util.Collection): boolean
|
||||
public bridge final method size(): int
|
||||
public final @org.jetbrains.annotations.NotNull method toArray(): java.lang.Integer[]
|
||||
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
|
||||
}
|
||||
Vendored
+62
@@ -0,0 +1,62 @@
|
||||
@kotlin.Metadata
|
||||
public final class InternalToArray {
|
||||
// source: 'customNonGenericToArray.kt'
|
||||
private synthetic final field $$delegate_0: java.util.Collection
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.util.Collection): void
|
||||
public method add(p0: java.lang.Object): boolean
|
||||
public method addAll(p0: java.util.Collection): boolean
|
||||
public method clear(): void
|
||||
public method contains(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
|
||||
public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
|
||||
public method getSize(): int
|
||||
public method isEmpty(): boolean
|
||||
public @org.jetbrains.annotations.NotNull method iterator(): java.util.Iterator
|
||||
public method remove(p0: java.lang.Object): boolean
|
||||
public method removeAll(p0: java.util.Collection): boolean
|
||||
public method retainAll(p0: java.util.Collection): boolean
|
||||
public bridge final method size(): int
|
||||
public final @org.jetbrains.annotations.NotNull method toArray(): java.lang.Integer[]
|
||||
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class PrivateToArray {
|
||||
// source: 'customNonGenericToArray.kt'
|
||||
private synthetic final field $$delegate_0: java.util.Collection
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.util.Collection): void
|
||||
public method add(p0: java.lang.Object): boolean
|
||||
public method addAll(p0: java.util.Collection): boolean
|
||||
public method clear(): void
|
||||
public method contains(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
|
||||
public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
|
||||
public method getSize(): int
|
||||
public method isEmpty(): boolean
|
||||
public @org.jetbrains.annotations.NotNull method iterator(): java.util.Iterator
|
||||
public method remove(p0: java.lang.Object): boolean
|
||||
public method removeAll(p0: java.util.Collection): boolean
|
||||
public method retainAll(p0: java.util.Collection): boolean
|
||||
public bridge final method size(): int
|
||||
public final @org.jetbrains.annotations.NotNull method toArray(): java.lang.Integer[]
|
||||
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class PublicToArray {
|
||||
// source: 'customNonGenericToArray.kt'
|
||||
private synthetic final field $$delegate_0: java.util.Collection
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.util.Collection): void
|
||||
public method add(p0: java.lang.Object): boolean
|
||||
public method addAll(p0: java.util.Collection): boolean
|
||||
public method clear(): void
|
||||
public method contains(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
|
||||
public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
|
||||
public method getSize(): int
|
||||
public method isEmpty(): boolean
|
||||
public @org.jetbrains.annotations.NotNull method iterator(): java.util.Iterator
|
||||
public method remove(p0: java.lang.Object): boolean
|
||||
public method removeAll(p0: java.util.Collection): boolean
|
||||
public method retainAll(p0: java.util.Collection): boolean
|
||||
public bridge final method size(): int
|
||||
public final @org.jetbrains.annotations.NotNull method toArray(): java.lang.Integer[]
|
||||
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
|
||||
}
|
||||
+23
-5
@@ -174,11 +174,6 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/noRemoveAtInReadOnly.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noToArrayInJava.kt")
|
||||
public void testNoToArrayInJava() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/noToArrayInJava.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("privateCompanionFields.kt")
|
||||
public void testPrivateCompanionFields() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt");
|
||||
@@ -616,6 +611,29 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/abstractStubSignatures/stringGenericMutableMap.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeListing/collectionStubs/toArray")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ToArray extends AbstractBytecodeListingTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInToArray() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/collectionStubs/toArray"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("customNonGenericToArray.kt")
|
||||
public void testCustomNonGenericToArray() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/toArray/customNonGenericToArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noToArrayInJava.kt")
|
||||
public void testNoToArrayInJava() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/toArray/noToArrayInJava.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeListing/coroutines")
|
||||
|
||||
+23
-5
@@ -174,11 +174,6 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
||||
runTest("compiler/testData/codegen/bytecodeListing/noRemoveAtInReadOnly.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noToArrayInJava.kt")
|
||||
public void testNoToArrayInJava() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/noToArrayInJava.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("privateCompanionFields.kt")
|
||||
public void testPrivateCompanionFields() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt");
|
||||
@@ -616,6 +611,29 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
||||
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/abstractStubSignatures/stringGenericMutableMap.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeListing/collectionStubs/toArray")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ToArray extends AbstractIrBytecodeListingTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInToArray() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/collectionStubs/toArray"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("customNonGenericToArray.kt")
|
||||
public void testCustomNonGenericToArray() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/toArray/customNonGenericToArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noToArrayInJava.kt")
|
||||
public void testNoToArrayInJava() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/toArray/noToArrayInJava.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeListing/coroutines")
|
||||
|
||||
Reference in New Issue
Block a user