Check for COROUTINE_SUSPENDED inside callable reference
#KT-41429 Fixed
This commit is contained in:
@@ -589,4 +589,8 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
|||||||
MemberScope scope = functionClass.getDefaultType().getMemberScope();
|
MemberScope scope = functionClass.getDefaultType().getMemberScope();
|
||||||
return scope.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).iterator().next();
|
return scope.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCallableReference() {
|
||||||
|
return functionReferenceTarget != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2742,6 +2742,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
addInlineMarker(v, false);
|
addInlineMarker(v, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a suspend function returns unboxed inline class, we should check for COROUTINE_SUSPENDED and only then box the inline class.
|
||||||
|
if (insideCallableReference() && resolvedCall.getResultingDescriptor() instanceof FunctionDescriptor) {
|
||||||
|
KotlinType unboxedInlineClass = CoroutineCodegenUtilKt.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(
|
||||||
|
(FunctionDescriptor) resolvedCall.getResultingDescriptor(), typeMapper);
|
||||||
|
if (unboxedInlineClass != null) {
|
||||||
|
CoroutineCodegenUtilKt.generateCoroutineSuspendedCheck(v, state.getLanguageVersionSettings());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
KotlinType returnType = resolvedCall.getResultingDescriptor().getReturnType();
|
KotlinType returnType = resolvedCall.getResultingDescriptor().getReturnType();
|
||||||
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
|
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
|
||||||
if (state.getUseKotlinNothingValueException()) {
|
if (state.getUseKotlinNothingValueException()) {
|
||||||
@@ -2756,8 +2765,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean insideCallableReference() {
|
private boolean insideCallableReference() {
|
||||||
return (parentCodegen instanceof ClosureCodegen) &&
|
return (parentCodegen instanceof ClosureCodegen) && ((ClosureCodegen) parentCodegen).isCallableReference();
|
||||||
((ClosureCodegen) parentCodegen).superClassAsmType.equals(FUNCTION_REFERENCE_IMPL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putReceiverAndInlineMarkerIfNeeded(
|
private void putReceiverAndInlineMarkerIfNeeded(
|
||||||
|
|||||||
@@ -726,12 +726,7 @@ class CoroutineCodegenForNamedFunction private constructor(
|
|||||||
with(codegen.v) {
|
with(codegen.v) {
|
||||||
// We need to box the returned inline class in resume path.
|
// We need to box the returned inline class in resume path.
|
||||||
// But first, check for COROUTINE_SUSPENDED, since the function can return it
|
// But first, check for COROUTINE_SUSPENDED, since the function can return it
|
||||||
dup()
|
generateCoroutineSuspendedCheck(languageVersionSettings)
|
||||||
loadCoroutineSuspendedMarker(languageVersionSettings)
|
|
||||||
val elseLabel = Label()
|
|
||||||
ifacmpne(elseLabel)
|
|
||||||
areturn(AsmTypes.OBJECT_TYPE)
|
|
||||||
mark(elseLabel)
|
|
||||||
// Now we box the inline class
|
// Now we box the inline class
|
||||||
StackValue.coerce(AsmTypes.OBJECT_TYPE, typeMapper.mapType(inlineClassToBoxInInvokeSuspend), this)
|
StackValue.coerce(AsmTypes.OBJECT_TYPE, typeMapper.mapType(inlineClassToBoxInInvokeSuspend), this)
|
||||||
StackValue.boxInlineClass(inlineClassToBoxInInvokeSuspend, this)
|
StackValue.boxInlineClass(inlineClassToBoxInInvokeSuspend, this)
|
||||||
|
|||||||
@@ -490,6 +490,15 @@ fun InstructionAdapter.loadCoroutineSuspendedMarker(languageVersionSettings: Lan
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun InstructionAdapter.generateCoroutineSuspendedCheck(languageVersionSettings: LanguageVersionSettings) {
|
||||||
|
dup()
|
||||||
|
loadCoroutineSuspendedMarker(languageVersionSettings)
|
||||||
|
val elseLabel = Label()
|
||||||
|
ifacmpne(elseLabel)
|
||||||
|
areturn(OBJECT_TYPE)
|
||||||
|
mark(elseLabel)
|
||||||
|
}
|
||||||
|
|
||||||
fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) {
|
fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) {
|
||||||
// .doResume(Unit, null)
|
// .doResume(Unit, null)
|
||||||
StackValue.putUnitInstance(this)
|
StackValue.putUnitInstance(this)
|
||||||
|
|||||||
Generated
+5
@@ -7441,6 +7441,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt")
|
||||||
|
public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
||||||
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
|
// IGNORE_BACKEND: JS_IR_ES6
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// WITH_COROUTINES
|
||||||
|
|
||||||
|
import helpers.*
|
||||||
|
import kotlin.coroutines.*
|
||||||
|
|
||||||
|
inline class R(val x: Any)
|
||||||
|
|
||||||
|
fun builder(c: suspend () -> Unit) {
|
||||||
|
c.startCoroutine(EmptyContinuation)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <T> call(fn: suspend () -> T) = fn()
|
||||||
|
|
||||||
|
fun useR(r: R) = if (r.x == "OK") "OK" else "fail: $r"
|
||||||
|
|
||||||
|
var c: Continuation<R>? = null
|
||||||
|
|
||||||
|
suspend fun ok() = suspendCoroutine<R> { c = it }
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var res: String = "fail"
|
||||||
|
builder {
|
||||||
|
res = useR(call(::ok))
|
||||||
|
}
|
||||||
|
c?.resume(R("OK"))
|
||||||
|
return res
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
// IGNORE_BACKEND: JVM_IR
|
||||||
|
|
||||||
import helpers.*
|
import helpers.*
|
||||||
import kotlin.coroutines.*
|
import kotlin.coroutines.*
|
||||||
|
|||||||
+2
-1
@@ -23,4 +23,5 @@ suspend fun test() {
|
|||||||
|
|
||||||
// -- 1 in 'useICAny(suspendGeneric(ICAny("")))
|
// -- 1 in 'useICAny(suspendGeneric(ICAny("")))
|
||||||
// -- 1 in 'equals-impl' for ICAny
|
// -- 1 in 'equals-impl' for ICAny
|
||||||
// 2 INVOKEVIRTUAL ICAny\.unbox-impl
|
// -- 2 on resume path of suspendICAny
|
||||||
|
// 4 INVOKEVIRTUAL ICAny\.unbox-impl
|
||||||
+3
-3
@@ -11,14 +11,14 @@ fun useIC(x: IC1) {}
|
|||||||
fun useAny(x: Any) {}
|
fun useAny(x: Any) {}
|
||||||
|
|
||||||
suspend fun test() {
|
suspend fun test() {
|
||||||
useIC(suspendIC())
|
useIC(suspendIC()) // IC1.unbox-impl of resume path
|
||||||
useIC(suspendGeneric(IC1(IC0("")))) // IC1.box-impl, IC1.unbox-impl
|
useIC(suspendGeneric(IC1(IC0("")))) // IC1.box-impl, IC1.unbox-impl
|
||||||
useAny(suspendAny())
|
useAny(suspendAny())
|
||||||
useAny(suspendIC()) // IC1.box-impl
|
useAny(suspendIC()) // IC1.box-impl, IC1.unbox-impl of resume path
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 INVOKESTATIC IC0\.box-impl
|
// 0 INVOKESTATIC IC0\.box-impl
|
||||||
// 3 INVOKESTATIC IC1\.box-impl
|
// 3 INVOKESTATIC IC1\.box-impl
|
||||||
|
|
||||||
// 1 INVOKEVIRTUAL IC0\.unbox-impl
|
// 1 INVOKEVIRTUAL IC0\.unbox-impl
|
||||||
// 2 INVOKEVIRTUAL IC1\.unbox-impl
|
// 4 INVOKEVIRTUAL IC1\.unbox-impl
|
||||||
|
|||||||
+2
-1
@@ -23,4 +23,5 @@ suspend fun test() {
|
|||||||
|
|
||||||
// -- 1 in 'useICString(suspendGeneric(ICString("")))
|
// -- 1 in 'useICString(suspendGeneric(ICString("")))
|
||||||
// -- 1 in 'equals-impl' for ICString
|
// -- 1 in 'equals-impl' for ICString
|
||||||
// 2 INVOKEVIRTUAL ICString\.unbox-impl
|
// -- 2 in resume path of suspendICString
|
||||||
|
// 4 INVOKEVIRTUAL ICString\.unbox-impl
|
||||||
+1
-1
@@ -7,5 +7,5 @@ inline class OurAny(val a: Any)
|
|||||||
|
|
||||||
suspend fun returnsUnboxed(): OurAny = OurAny("OK")
|
suspend fun returnsUnboxed(): OurAny = OurAny("OK")
|
||||||
|
|
||||||
// 1 INVOKESTATIC kotlin/Result.box-impl
|
// 0 INVOKESTATIC kotlin/Result.box-impl
|
||||||
// 0 INVOKESTATIC OurAny.box-impl
|
// 0 INVOKESTATIC OurAny.box-impl
|
||||||
+5
@@ -8151,6 +8151,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt")
|
||||||
|
public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
||||||
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
||||||
|
|||||||
+5
@@ -8151,6 +8151,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt")
|
||||||
|
public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
||||||
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
||||||
|
|||||||
+5
@@ -7441,6 +7441,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt")
|
||||||
|
public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
||||||
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
||||||
|
|||||||
Generated
+5
@@ -6261,6 +6261,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
|||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt")
|
||||||
|
public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
||||||
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
||||||
|
|||||||
Generated
+5
@@ -6261,6 +6261,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt")
|
||||||
|
public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
||||||
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
||||||
|
|||||||
+5
@@ -6261,6 +6261,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt")
|
||||||
|
public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
@TestMetadata("boxReturnValueOfSuspendLambda.kt")
|
||||||
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
public void testBoxReturnValueOfSuspendLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user