diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 78df49652d8..6f22c43fca6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -204,53 +204,6 @@ public class FunctionCodegen { return; } - boolean isOpenSuspendInClass = - functionDescriptor.isSuspend() && - functionDescriptor.getModality() != Modality.ABSTRACT && isOverridable(functionDescriptor) && - !isInterface(functionDescriptor.getContainingDeclaration()) && - origin.getOriginKind() != JvmDeclarationOriginKind.CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL; - - if (isOpenSuspendInClass) { - MethodVisitor mv = - v.newMethod(origin, - flags, - asmMethod.getName(), - asmMethod.getDescriptor(), - jvmSignature.getGenericsSignature(), - getThrownExceptions(functionDescriptor, typeMapper) - ); - - mv.visitCode(); - mv.visitVarInsn(Opcodes.ALOAD, 0); - int index = 1; - for (Type type : asmMethod.getArgumentTypes()) { - mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index); - index += type.getSize(); - } - - asmMethod = CoroutineCodegenUtilKt.getImplForOpenMethod(asmMethod, v.getThisName()); - // remove generic signature as it's unnecessary for synthetic methods - jvmSignature = - new JvmMethodGenericSignature( - asmMethod, - jvmSignature.getValueParameters(), - null - ); - - mv.visitMethodInsn( - Opcodes.INVOKESTATIC, - v.getThisName(), asmMethod.getName(), asmMethod.getDescriptor(), - false - ); - - mv.visitInsn(Opcodes.ARETURN); - mv.visitEnd(); - - flags |= Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC; - flags &= ~getVisibilityAccessFlag(functionDescriptor); - flags |= AsmUtil.NO_FLAG_PACKAGE_PRIVATE; - } - MethodVisitor mv = strategy.wrapMethodVisitor( v.newMethod(origin, @@ -286,6 +239,79 @@ public class FunctionCodegen { parentBodyCodegen.addAdditionalTask(new JvmStaticInCompanionObjectGenerator(functionDescriptor, origin, state, parentBodyCodegen)); } + boolean isOpenSuspendInClass = + functionDescriptor.isSuspend() && + functionDescriptor.getModality() != Modality.ABSTRACT && isOverridable(functionDescriptor) && + !isInterface(functionDescriptor.getContainingDeclaration()) && + origin.getOriginKind() != JvmDeclarationOriginKind.CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL; + + if (isOpenSuspendInClass) { + mv.visitCode(); + mv.visitVarInsn(Opcodes.ALOAD, 0); + int index = 1; + for (Type type : asmMethod.getArgumentTypes()) { + mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index); + index += type.getSize(); + } + + Method asmMethodForOpenSuspendImpl = CoroutineCodegenUtilKt.getImplForOpenMethod(asmMethod, v.getThisName()); + // remove generic signature as it's unnecessary for synthetic methods + JvmMethodSignature jvmSignatureForOpenSuspendImpl = + new JvmMethodGenericSignature( + asmMethodForOpenSuspendImpl, + jvmSignature.getValueParameters(), + null + ); + + mv.visitMethodInsn( + Opcodes.INVOKESTATIC, + v.getThisName(), asmMethodForOpenSuspendImpl.getName(), asmMethodForOpenSuspendImpl.getDescriptor(), + false + ); + + mv.visitInsn(Opcodes.ARETURN); + mv.visitEnd(); + + int flagsForOpenSuspendImpl = flags; + flagsForOpenSuspendImpl |= Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC; + flagsForOpenSuspendImpl &= ~getVisibilityAccessFlag(functionDescriptor); + flagsForOpenSuspendImpl |= AsmUtil.NO_FLAG_PACKAGE_PRIVATE; + + MethodVisitor mvForOpenSuspendImpl = strategy.wrapMethodVisitor( + v.newMethod(origin, + flagsForOpenSuspendImpl, + asmMethodForOpenSuspendImpl.getName(), + asmMethodForOpenSuspendImpl.getDescriptor(), + null, + getThrownExceptions(functionDescriptor, typeMapper) + ), + flagsForOpenSuspendImpl, asmMethodForOpenSuspendImpl.getName(), + asmMethodForOpenSuspendImpl.getDescriptor() + ); + + generateMethodBody( + origin, functionDescriptor, methodContext, strategy, mvForOpenSuspendImpl, jvmSignatureForOpenSuspendImpl, + staticInCompanionObject + ); + } + else { + generateMethodBody( + origin, functionDescriptor, methodContext, strategy, mv, jvmSignature, staticInCompanionObject + ); + } + + } + + private void generateMethodBody( + @NotNull JvmDeclarationOrigin origin, + @NotNull FunctionDescriptor functionDescriptor, + @NotNull MethodContext methodContext, + @NotNull FunctionGenerationStrategy strategy, + @NotNull MethodVisitor mv, + @NotNull JvmMethodSignature jvmSignature, + boolean staticInCompanionObject + ) { + OwnerKind contextKind = methodContext.getContextKind(); if (!state.getClassBuilderMode().generateBodies || isAbstractMethod(functionDescriptor, contextKind, state)) { generateLocalVariableTable( mv, diff --git a/compiler/testData/codegen/box/reflection/annotations/openSuspendFun.kt b/compiler/testData/codegen/box/reflection/annotations/openSuspendFun.kt new file mode 100644 index 00000000000..36e5bb880c6 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/annotations/openSuspendFun.kt @@ -0,0 +1,28 @@ +// WITH_REFLECT +// IGNORE_BACKEND: JS, NATIVE + +import kotlin.reflect.full.declaredMemberFunctions +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +annotation class Anno + +open class Aaa { + @Anno + suspend open fun aaa() {} +} + +class Bbb { + @Anno + suspend fun bbb() {} +} + +fun box(): String { + val bbb = Bbb::class.declaredMemberFunctions.first { it.name == "bbb" }.annotations + assertEquals(1, bbb.size) + assertTrue(bbb.single() is Anno) + val aaa = Aaa::class.declaredMemberFunctions.first { it.name == "aaa" }.annotations + assertEquals(1, aaa.size) + assertTrue(aaa.single() is Anno) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/mapping/openSuspendFun.kt b/compiler/testData/codegen/box/reflection/mapping/openSuspendFun.kt new file mode 100644 index 00000000000..1cdf1b68181 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/mapping/openSuspendFun.kt @@ -0,0 +1,22 @@ +// WITH_REFLECT +// IGNORE_BACKEND: JS, NATIVE + +import kotlin.reflect.full.declaredMemberFunctions +import kotlin.reflect.jvm.javaMethod +import kotlin.test.assertEquals + +open class Aaa { + suspend open fun aaa() {} +} + +class Bbb { + suspend fun bbb() {} +} + +fun box(): String { + val bbb = Bbb::class.declaredMemberFunctions.first { it.name == "bbb" }.javaMethod + assertEquals("bbb", bbb!!.name) + val aaa = Aaa::class.declaredMemberFunctions.first { it.name == "aaa" }.javaMethod + assertEquals("aaa", aaa!!.name) + return "OK" +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index f95735a3585..562c4e63ec6 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -14419,6 +14419,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("openSuspendFun.kt") + public void testOpenSuspendFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/annotations/openSuspendFun.kt"); + doTest(fileName); + } + @TestMetadata("privateAnnotation.kt") public void testPrivateAnnotation() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/annotations/privateAnnotation.kt"); @@ -15547,6 +15553,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("openSuspendFun.kt") + public void testOpenSuspendFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/openSuspendFun.kt"); + doTest(fileName); + } + @TestMetadata("propertyAccessors.kt") public void testPropertyAccessors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/propertyAccessors.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 9e04bcd6821..23d951696af 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -14419,6 +14419,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("openSuspendFun.kt") + public void testOpenSuspendFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/annotations/openSuspendFun.kt"); + doTest(fileName); + } + @TestMetadata("privateAnnotation.kt") public void testPrivateAnnotation() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/annotations/privateAnnotation.kt"); @@ -15547,6 +15553,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("openSuspendFun.kt") + public void testOpenSuspendFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/openSuspendFun.kt"); + doTest(fileName); + } + @TestMetadata("propertyAccessors.kt") public void testPropertyAccessors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/propertyAccessors.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 6add202f7b8..e71d90ab6b6 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -14419,6 +14419,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("openSuspendFun.kt") + public void testOpenSuspendFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/annotations/openSuspendFun.kt"); + doTest(fileName); + } + @TestMetadata("privateAnnotation.kt") public void testPrivateAnnotation() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/annotations/privateAnnotation.kt"); @@ -15547,6 +15553,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("openSuspendFun.kt") + public void testOpenSuspendFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/openSuspendFun.kt"); + doTest(fileName); + } + @TestMetadata("propertyAccessors.kt") public void testPropertyAccessors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/propertyAccessors.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 5dd9601b228..55388d0ec83 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -16309,6 +16309,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); } + @TestMetadata("openSuspendFun.kt") + public void testOpenSuspendFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/annotations/openSuspendFun.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } + @TestMetadata("privateAnnotation.kt") public void testPrivateAnnotation() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/annotations/privateAnnotation.kt"); @@ -18403,6 +18415,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); } + @TestMetadata("openSuspendFun.kt") + public void testOpenSuspendFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/openSuspendFun.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } + @TestMetadata("propertyAccessors.kt") public void testPropertyAccessors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/propertyAccessors.kt");