JVM IR: Handle suspend interface default methods with generic types (KT-45166)

This commit is contained in:
Steven Schäfer
2021-04-09 13:51:37 +02:00
committed by Alexander Udalov
parent 7d62f0b5aa
commit 7a9ff15d73
9 changed files with 67 additions and 11 deletions
@@ -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 {
@@ -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<IrFunction>? {
private fun transformToView(function: IrSimpleFunction): List<IrFunction> {
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<RetType>): 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 : IrMemberAccessExpression<IrFunctionSymbol>> T.retargetToSuspend
// While the new callee technically returns `<original type> | 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
@@ -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<T> {
suspend fun f(x: T): String = "OK"
}
class C : I<String>
fun box(): String {
var result = "Fail"
suspend {
result = (C() as I<String>).f("Fail")
}.startCoroutine(EmptyContinuation)
return result
}
@@ -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 {
@@ -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 {
@@ -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");
@@ -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");
@@ -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");
@@ -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");