From 7a9ff15d73ec006583587318d9d2d7253465e2d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Sch=C3=A4fer?= Date: Fri, 9 Apr 2021 13:51:37 +0200 Subject: [PATCH] JVM IR: Handle suspend interface default methods with generic types (KT-45166) --- .../FirBlackBoxCodegenTestGenerated.java | 6 ++++++ .../jvm/lower/AddContinuationLowering.kt | 21 +++++++++---------- .../bridges/interfaceGenericDefault.kt | 19 +++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++++++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++++++ .../LightAnalysisModeTestGenerated.java | 5 +++++ .../IrJsCodegenBoxES6TestGenerated.java | 5 +++++ .../IrJsCodegenBoxTestGenerated.java | 5 +++++ .../semantics/JsCodegenBoxTestGenerated.java | 5 +++++ 9 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index c35c93e1dbf..ff5b5a76677 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -9429,6 +9429,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/bridges"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("interfaceGenericDefault.kt") + public void testInterfaceGenericDefault() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt"); + } + @Test @TestMetadata("interfaceSpecialization.kt") public void testInterfaceSpecialization() throws Exception { 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 c44bc3d8a26..410e4ed2eb6 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 @@ -79,8 +79,8 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower val transformed = super.visitCall(expression) as IrCall return transformed.retargetToSuspendView(context, functionStack.peek() ?: return transformed) { IrCallImpl.fromSymbolOwner( - startOffset, endOffset, type, it, - origin = origin, superQualifierSymbol = superQualifierSymbol + startOffset, endOffset, type, it, + origin = origin, superQualifierSymbol = superQualifierSymbol ) } } @@ -261,11 +261,11 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower return declaration } - private fun transformToView(function: IrSimpleFunction): List? { + private fun transformToView(function: IrSimpleFunction): List { val flag = MutableFlag(false) function.accept(this, flag) - val view = function.suspendFunctionViewOrStub(context) as IrSimpleFunction + val view = function.suspendFunctionViewOrStub(context) val continuationParameter = view.continuationParameter() val parameterMap = function.explicitParameters.zip(view.explicitParameters.filter { it != continuationParameter }).toMap() view.body = function.moveBodyTo(view, parameterMap) @@ -334,7 +334,7 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower // Transform `suspend fun foo(params): RetType` into `fun foo(params, $completion: Continuation): Any?` // the result is called 'view', just to be consistent with old backend. -private fun IrSimpleFunction.suspendFunctionViewOrStub(context: JvmBackendContext): IrFunction { +private fun IrSimpleFunction.suspendFunctionViewOrStub(context: JvmBackendContext): IrSimpleFunction { if (!isSuspend) return this return context.suspendFunctionOriginalToView.getOrPut(suspendFunctionOriginal()) { createSuspendFunctionStub(context) } } @@ -377,10 +377,7 @@ private fun IrSimpleFunction.createSuspendFunctionStub(context: JvmBackendContex val substitutionMap = makeTypeParameterSubstitutionMap(this, function) function.copyReceiverParametersFrom(this, substitutionMap) - if (origin != JvmLoweredDeclarationOrigin.SUPER_INTERFACE_METHOD_BRIDGE) { - function.overriddenSymbols += - overriddenSymbols.map { it.owner.suspendFunctionViewOrStub(context).symbol as IrSimpleFunctionSymbol } - } + function.overriddenSymbols += overriddenSymbols.map { it.owner.suspendFunctionViewOrStub(context).symbol } // The continuation parameter goes before the default argument mask(s) and handler for default argument stubs. // TODO: It would be nice if AddContinuationLowering could insert the continuation argument before default stub generation. @@ -390,7 +387,9 @@ private fun IrSimpleFunction.createSuspendFunctionStub(context: JvmBackendContex it.copyTo(function, index = it.index, type = it.type.substitute(substitutionMap)) } function.addValueParameter( - SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME, continuationType(context).substitute(substitutionMap), JvmLoweredDeclarationOrigin.CONTINUATION_CLASS + SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME, + continuationType(context).substitute(substitutionMap), + JvmLoweredDeclarationOrigin.CONTINUATION_CLASS ) function.valueParameters += valueParameters.drop(index).map { it.copyTo(function, index = it.index + 1, type = it.type.substitute(substitutionMap)) @@ -427,7 +426,7 @@ private fun > T.retargetToSuspend // While the new callee technically returns ` | COROUTINE_SUSPENDED`, the latter case is handled // by a method visitor so at an IR overview we don't need to consider it. - return copyWithTargetSymbol(view.symbol as IrSimpleFunctionSymbol).also { + return copyWithTargetSymbol(view.symbol).also { it.copyAttributes(this) it.copyTypeArgumentsFrom(this) it.dispatchReceiver = dispatchReceiver diff --git a/compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt b/compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt new file mode 100644 index 00000000000..dfb00855c46 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt @@ -0,0 +1,19 @@ +// Corresponds to KT-45166, KT-45320, KT-45490, and KT-45954. +// WITH_RUNTIME +// WITH_COROUTINES +import helpers.* +import kotlin.coroutines.* + +interface I { + suspend fun f(x: T): String = "OK" +} + +class C : I + +fun box(): String { + var result = "Fail" + suspend { + result = (C() as I).f("Fail") + }.startCoroutine(EmptyContinuation) + return result +} 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 1cc09af74ba..23e7047a061 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 @@ -9429,6 +9429,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/bridges"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @Test + @TestMetadata("interfaceGenericDefault.kt") + public void testInterfaceGenericDefault() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt"); + } + @Test @TestMetadata("interfaceSpecialization.kt") public void testInterfaceSpecialization() 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 25f80d530f4..d196360fef6 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 @@ -9429,6 +9429,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/bridges"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("interfaceGenericDefault.kt") + public void testInterfaceGenericDefault() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt"); + } + @Test @TestMetadata("interfaceSpecialization.kt") public void testInterfaceSpecialization() 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 d102066ab77..82abf7b6025 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -7386,6 +7386,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/bridges"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("interfaceGenericDefault.kt") + public void testInterfaceGenericDefault() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt"); + } + @TestMetadata("interfaceSpecialization.kt") public void testInterfaceSpecialization() throws Exception { runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index e9275bb01a4..66f8b81a731 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -6605,6 +6605,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/bridges"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); } + @TestMetadata("interfaceGenericDefault.kt") + public void testInterfaceGenericDefault() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt"); + } + @TestMetadata("interfaceSpecialization.kt") public void testInterfaceSpecialization() throws Exception { runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 8d58f61dfba..c9f406b48b6 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -6026,6 +6026,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/bridges"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); } + @TestMetadata("interfaceGenericDefault.kt") + public void testInterfaceGenericDefault() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt"); + } + @TestMetadata("interfaceSpecialization.kt") public void testInterfaceSpecialization() throws Exception { runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index d02e90575a6..e1ee7753765 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -6026,6 +6026,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/bridges"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); } + @TestMetadata("interfaceGenericDefault.kt") + public void testInterfaceGenericDefault() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceGenericDefault.kt"); + } + @TestMetadata("interfaceSpecialization.kt") public void testInterfaceSpecialization() throws Exception { runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt");