Support coroutines stack-unwinding in JVM backend

#KT-14924 In Progress
This commit is contained in:
Denis Zharkov
2016-11-29 10:30:33 +03:00
parent 27e4caf046
commit fcd9ee037e
86 changed files with 404 additions and 35 deletions
@@ -2810,7 +2810,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, bindingContext)) { if (CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, bindingContext)) {
// Suspension points should behave like they leave actual values on stack, while real methods return VOID // Suspension points should behave like they leave actual values on stack, while real methods return VOID
return new OperationStackValue(getSuspensionReturnTypeByResolvedCall(resolvedCall), ((OperationStackValue) result).getLambda()); return new OperationStackValue(getSuspensionBoxedReturnTypeByResolvedCall(resolvedCall), ((OperationStackValue) result).getLambda());
} }
return result; return result;
@@ -2925,7 +2925,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
} }
if (isSuspensionPoint) { if (isSuspensionPoint) {
v.tconst(getSuspensionReturnTypeByResolvedCall(resolvedCall)); v.tconst(getSuspensionBoxedReturnTypeByResolvedCall(resolvedCall));
v.invokestatic( v.invokestatic(
CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER, CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
CoroutineCodegenUtilKt.BEFORE_SUSPENSION_POINT_MARKER_NAME, CoroutineCodegenUtilKt.BEFORE_SUSPENSION_POINT_MARKER_NAME,
@@ -2935,7 +2935,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this); callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this);
if (isSuspensionPoint) { if (isSuspensionPoint) {
AsmUtil.pushDefaultValueOnStack(getSuspensionReturnTypeByResolvedCall(resolvedCall), v);
v.invokestatic( v.invokestatic(
CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER, CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
CoroutineCodegenUtilKt.AFTER_SUSPENSION_POINT_MARKER_NAME, "()V", false); CoroutineCodegenUtilKt.AFTER_SUSPENSION_POINT_MARKER_NAME, "()V", false);
@@ -2950,7 +2949,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
} }
@NotNull @NotNull
private Type getSuspensionReturnTypeByResolvedCall(@NotNull ResolvedCall<?> resolvedCall) { private Type getSuspensionBoxedReturnTypeByResolvedCall(@NotNull ResolvedCall<?> resolvedCall) {
assert resolvedCall.getResultingDescriptor() instanceof SimpleFunctionDescriptor assert resolvedCall.getResultingDescriptor() instanceof SimpleFunctionDescriptor
: "Suspension point resolved call should be built on SimpleFunctionDescriptor"; : "Suspension point resolved call should be built on SimpleFunctionDescriptor";
@@ -2963,7 +2962,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
KotlinType returnType = initialSignature.getReturnType(); KotlinType returnType = initialSignature.getReturnType();
assert returnType != null : "Return type of suspension point should not be null"; assert returnType != null : "Return type of suspension point should not be null";
return typeMapper.mapType(returnType); return typeMapper.mapType(TypeUtils.makeNullable(returnType));
} }
@NotNull @NotNull
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.codegen.optimization.common.analyzeLiveness import org.jetbrains.kotlin.codegen.optimization.common.analyzeLiveness
import org.jetbrains.kotlin.codegen.optimization.common.insnListOf import org.jetbrains.kotlin.codegen.optimization.common.insnListOf
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.utils.sure import org.jetbrains.kotlin.utils.sure
@@ -95,8 +96,10 @@ class CoroutineTransformerMethodVisitor(
spillVariables(suspensionPoints, methodNode) spillVariables(suspensionPoints, methodNode)
val suspendMarkerVarIndex = methodNode.maxLocals++
val suspensionPointLabels = suspensionPoints.withIndex().map { val suspensionPointLabels = suspensionPoints.withIndex().map {
transformCallAndReturnContinuationLabel(it.index + 1, it.value, methodNode) transformCallAndReturnContinuationLabel(it.index + 1, it.value, methodNode, suspendMarkerVarIndex)
} }
methodNode.instructions.apply { methodNode.instructions.apply {
@@ -116,6 +119,13 @@ class CoroutineTransformerMethodVisitor(
// tableswitch(this.label) // tableswitch(this.label)
insertBefore(firstToInsertBefore, insertBefore(firstToInsertBefore,
insnListOf( insnListOf(
FieldInsnNode(
Opcodes.GETSTATIC,
AsmTypes.COROUTINES_SUSPEND.internalName,
JvmAbi.INSTANCE_FIELD,
AsmTypes.COROUTINES_SUSPEND.descriptor
),
VarInsnNode(Opcodes.ASTORE, suspendMarkerVarIndex),
VarInsnNode(Opcodes.ALOAD, 0), VarInsnNode(Opcodes.ALOAD, 0),
FieldInsnNode( FieldInsnNode(
Opcodes.GETFIELD, Opcodes.GETFIELD,
@@ -178,20 +188,16 @@ class CoroutineTransformerMethodVisitor(
methodNode.instructions.remove(beforeSuspensionPointMarker.previous) methodNode.instructions.remove(beforeSuspensionPointMarker.previous)
beforeSuspensionPointMarker.desc = "()V" beforeSuspensionPointMarker.desc = "()V"
if (suspensionPoint.returnType != Type.VOID_TYPE) { assert(suspensionPoint.returnType != Type.VOID_TYPE) { "Suspension point can't be VOID" }
val previous = suspensionPoint.suspensionCallEnd.previous
assert(previous.opcode in DEFAULT_VALUE_OPCODES) {
"Expected on of default value bytecodes, but ${previous.opcode} was found"
}
fakeReturnValueInsns.add(previous)
if (previous.opcode == Opcodes.ACONST_NULL) { // Checkcast only is needed to tell analyzer what type exactly should be returned from suspension point
// Checkcast is needed to tell analyzer what type exactly should be returned from suspension point // This type is used when for restoring spilled variables into fields
val checkCast = TypeInsnNode(Opcodes.CHECKCAST, suspensionPoint.returnType.internalName) val checkCast = TypeInsnNode(Opcodes.CHECKCAST, suspensionPoint.returnType.internalName)
methodNode.instructions.insert(previous, checkCast) methodNode.instructions.insertBefore(
fakeReturnValueInsns.add(checkCast) suspensionPoint.suspensionCallEnd, checkCast
} )
}
fakeReturnValueInsns.add(checkCast)
} }
} }
} }
@@ -317,8 +323,14 @@ class CoroutineTransformerMethodVisitor(
return suspensionCallEnd.next as LabelNode return suspensionCallEnd.next as LabelNode
} }
private fun transformCallAndReturnContinuationLabel(id: Int, suspension: SuspensionPoint, methodNode: MethodNode): LabelNode { private fun transformCallAndReturnContinuationLabel(
id: Int,
suspension: SuspensionPoint,
methodNode: MethodNode,
suspendMarkerVarIndex: Int
): LabelNode {
val continuationLabel = LabelNode() val continuationLabel = LabelNode()
val continuationLabelAfterLoadedResult = LabelNode()
with(methodNode.instructions) { with(methodNode.instructions) {
// Save state // Save state
insertBefore(suspension.suspensionCallBegin, insertBefore(suspension.suspensionCallBegin,
@@ -336,6 +348,10 @@ class CoroutineTransformerMethodVisitor(
suspension.fakeReturnValueInsns.forEach { methodNode.instructions.remove(it) } suspension.fakeReturnValueInsns.forEach { methodNode.instructions.remove(it) }
insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter { insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter {
dup()
load(suspendMarkerVarIndex, AsmTypes.COROUTINES_SUSPEND)
ifacmpne(continuationLabelAfterLoadedResult.label)
// Exit // Exit
areturn(Type.VOID_TYPE) areturn(Type.VOID_TYPE)
// Mark place for continuation // Mark place for continuation
@@ -358,6 +374,8 @@ class CoroutineTransformerMethodVisitor(
// Load continuation argument just like suspending function returns it // Load continuation argument just like suspending function returns it
load(1, AsmTypes.OBJECT_TYPE) load(1, AsmTypes.OBJECT_TYPE)
visitLabel(continuationLabelAfterLoadedResult.label)
StackValue.coerce(AsmTypes.OBJECT_TYPE, suspension.returnType, this) StackValue.coerce(AsmTypes.OBJECT_TYPE, suspension.returnType, this)
}) })
} }
@@ -371,8 +389,7 @@ class CoroutineTransformerMethodVisitor(
// How suspension point area will look like after all transformations: // How suspension point area will look like after all transformations:
// <spill variables> // <spill variables>
// INVOKESTATIC beforeSuspensionMarker // INVOKESTATIC beforeSuspensionMarker
// INVOKEVIRTUAL suspensionMethod()V // INVOKEVIRTUAL suspensionMethod()Ljava/lang/Object;
// ACONST_NULL -- default value
// CHECKCAST SomeType // CHECKCAST SomeType
// INVOKESTATIC afterSuspensionMarker // INVOKESTATIC afterSuspensionMarker
// L1: -- end of all TCB's that are containing the suspension point (inserted by this method) // L1: -- end of all TCB's that are containing the suspension point (inserted by this method)
@@ -480,8 +497,7 @@ private fun Type.normalize() =
/** /**
* Suspension call may consists of several instructions: * Suspension call may consists of several instructions:
* INVOKESTATIC beforeSuspensionMarker * INVOKESTATIC beforeSuspensionMarker
* INVOKEVIRTUAL suspensionMethod()V // actually it could be some inline method instead of plain call * INVOKEVIRTUAL suspensionMethod()Ljava/lang/Object; // actually it could be some inline method instead of plain call
* ACONST_NULL // It's only needed when the suspension point returns something beside VOID
* CHECKCAST Type * CHECKCAST Type
* INVOKESTATIC afterSuspensionMarker * INVOKESTATIC afterSuspensionMarker
*/ */
@@ -189,7 +189,7 @@ fun ResolvedCall<*>.isSuspensionPoint(bindingContext: BindingContext) =
bindingContext[BindingContext.COROUTINE_RECEIVER_FOR_SUSPENSION_POINT, call] != null bindingContext[BindingContext.COROUTINE_RECEIVER_FOR_SUSPENSION_POINT, call] != null
// Suspend functions have irregular signatures on JVM, containing an additional last parameter with type `Continuation<return-type>`, // Suspend functions have irregular signatures on JVM, containing an additional last parameter with type `Continuation<return-type>`,
// and return type Unit (later it will be replaced with 'Any?') // and return type Any?
// This function returns a function descriptor reflecting how the suspend function looks from point of view of JVM // This function returns a function descriptor reflecting how the suspend function looks from point of view of JVM
fun <D : FunctionDescriptor> createJvmSuspendFunctionView(function: D): D { fun <D : FunctionDescriptor> createJvmSuspendFunctionView(function: D): D {
val continuationParameter = ValueParameterDescriptorImpl( val continuationParameter = ValueParameterDescriptorImpl(
@@ -201,7 +201,7 @@ fun <D : FunctionDescriptor> createJvmSuspendFunctionView(function: D): D {
return function.createCustomCopy { return function.createCustomCopy {
setPreserveSourceElement() setPreserveSourceElement()
setReturnType(function.builtIns.unitType) setReturnType(function.builtIns.nullableAnyType)
setValueParameters(it.valueParameters + continuationParameter) setValueParameters(it.valueParameters + continuationParameter)
putUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION, it) putUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION, it)
} }
@@ -288,8 +288,7 @@ fun createMethodNodeForSuspendWithCurrentContinuation(
"(${AsmTypes.OBJECT_TYPE})${AsmTypes.OBJECT_TYPE}", "(${AsmTypes.OBJECT_TYPE})${AsmTypes.OBJECT_TYPE}",
true true
) )
node.visitInsn(Opcodes.POP) node.visitInsn(Opcodes.ARETURN)
node.visitInsn(Opcodes.RETURN)
node.visitMaxs(2, 2) node.visitMaxs(2, 2)
return node return node
@@ -41,6 +41,7 @@ public class AsmTypes {
public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1"); public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1");
public static final Type MUTABLE_PROPERTY_REFERENCE2 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference2"); public static final Type MUTABLE_PROPERTY_REFERENCE2 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference2");
public static final Type COROUTINE_IMPL = Type.getObjectType("kotlin/jvm/internal/CoroutineImpl"); public static final Type COROUTINE_IMPL = Type.getObjectType("kotlin/jvm/internal/CoroutineImpl");
public static final Type COROUTINES_SUSPEND = Type.getObjectType("kotlin/coroutines/Suspend");
public static final Type[] PROPERTY_REFERENCE_IMPL = { public static final Type[] PROPERTY_REFERENCE_IMPL = {
@@ -7,7 +7,7 @@ class Controller {
exception = t exception = t
} }
suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x ->} suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x -> }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
} }
@@ -7,6 +7,7 @@ class Controller {
suspend fun <T> await(t: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> await(t: T): T = suspendWithCurrentContinuation { c ->
c.resume(t) c.resume(t)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -7,6 +7,7 @@ class Controller {
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
c.resume(value) c.resume(value)
Suspend
} }
} }
@@ -7,6 +7,7 @@ class Controller {
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
c.resume(value) c.resume(value)
Suspend
} }
} }
@@ -7,6 +7,7 @@ class Controller {
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
c.resume(value) c.resume(value)
Suspend
} }
} }
@@ -7,6 +7,7 @@ class Controller {
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
c.resume(value) c.resume(value)
Suspend
} }
} }
@@ -7,6 +7,7 @@ class Controller {
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
c.resume(value) c.resume(value)
Suspend
} }
} }
@@ -7,6 +7,7 @@ class Controller {
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
c.resume(value) c.resume(value)
Suspend
} }
} }
@@ -12,6 +12,7 @@ class Controller {
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c ->
result += "suspend($value);" result += "suspend($value);"
c.resume(value) c.resume(value)
Suspend
} }
operator fun handleResult(value: String, c: Continuation<Nothing>) { operator fun handleResult(value: String, c: Continuation<Nothing>) {
@@ -8,6 +8,7 @@ class Controller {
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
result += "[" result += "["
c.resume(value) c.resume(value)
Suspend
} }
} }
@@ -8,11 +8,13 @@ class Controller {
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c ->
result += "suspend($value);" result += "suspend($value);"
c.resume(value) c.resume(value)
Suspend
} }
suspend fun suspendLogAndThrow(exception: Throwable): Nothing = suspendWithCurrentContinuation { c -> suspend fun suspendLogAndThrow(exception: Throwable): Nothing = suspendWithCurrentContinuation { c ->
result += "throw(${exception.message});" result += "throw(${exception.message});"
c.resumeWithException(exception) c.resumeWithException(exception)
Suspend
} }
operator fun handleException(exception: Throwable, c: Continuation<Nothing>) { operator fun handleException(exception: Throwable, c: Continuation<Nothing>) {
@@ -8,6 +8,7 @@ class Controller {
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c ->
result += "suspend($value);" result += "suspend($value);"
c.resume(value) c.resume(value)
Suspend
} }
operator fun handleException(exception: Throwable, c: Continuation<Nothing>) { operator fun handleException(exception: Throwable, c: Continuation<Nothing>) {
@@ -7,6 +7,7 @@ class Controller {
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
c.resume(value) c.resume(value)
Suspend
} }
} }
@@ -3,6 +3,7 @@ class Controller {
var result = false var result = false
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
fun foo() { fun foo() {
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(a: String = "abc", i: Int = 2): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(a: String = "abc", i: Int = 2): String = suspendWithCurrentContinuation { x ->
x.resume(a + "#" + (i + 1)) x.resume(a + "#" + (i + 1))
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -5,6 +5,7 @@ class Controller {
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
result++ result++
x.resume("OK") x.resume("OK")
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun <T> suspendHere(v: T): T = suspendWithCurrentContinuation { x -> suspend fun <T> suspendHere(v: T): T = suspendWithCurrentContinuation { x ->
x.resume(v) x.resume(v)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
+2
View File
@@ -47,6 +47,8 @@ class GeneratorController<T>() : AbstractIterator<T>() {
suspend fun yield(value: T): Unit = suspendWithCurrentContinuation { c -> suspend fun yield(value: T): Unit = suspendWithCurrentContinuation { c ->
setNext(value) setNext(value)
setNextStep(c) setNextStep(c)
Suspend
} }
operator fun handleResult(result: Unit, c: Continuation<Nothing>) { operator fun handleResult(result: Unit, c: Continuation<Nothing>) {
@@ -8,12 +8,16 @@ class Controller {
postponedActions.add { postponedActions.add {
x.resume(v) x.resume(v)
} }
Suspend
} }
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
postponedActions.add { postponedActions.add {
x.resumeWithException(e) x.resumeWithException(e)
} }
Suspend
} }
operator fun handleException(t: Throwable, c: Continuation<Nothing>) { operator fun handleException(t: Throwable, c: Continuation<Nothing>) {
@@ -3,6 +3,7 @@ class Controller {
var isCompleted = false var isCompleted = false
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
operator fun handleResult(x: Unit, y: Continuation<Nothing>) { operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
@@ -5,6 +5,7 @@ class Controller {
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { x -> suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { x ->
log += "suspend($value);" log += "suspend($value);"
x.resume(value) x.resume(value)
Suspend
} }
operator fun handleResult(value: String, y: Continuation<Nothing>) { operator fun handleResult(value: String, y: Continuation<Nothing>) {
@@ -5,6 +5,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
} }
@@ -11,6 +11,7 @@ class Controller {
suspend inline fun suspendInline(v: String): String = suspendWithCurrentContinuation { x -> suspend inline fun suspendInline(v: String): String = suspendWithCurrentContinuation { x ->
withValue(v, x) withValue(v, x)
Suspend
} }
suspend inline fun suspendInline(crossinline b: () -> String): String = suspendInline(b()) suspend inline fun suspendInline(crossinline b: () -> String): String = suspendInline(b())
@@ -9,12 +9,16 @@ class Controller {
postponedActions.add { postponedActions.add {
x.resume(v) x.resume(v)
} }
Suspend
} }
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
postponedActions.add { postponedActions.add {
x.resumeWithException(e) x.resumeWithException(e)
} }
Suspend
} }
operator fun handleResult(x: String, c: Continuation<Nothing>) { operator fun handleResult(x: String, c: Continuation<Nothing>) {
@@ -3,6 +3,7 @@ class Controller {
var i = 0 var i = 0
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume((i++).toString()) x.resume((i++).toString())
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -6,11 +6,13 @@ class Controller {
suspend fun runInstanceOf(): Boolean = suspendWithCurrentContinuation { x -> suspend fun runInstanceOf(): Boolean = suspendWithCurrentContinuation { x ->
val y: Any = x val y: Any = x
x.resume(x is Continuation<*>) x.resume(x is Continuation<*>)
Suspend
} }
suspend fun runCast(): Boolean = suspendWithCurrentContinuation { x -> suspend fun runCast(): Boolean = suspendWithCurrentContinuation { x ->
val y: Any = x val y: Any = x
x.resume(Continuation::class.isInstance(y as Continuation<*>)) x.resume(Continuation::class.isInstance(y as Continuation<*>))
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -4,6 +4,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -4,6 +4,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
x.resume(Unit) x.resume(Unit)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
+1
View File
@@ -3,6 +3,7 @@ class Controller {
var result = "fail" var result = "fail"
suspend fun <V> suspendHere(v: V): V = suspendWithCurrentContinuation { x -> suspend fun <V> suspendHere(v: V): V = suspendWithCurrentContinuation { x ->
x.resume(v) x.resume(v)
Suspend
} }
operator fun handleResult(x: String, c: Continuation<Nothing>) { operator fun handleResult(x: String, c: Continuation<Nothing>) {
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x ->
x.resume(v) x.resume(v)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -5,6 +5,7 @@ class Controller {
suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x ->
result += v result += v
x.resume(Unit) x.resume(Unit)
Suspend
} }
operator fun handleResult(u: Unit, v: Continuation<Nothing>) { operator fun handleResult(u: Unit, v: Continuation<Nothing>) {
@@ -3,6 +3,7 @@ class Controller {
var wasHandleResultCalled = false var wasHandleResultCalled = false
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
operator fun handleResult(x: Unit, y: Continuation<Nothing>) { operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
@@ -3,6 +3,7 @@ class Controller {
var wasHandleResultCalled = false var wasHandleResultCalled = false
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
operator fun handleResult(x: Unit, y: Continuation<Nothing>) { operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
@@ -5,6 +5,7 @@ class Controller {
suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x -> suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x ->
this.v = v this.v = v
x.resume(Unit) x.resume(Unit)
Suspend
} }
operator fun handleResult(u: Unit, v: Continuation<Nothing>) { operator fun handleResult(u: Unit, v: Continuation<Nothing>) {
@@ -3,6 +3,7 @@
class Controller { class Controller {
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -6,6 +6,7 @@ package lib
class Controller { class Controller {
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -7,6 +7,7 @@ package lib
class Controller { class Controller {
suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume(this) x.resume(this)
Suspend
} }
inline suspend fun String.inlineSuspendHere(): String = suspendHere() inline suspend fun String.inlineSuspendHere(): String = suspendHere()
@@ -4,7 +4,7 @@ class Controller {
var result = "fail" var result = "fail"
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
lastSuspension = x lastSuspension = x
Unit Suspend
} }
fun hasNext() = lastSuspension != null fun hasNext() = lastSuspension != null
@@ -4,7 +4,7 @@ class Controller {
var result = "fail" var result = "fail"
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
lastSuspension = x lastSuspension = x
Unit Suspend
} }
fun hasNext() = lastSuspension != null fun hasNext() = lastSuspension != null
@@ -4,7 +4,7 @@ class Controller {
var result = "fail" var result = "fail"
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
lastSuspension = x lastSuspension = x
Unit Suspend
} }
fun hasNext() = lastSuspension != null fun hasNext() = lastSuspension != null
@@ -4,7 +4,7 @@ class Controller {
var result = "fail" var result = "fail"
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
lastSuspension = x lastSuspension = x
Unit Suspend
} }
fun hasNext() = lastSuspension != null fun hasNext() = lastSuspension != null
@@ -9,12 +9,16 @@ class Controller {
postponedActions.add { postponedActions.add {
x.resume(v) x.resume(v)
} }
Suspend
} }
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
postponedActions.add { postponedActions.add {
x.resumeWithException(e) x.resumeWithException(e)
} }
Suspend
} }
operator fun handleResult(x: String, c: Continuation<Nothing>) { operator fun handleResult(x: String, c: Continuation<Nothing>) {
@@ -3,6 +3,7 @@ class Controller {
var cResult = 0 var cResult = 0
suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x -> suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x ->
x.resume(v * 2) x.resume(v * 2)
Suspend
} }
operator fun handleResult(x: Int, y: Continuation<Nothing>) { operator fun handleResult(x: Int, y: Continuation<Nothing>) {
@@ -5,6 +5,7 @@ class Controller {
var cResult = 0 var cResult = 0
suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x -> suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x ->
x.resume(v * 2) x.resume(v * 2)
Suspend
} }
operator fun handleResult(x: Int, y: Continuation<Nothing>) { operator fun handleResult(x: Int, y: Continuation<Nothing>) {
@@ -3,6 +3,7 @@ class Controller {
var res = 0 var res = 0
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
operator fun handleResult(x: Int, y: Continuation<Nothing>) { operator fun handleResult(x: Int, y: Continuation<Nothing>) {
+1
View File
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resumeWithException(RuntimeException("OK")) x.resumeWithException(RuntimeException("OK"))
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -3,6 +3,7 @@ class Controller {
var res = 0 var res = 0
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
operator fun handleResult(x: Int, y: Continuation<Nothing>) { operator fun handleResult(x: Int, y: Continuation<Nothing>) {
@@ -0,0 +1,19 @@
class Controller {
suspend fun suspendHere(): String = throw RuntimeException("OK")
// INTERCEPT_RESUME_PLACEHOLDER
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
c(Controller()).resume(Unit)
}
fun box(): String {
var result = ""
builder {
result = try { suspendHere() } catch (e: RuntimeException) { e.message!! }
}
return result
}
@@ -0,0 +1,36 @@
// WITH_RUNTIME
// WITH_REFLECT
// CHECK_NOT_CALLED: suspendInline_die06n$
// CHECK_NOT_CALLED: suspendInline_nesahw$
// CHECK_NOT_CALLED: suspendInline_grpnnl$
class Controller {
suspend inline fun suspendInline(v: String): String = v
suspend inline fun suspendInline(crossinline b: () -> String): String = suspendInline(b())
suspend inline fun <reified T : Any> suspendInline(): String = suspendInline({ T::class.simpleName!! })
// INTERCEPT_RESUME_PLACEHOLDER
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
c(Controller()).resume(Unit)
}
class OK
fun box(): String {
var result = ""
builder {
result = suspendInline("56")
if (result != "56") throw RuntimeException("fail 1")
result = suspendInline { "57" }
if (result != "57") throw RuntimeException("fail 2")
result = suspendInline<OK>()
}
return result
}
@@ -0,0 +1,19 @@
class Controller {
suspend fun suspendHere() = "OK"
// INTERCEPT_RESUME_PLACEHOLDER
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
c(Controller()).resume(Unit)
}
fun box(): String {
var result = ""
builder {
result = suspendHere()
}
return result
}
@@ -0,0 +1,47 @@
// IGNORE_BACKEND: JS
class Controller {
suspend fun suspendHere(): Int = suspendWithCurrentContinuation { x ->
1
}
suspend fun suspendThere(): String = suspendWithCurrentContinuation { x ->
"?"
}
// INTERCEPT_RESUME_PLACEHOLDER
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
c(Controller()).resume(Unit)
}
fun box(): String {
var result = ""
builder {
result += "-"
for (i in 0..10000) {
if (i % 2 == 0) {
result += suspendHere().toString()
}
else if (i == 3) {
result += suspendThere()
}
}
result += "+"
}
var mustBe = "-"
for (i in 0..10000) {
if (i % 2 == 0) {
mustBe += "1"
}
else if (i == 3) {
mustBe += "?"
}
}
mustBe += "+"
if (result != mustBe) return "fail: $result/$mustBe"
return "OK"
}
@@ -3,6 +3,7 @@ var globalResult = ""
class Controller { class Controller {
suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x -> suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x ->
x.resume(v) x.resume(v)
Suspend
} }
operator fun handleResult(x: String, c: Continuation<Nothing>) { operator fun handleResult(x: String, c: Continuation<Nothing>) {
@@ -4,6 +4,7 @@ class Controller {
suspend fun suspendThere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendThere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -3,6 +3,7 @@
class Controller { class Controller {
suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume(this) x.resume(this)
Suspend
} }
inline suspend fun String.inlineSuspendHere(): String = suspendHere() inline suspend fun String.inlineSuspendHere(): String = suspendHere()
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x -> suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x ->
x.resume(v * 2) x.resume(v * 2)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -3,9 +3,11 @@ class Controller {
var i = 0 var i = 0
suspend fun suspendHere(): Int = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): Int = suspendWithCurrentContinuation { x ->
x.resume(i++) x.resume(i++)
Suspend
} }
suspend fun suspendThere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendThere(): String = suspendWithCurrentContinuation { x ->
x.resume("?") x.resume("?")
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,14 +2,17 @@
class Controller { class Controller {
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("K") x.resume("K")
Suspend
} }
suspend fun suspendWithArgument(v: String): String = suspendWithCurrentContinuation { x -> suspend fun suspendWithArgument(v: String): String = suspendWithCurrentContinuation { x ->
x.resume(v) x.resume(v)
Suspend
} }
suspend fun suspendWithDouble(v: Double): Double = suspendWithCurrentContinuation { x -> suspend fun suspendWithDouble(v: Double): Double = suspendWithCurrentContinuation { x ->
x.resume(v) x.resume(v)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -9,12 +9,16 @@ class Controller {
postponedActions.add { postponedActions.add {
x.resume(v) x.resume(v)
} }
Suspend
} }
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
postponedActions.add { postponedActions.add {
x.resumeWithException(e) x.resumeWithException(e)
} }
Suspend
} }
operator fun handleResult(x: String, c: Continuation<Nothing>) { operator fun handleResult(x: String, c: Continuation<Nothing>) {
@@ -9,12 +9,16 @@ class Controller {
postponedActions.add { postponedActions.add {
x.resume(v) x.resume(v)
} }
Suspend
} }
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
postponedActions.add { postponedActions.add {
x.resumeWithException(e) x.resumeWithException(e)
} }
Suspend
} }
operator fun handleResult(x: String, c: Continuation<Nothing>) { operator fun handleResult(x: String, c: Continuation<Nothing>) {
@@ -2,6 +2,8 @@
class Controller { class Controller {
suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x ->
x.resume(v) x.resume(v)
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -9,12 +9,16 @@ class Controller {
postponedActions.add { postponedActions.add {
x.resume(v) x.resume(v)
} }
Suspend
} }
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
postponedActions.add { postponedActions.add {
x.resumeWithException(e) x.resumeWithException(e)
} }
Suspend
} }
operator fun handleResult(x: String, c: Continuation<Nothing>) { operator fun handleResult(x: String, c: Continuation<Nothing>) {
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -2,6 +2,7 @@
class Controller { class Controller {
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
// INTERCEPT_RESUME_PLACEHOLDER // INTERCEPT_RESUME_PLACEHOLDER
@@ -1,7 +1,7 @@
@kotlin.Metadata @kotlin.Metadata
public final class Controller { public final class Controller {
public method <init>(): void public method <init>(): void
public final method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): void public final @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
} }
@kotlin.Metadata @kotlin.Metadata
+2 -1
View File
@@ -19,4 +19,5 @@ fun box(): String {
} }
// 1 GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit; // 1 GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
// 1 GETSTATIC // 1 GETSTATIC kotlin/coroutines/Suspend.INSTANCE
// 2 GETSTATIC
+2
View File
@@ -60,6 +60,8 @@ class FutureController<T> {
else else
machine.resumeWithException(throwable) machine.resumeWithException(throwable)
} }
Suspend
} }
operator fun handleResult(value: T, c: Continuation<Nothing>) { operator fun handleResult(value: T, c: Continuation<Nothing>) {
+2
View File
@@ -56,6 +56,8 @@ class FutureController<T> {
else else
machine.resumeWithException(throwable) machine.resumeWithException(throwable)
} }
Suspend
} }
operator fun handleResult(value: T, c: Continuation<Nothing>) { operator fun handleResult(value: T, c: Continuation<Nothing>) {
@@ -3,6 +3,7 @@ package a
class Controller { class Controller {
suspend fun suspendHere() = suspendWithCurrentContinuation<String> { x -> suspend fun suspendHere() = suspendWithCurrentContinuation<String> { x ->
x.resume("OK") x.resume("OK")
Suspend
} }
} }
@@ -4945,6 +4945,39 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName); doTest(fileName);
} }
} }
@TestMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class StackUnwinding extends AbstractIrBlackBoxCodegenTest {
public void testAllFilesPresentInStackUnwinding() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/stackUnwinding"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("exception.kt")
public void testException() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/exception.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendFunction.kt")
public void testInlineSuspendFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/inlineSuspendFunction.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/simple.kt");
doTest(fileName);
}
@TestMetadata("suspendInCycle.kt")
public void testSuspendInCycle() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/suspendInCycle.kt");
doTest(fileName);
}
}
} }
@TestMetadata("compiler/testData/codegen/box/dataClasses") @TestMetadata("compiler/testData/codegen/box/dataClasses")
@@ -423,4 +423,37 @@ public class AdditionalCoroutineBlackBoxCodegenTestGenerated extends AbstractAdd
doTest(fileName); doTest(fileName);
} }
} }
@TestMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class StackUnwinding extends AbstractAdditionalCoroutineBlackBoxCodegenTest {
public void testAllFilesPresentInStackUnwinding() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/stackUnwinding"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("exception.kt")
public void testException() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/exception.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendFunction.kt")
public void testInlineSuspendFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/inlineSuspendFunction.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/simple.kt");
doTest(fileName);
}
@TestMetadata("suspendInCycle.kt")
public void testSuspendInCycle() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/suspendInCycle.kt");
doTest(fileName);
}
}
} }
@@ -4945,6 +4945,39 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName); doTest(fileName);
} }
} }
@TestMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class StackUnwinding extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInStackUnwinding() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/stackUnwinding"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("exception.kt")
public void testException() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/exception.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendFunction.kt")
public void testInlineSuspendFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/inlineSuspendFunction.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/simple.kt");
doTest(fileName);
}
@TestMetadata("suspendInCycle.kt")
public void testSuspendInCycle() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/suspendInCycle.kt");
doTest(fileName);
}
}
} }
@TestMetadata("compiler/testData/codegen/box/dataClasses") @TestMetadata("compiler/testData/codegen/box/dataClasses")
@@ -6152,6 +6152,45 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
} }
} }
@TestMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class StackUnwinding extends AbstractJsCodegenBoxTest {
public void testAllFilesPresentInStackUnwinding() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/stackUnwinding"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("exception.kt")
public void testException() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/exception.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendFunction.kt")
public void testInlineSuspendFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/inlineSuspendFunction.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/simple.kt");
doTest(fileName);
}
@TestMetadata("suspendInCycle.kt")
public void testSuspendInCycle() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding/suspendInCycle.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
}
} }
@TestMetadata("compiler/testData/codegen/box/dataClasses") @TestMetadata("compiler/testData/codegen/box/dataClasses")