Fix problem with empty vararg of boxed primitives in JVM_IR

When calling a generic Java generic method with vararg parameters with empty
vararg, incorrect array creation instruction was generated for primitive type:
NEWARRAY T_INT instead of ANEWARRAY java/lang/Integer. Here for Java method

  public static <T> void takesVarargOfT(T x1, T... xs) {}

corresponding vararg parameter was considered to be of type 'Array<T>?',
which is not a non-null array type, so, NewArray intrinsic failed to generate
proper bytecode.
This commit is contained in:
Dmitry Petrov
2019-12-27 16:12:16 +03:00
parent 0667ee9796
commit 98bf0e278f
7 changed files with 67 additions and 2 deletions
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.ir.getArrayElementType
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.types.isArray
import org.jetbrains.kotlin.ir.types.isNullableArray
import org.jetbrains.org.objectweb.asm.Type
object NewArray : IntrinsicMethod() {
@@ -19,7 +20,7 @@ object NewArray : IntrinsicMethod() {
codegen.gen(expression.getValueArgument(0)!!, Type.INT_TYPE, codegen.context.irBuiltIns.intType, data)
return with(codegen) {
val elementIrType = expression.type.getArrayElementType(context.irBuiltIns)
if (expression.type.isArray()) {
if (expression.type.isArray() || expression.type.isNullableArray()) {
putReifiedOperationMarkerIfTypeIsReifiedParameter(elementIrType, ReifiedTypeInliner.OperationKind.NEW_ARRAY)
mv.newarray(typeMapper.boxType(elementIrType))
} else {
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
@@ -56,7 +57,7 @@ private class VarargLowering(val context: JvmBackendContext) : FileLoweringPass,
val parameter = function.owner.valueParameters[i]
if (parameter.varargElementType != null && !parameter.hasDefaultValue()) {
// Compute the correct type for the array argument.
val arrayType = parameter.type.substitute(expression.typeSubstitutionMap)
val arrayType = parameter.type.substitute(expression.typeSubstitutionMap).makeNotNull()
expression.putValueArgument(i, createBuilder().irArrayOf(arrayType))
}
}
@@ -0,0 +1,43 @@
// TARGET_BACKEND: JVM
// FILE: emptyVarargOfBoxedPrimitiveType.kt
fun box(): String {
takesVarargOfInt(1)
takesVarargOfT(1)
J.takesVarargOfInt(1)
J.takesVarargOfInteger(1)
J.takesVarargOfT(1)
takesVarargOfInt(1, 2)
takesVarargOfT(1, 2)
J.takesVarargOfInt(1, 2)
J.takesVarargOfInteger(1, 2)
J.takesVarargOfT(1, 2)
return "OK"
}
fun takesVarargOfInt(x: Int, vararg xs: Int) {}
fun <T> takesVarargOfT(x: T, vararg xs: T) {}
// FILE: J.java
public class J {
public static void takesVarargOfInt(int x1, int... xs) {}
public static void takesVarargOfInteger(Integer x1, Integer... xs) {}
public static <T> void takesVarargOfT(T x1, T... xs) {
Class<?> x1Class = x1.getClass();
Class<?> xsClass = xs.getClass();
Class<?> xsComponentClass = xsClass.getComponentType();
if (!xsComponentClass.equals(x1Class)) {
throw new AssertionError(
"Wrong array component type " + xsComponentClass +
" for array class " + xsClass +
", expected: " + x1Class
);
}
}
}
@@ -28301,6 +28301,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt");
}
@TestMetadata("emptyVarargOfBoxedPrimitiveType.kt")
public void testEmptyVarargOfBoxedPrimitiveType() throws Exception {
runTest("compiler/testData/codegen/box/vararg/emptyVarargOfBoxedPrimitiveType.kt");
}
@TestMetadata("kt1978.kt")
public void testKt1978() throws Exception {
runTest("compiler/testData/codegen/box/vararg/kt1978.kt");
@@ -27118,6 +27118,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt");
}
@TestMetadata("emptyVarargOfBoxedPrimitiveType.kt")
public void testEmptyVarargOfBoxedPrimitiveType() throws Exception {
runTest("compiler/testData/codegen/box/vararg/emptyVarargOfBoxedPrimitiveType.kt");
}
@TestMetadata("kt1978.kt")
public void testKt1978() throws Exception {
runTest("compiler/testData/codegen/box/vararg/kt1978.kt");
@@ -26800,6 +26800,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt");
}
@TestMetadata("emptyVarargOfBoxedPrimitiveType.kt")
public void testEmptyVarargOfBoxedPrimitiveType() throws Exception {
runTest("compiler/testData/codegen/box/vararg/emptyVarargOfBoxedPrimitiveType.kt");
}
@TestMetadata("kt1978.kt")
public void testKt1978() throws Exception {
runTest("compiler/testData/codegen/box/vararg/kt1978.kt");
@@ -26800,6 +26800,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt");
}
@TestMetadata("emptyVarargOfBoxedPrimitiveType.kt")
public void testEmptyVarargOfBoxedPrimitiveType() throws Exception {
runTest("compiler/testData/codegen/box/vararg/emptyVarargOfBoxedPrimitiveType.kt");
}
@TestMetadata("kt1978.kt")
public void testKt1978() throws Exception {
runTest("compiler/testData/codegen/box/vararg/kt1978.kt");