JVM IR: fix handling of suspend extension lambdas with captured receiver
The problem in the added test was that a suspend lambda was represented by a function reference with a bound argument for the ObjectRef value, and the corresponding parameter was not the first parameter of the referenced local function. This happens because LocalDeclarationsLowering lifts the local function up and adds a new parameter for the captured ObjectRef (which is bound at the call site), but the original receiver parameter remains the first unbound parameter. So, it's no longer correct to rely on the fact that all bound parameters of a function reference are located in the beginning of the parameter list, which was kind of assumed in the `withIndex` call in `AddContinuationLowering.addCreate`.
This commit is contained in:
+7
-5
@@ -121,8 +121,10 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
val parametersFields = info.function.valueParameters.map { addField(it.name, it.type) }
|
||||
val parametersWithoutArguments = parametersFields.withIndex()
|
||||
.mapNotNull { (i, field) -> if (info.reference.getValueArgument(i) == null) field else null }
|
||||
val parametersWithArguments = parametersFields - parametersWithoutArguments
|
||||
val constructor = addPrimaryConstructorForLambda(info.arity, info.reference, parametersFields)
|
||||
val parametersWithArguments = parametersFields.withIndex()
|
||||
.filter { info.reference.getValueArgument(it.index) != null }
|
||||
val fieldsForArguments = parametersWithArguments.map(IndexedValue<IrField>::value)
|
||||
val constructor = addPrimaryConstructorForLambda(info.arity, info.reference, fieldsForArguments)
|
||||
val invokeToOverride = functionNClass.functions.single {
|
||||
it.owner.valueParameters.size == info.arity + 1 && it.owner.name.asString() == "invoke"
|
||||
}
|
||||
@@ -140,7 +142,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
constructor,
|
||||
invokeSuspend,
|
||||
invokeToOverride,
|
||||
parametersWithArguments,
|
||||
fieldsForArguments,
|
||||
listOfNotNull(receiverField) + parametersWithoutArguments
|
||||
)
|
||||
}
|
||||
@@ -308,7 +310,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
constructor: IrFunction,
|
||||
superType: IrClass,
|
||||
info: SuspendLambdaInfo,
|
||||
parametersWithArguments: List<IrField>,
|
||||
parametersWithArguments: List<IndexedValue<IrField>>,
|
||||
singleParameterField: IrField?
|
||||
): IrFunction {
|
||||
val create = superType.functions.single {
|
||||
@@ -323,7 +325,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
for (typeParameter in typeParameters) {
|
||||
it.putTypeArgument(typeParameter.index, typeParameter.defaultType)
|
||||
}
|
||||
for ((i, field) in parametersWithArguments.withIndex()) {
|
||||
for ((i, field) in parametersWithArguments) {
|
||||
if (info.reference.getValueArgument(i) == null) continue
|
||||
it.putValueArgument(index++, irGetField(irGet(function.dispatchReceiverParameter!!), field))
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
|
||||
import helpers.*
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
fun builder(c: suspend String.() -> Unit) {
|
||||
c.startCoroutine("OK", EmptyContinuation)
|
||||
}
|
||||
|
||||
interface A {
|
||||
var result: String
|
||||
|
||||
fun test(): String {
|
||||
builder { result = this }
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String =
|
||||
object : A {
|
||||
override var result = "Fail"
|
||||
}.test()
|
||||
+5
@@ -7150,6 +7150,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/inlineSuspendFinally.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceMethodWithBody.kt")
|
||||
public void testInterfaceMethodWithBody() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallOnTwoReceiversLong.kt")
|
||||
public void testSafeCallOnTwoReceiversLong_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines.experimental");
|
||||
|
||||
+5
@@ -7150,6 +7150,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/inlineSuspendFinally.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceMethodWithBody.kt")
|
||||
public void testInterfaceMethodWithBody() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallOnTwoReceiversLong.kt")
|
||||
public void testSafeCallOnTwoReceiversLong_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines.experimental");
|
||||
|
||||
+5
@@ -6565,6 +6565,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/inlineSuspendFinally.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceMethodWithBody.kt")
|
||||
public void testInterfaceMethodWithBody() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallOnTwoReceiversLong.kt")
|
||||
public void testSafeCallOnTwoReceiversLong_1_3() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines");
|
||||
|
||||
+5
@@ -6565,6 +6565,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/inlineSuspendFinally.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceMethodWithBody.kt")
|
||||
public void testInterfaceMethodWithBody() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallOnTwoReceiversLong.kt")
|
||||
public void testSafeCallOnTwoReceiversLong_1_3() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines");
|
||||
|
||||
Generated
+5
@@ -5580,6 +5580,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/inlineSuspendFinally.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceMethodWithBody.kt")
|
||||
public void testInterfaceMethodWithBody() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallOnTwoReceiversLong.kt")
|
||||
public void testSafeCallOnTwoReceiversLong_1_3() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines");
|
||||
|
||||
+5
@@ -6125,6 +6125,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/inlineSuspendFinally.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceMethodWithBody.kt")
|
||||
public void testInterfaceMethodWithBody() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/interfaceMethodWithBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallOnTwoReceiversLong.kt")
|
||||
public void testSafeCallOnTwoReceiversLong_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/safeCallOnTwoReceiversLong.kt", "kotlin.coroutines.experimental");
|
||||
|
||||
Reference in New Issue
Block a user