From 0acaedef92d6f90625cf608c11b2349fcf90a635 Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Tue, 12 May 2020 20:28:29 +0200 Subject: [PATCH] Fix attribute clash between STATIC_INLINE_CLASS_REPLACEMENT and original Attributes are used to name continuation classes and are generated before inline classes processing. During the processing, for override functions in inlined classes, the compiler generates STATIC_INLINE_CLASS_REPLACEMENT function with body of the override. The override's body is replaced with delegating call to STATIC_INLINE_CLASS_REPLACEMENT. However, since we need to keep the name of the continuation class, we copy attributes from the override to STATIC_INLINE_CLASS_REPLACEMENT. This leads to attribute clash during AddContinuationLowering. So, to fix the issue, do not use the attribute of STATIC_INLINE_CLASS_REPLACEMENT in original->suspend map. As an optimization, do not generate continuation for the override function. --- .../ir/FirBlackBoxCodegenTestGenerated.java | 5 +++ .../backend/jvm/codegen/CoroutineCodegen.kt | 8 ++++- .../jvm/lower/AddContinuationLowering.kt | 4 ++- .../overrideInInlineClass.kt | 31 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 +++ .../LightAnalysisModeTestGenerated.java | 5 +++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 +++ .../IrJsCodegenBoxTestGenerated.java | 5 +++ .../semantics/JsCodegenBoxTestGenerated.java | 5 +++ 9 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 0c51ec004ad..e17f01c3271 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -6994,6 +6994,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBodyGeneric.kt"); } + @TestMetadata("overrideInInlineClass.kt") + public void testOverrideInInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt"); + } + @TestMetadata("safeCallOnTwoReceiversLong.kt") public void testSafeCallOnTwoReceiversLong_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines"); diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt index fafbe7c0721..6f7ebc065d9 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt @@ -117,6 +117,11 @@ private fun IrFunction.isBridgeToSuspendImplMethod(): Boolean = it.name.asString() == name.asString() + SUSPEND_IMPL_NAME_SUFFIX && it.attributeOwnerId == attributeOwnerId } +private fun IrFunction.isStaticInlineClassReplacementDelegatingCall(): Boolean = + this is IrAttributeContainer && origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT && + parentAsClass.declarations.find { it is IrAttributeContainer && it.attributeOwnerId == attributeOwnerId && it !== this } + ?.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT + internal fun IrFunction.shouldContainSuspendMarkers(): Boolean = !isInvokeSuspendOfContinuation() && // These are tail-call bridges and do not require any bytecode modifications. origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER && @@ -129,7 +134,8 @@ internal fun IrFunction.shouldContainSuspendMarkers(): Boolean = !isInvokeSuspen origin != IrDeclarationOrigin.BRIDGE_SPECIAL && origin != IrDeclarationOrigin.DELEGATED_MEMBER && !isInvokeOfSuspendCallableReference() && - !isBridgeToSuspendImplMethod() + !isBridgeToSuspendImplMethod() && + !isStaticInlineClassReplacementDelegatingCall() internal fun IrFunction.hasContinuation(): Boolean = isSuspend && shouldContainSuspendMarkers() && // This is inline-only function diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt index b700aab80cb..184990f3938 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt @@ -640,7 +640,9 @@ private fun IrFunction.suspendFunctionViewOrStub(context: JvmBackendContext): Ir } internal fun IrFunction.suspendFunctionOriginal(): IrFunction = - if (this is IrSimpleFunction && isSuspend) attributeOwnerId as IrFunction else this + if (this is IrSimpleFunction && isSuspend && origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT) + attributeOwnerId as IrFunction + else this private fun IrFunction.createSuspendFunctionStub(context: JvmBackendContext): IrFunction { require(this.isSuspend && this is IrSimpleFunction) diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt new file mode 100644 index 00000000000..20a170201b0 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt @@ -0,0 +1,31 @@ +// KJS_WITH_FULL_RUNTIME +// WITH_RUNTIME +// WITH_COROUTINES + +import kotlin.coroutines.* +import helpers.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +class Delegate { + fun build(): String = "OK" +} + +interface Digest { + suspend fun build(): String +} + +inline class DigestImpl(val delegate: Delegate) : Digest { + override suspend fun build(): String = delegate.build() +} + +fun box(): String { + var res = "FAIL" + val digest: Digest = DigestImpl(Delegate()) + builder { + res = digest.build() + } + return res +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 9b9896a52e7..bb73965512e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -7594,6 +7594,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBodyGeneric.kt"); } + @TestMetadata("overrideInInlineClass.kt") + public void testOverrideInInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt"); + } + @TestMetadata("safeCallOnTwoReceiversLong.kt") public void testSafeCallOnTwoReceiversLong_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines.experimental"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 198a7cccb95..8ee9039f272 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -7594,6 +7594,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBodyGeneric.kt"); } + @TestMetadata("overrideInInlineClass.kt") + public void testOverrideInInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt"); + } + @TestMetadata("safeCallOnTwoReceiversLong.kt") public void testSafeCallOnTwoReceiversLong_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines.experimental"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 4d47782ae73..65aacfb4635 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -6994,6 +6994,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBodyGeneric.kt"); } + @TestMetadata("overrideInInlineClass.kt") + public void testOverrideInInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt"); + } + @TestMetadata("safeCallOnTwoReceiversLong.kt") public void testSafeCallOnTwoReceiversLong_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index c69ac957b58..82e193a4b88 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -5904,6 +5904,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBodyGeneric.kt"); } + @TestMetadata("overrideInInlineClass.kt") + public void testOverrideInInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt"); + } + @TestMetadata("safeCallOnTwoReceiversLong.kt") public void testSafeCallOnTwoReceiversLong_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines"); 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 c105bb1199e..61be49410c4 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 @@ -5904,6 +5904,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBodyGeneric.kt"); } + @TestMetadata("overrideInInlineClass.kt") + public void testOverrideInInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt"); + } + @TestMetadata("safeCallOnTwoReceiversLong.kt") public void testSafeCallOnTwoReceiversLong_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines");