JVM_IR: generate continuation classes for suspend inline references

This is somewhat suboptimal since this results in `::suspendInline`
generating 2 classes while `{ suspendInline() }` only creates 1, but
it's the best allowed by the existing hierarchy of classes in stdlib. At
least it works?

^KT-50832 Fixed
This commit is contained in:
pyos
2022-05-09 14:28:44 +02:00
committed by teamcity
parent 9f31f074da
commit b19b265735
11 changed files with 82 additions and 4 deletions
@@ -10485,6 +10485,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstructionWithJumpOut.kt");
}
@Test
@TestMetadata("suspendInlineReference.kt")
public void testSuspendInlineReference() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendInlineReference.kt");
}
@Test
@TestMetadata("suspendJavaOverrides.kt")
public void testSuspendJavaOverrides() throws Exception {
@@ -313,10 +313,12 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
val result = mutableListOf(view)
if (function.body == null || !function.hasContinuation()) return result
// This is a suspend function inside of SAM adapter.
// The attribute of function reference is used for the SAM adapter.
// So, we hack new attributes for continuation class.
if (function.parentAsClass.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL) {
// Sometimes, suspend methods of SAM adapters or function references require a continuation class.
// However, the attribute owner is used to store the name of the SAM adapter or the function reference itself.
// So here we add a local class name using the suspend method itself as the key.
if (function.parentAsClass.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL ||
function.parentAsClass.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
) {
context.putLocalClassType(
function.attributeOwnerId,
Type.getObjectType("${context.getLocalClassType(function.parentAsClass)!!.internalName}$${function.name}$1")
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_IMPL_NAME_SUFFIX
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.IrGetField
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.util.functions
@@ -36,6 +37,10 @@ fun IrFunction.isInvokeSuspendOfContinuation(): Boolean =
private fun IrFunction.isInvokeOfSuspendCallableReference(): Boolean =
isSuspend && name.asString().let { name -> name == "invoke" || name.startsWith("invoke-") }
&& parentAsClass.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
// References to inline functions don't count since they're not really *references* - the contents
// of the inline function are copy-pasted into the `invoke` method, and may require a continuation.
// (TODO: maybe the reference itself should be the continuation, just like lambdas?)
&& (parentAsClass.attributeOwnerId as? IrFunctionReference)?.symbol?.owner?.isInline != true
private fun IrFunction.isBridgeToSuspendImplMethod(): Boolean =
isSuspend && this is IrSimpleFunction && (parent as? IrClass)?.functions?.any {
@@ -0,0 +1,25 @@
// WITH_STDLIB
// WITH_COROUTINES
// IGNORE_BACKEND: JVM, JS
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
suspend fun suspendHere() = suspendCoroutineUninterceptedOrReturn {
it.resume(Unit)
COROUTINE_SUSPENDED
}
suspend inline fun foo(): String {
suspendHere()
return "OK"
}
fun box(): String {
var result = ""
suspend {
val ref = ::foo
result = ref()
}.startCoroutine(EmptyContinuation)
return result
}
@@ -10365,6 +10365,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstructionWithJumpOut.kt");
}
@Test
@TestMetadata("suspendInlineReference.kt")
public void testSuspendInlineReference() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendInlineReference.kt");
}
@Test
@TestMetadata("suspendJavaOverrides.kt")
public void testSuspendJavaOverrides() throws Exception {
@@ -10485,6 +10485,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstructionWithJumpOut.kt");
}
@Test
@TestMetadata("suspendInlineReference.kt")
public void testSuspendInlineReference() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendInlineReference.kt");
}
@Test
@TestMetadata("suspendJavaOverrides.kt")
public void testSuspendJavaOverrides() throws Exception {
@@ -7566,6 +7566,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/coroutines/suspendFunctionAsSupertype.kt");
}
@TestMetadata("suspendInlineReference.kt")
public void ignoreSuspendInlineReference() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendInlineReference.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -7433,6 +7433,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstructionWithJumpOut.kt");
}
@Test
@TestMetadata("suspendInlineReference.kt")
public void testSuspendInlineReference() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendInlineReference.kt");
}
@Test
@TestMetadata("suspendLambdaInInterface.kt")
public void testSuspendLambdaInInterface() throws Exception {
@@ -7475,6 +7475,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstructionWithJumpOut.kt");
}
@Test
@TestMetadata("suspendInlineReference.kt")
public void testSuspendInlineReference() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendInlineReference.kt");
}
@Test
@TestMetadata("suspendLambdaInInterface.kt")
public void testSuspendLambdaInInterface() throws Exception {
@@ -6564,6 +6564,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstructionWithJumpOut.kt");
}
@TestMetadata("suspendInlineReference.kt")
public void testSuspendInlineReference() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendInlineReference.kt");
}
@TestMetadata("suspendLambdaInInterface.kt")
public void testSuspendLambdaInInterface() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendLambdaInInterface.kt");
@@ -8317,6 +8317,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
runTest("compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstructionWithJumpOut.kt");
}
@Test
@TestMetadata("suspendInlineReference.kt")
public void testSuspendInlineReference() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendInlineReference.kt");
}
@Test
@TestMetadata("suspendLambdaInInterface.kt")
public void testSuspendLambdaInInterface() throws Exception {