JVM_IR: refactor ToArrayLowering and make matching more precise
* If `toArray` is inherited from Java, it may take an argument or
return a value of a flexible type, which looks nullable in IR;
* The returned array may also have `out` variance of the type
argument;
* `Array<T>` is not the same as `Array<Any?>` if `T` is neither `Any`
nor `in Something`, so presence of `toArray(): Array<T>` does not
mean we don't need to generate a new `toArray`.
This commit is contained in:
Generated
+5
@@ -26683,6 +26683,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayAlreadyPresent.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayFromJava.kt")
|
||||
public void testToArrayFromJava() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayFromJava.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayShouldBePublic.kt")
|
||||
public void testToArrayShouldBePublic() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayShouldBePublic.kt");
|
||||
|
||||
+2
-3
@@ -559,9 +559,8 @@ 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() || symbolOwner.isGenericToArray(context))) {
|
||||
val parent = symbolOwner.parent
|
||||
if (parent is IrClass && parent.isCollectionSubClass()) {
|
||||
if (symbolOwner is IrSimpleFunction && (symbolOwner.isNonGenericToArray(context) || symbolOwner.isGenericToArray(context))) {
|
||||
if (symbolOwner.parentAsClass.isCollectionSubClass) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+82
-177
@@ -11,33 +11,27 @@ 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.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addDispatchReceiver
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addTypeParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedTypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.isClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
|
||||
internal val toArrayPhase = makeIrFilePhase(
|
||||
@@ -47,188 +41,99 @@ internal val toArrayPhase = makeIrFilePhase(
|
||||
)
|
||||
|
||||
private class ToArrayLowering(private val context: JvmBackendContext) : ClassLoweringPass {
|
||||
private val symbols = context.ir.symbols
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (irClass.isJvmInterface || !irClass.isCollectionSubClass()) return
|
||||
if (irClass.isJvmInterface || !irClass.isCollectionSubClass) return
|
||||
|
||||
val irBuiltIns = context.irBuiltIns
|
||||
val symbols = context.ir.symbols
|
||||
val indirectCollectionSubClass = generateSequence(irClass.superClass, IrClass::superClass).firstOrNull {
|
||||
it.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
|
||||
}?.isCollectionSubClass == true
|
||||
|
||||
val toArrayName = Name.identifier("toArray")
|
||||
val genericToArray = irClass.declarations.filterIsInstance<IrSimpleFunction>().find { it.isGenericToArray(context) }
|
||||
val nonGenericToArray = irClass.declarations.filterIsInstance<IrSimpleFunction>().find { it.isNonGenericToArray() }
|
||||
val isDirectCollectionSubClass = irClass.isDirectCollectionSubClass()
|
||||
if (genericToArray == null) {
|
||||
if (isDirectCollectionSubClass) {
|
||||
val typeParameterDescriptor = WrappedTypeParameterDescriptor()
|
||||
val typeParameter = IrTypeParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
JvmLoweredDeclarationOrigin.TO_ARRAY,
|
||||
IrTypeParameterSymbolImpl(typeParameterDescriptor),
|
||||
Name.identifier("T"),
|
||||
index = 0,
|
||||
variance = Variance.INVARIANT,
|
||||
isReified = false
|
||||
).apply {
|
||||
typeParameterDescriptor.bind(this)
|
||||
superTypes.add(irBuiltIns.anyNType)
|
||||
irClass.findOrCreate(indirectCollectionSubClass, { it.isGenericToArray(context) }) {
|
||||
irClass.addFunction {
|
||||
name = Name.identifier("toArray")
|
||||
origin = JvmLoweredDeclarationOrigin.TO_ARRAY
|
||||
modality = Modality.OPEN
|
||||
}.apply {
|
||||
val elementType = addTypeParameter {
|
||||
name = Name.identifier("T")
|
||||
origin = JvmLoweredDeclarationOrigin.TO_ARRAY
|
||||
superTypes.add(context.irBuiltIns.anyNType)
|
||||
}
|
||||
|
||||
val substitutedArrayType = irBuiltIns.arrayClass.typeWith(typeParameter.defaultType)
|
||||
val functionDescriptor = WrappedSimpleFunctionDescriptor()
|
||||
val irFunction = IrFunctionImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
JvmLoweredDeclarationOrigin.TO_ARRAY,
|
||||
IrSimpleFunctionSymbolImpl(functionDescriptor),
|
||||
toArrayName,
|
||||
Visibilities.PUBLIC,
|
||||
Modality.OPEN,
|
||||
returnType = substitutedArrayType,
|
||||
isInline = false,
|
||||
isExternal = false,
|
||||
isTailrec = false,
|
||||
isSuspend = false,
|
||||
isExpect = false,
|
||||
isFakeOverride = false,
|
||||
isOperator = false
|
||||
)
|
||||
functionDescriptor.bind(irFunction)
|
||||
irFunction.parent = irClass
|
||||
|
||||
typeParameter.parent = irFunction
|
||||
irFunction.typeParameters += typeParameter
|
||||
|
||||
val dispatchReceiverParameterDescriptor = WrappedValueParameterDescriptor()
|
||||
irFunction.dispatchReceiverParameter = IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
JvmLoweredDeclarationOrigin.TO_ARRAY,
|
||||
IrValueParameterSymbolImpl(dispatchReceiverParameterDescriptor),
|
||||
Name.special("<this>"),
|
||||
index = -1,
|
||||
type = irClass.defaultType,
|
||||
varargElementType = null,
|
||||
isCrossinline = false,
|
||||
isNoinline = false
|
||||
).apply {
|
||||
parent = irFunction
|
||||
returnType = context.irBuiltIns.arrayClass.typeWith(elementType.defaultType)
|
||||
val receiver = addDispatchReceiver {
|
||||
type = irClass.defaultType
|
||||
origin = JvmLoweredDeclarationOrigin.TO_ARRAY
|
||||
}
|
||||
val valueParameterDescriptor = WrappedValueParameterDescriptor()
|
||||
irFunction.valueParameters +=
|
||||
IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
JvmLoweredDeclarationOrigin.TO_ARRAY,
|
||||
IrValueParameterSymbolImpl(valueParameterDescriptor),
|
||||
Name.identifier("array"),
|
||||
index = 0,
|
||||
varargElementType = null,
|
||||
type = substitutedArrayType,
|
||||
isCrossinline = false,
|
||||
isNoinline = false
|
||||
).apply {
|
||||
valueParameterDescriptor.bind(this)
|
||||
parent = irFunction
|
||||
}
|
||||
|
||||
irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody {
|
||||
+irReturn(
|
||||
irCall(symbols.genericToArray, symbols.genericToArray.owner.returnType).apply {
|
||||
putValueArgument(
|
||||
0,
|
||||
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.dispatchReceiverParameter!!.symbol)
|
||||
)
|
||||
putValueArgument(1, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.valueParameters[0].symbol))
|
||||
})
|
||||
val prototype = addValueParameter("array", returnType, JvmLoweredDeclarationOrigin.TO_ARRAY)
|
||||
body = context.createIrBuilder(symbol).irBlockBody {
|
||||
+irReturn(irCall(symbols.genericToArray, symbols.genericToArray.owner.returnType).apply {
|
||||
putValueArgument(0, irGet(receiver))
|
||||
putValueArgument(1, irGet(prototype))
|
||||
})
|
||||
}
|
||||
|
||||
irClass.declarations.add(irFunction)
|
||||
}
|
||||
} else {
|
||||
(genericToArray as IrFunctionImpl).visibility = Visibilities.PUBLIC
|
||||
}
|
||||
|
||||
if (nonGenericToArray == null) {
|
||||
if (isDirectCollectionSubClass) {
|
||||
val functionDescriptor = WrappedSimpleFunctionDescriptor()
|
||||
val irFunction = IrFunctionImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
JvmLoweredDeclarationOrigin.TO_ARRAY,
|
||||
IrSimpleFunctionSymbolImpl(functionDescriptor),
|
||||
toArrayName,
|
||||
Visibilities.PUBLIC,
|
||||
Modality.OPEN,
|
||||
returnType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType),
|
||||
isInline = false,
|
||||
isExternal = false,
|
||||
isTailrec = false,
|
||||
isSuspend = false,
|
||||
isExpect = false,
|
||||
isFakeOverride = false,
|
||||
isOperator = false
|
||||
)
|
||||
functionDescriptor.bind(irFunction)
|
||||
irFunction.parent = irClass
|
||||
|
||||
val dispatchReceiverParameterDescriptor = WrappedValueParameterDescriptor()
|
||||
irFunction.dispatchReceiverParameter = IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
JvmLoweredDeclarationOrigin.TO_ARRAY,
|
||||
IrValueParameterSymbolImpl(dispatchReceiverParameterDescriptor),
|
||||
Name.special("<this>"),
|
||||
index = -1,
|
||||
type = irClass.defaultType,
|
||||
varargElementType = null,
|
||||
isCrossinline = false,
|
||||
isNoinline = false
|
||||
).apply {
|
||||
parent = irFunction
|
||||
irClass.findOrCreate(indirectCollectionSubClass, { it.isNonGenericToArray(context) }) {
|
||||
irClass.addFunction {
|
||||
name = Name.identifier("toArray")
|
||||
origin = JvmLoweredDeclarationOrigin.TO_ARRAY
|
||||
modality = Modality.OPEN
|
||||
returnType = context.irBuiltIns.arrayClass.typeWith(context.irBuiltIns.anyNType)
|
||||
}.apply {
|
||||
val receiver = addDispatchReceiver {
|
||||
type = irClass.defaultType
|
||||
origin = JvmLoweredDeclarationOrigin.TO_ARRAY
|
||||
}
|
||||
|
||||
irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody {
|
||||
+irReturn(
|
||||
irCall(symbols.nonGenericToArray, symbols.nonGenericToArray.owner.returnType).apply {
|
||||
putValueArgument(
|
||||
0,
|
||||
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.dispatchReceiverParameter!!.symbol)
|
||||
)
|
||||
})
|
||||
body = context.createIrBuilder(symbol).irBlockBody {
|
||||
+irReturn(irCall(symbols.nonGenericToArray, symbols.nonGenericToArray.owner.returnType).apply {
|
||||
putValueArgument(0, irGet(receiver))
|
||||
})
|
||||
}
|
||||
|
||||
irClass.declarations.add(irFunction)
|
||||
}
|
||||
} else {
|
||||
(nonGenericToArray as IrFunctionImpl).visibility = Visibilities.PUBLIC
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.findOrCreate(indirectSubclass: Boolean, matcher: (IrSimpleFunction) -> Boolean, fallback: () -> IrSimpleFunction) {
|
||||
val existing = functions.find(matcher) as? IrFunctionImpl
|
||||
if (existing != null) {
|
||||
// This is an explicit override of a method defined in `kotlin.collections.AbstractCollection`
|
||||
// or `java.util.Collection`. From here on, the frontend will check the existence of implementations;
|
||||
// we just need to match visibility in the former case to the latter.
|
||||
existing.visibility = Visibilities.PUBLIC
|
||||
return
|
||||
}
|
||||
if (indirectSubclass) {
|
||||
// There's a Kotlin class up the hierarchy that should already have `toArray`.
|
||||
return
|
||||
}
|
||||
fallback()
|
||||
}
|
||||
}
|
||||
|
||||
private val IrClass.superClasses
|
||||
get() = superTypes.mapNotNull { it.getClass() }
|
||||
private val IrClass.superClass: IrClass?
|
||||
get() = superTypes.mapNotNull { it.getClass()?.takeIf { superClass -> superClass.isClass } }.singleOrNull()
|
||||
|
||||
// Have to check by name, since irBuiltins is unreliable.
|
||||
internal fun IrClass.isCollectionSubClass() =
|
||||
DFS.ifAny(listOf(this), IrClass::superClasses) { it.defaultType.isCollection() }
|
||||
internal val IrClass.isCollectionSubClass: Boolean
|
||||
get() = DFS.ifAny(superTypes, { it.getClass()?.superTypes ?: listOf() }) { it.isCollection() }
|
||||
|
||||
// If this class inherits from another Kotlin class that implements Collection, it already has toArray.
|
||||
private fun IrClass.isDirectCollectionSubClass() =
|
||||
isCollectionSubClass() && !superClasses.any {
|
||||
it.isClass && it.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && it.isCollectionSubClass()
|
||||
private fun IrType.isArrayOrNullableArrayOf(context: JvmBackendContext, element: IrClassifierSymbol): Boolean =
|
||||
this is IrSimpleType && (isArray() || isNullableArray()) && arguments.size == 1 && element == when (val it = arguments[0]) {
|
||||
is IrStarProjection -> context.irBuiltIns.anyClass
|
||||
is IrTypeProjection -> if (it.variance == Variance.IN_VARIANCE) context.irBuiltIns.anyClass else it.type.classifierOrNull
|
||||
else -> null
|
||||
}
|
||||
|
||||
// Match `fun <T> toArray(prototype: Array<T>): Array<T>`
|
||||
internal fun IrSimpleFunction.isGenericToArray(context: JvmBackendContext): Boolean =
|
||||
name.asString() == "toArray" && typeParameters.size == 1 && valueParameters.size == 1 &&
|
||||
extensionReceiverParameter == null &&
|
||||
returnType.isArrayOrNullableArrayOf(context, typeParameters[0].symbol) &&
|
||||
valueParameters[0].type.isArrayOrNullableArrayOf(context, typeParameters[0].symbol)
|
||||
|
||||
internal fun IrSimpleFunction.isGenericToArray(context: JvmBackendContext): Boolean {
|
||||
if (name.asString() != "toArray") return false
|
||||
if (typeParameters.size != 1 || valueParameters.size != 1 || extensionReceiverParameter != null) return false
|
||||
|
||||
val paramType = valueParameters[0].type
|
||||
|
||||
if (!returnType.isArray() || !paramType.isArray()) return false
|
||||
|
||||
val elementType = typeParameters[0].defaultType
|
||||
val expectedType = context.ir.symbols.array.typeWith(elementType)
|
||||
return expectedType == paramType && expectedType == returnType
|
||||
}
|
||||
|
||||
internal fun IrSimpleFunction.isNonGenericToArray(): Boolean {
|
||||
if (name.asString() != "toArray") return false
|
||||
if (typeParameters.isNotEmpty() || valueParameters.isNotEmpty() || extensionReceiverParameter != null) return false
|
||||
return returnType.isArray()
|
||||
}
|
||||
// Match `fun toArray(): Array<Any?>`
|
||||
internal fun IrSimpleFunction.isNonGenericToArray(context: JvmBackendContext): Boolean =
|
||||
name.asString() == "toArray" && typeParameters.isEmpty() && valueParameters.isEmpty() &&
|
||||
extensionReceiverParameter == null && returnType.isArrayOrNullableArrayOf(context, context.irBuiltIns.anyClass)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// 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
|
||||
|
||||
public abstract class MyListWithCustomToArray<E> extends java.util.AbstractList<E> {
|
||||
public Object[] toArray() {
|
||||
return new Object[]{null};
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: a.kt
|
||||
class MyList<T>(val list: List<T>): java.util.AbstractList<T>() {
|
||||
override fun get(index: Int): T = list[index]
|
||||
|
||||
override val size: Int
|
||||
get() = list.size
|
||||
}
|
||||
|
||||
class MyListSubclass<T>(val list: List<T>): MyListWithCustomToArray<T>() {
|
||||
override fun get(index: Int): T = list[index]
|
||||
|
||||
override val size: Int
|
||||
get() = list.size
|
||||
}
|
||||
|
||||
class MyCollection<T>(val list: List<T>) : Collection<T> by list {
|
||||
fun toArray(): Array<Int?> =
|
||||
arrayOfNulls<Int>(0)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val list1 = MyList(listOf(2, 3, 9)) as java.util.Collection<*>
|
||||
list1.toArray().contentToString().let { if (it != "[2, 3, 9]") return "fail 1: $it" }
|
||||
list1.toArray(arrayOfNulls<Int>(0)).contentToString().let { if (it != "[2, 3, 9]") return "fail 2: $it" }
|
||||
|
||||
val list2 = MyListSubclass(listOf(2, 3, 9)) as java.util.Collection<*>
|
||||
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<*>
|
||||
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"
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
|
||||
// FILE: SingletonCollection.kt
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
|
||||
|
||||
+5
@@ -28199,6 +28199,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayAlreadyPresent.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayFromJava.kt")
|
||||
public void testToArrayFromJava() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayFromJava.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayShouldBePublic.kt")
|
||||
public void testToArrayShouldBePublic() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayShouldBePublic.kt");
|
||||
|
||||
+5
@@ -26983,6 +26983,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ToArray extends AbstractLightAnalysisModeTest {
|
||||
@TestMetadata("toArrayFromJava.kt")
|
||||
public void ignoreToArrayFromJava() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayFromJava.kt");
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
+5
@@ -26683,6 +26683,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayAlreadyPresent.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayFromJava.kt")
|
||||
public void testToArrayFromJava() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayFromJava.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayShouldBePublic.kt")
|
||||
public void testToArrayShouldBePublic() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/toArray/toArrayShouldBePublic.kt");
|
||||
|
||||
Reference in New Issue
Block a user