From 1ecf5943abbd8f5969be46cd7c102245b806b591 Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Thu, 29 Oct 2020 08:10:39 +0100 Subject: [PATCH] [JVM_IR] Determine correct type of empty varargs array. When calling vararg methods with a generic vararg type without passing explicit parameters, we have to allocate an empty array of the right type. We failed to do so previously, as we did not take the type arguments for the dispatch receiver into account. --- ...ackBoxAgainstJavaCodegenTestGenerated.java | 28 ++++++++++++++ .../jvm/lower/FunctionReferenceLowering.kt | 4 +- .../kotlin/ir/types/IrTypeSystemContext.kt | 1 - .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 22 ++++++++--- .../boxAgainstJava/varargs/varargsOverride.kt | 18 +++++++++ .../varargs/varargsOverride2.kt | 21 +++++++++++ .../varargs/varargsOverride3.kt | 37 +++++++++++++++++++ ...ackBoxAgainstJavaCodegenTestGenerated.java | 28 ++++++++++++++ ...ackBoxAgainstJavaCodegenTestGenerated.java | 28 ++++++++++++++ 9 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride.kt create mode 100644 compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride2.kt create mode 100644 compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride3.kt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxAgainstJavaCodegenTestGenerated.java index 8b03298d54d..b8e90b35bf7 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxAgainstJavaCodegenTestGenerated.java @@ -1066,6 +1066,34 @@ public class FirBlackBoxAgainstJavaCodegenTestGenerated extends AbstractFirBlack } } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/varargs") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Varargs extends AbstractFirBlackBoxAgainstJavaCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM_IR, testDataFilePath, "// IGNORE_BACKEND_FIR: "); + } + + public void testAllFilesPresentInVarargs() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/varargs"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("varargsOverride.kt") + public void testVarargsOverride() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride.kt"); + } + + @TestMetadata("varargsOverride2.kt") + public void testVarargsOverride2() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride2.kt"); + } + + @TestMetadata("varargsOverride3.kt") + public void testVarargsOverride3() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride3.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/visibility") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt index b0bc0bbbf4b..4dd8caa22a0 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt @@ -401,8 +401,8 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) body = context.createJvmIrBuilder(symbol, startOffset, endOffset).run { var unboundIndex = 0 irExprBody(irCall(callee).apply { - for ((typeParameter, typeArgument) in typeArgumentsMap) { - putTypeArgument(typeParameter.owner.index, typeArgument) + for (typeParameter in irFunctionReference.symbol.owner.allTypeParameters) { + putTypeArgument(typeParameter.index, typeArgumentsMap[typeParameter.symbol]) } for (parameter in callee.explicitParameters) { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index 99acfb35440..21d5d108720 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -389,7 +389,6 @@ fun extractTypeParameters(klass: IrDeclarationParent): List { val result = mutableListOf() var current: IrDeclarationParent? = klass while (current != null) { -// result += current.typeParameters (current as? IrTypeParametersContainer)?.let { result += it.typeParameters } current = when (current) { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index f1435afa502..2529dc3df0e 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -16,10 +16,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.symbols.* -import org.jetbrains.kotlin.ir.types.IrSimpleType -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.isAny -import org.jetbrains.kotlin.ir.types.isSubtypeOf +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.utils.DFS @@ -518,9 +515,24 @@ val IrFunction.allTypeParameters: List else typeParameters + fun IrMemberAccessExpression<*>.getTypeSubstitutionMap(irFunction: IrFunction): Map { val typeParameters = irFunction.allTypeParameters - return if (typeParameters.isEmpty()) emptyMap() else typeParameters.withIndex().associate { + val dispatchReceiverTypeArguments = (dispatchReceiver?.type as? IrSimpleType)?.arguments ?: emptyList() + if (typeParameters.isEmpty() && dispatchReceiverTypeArguments.isEmpty()) { + return emptyMap() + } + + val result = mutableMapOf() + if (dispatchReceiverTypeArguments.isNotEmpty()) { + val parentTypeParameters = extractTypeParameters(irFunction.parentClassOrNull!!) + parentTypeParameters.withIndex().forEach { (index, typeParam) -> + dispatchReceiverTypeArguments[index].typeOrNull?.let { + result[typeParam.symbol] = it + } + } + } + return typeParameters.withIndex().associateTo(result) { it.value.symbol to getTypeArgument(it.index)!! } } diff --git a/compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride.kt b/compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride.kt new file mode 100644 index 00000000000..f0bd8bceb3c --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride.kt @@ -0,0 +1,18 @@ +// FILE: A.java + +public abstract class A { + protected abstract String doIt(T... args); + + public String test(T... args) { + return doIt(args); + } +} + +// FILE: 1.kt + +val a: A = + object : A() { + override fun doIt(vararg parameters: Void): String = "OK" + } + +fun box(): String = a.test() diff --git a/compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride2.kt b/compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride2.kt new file mode 100644 index 00000000000..68e8a7e1704 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride2.kt @@ -0,0 +1,21 @@ +// FILE: A.java + +public abstract class A { + protected abstract String doIt(T... args); + + public String test(S... args) { + return doIt(args); + } +} + +// FILE: 1.kt + +open class Super +class Sub: Super() + +val a: A = + object : A() { + override fun doIt(vararg parameters: Super): String = "OK" + } + +fun box(): String = a.test() diff --git a/compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride3.kt b/compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride3.kt new file mode 100644 index 00000000000..643002804b5 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride3.kt @@ -0,0 +1,37 @@ +// FILE: A.java + +public abstract class A { + protected abstract String doIt(T... args); + + class B { + public String test(T... args) { + return doIt(args); + } + + public String test2(S... args) { + return doIt(args); + } + + public String test3(U... args) { + return doIt(args); + } + } +} + +// FILE: 1.kt + +open class Super +open class Sub: Super() +class Sub2: Sub() + +val a: A = + object : A() { + override fun doIt(vararg parameters: Super): String = "OK" + } + +fun box(): String { + val b = a.B() + if (b.test() != "OK") return "FAIL1" + if (b.test2() != "OK") return "FAIL2" + return b.test3() +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java index bb87213aa4c..bf6e05f1343 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java @@ -1096,6 +1096,34 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxAga } } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/varargs") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Varargs extends AbstractBlackBoxAgainstJavaCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInVarargs() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/varargs"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("varargsOverride.kt") + public void testVarargsOverride() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride.kt"); + } + + @TestMetadata("varargsOverride2.kt") + public void testVarargsOverride2() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride2.kt"); + } + + @TestMetadata("varargsOverride3.kt") + public void testVarargsOverride3() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride3.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/visibility") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxAgainstJavaCodegenTestGenerated.java index 29a0d786631..e77d6e67d6a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxAgainstJavaCodegenTestGenerated.java @@ -1066,6 +1066,34 @@ public class IrBlackBoxAgainstJavaCodegenTestGenerated extends AbstractIrBlackBo } } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/varargs") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Varargs extends AbstractIrBlackBoxAgainstJavaCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInVarargs() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/varargs"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("varargsOverride.kt") + public void testVarargsOverride() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride.kt"); + } + + @TestMetadata("varargsOverride2.kt") + public void testVarargsOverride2() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride2.kt"); + } + + @TestMetadata("varargsOverride3.kt") + public void testVarargsOverride3() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/varargs/varargsOverride3.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxAgainstJava/visibility") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)