Support coroutines stack-unwinding in JVM backend
#KT-14924 In Progress
This commit is contained in:
@@ -2810,7 +2810,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
if (CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, bindingContext)) {
|
||||
// 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;
|
||||
@@ -2925,7 +2925,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
if (isSuspensionPoint) {
|
||||
v.tconst(getSuspensionReturnTypeByResolvedCall(resolvedCall));
|
||||
v.tconst(getSuspensionBoxedReturnTypeByResolvedCall(resolvedCall));
|
||||
v.invokestatic(
|
||||
CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
|
||||
CoroutineCodegenUtilKt.BEFORE_SUSPENSION_POINT_MARKER_NAME,
|
||||
@@ -2935,7 +2935,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this);
|
||||
|
||||
if (isSuspensionPoint) {
|
||||
AsmUtil.pushDefaultValueOnStack(getSuspensionReturnTypeByResolvedCall(resolvedCall), v);
|
||||
v.invokestatic(
|
||||
CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
|
||||
CoroutineCodegenUtilKt.AFTER_SUSPENSION_POINT_MARKER_NAME, "()V", false);
|
||||
@@ -2950,7 +2949,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Type getSuspensionReturnTypeByResolvedCall(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
private Type getSuspensionBoxedReturnTypeByResolvedCall(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
assert resolvedCall.getResultingDescriptor() instanceof 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();
|
||||
|
||||
assert returnType != null : "Return type of suspension point should not be null";
|
||||
return typeMapper.mapType(returnType);
|
||||
return typeMapper.mapType(TypeUtils.makeNullable(returnType));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+35
-19
@@ -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.insnListOf
|
||||
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.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
@@ -95,8 +96,10 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
spillVariables(suspensionPoints, methodNode)
|
||||
|
||||
val suspendMarkerVarIndex = methodNode.maxLocals++
|
||||
|
||||
val suspensionPointLabels = suspensionPoints.withIndex().map {
|
||||
transformCallAndReturnContinuationLabel(it.index + 1, it.value, methodNode)
|
||||
transformCallAndReturnContinuationLabel(it.index + 1, it.value, methodNode, suspendMarkerVarIndex)
|
||||
}
|
||||
|
||||
methodNode.instructions.apply {
|
||||
@@ -116,6 +119,13 @@ class CoroutineTransformerMethodVisitor(
|
||||
// tableswitch(this.label)
|
||||
insertBefore(firstToInsertBefore,
|
||||
insnListOf(
|
||||
FieldInsnNode(
|
||||
Opcodes.GETSTATIC,
|
||||
AsmTypes.COROUTINES_SUSPEND.internalName,
|
||||
JvmAbi.INSTANCE_FIELD,
|
||||
AsmTypes.COROUTINES_SUSPEND.descriptor
|
||||
),
|
||||
VarInsnNode(Opcodes.ASTORE, suspendMarkerVarIndex),
|
||||
VarInsnNode(Opcodes.ALOAD, 0),
|
||||
FieldInsnNode(
|
||||
Opcodes.GETFIELD,
|
||||
@@ -178,20 +188,16 @@ class CoroutineTransformerMethodVisitor(
|
||||
methodNode.instructions.remove(beforeSuspensionPointMarker.previous)
|
||||
beforeSuspensionPointMarker.desc = "()V"
|
||||
|
||||
if (suspensionPoint.returnType != Type.VOID_TYPE) {
|
||||
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)
|
||||
assert(suspensionPoint.returnType != Type.VOID_TYPE) { "Suspension point can't be VOID" }
|
||||
|
||||
if (previous.opcode == Opcodes.ACONST_NULL) {
|
||||
// Checkcast is needed to tell analyzer what type exactly should be returned from suspension point
|
||||
val checkCast = TypeInsnNode(Opcodes.CHECKCAST, suspensionPoint.returnType.internalName)
|
||||
methodNode.instructions.insert(previous, checkCast)
|
||||
fakeReturnValueInsns.add(checkCast)
|
||||
}
|
||||
}
|
||||
// Checkcast only 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)
|
||||
methodNode.instructions.insertBefore(
|
||||
suspensionPoint.suspensionCallEnd, checkCast
|
||||
)
|
||||
|
||||
fakeReturnValueInsns.add(checkCast)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,8 +323,14 @@ class CoroutineTransformerMethodVisitor(
|
||||
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 continuationLabelAfterLoadedResult = LabelNode()
|
||||
with(methodNode.instructions) {
|
||||
// Save state
|
||||
insertBefore(suspension.suspensionCallBegin,
|
||||
@@ -336,6 +348,10 @@ class CoroutineTransformerMethodVisitor(
|
||||
suspension.fakeReturnValueInsns.forEach { methodNode.instructions.remove(it) }
|
||||
|
||||
insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter {
|
||||
dup()
|
||||
load(suspendMarkerVarIndex, AsmTypes.COROUTINES_SUSPEND)
|
||||
ifacmpne(continuationLabelAfterLoadedResult.label)
|
||||
|
||||
// Exit
|
||||
areturn(Type.VOID_TYPE)
|
||||
// Mark place for continuation
|
||||
@@ -358,6 +374,8 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
// Load continuation argument just like suspending function returns it
|
||||
load(1, AsmTypes.OBJECT_TYPE)
|
||||
|
||||
visitLabel(continuationLabelAfterLoadedResult.label)
|
||||
StackValue.coerce(AsmTypes.OBJECT_TYPE, suspension.returnType, this)
|
||||
})
|
||||
}
|
||||
@@ -371,8 +389,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
// How suspension point area will look like after all transformations:
|
||||
// <spill variables>
|
||||
// INVOKESTATIC beforeSuspensionMarker
|
||||
// INVOKEVIRTUAL suspensionMethod()V
|
||||
// ACONST_NULL -- default value
|
||||
// INVOKEVIRTUAL suspensionMethod()Ljava/lang/Object;
|
||||
// CHECKCAST SomeType
|
||||
// INVOKESTATIC afterSuspensionMarker
|
||||
// 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:
|
||||
* INVOKESTATIC beforeSuspensionMarker
|
||||
* INVOKEVIRTUAL suspensionMethod()V // 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
|
||||
* INVOKEVIRTUAL suspensionMethod()Ljava/lang/Object; // actually it could be some inline method instead of plain call
|
||||
* CHECKCAST Type
|
||||
* INVOKESTATIC afterSuspensionMarker
|
||||
*/
|
||||
|
||||
+3
-4
@@ -189,7 +189,7 @@ fun ResolvedCall<*>.isSuspensionPoint(bindingContext: BindingContext) =
|
||||
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>`,
|
||||
// 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
|
||||
fun <D : FunctionDescriptor> createJvmSuspendFunctionView(function: D): D {
|
||||
val continuationParameter = ValueParameterDescriptorImpl(
|
||||
@@ -201,7 +201,7 @@ fun <D : FunctionDescriptor> createJvmSuspendFunctionView(function: D): D {
|
||||
|
||||
return function.createCustomCopy {
|
||||
setPreserveSourceElement()
|
||||
setReturnType(function.builtIns.unitType)
|
||||
setReturnType(function.builtIns.nullableAnyType)
|
||||
setValueParameters(it.valueParameters + continuationParameter)
|
||||
putUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION, it)
|
||||
}
|
||||
@@ -288,8 +288,7 @@ fun createMethodNodeForSuspendWithCurrentContinuation(
|
||||
"(${AsmTypes.OBJECT_TYPE})${AsmTypes.OBJECT_TYPE}",
|
||||
true
|
||||
)
|
||||
node.visitInsn(Opcodes.POP)
|
||||
node.visitInsn(Opcodes.RETURN)
|
||||
node.visitInsn(Opcodes.ARETURN)
|
||||
node.visitMaxs(2, 2)
|
||||
|
||||
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_REFERENCE2 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference2");
|
||||
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 = {
|
||||
|
||||
@@ -7,7 +7,7 @@ class Controller {
|
||||
exception = t
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x ->}
|
||||
suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x -> }
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ class Controller {
|
||||
|
||||
suspend fun <T> await(t: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(t)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -7,6 +7,7 @@ class Controller {
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ class Controller {
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ class Controller {
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ class Controller {
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ class Controller {
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ class Controller {
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ class Controller {
|
||||
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
result += "suspend($value);"
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(value: String, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -8,6 +8,7 @@ class Controller {
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
result += "["
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@ class Controller {
|
||||
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
result += "suspend($value);"
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun suspendLogAndThrow(exception: Throwable): Nothing = suspendWithCurrentContinuation { c ->
|
||||
result += "throw(${exception.message});"
|
||||
c.resumeWithException(exception)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleException(exception: Throwable, c: Continuation<Nothing>) {
|
||||
|
||||
+1
@@ -8,6 +8,7 @@ class Controller {
|
||||
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
result += "suspend($value);"
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleException(exception: Throwable, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -7,6 +7,7 @@ class Controller {
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ class Controller {
|
||||
var result = false
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(a: String = "abc", i: Int = 2): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(a + "#" + (i + 1))
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -5,6 +5,7 @@ class Controller {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
result++
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun <T> suspendHere(v: T): T = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -47,6 +47,8 @@ class GeneratorController<T>() : AbstractIterator<T>() {
|
||||
suspend fun yield(value: T): Unit = suspendWithCurrentContinuation { c ->
|
||||
setNext(value)
|
||||
setNextStep(c)
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(result: Unit, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -8,12 +8,16 @@ class Controller {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleException(t: Throwable, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -3,6 +3,7 @@ class Controller {
|
||||
var isCompleted = false
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
|
||||
|
||||
@@ -5,6 +5,7 @@ class Controller {
|
||||
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { x ->
|
||||
log += "suspend($value);"
|
||||
x.resume(value)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(value: String, y: Continuation<Nothing>) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ class Controller {
|
||||
|
||||
suspend inline fun suspendInline(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
withValue(v, x)
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend inline fun suspendInline(crossinline b: () -> String): String = suspendInline(b())
|
||||
|
||||
@@ -9,12 +9,16 @@ class Controller {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -3,6 +3,7 @@ class Controller {
|
||||
var i = 0
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume((i++).toString())
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -6,11 +6,13 @@ class Controller {
|
||||
suspend fun runInstanceOf(): Boolean = suspendWithCurrentContinuation { x ->
|
||||
val y: Any = x
|
||||
x.resume(x is Continuation<*>)
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun runCast(): Boolean = suspendWithCurrentContinuation { x ->
|
||||
val y: Any = x
|
||||
x.resume(Continuation::class.isInstance(y as Continuation<*>))
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
+1
@@ -4,6 +4,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -3,6 +3,7 @@ class Controller {
|
||||
var result = "fail"
|
||||
suspend fun <V> suspendHere(v: V): V = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -5,6 +5,7 @@ class Controller {
|
||||
suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x ->
|
||||
result += v
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(u: Unit, v: Continuation<Nothing>) {
|
||||
|
||||
@@ -3,6 +3,7 @@ class Controller {
|
||||
var wasHandleResultCalled = false
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
|
||||
|
||||
@@ -3,6 +3,7 @@ class Controller {
|
||||
var wasHandleResultCalled = false
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
|
||||
|
||||
@@ -5,6 +5,7 @@ class Controller {
|
||||
suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x ->
|
||||
this.v = v
|
||||
x.resume(Unit)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(u: Unit, v: Continuation<Nothing>) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -6,6 +6,7 @@ package lib
|
||||
class Controller {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -7,6 +7,7 @@ package lib
|
||||
class Controller {
|
||||
suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(this)
|
||||
Suspend
|
||||
}
|
||||
|
||||
inline suspend fun String.inlineSuspendHere(): String = suspendHere()
|
||||
|
||||
@@ -4,7 +4,7 @@ class Controller {
|
||||
var result = "fail"
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
lastSuspension = x
|
||||
Unit
|
||||
Suspend
|
||||
}
|
||||
|
||||
fun hasNext() = lastSuspension != null
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ class Controller {
|
||||
var result = "fail"
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
lastSuspension = x
|
||||
Unit
|
||||
Suspend
|
||||
}
|
||||
|
||||
fun hasNext() = lastSuspension != null
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ class Controller {
|
||||
var result = "fail"
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
lastSuspension = x
|
||||
Unit
|
||||
Suspend
|
||||
}
|
||||
|
||||
fun hasNext() = lastSuspension != null
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ class Controller {
|
||||
var result = "fail"
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
lastSuspension = x
|
||||
Unit
|
||||
Suspend
|
||||
}
|
||||
|
||||
fun hasNext() = lastSuspension != null
|
||||
|
||||
@@ -9,12 +9,16 @@ class Controller {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -3,6 +3,7 @@ class Controller {
|
||||
var cResult = 0
|
||||
suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v * 2)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: Int, y: Continuation<Nothing>) {
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ class Controller {
|
||||
var cResult = 0
|
||||
suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v * 2)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: Int, y: Continuation<Nothing>) {
|
||||
|
||||
@@ -3,6 +3,7 @@ class Controller {
|
||||
var res = 0
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: Int, y: Continuation<Nothing>) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resumeWithException(RuntimeException("OK"))
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -3,6 +3,7 @@ class Controller {
|
||||
var res = 0
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
+36
@@ -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 {
|
||||
suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -4,6 +4,7 @@ class Controller {
|
||||
|
||||
suspend fun suspendThere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class Controller {
|
||||
suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(this)
|
||||
Suspend
|
||||
}
|
||||
|
||||
inline suspend fun String.inlineSuspendHere(): String = suspendHere()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v * 2)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -3,9 +3,11 @@ class Controller {
|
||||
var i = 0
|
||||
suspend fun suspendHere(): Int = suspendWithCurrentContinuation { x ->
|
||||
x.resume(i++)
|
||||
Suspend
|
||||
}
|
||||
suspend fun suspendThere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("?")
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
+3
@@ -2,14 +2,17 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("K")
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun suspendWithArgument(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun suspendWithDouble(v: Double): Double = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -9,12 +9,16 @@ class Controller {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -9,12 +9,16 @@ class Controller {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -9,12 +9,16 @@ class Controller {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@kotlin.Metadata
|
||||
public final class Controller {
|
||||
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
|
||||
|
||||
@@ -19,4 +19,5 @@ fun box(): String {
|
||||
}
|
||||
|
||||
// 1 GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
|
||||
// 1 GETSTATIC
|
||||
// 1 GETSTATIC kotlin/coroutines/Suspend.INSTANCE
|
||||
// 2 GETSTATIC
|
||||
|
||||
@@ -60,6 +60,8 @@ class FutureController<T> {
|
||||
else
|
||||
machine.resumeWithException(throwable)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(value: T, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -56,6 +56,8 @@ class FutureController<T> {
|
||||
else
|
||||
machine.resumeWithException(throwable)
|
||||
}
|
||||
|
||||
Suspend
|
||||
}
|
||||
|
||||
operator fun handleResult(value: T, c: Continuation<Nothing>) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package a
|
||||
class Controller {
|
||||
suspend fun suspendHere() = suspendWithCurrentContinuation<String> { x ->
|
||||
x.resume("OK")
|
||||
Suspend
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+33
@@ -4945,6 +4945,39 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
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")
|
||||
|
||||
+33
@@ -423,4 +423,37 @@ public class AdditionalCoroutineBlackBoxCodegenTestGenerated extends AbstractAdd
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@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")
|
||||
|
||||
+39
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
@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")
|
||||
|
||||
Reference in New Issue
Block a user