From c06ec84bb1c70008385c56e83cadd4133860233f Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 8 May 2023 15:27:19 +0200 Subject: [PATCH] JVM: fix type mapping of big arity suspend function types The code in IrTypeMapper was incorrectly translated from KotlinTypeMapper during the development of JVM IR. The `classDescriptor.hasBigArity` condition in KotlinTypeMapper was checking if the class represents a function or a suspend function with big arity, and the suspend function part was lost during conversion. This resulted in incorrect generic signature being generated, which led to malformed type exceptions from reflection, and compilation errors from kapt stub generation. Also, change a comment in irCodegenUtils to avoid confusion of numbered function types (kotlin.jvm.functions.Function1, ...) with the big-arity type kotlin.jvm.functions.FunctionN. #KT-58375 Fixed --- ...LightTreeBlackBoxCodegenTestGenerated.java | 6 +++ .../FirPsiBlackBoxCodegenTestGenerated.java | 6 +++ .../backend/jvm/codegen/irCodegenUtils.kt | 4 +- .../backend/jvm/mapping/IrTypeMapper.kt | 11 ++-- .../box/coroutines/reflect/bigArityLambda.kt | 34 ++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ .../IrBlackBoxCodegenTestGenerated.java | 6 +++ ...kBoxCodegenWithIrInlinerTestGenerated.java | 6 +++ .../LightAnalysisModeTestGenerated.java | 5 ++ .../suspendFunctionWithBigArity.ir.txt | 43 +++++++++++++++ .../converter/suspendFunctionWithBigArity.kt | 54 +++++++++++++++++++ .../converter/suspendFunctionWithBigArity.txt | 43 +++++++++++++++ ...ileToSourceStubConverterTestGenerated.java | 6 +++ ...ileToSourceStubConverterTestGenerated.java | 6 +++ 14 files changed, 230 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt create mode 100644 plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.ir.txt create mode 100644 plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.kt create mode 100644 plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.txt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index 0ce2e98d08e..8d996b46fae 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -12954,6 +12954,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr runTest("compiler/testData/codegen/box/coroutines/reflect/bigArity.kt"); } + @Test + @TestMetadata("bigArityLambda.kt") + public void testBigArityLambda() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt"); + } + @Test @TestMetadata("callSuspend.kt") public void testCallSuspend() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index bc62249fff9..a39a44268f9 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -12954,6 +12954,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo runTest("compiler/testData/codegen/box/coroutines/reflect/bigArity.kt"); } + @Test + @TestMetadata("bigArityLambda.kt") + public void testBigArityLambda() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt"); + } + @Test @TestMetadata("callSuspend.kt") public void testCallSuspend() throws Exception { diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt index a34d10f49a6..9b7ed45f9d7 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt @@ -241,8 +241,8 @@ internal fun IrTypeMapper.mapClassSignature(irClass: IrClass, type: Type, genera if (generateBodies && irClass.superTypes.any { it.isSuspendFunction() || it.isKSuspendFunction() }) { // Do not generate this class in the kapt3 mode (generateBodies=false), because kapt3 transforms supertypes correctly in the // "correctErrorTypes" mode only when the number of supertypes between PSI and bytecode is equal. Otherwise it tries to "correct" - // the FunctionN type and fails, because that type doesn't need an import in the Kotlin source (kotlin.FunctionN), but needs one - // in the Java source (kotlin.jvm.functions.FunctionN), and kapt3 doesn't perform any Kotlin->Java name lookup. + // the Function{n} type and fails, because that type doesn't need an import in the Kotlin source (kotlin.Function{n}), but needs one + // in the Java source (kotlin.jvm.functions.Function{n}), and kapt3 doesn't perform any Kotlin->Java name lookup. kotlinMarkerInterfaces.add("kotlin/coroutines/jvm/internal/SuspendFunction") } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/mapping/IrTypeMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/mapping/IrTypeMapper.kt index e05a90ccb86..cdf770c9269 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/mapping/IrTypeMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/mapping/IrTypeMapper.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.util.isSuspendFunction import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.types.AbstractTypeMapper @@ -195,9 +196,7 @@ open class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapp val parameters = classifier.typeParameters.map(IrTypeParameter::symbol) val arguments = type.arguments - if ((classifier.symbol.isFunction() && arguments.size > BuiltInFunctionArity.BIG_ARITY) - || classifier.symbol.isKFunction() || classifier.symbol.isKSuspendFunction() - ) { + if (isBigArityFunction(classifier, arguments) || classifier.symbol.isKFunction() || classifier.symbol.isKSuspendFunction()) { writeGenericArguments(sw, listOf(arguments.last()), listOf(parameters.last()), mode) return } @@ -205,11 +204,15 @@ open class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapp writeGenericArguments(sw, arguments, parameters, mode) } + private fun isBigArityFunction(classifier: IrClass, arguments: List): Boolean = + arguments.size > BuiltInFunctionArity.BIG_ARITY && + (classifier.symbol.isFunction() || classifier.symbol.isSuspendFunction()) + private fun writeGenericArguments( sw: JvmSignatureWriter, arguments: List, parameters: List, - mode: TypeMappingMode + mode: TypeMappingMode, ) { with(KotlinTypeMapper) { typeSystem.writeGenericArguments(sw, arguments, parameters, mode) { type, sw, mode -> diff --git a/compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt b/compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt new file mode 100644 index 00000000000..9ad2b462a2c --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt @@ -0,0 +1,34 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* +import kotlin.reflect.full.* + + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +interface Flow + +class C + +suspend fun foo( + f: suspend (C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C) -> String +): String = + f(C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C(), C()) + +fun box(): String { + var res = "Fail" + builder { + val f: suspend (C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C) -> String = { + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ -> + "OK" + } + res = ::foo.callSuspend(f) + } + return res +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index d0478b0da14..4681dd1c018 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -12684,6 +12684,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/coroutines/reflect/bigArity.kt"); } + @Test + @TestMetadata("bigArityLambda.kt") + public void testBigArityLambda() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt"); + } + @Test @TestMetadata("callSuspend.kt") public void testCallSuspend() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 56b875e97a4..6899b7f3b98 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -12954,6 +12954,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/coroutines/reflect/bigArity.kt"); } + @Test + @TestMetadata("bigArityLambda.kt") + public void testBigArityLambda() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt"); + } + @Test @TestMetadata("callSuspend.kt") public void testCallSuspend() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java index 0019c7afad2..1e842537f19 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java @@ -12954,6 +12954,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack runTest("compiler/testData/codegen/box/coroutines/reflect/bigArity.kt"); } + @Test + @TestMetadata("bigArityLambda.kt") + public void testBigArityLambda() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt"); + } + @Test @TestMetadata("callSuspend.kt") public void testCallSuspend() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 15926f404dd..399ed99134b 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10216,6 +10216,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/coroutines/reflect/bigArity.kt"); } + @TestMetadata("bigArityLambda.kt") + public void testBigArityLambda() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/reflect/bigArityLambda.kt"); + } + @TestMetadata("callSuspend.kt") public void testCallSuspend() throws Exception { runTest("compiler/testData/codegen/box/coroutines/reflect/callSuspend.kt"); diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.ir.txt b/plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.ir.txt new file mode 100644 index 00000000000..8767c79c71c --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.ir.txt @@ -0,0 +1,43 @@ +@kotlin.Metadata() +public abstract interface Flow { +} + +//////////////////// + + +@kotlin.Metadata() +public final class SuspendFunctionWithBigArityKt { + + public SuspendFunctionWithBigArityKt() { + super(); + } + + @org.jetbrains.annotations.NotNull() + public static final Flow combine(@org.jetbrains.annotations.NotNull() + Flow flow, @org.jetbrains.annotations.NotNull() + Flow flow2, @org.jetbrains.annotations.NotNull() + Flow flow3, @org.jetbrains.annotations.NotNull() + Flow flow4, @org.jetbrains.annotations.NotNull() + Flow flow5, @org.jetbrains.annotations.NotNull() + Flow flow6, @org.jetbrains.annotations.NotNull() + Flow flow7, @org.jetbrains.annotations.NotNull() + Flow flow8, @org.jetbrains.annotations.NotNull() + Flow flow9, @org.jetbrains.annotations.NotNull() + Flow flow10, @org.jetbrains.annotations.NotNull() + Flow flow11, @org.jetbrains.annotations.NotNull() + Flow flow12, @org.jetbrains.annotations.NotNull() + Flow flow13, @org.jetbrains.annotations.NotNull() + Flow flow14, @org.jetbrains.annotations.NotNull() + Flow flow15, @org.jetbrains.annotations.NotNull() + Flow flow16, @org.jetbrains.annotations.NotNull() + Flow flow17, @org.jetbrains.annotations.NotNull() + Flow flow18, @org.jetbrains.annotations.NotNull() + Flow flow19, @org.jetbrains.annotations.NotNull() + Flow flow20, @org.jetbrains.annotations.NotNull() + Flow flow21, @org.jetbrains.annotations.NotNull() + Flow flow22, @org.jetbrains.annotations.NotNull() + Flow flow23, @org.jetbrains.annotations.NotNull() + kotlin.jvm.functions.FunctionN transform) { + return null; + } +} diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.kt b/plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.kt new file mode 100644 index 00000000000..7bc594c539a --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.kt @@ -0,0 +1,54 @@ +interface Flow + +fun combine( + flow: Flow, + flow2: Flow, + flow3: Flow, + flow4: Flow, + flow5: Flow, + flow6: Flow, + flow7: Flow, + flow8: Flow, + flow9: Flow, + flow10: Flow, + flow11: Flow, + flow12: Flow, + flow13: Flow, + flow14: Flow, + flow15: Flow, + flow16: Flow, + flow17: Flow, + flow18: Flow, + flow19: Flow, + flow20: Flow, + flow21: Flow, + flow22: Flow, + flow23: Flow, + transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23) -> R +): Flow = combine(flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8, flow9, flow10, flow11, flow12, flow13, flow14, flow15, flow16, flow17, flow18, flow19, flow20, flow21, flow22, flow23) { args: Array<*> -> + transform( + args[0] as T1, + args[1] as T2, + args[2] as T3, + args[3] as T4, + args[4] as T5, + args[5] as T6, + args[6] as T7, + args[7] as T8, + args[8] as T9, + args[9] as T10, + args[10] as T11, + args[11] as T12, + args[12] as T13, + args[13] as T14, + args[14] as T15, + args[15] as T16, + args[16] as T17, + args[17] as T18, + args[18] as T19, + args[19] as T20, + args[20] as T21, + args[21] as T22, + args[22] as T23, + ) +} diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.txt b/plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.txt new file mode 100644 index 00000000000..06219c88244 --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.txt @@ -0,0 +1,43 @@ +@kotlin.Metadata() +public abstract interface Flow { +} + +//////////////////// + + +@kotlin.Metadata() +public final class SuspendFunctionWithBigArityKt { + + public SuspendFunctionWithBigArityKt() { + super(); + } + + @org.jetbrains.annotations.NotNull() + public static final Flow combine(@org.jetbrains.annotations.NotNull() + Flow flow, @org.jetbrains.annotations.NotNull() + Flow flow2, @org.jetbrains.annotations.NotNull() + Flow flow3, @org.jetbrains.annotations.NotNull() + Flow flow4, @org.jetbrains.annotations.NotNull() + Flow flow5, @org.jetbrains.annotations.NotNull() + Flow flow6, @org.jetbrains.annotations.NotNull() + Flow flow7, @org.jetbrains.annotations.NotNull() + Flow flow8, @org.jetbrains.annotations.NotNull() + Flow flow9, @org.jetbrains.annotations.NotNull() + Flow flow10, @org.jetbrains.annotations.NotNull() + Flow flow11, @org.jetbrains.annotations.NotNull() + Flow flow12, @org.jetbrains.annotations.NotNull() + Flow flow13, @org.jetbrains.annotations.NotNull() + Flow flow14, @org.jetbrains.annotations.NotNull() + Flow flow15, @org.jetbrains.annotations.NotNull() + Flow flow16, @org.jetbrains.annotations.NotNull() + Flow flow17, @org.jetbrains.annotations.NotNull() + Flow flow18, @org.jetbrains.annotations.NotNull() + Flow flow19, @org.jetbrains.annotations.NotNull() + Flow flow20, @org.jetbrains.annotations.NotNull() + Flow flow21, @org.jetbrains.annotations.NotNull() + Flow flow22, @org.jetbrains.annotations.NotNull() + Flow flow23, @org.jetbrains.annotations.NotNull() + kotlin.jvm.functions.FunctionN transform) { + return null; + } +} diff --git a/plugins/kapt3/kapt3-compiler/tests-gen/org/jetbrains/kotlin/kapt3/test/runners/ClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/kapt3-compiler/tests-gen/org/jetbrains/kotlin/kapt3/test/runners/ClassFileToSourceStubConverterTestGenerated.java index e8048962e2d..ff7c6c836ac 100644 --- a/plugins/kapt3/kapt3-compiler/tests-gen/org/jetbrains/kotlin/kapt3/test/runners/ClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/kapt3-compiler/tests-gen/org/jetbrains/kotlin/kapt3/test/runners/ClassFileToSourceStubConverterTestGenerated.java @@ -631,6 +631,12 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi runTest("plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionSupertype.kt"); } + @Test + @TestMetadata("suspendFunctionWithBigArity.kt") + public void testSuspendFunctionWithBigArity() throws Exception { + runTest("plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.kt"); + } + @Test @TestMetadata("topLevel.kt") public void testTopLevel() throws Exception { diff --git a/plugins/kapt3/kapt3-compiler/tests-gen/org/jetbrains/kotlin/kapt3/test/runners/IrClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/kapt3-compiler/tests-gen/org/jetbrains/kotlin/kapt3/test/runners/IrClassFileToSourceStubConverterTestGenerated.java index 60937182910..6830082106f 100644 --- a/plugins/kapt3/kapt3-compiler/tests-gen/org/jetbrains/kotlin/kapt3/test/runners/IrClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/kapt3-compiler/tests-gen/org/jetbrains/kotlin/kapt3/test/runners/IrClassFileToSourceStubConverterTestGenerated.java @@ -631,6 +631,12 @@ public class IrClassFileToSourceStubConverterTestGenerated extends AbstractIrCla runTest("plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionSupertype.kt"); } + @Test + @TestMetadata("suspendFunctionWithBigArity.kt") + public void testSuspendFunctionWithBigArity() throws Exception { + runTest("plugins/kapt3/kapt3-compiler/testData/converter/suspendFunctionWithBigArity.kt"); + } + @Test @TestMetadata("topLevel.kt") public void testTopLevel() throws Exception {