JVM IR: Handle suspend interface default methods with generic types (KT-45166)
This commit is contained in:
committed by
Alexander Udalov
parent
7d62f0b5aa
commit
7a9ff15d73
+6
@@ -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);
|
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
|
@Test
|
||||||
@TestMetadata("interfaceSpecialization.kt")
|
@TestMetadata("interfaceSpecialization.kt")
|
||||||
public void testInterfaceSpecialization() throws Exception {
|
public void testInterfaceSpecialization() throws Exception {
|
||||||
|
|||||||
+10
-11
@@ -79,8 +79,8 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
|||||||
val transformed = super.visitCall(expression) as IrCall
|
val transformed = super.visitCall(expression) as IrCall
|
||||||
return transformed.retargetToSuspendView(context, functionStack.peek() ?: return transformed) {
|
return transformed.retargetToSuspendView(context, functionStack.peek() ?: return transformed) {
|
||||||
IrCallImpl.fromSymbolOwner(
|
IrCallImpl.fromSymbolOwner(
|
||||||
startOffset, endOffset, type, it,
|
startOffset, endOffset, type, it,
|
||||||
origin = origin, superQualifierSymbol = superQualifierSymbol
|
origin = origin, superQualifierSymbol = superQualifierSymbol
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,11 +261,11 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
|||||||
return declaration
|
return declaration
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformToView(function: IrSimpleFunction): List<IrFunction>? {
|
private fun transformToView(function: IrSimpleFunction): List<IrFunction> {
|
||||||
val flag = MutableFlag(false)
|
val flag = MutableFlag(false)
|
||||||
function.accept(this, flag)
|
function.accept(this, flag)
|
||||||
|
|
||||||
val view = function.suspendFunctionViewOrStub(context) as IrSimpleFunction
|
val view = function.suspendFunctionViewOrStub(context)
|
||||||
val continuationParameter = view.continuationParameter()
|
val continuationParameter = view.continuationParameter()
|
||||||
val parameterMap = function.explicitParameters.zip(view.explicitParameters.filter { it != continuationParameter }).toMap()
|
val parameterMap = function.explicitParameters.zip(view.explicitParameters.filter { it != continuationParameter }).toMap()
|
||||||
view.body = function.moveBodyTo(view, parameterMap)
|
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?`
|
// 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.
|
// 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
|
if (!isSuspend) return this
|
||||||
return context.suspendFunctionOriginalToView.getOrPut(suspendFunctionOriginal()) { createSuspendFunctionStub(context) }
|
return context.suspendFunctionOriginalToView.getOrPut(suspendFunctionOriginal()) { createSuspendFunctionStub(context) }
|
||||||
}
|
}
|
||||||
@@ -377,10 +377,7 @@ private fun IrSimpleFunction.createSuspendFunctionStub(context: JvmBackendContex
|
|||||||
val substitutionMap = makeTypeParameterSubstitutionMap(this, function)
|
val substitutionMap = makeTypeParameterSubstitutionMap(this, function)
|
||||||
function.copyReceiverParametersFrom(this, substitutionMap)
|
function.copyReceiverParametersFrom(this, substitutionMap)
|
||||||
|
|
||||||
if (origin != JvmLoweredDeclarationOrigin.SUPER_INTERFACE_METHOD_BRIDGE) {
|
function.overriddenSymbols += overriddenSymbols.map { it.owner.suspendFunctionViewOrStub(context).symbol }
|
||||||
function.overriddenSymbols +=
|
|
||||||
overriddenSymbols.map { it.owner.suspendFunctionViewOrStub(context).symbol as IrSimpleFunctionSymbol }
|
|
||||||
}
|
|
||||||
|
|
||||||
// The continuation parameter goes before the default argument mask(s) and handler for default argument stubs.
|
// 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.
|
// 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))
|
it.copyTo(function, index = it.index, type = it.type.substitute(substitutionMap))
|
||||||
}
|
}
|
||||||
function.addValueParameter(
|
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 {
|
function.valueParameters += valueParameters.drop(index).map {
|
||||||
it.copyTo(function, index = it.index + 1, type = it.type.substitute(substitutionMap))
|
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
|
// 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.
|
// 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.copyAttributes(this)
|
||||||
it.copyTypeArgumentsFrom(this)
|
it.copyTypeArgumentsFrom(this)
|
||||||
it.dispatchReceiver = dispatchReceiver
|
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
|
||||||
|
}
|
||||||
+6
@@ -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);
|
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
|
@Test
|
||||||
@TestMetadata("interfaceSpecialization.kt")
|
@TestMetadata("interfaceSpecialization.kt")
|
||||||
public void testInterfaceSpecialization() throws Exception {
|
public void testInterfaceSpecialization() throws Exception {
|
||||||
|
|||||||
+6
@@ -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);
|
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
|
@Test
|
||||||
@TestMetadata("interfaceSpecialization.kt")
|
@TestMetadata("interfaceSpecialization.kt")
|
||||||
public void testInterfaceSpecialization() throws Exception {
|
public void testInterfaceSpecialization() throws Exception {
|
||||||
|
|||||||
+5
@@ -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);
|
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")
|
@TestMetadata("interfaceSpecialization.kt")
|
||||||
public void testInterfaceSpecialization() throws Exception {
|
public void testInterfaceSpecialization() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt");
|
runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt");
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+5
@@ -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);
|
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")
|
@TestMetadata("interfaceSpecialization.kt")
|
||||||
public void testInterfaceSpecialization() throws Exception {
|
public void testInterfaceSpecialization() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt");
|
runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt");
|
||||||
|
|||||||
Generated
+5
@@ -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);
|
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")
|
@TestMetadata("interfaceSpecialization.kt")
|
||||||
public void testInterfaceSpecialization() throws Exception {
|
public void testInterfaceSpecialization() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt");
|
runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt");
|
||||||
|
|||||||
Generated
+5
@@ -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);
|
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")
|
@TestMetadata("interfaceSpecialization.kt")
|
||||||
public void testInterfaceSpecialization() throws Exception {
|
public void testInterfaceSpecialization() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt");
|
runTest("compiler/testData/codegen/box/coroutines/bridges/interfaceSpecialization.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user