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:
+6
@@ -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 {
|
||||
|
||||
+6
-4
@@ -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
|
||||
}
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+5
@@ -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);
|
||||
}
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user