JVM_IR: unwrap suspend views when generating SAM wrappers
If the super class is in a file that has already been lowered, the base method has an extra continuation parameter which breaks things. Also, SAM wrappers around functional objects are tail-call and do not need continuations ever, so don't even try. ^KT-50950 Fixed
This commit is contained in:
+6
@@ -11284,6 +11284,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
public void testKt49294() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt49294.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt50950.kt")
|
||||
public void testKt50950() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+17
-13
@@ -66,6 +66,9 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) :
|
||||
protected open fun getWrappedFunctionType(klass: IrClass): IrType =
|
||||
klass.defaultType
|
||||
|
||||
protected open fun getSuspendFunctionWithoutContinuation(function: IrSimpleFunction): IrSimpleFunction =
|
||||
function
|
||||
|
||||
protected open fun IrFunctionBuilder.setConstructorSourceRange(createFor: IrElement) {
|
||||
setSourceRange(createFor)
|
||||
}
|
||||
@@ -156,15 +159,16 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) :
|
||||
val superFqName = superClass.fqNameWhenAvailable!!.asString().replace('.', '_')
|
||||
val inlinePrefix = if (wrapperVisibility == DescriptorVisibilities.PUBLIC) "\$i" else ""
|
||||
val wrapperName = Name.identifier("sam$inlinePrefix\$$superFqName$SAM_WRAPPER_SUFFIX")
|
||||
val superMethod = superClass.functions.single { it.modality == Modality.ABSTRACT }
|
||||
val extensionReceiversCount = if (superMethod.extensionReceiverParameter == null) 0 else 1
|
||||
val transformedSuperMethod = superClass.functions.single { it.modality == Modality.ABSTRACT }
|
||||
val originalSuperMethod = getSuspendFunctionWithoutContinuation(transformedSuperMethod)
|
||||
val extensionReceiversCount = if (originalSuperMethod.extensionReceiverParameter == null) 0 else 1
|
||||
// TODO: have psi2ir cast the argument to the correct function type. Also see the TODO
|
||||
// about type parameters in `visitTypeOperator`.
|
||||
val wrappedFunctionClass =
|
||||
if (superMethod.isSuspend)
|
||||
context.ir.symbols.suspendFunctionN(superMethod.valueParameters.size + extensionReceiversCount).owner
|
||||
if (originalSuperMethod.isSuspend)
|
||||
context.ir.symbols.suspendFunctionN(originalSuperMethod.valueParameters.size + extensionReceiversCount).owner
|
||||
else
|
||||
context.ir.symbols.functionN(superMethod.valueParameters.size + extensionReceiversCount).owner
|
||||
context.ir.symbols.functionN(originalSuperMethod.valueParameters.size + extensionReceiversCount).owner
|
||||
val wrappedFunctionType = getWrappedFunctionType(wrappedFunctionClass)
|
||||
|
||||
val subclass = context.irFactory.buildClass {
|
||||
@@ -207,23 +211,23 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) :
|
||||
}
|
||||
|
||||
subclass.addFunction {
|
||||
name = superMethod.name
|
||||
returnType = superMethod.returnType
|
||||
visibility = superMethod.visibility
|
||||
name = originalSuperMethod.name
|
||||
returnType = originalSuperMethod.returnType
|
||||
visibility = originalSuperMethod.visibility
|
||||
modality = Modality.FINAL
|
||||
origin = IrDeclarationOrigin.SYNTHETIC_GENERATED_SAM_IMPLEMENTATION
|
||||
isSuspend = superMethod.isSuspend
|
||||
isSuspend = originalSuperMethod.isSuspend
|
||||
setSourceRange(createFor)
|
||||
}.apply {
|
||||
overriddenSymbols = listOf(superMethod.symbol)
|
||||
overriddenSymbols = listOf(transformedSuperMethod.symbol)
|
||||
dispatchReceiverParameter = subclass.thisReceiver!!.copyTo(this)
|
||||
extensionReceiverParameter = superMethod.extensionReceiverParameter?.copyTo(this)
|
||||
valueParameters = superMethod.valueParameters.map { it.copyTo(this) }
|
||||
extensionReceiverParameter = originalSuperMethod.extensionReceiverParameter?.copyTo(this)
|
||||
valueParameters = originalSuperMethod.valueParameters.map { it.copyTo(this) }
|
||||
body = context.createIrBuilder(symbol).irBlockBody {
|
||||
+irReturn(
|
||||
irCall(
|
||||
wrappedFunctionClass.functions.single { it.name == OperatorNameConventions.INVOKE }.symbol,
|
||||
superMethod.returnType
|
||||
originalSuperMethod.returnType
|
||||
).apply {
|
||||
dispatchReceiver = irGetField(irGet(dispatchReceiverParameter!!), field)
|
||||
extensionReceiverParameter?.let { putValueArgument(0, irGet(it)) }
|
||||
|
||||
+5
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.rawType
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.suspendFunctionOriginal
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -20,6 +21,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.IrFunctionBuilder
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
@@ -51,6 +53,9 @@ private class JvmSingleAbstractMethodLowering(context: JvmBackendContext) : Sing
|
||||
override fun getWrappedFunctionType(klass: IrClass): IrType =
|
||||
klass.rawType(context as JvmBackendContext)
|
||||
|
||||
override fun getSuspendFunctionWithoutContinuation(function: IrSimpleFunction): IrSimpleFunction =
|
||||
function.suspendFunctionOriginal()
|
||||
|
||||
// The constructor of a SAM wrapper is non-synthetic and should not have line numbers.
|
||||
// Otherwise the debugger will try to step into it.
|
||||
override fun IrFunctionBuilder.setConstructorSourceRange(createFor: IrElement) {
|
||||
|
||||
@@ -67,6 +67,7 @@ private val BRIDGE_ORIGINS = setOf(
|
||||
JvmLoweredDeclarationOrigin.SUPER_INTERFACE_METHOD_BRIDGE,
|
||||
IrDeclarationOrigin.BRIDGE,
|
||||
IrDeclarationOrigin.BRIDGE_SPECIAL,
|
||||
IrDeclarationOrigin.SYNTHETIC_GENERATED_SAM_IMPLEMENTATION,
|
||||
)
|
||||
|
||||
// These functions contain a single `suspend` tail call, the value of which should be returned as is
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// IGNORE_BACKEND: JVM
|
||||
// WITH_COROUTINES
|
||||
// WITH_STDLIB
|
||||
// FILE: a.kt
|
||||
fun interface A {
|
||||
suspend fun run()
|
||||
}
|
||||
|
||||
// FILE: b.kt
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
import helpers.EmptyContinuation
|
||||
|
||||
suspend fun run(block: suspend () -> Unit) = A(block).run()
|
||||
|
||||
fun box(): String {
|
||||
suspend {
|
||||
run {}
|
||||
}.startCoroutine(EmptyContinuation)
|
||||
return "OK"
|
||||
}
|
||||
+6
@@ -11116,6 +11116,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
public void testKt49294() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt49294.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt50950.kt")
|
||||
public void testKt50950() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+6
@@ -11284,6 +11284,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
public void testKt49294() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt49294.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt50950.kt")
|
||||
public void testKt50950() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+5
@@ -8804,6 +8804,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt49294.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt50950.kt")
|
||||
public void ignoreKt50950() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt");
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
+6
@@ -8010,6 +8010,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
public void testKt49294() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt49294.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt50950.kt")
|
||||
public void testKt50950() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+6
@@ -8100,6 +8100,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
public void testKt49294() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt49294.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt50950.kt")
|
||||
public void testKt50950() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+5
@@ -7131,6 +7131,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
||||
public void testKt49294() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt49294.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt50950.kt")
|
||||
public void testKt50950() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/jvmDefault")
|
||||
|
||||
+6
@@ -8980,6 +8980,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
|
||||
public void testKt49294() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt49294.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt50950.kt")
|
||||
public void testKt50950() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/funInterface/kt50950.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
Reference in New Issue
Block a user