Support non-tail suspend calls in JVM back-end
#KT-15597 In Progress
This commit is contained in:
@@ -198,7 +198,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
);
|
||||
}
|
||||
|
||||
private void generateBridges() {
|
||||
protected void generateBridges() {
|
||||
FunctionDescriptor erasedInterfaceFunction;
|
||||
if (samType == null) {
|
||||
erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor);
|
||||
@@ -233,7 +233,10 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
protected void generateKotlinMetadataAnnotation() {
|
||||
FunctionDescriptor freeLambdaDescriptor = createFreeLambdaDescriptor(funDescriptor);
|
||||
Method method = v.getSerializationBindings().get(METHOD_FOR_FUNCTION, funDescriptor);
|
||||
assert method != null : "No method for " + funDescriptor;
|
||||
|
||||
// Can be null for named suspend function
|
||||
if (method == null) return;
|
||||
|
||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, freeLambdaDescriptor, method);
|
||||
|
||||
final DescriptorSerializer serializer =
|
||||
|
||||
@@ -51,7 +51,6 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
||||
@@ -182,7 +181,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (originalCoroutineDescriptor != null) return originalCoroutineDescriptor;
|
||||
|
||||
if (context.getFunctionDescriptor().isSuspend()) {
|
||||
return (FunctionDescriptor) CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(context.getFunctionDescriptor());
|
||||
return CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(context.getFunctionDescriptor());
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -192,7 +191,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
private static FunctionDescriptor getOriginalCoroutineDescriptor(MethodContext context) {
|
||||
if ((context.getParentContext() instanceof ClosureContext) &&
|
||||
(context.getParentContext().closure != null) &&
|
||||
context.getParentContext().closure.isCoroutine()) {
|
||||
context.getParentContext().closure.isSuspend()) {
|
||||
return ((ClosureContext) context.getParentContext()).getCoroutineDescriptor();
|
||||
}
|
||||
|
||||
@@ -1650,7 +1649,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
declaration.getContainingFile()
|
||||
);
|
||||
|
||||
ClosureCodegen coroutineCodegen = CoroutineCodegen.create(this, descriptor, declaration, cv);
|
||||
ClosureCodegen coroutineCodegen = CoroutineCodegen.createByLambda(this, descriptor, declaration, cv);
|
||||
ClosureCodegen closureCodegen = coroutineCodegen != null ? coroutineCodegen : new ClosureCodegen(
|
||||
state, declaration, samType, context.intoClosure(descriptor, this, typeMapper),
|
||||
functionReferenceTarget, strategy, parentCodegen, cv
|
||||
@@ -1658,6 +1657,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
closureCodegen.generate();
|
||||
|
||||
return putClosureInstanceOnStack(closureCodegen, functionReferenceReceiver);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue putClosureInstanceOnStack(
|
||||
@NotNull ClosureCodegen closureCodegen,
|
||||
@Nullable StackValue functionReferenceReceiver
|
||||
) {
|
||||
if (closureCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
|
||||
ReifiedTypeInliner.putNeedClassReificationMarker(v);
|
||||
propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages());
|
||||
@@ -1770,9 +1777,20 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
);
|
||||
}
|
||||
|
||||
if (closure.isCoroutine()) {
|
||||
if (closure.isSuspend()) {
|
||||
// resultContinuation
|
||||
v.aconst(null);
|
||||
if (closure.isSuspendLambda()) {
|
||||
v.aconst(null);
|
||||
}
|
||||
else {
|
||||
assert context.getFunctionDescriptor().isSuspend() : "Coroutines closure must be created only inside suspend functions";
|
||||
ValueParameterDescriptor continuationParameter = CollectionsKt.last(context.getFunctionDescriptor().getValueParameters());
|
||||
StackValue continuationValue = findLocalOrCapturedValue(continuationParameter);
|
||||
|
||||
assert continuationValue != null : "Couldn't find a value for continuation parameter of " + context.getFunctionDescriptor();
|
||||
|
||||
callGenerator.putCapturedValueOnStack(continuationValue, continuationValue.type, paramIndex++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1870,17 +1888,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
@Nullable
|
||||
private StackValue getCoroutineInstanceValueForSuspensionPoint(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
CallableDescriptor enclosingSuspendLambdaForSuspensionPoint =
|
||||
bindingContext.get(ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, resolvedCall.getCall());
|
||||
FunctionDescriptor enclosingSuspendLambdaForSuspensionPoint =
|
||||
bindingContext.get(ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
|
||||
|
||||
if (enclosingSuspendLambdaForSuspensionPoint == null) return null;
|
||||
return genCoroutineInstanceByLambda(enclosingSuspendLambdaForSuspensionPoint);
|
||||
return genCoroutineInstanceBySuspendFunction(enclosingSuspendLambdaForSuspensionPoint);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue genCoroutineInstanceByLambda(@NotNull CallableDescriptor suspendLambda) {
|
||||
ClassDescriptor suspendLambdaClassDescriptor =
|
||||
bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendLambda);
|
||||
@Nullable
|
||||
private StackValue genCoroutineInstanceBySuspendFunction(@NotNull FunctionDescriptor suspendFunction) {
|
||||
if (!CoroutineCodegenUtilKt.isStateMachineNeeded(suspendFunction, bindingContext)) return null;
|
||||
ClassDescriptor suspendLambdaClassDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendFunction);
|
||||
assert suspendLambdaClassDescriptor != null : "Coroutine class descriptor should not be null";
|
||||
|
||||
return StackValue.thisOrOuter(this, suspendLambdaClassDescriptor, false, false);
|
||||
@@ -2772,8 +2790,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
StackValue result = callable.invokeMethodWithArguments(resolvedCall, receiver, this);
|
||||
|
||||
if (bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall()) != null) {
|
||||
// Suspend function's calls inside another suspend function should behave like they leave values of correct type,
|
||||
if (resolvedCall.getResultingDescriptor() instanceof FunctionDescriptor &&
|
||||
((FunctionDescriptor) resolvedCall.getResultingDescriptor()).isSuspend() &&
|
||||
!CoroutineCodegenUtilKt.isSuspensionPointInStateMachine(resolvedCall, bindingContext)) {
|
||||
// Suspend function's tail calls inside another suspend function should behave like they leave values of correct type,
|
||||
// while real methods return java/lang/Object.
|
||||
// NB: They are always in return position at the moment.
|
||||
// If we didn't do this, StackValue.coerce would add proper CHECKCAST that would've failed in case of callee function
|
||||
@@ -2785,13 +2805,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
private StackValue getContinuationParameterFromEnclosingSuspendFunction(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
SimpleFunctionDescriptor enclosingSuspendFunction =
|
||||
FunctionDescriptor enclosingSuspendFunction =
|
||||
bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
|
||||
|
||||
assert enclosingSuspendFunction != null
|
||||
: "Suspend functions may be called either as suspension points or from another suspend function";
|
||||
|
||||
SimpleFunctionDescriptor enclosingSuspendFunctionJvmView =
|
||||
FunctionDescriptor enclosingSuspendFunctionJvmView =
|
||||
bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, enclosingSuspendFunction);
|
||||
|
||||
assert enclosingSuspendFunctionJvmView != null : "No JVM view function found for " + enclosingSuspendFunction;
|
||||
@@ -2855,7 +2875,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
@NotNull CallGenerator callGenerator,
|
||||
@NotNull ArgumentGenerator argumentGenerator
|
||||
) {
|
||||
boolean isSuspensionPoint = CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, bindingContext);
|
||||
boolean isSuspensionPoint = CoroutineCodegenUtilKt.isSuspensionPointInStateMachine(resolvedCall, bindingContext);
|
||||
if (isSuspensionPoint) {
|
||||
// Inline markers are used to spill the stack before coroutine suspension
|
||||
addInlineMarker(v, true);
|
||||
|
||||
@@ -31,6 +31,8 @@ import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -119,17 +121,29 @@ public class FunctionCodegen {
|
||||
|
||||
public void gen(@NotNull KtNamedFunction function) {
|
||||
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function);
|
||||
if (bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, functionDescriptor) != null) {
|
||||
functionDescriptor =
|
||||
(SimpleFunctionDescriptor) bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, functionDescriptor);
|
||||
}
|
||||
|
||||
if (functionDescriptor == null) {
|
||||
throw ExceptionLogger.logDescriptorNotFound("No descriptor for function " + function.getName(), function);
|
||||
}
|
||||
|
||||
if (bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, functionDescriptor) != null) {
|
||||
functionDescriptor = bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, functionDescriptor);
|
||||
}
|
||||
|
||||
if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) {
|
||||
generateMethod(JvmDeclarationOriginKt.OtherOrigin(function, functionDescriptor), functionDescriptor,
|
||||
new FunctionGenerationStrategy.FunctionDefault(state, function));
|
||||
FunctionGenerationStrategy strategy;
|
||||
if (functionDescriptor.isSuspend()) {
|
||||
strategy = new SuspendFunctionGenerationStrategy(
|
||||
state,
|
||||
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(functionDescriptor),
|
||||
function
|
||||
);
|
||||
}
|
||||
else {
|
||||
strategy = new FunctionGenerationStrategy.FunctionDefault(state, function);
|
||||
}
|
||||
|
||||
generateMethod(JvmDeclarationOriginKt.OtherOrigin(function, functionDescriptor), functionDescriptor, strategy);
|
||||
}
|
||||
|
||||
generateDefaultIfNeeded(owner.intoFunction(functionDescriptor, true), functionDescriptor, owner.getContextKind(),
|
||||
|
||||
@@ -114,7 +114,7 @@ public class JvmCodegenUtil {
|
||||
return closure.getCaptureThis() == null &&
|
||||
closure.getCaptureReceiverType() == null &&
|
||||
closure.getCaptureVariables().isEmpty() &&
|
||||
!closure.isCoroutine();
|
||||
!closure.isSuspend();
|
||||
}
|
||||
|
||||
private static boolean isCallInsideSameClassAsDeclared(@NotNull CallableMemberDescriptor descriptor, @NotNull CodegenContext context) {
|
||||
|
||||
@@ -70,7 +70,7 @@ class JvmRuntimeTypes(module: ModuleDescriptor) {
|
||||
fun getSupertypesForClosure(descriptor: FunctionDescriptor): Collection<KotlinType> {
|
||||
|
||||
val actualFunctionDescriptor =
|
||||
if (descriptor.isSuspendLambda)
|
||||
if (descriptor.isSuspend)
|
||||
createJvmSuspendFunctionView(descriptor)
|
||||
else
|
||||
descriptor
|
||||
@@ -84,15 +84,17 @@ class JvmRuntimeTypes(module: ModuleDescriptor) {
|
||||
actualFunctionDescriptor.returnType!!
|
||||
)
|
||||
|
||||
if (descriptor.isSuspendLambda) {
|
||||
if (descriptor.isSuspend) {
|
||||
return mutableListOf<KotlinType>().apply {
|
||||
add(coroutineImplClass.defaultType)
|
||||
add(functionType)
|
||||
|
||||
val parametersNumber =
|
||||
descriptor.valueParameters.size + (if (functionType.isExtensionFunctionType) 1 else 0)
|
||||
if (descriptor.isSuspendLambda) {
|
||||
val parametersNumber =
|
||||
descriptor.valueParameters.size + (if (functionType.isExtensionFunctionType) 1 else 0)
|
||||
|
||||
addIfNotNull(suspendFunctions.getOrNull(parametersNumber)?.defaultType)
|
||||
addIfNotNull(suspendFunctions.getOrNull(parametersNumber)?.defaultType)
|
||||
add(functionType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,5 +44,7 @@ public interface CalculatedClosure {
|
||||
@NotNull
|
||||
List<Pair<String, Type>> getRecordedFields();
|
||||
|
||||
boolean isCoroutine();
|
||||
boolean isSuspend();
|
||||
|
||||
boolean isSuspendLambda();
|
||||
}
|
||||
|
||||
+50
-14
@@ -100,10 +100,21 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
@NotNull CallableDescriptor callableDescriptor,
|
||||
@NotNull Collection<KotlinType> supertypes,
|
||||
@NotNull String name
|
||||
) {
|
||||
return recordClassForCallable(element, callableDescriptor, supertypes, name, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor recordClassForCallable(
|
||||
@NotNull KtElement element,
|
||||
@NotNull CallableDescriptor callableDescriptor,
|
||||
@NotNull Collection<KotlinType> supertypes,
|
||||
@NotNull String name,
|
||||
@Nullable DeclarationDescriptor customContainer
|
||||
) {
|
||||
String simpleName = name.substring(name.lastIndexOf('/') + 1);
|
||||
ClassDescriptor classDescriptor = new SyntheticClassDescriptorForLambda(
|
||||
correctContainerForLambda(callableDescriptor, element),
|
||||
customContainer != null ? customContainer : correctContainerForLambda(callableDescriptor, element),
|
||||
Name.special("<closure-" + simpleName + ">"),
|
||||
supertypes,
|
||||
element
|
||||
@@ -289,7 +300,8 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
nameStack.push(name);
|
||||
|
||||
if (CoroutineUtilKt.isSuspendLambda(functionDescriptor)) {
|
||||
closure.setCoroutine(true);
|
||||
closure.setSuspend(true);
|
||||
closure.setSuspendLambda();
|
||||
}
|
||||
|
||||
super.visitLambdaExpression(lambdaExpression);
|
||||
@@ -415,6 +427,8 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
// working around a problem with shallow analysis
|
||||
if (functionDescriptor == null) return;
|
||||
|
||||
String nameForClassOrPackageMember = getNameForClassOrPackageMember(functionDescriptor);
|
||||
|
||||
if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend()) {
|
||||
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
||||
CoroutineCodegenUtilKt.createJvmSuspendFunctionView(
|
||||
@@ -437,31 +451,53 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
|
||||
bindingTrace.record(
|
||||
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
|
||||
(SimpleFunctionDescriptor) functionDescriptor,
|
||||
functionDescriptor,
|
||||
jvmSuspendFunctionView
|
||||
);
|
||||
|
||||
if (CoroutineCodegenUtilKt.containsNonTailSuspensionCalls(functionDescriptor, bindingContext)) {
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.push(nameForClassOrPackageMember);
|
||||
}
|
||||
|
||||
processNamedFunctionWithClosure(function, functionDescriptor, functionDescriptor).setSuspend(true);
|
||||
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.pop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String nameForClassOrPackageMember = getNameForClassOrPackageMember(functionDescriptor);
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.push(nameForClassOrPackageMember);
|
||||
super.visitNamedFunction(function);
|
||||
nameStack.pop();
|
||||
}
|
||||
else {
|
||||
String name = inventAnonymousClassName();
|
||||
Collection<KotlinType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(function, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
nameStack.push(name);
|
||||
super.visitNamedFunction(function);
|
||||
nameStack.pop();
|
||||
classStack.pop();
|
||||
processNamedFunctionWithClosure(function, functionDescriptor, null);
|
||||
}
|
||||
}
|
||||
|
||||
private MutableClosure processNamedFunctionWithClosure(
|
||||
@NotNull KtNamedFunction function,
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@Nullable DeclarationDescriptor customContainer
|
||||
) {
|
||||
String name = inventAnonymousClassName();
|
||||
Collection<KotlinType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(function, functionDescriptor, supertypes, name, customContainer);
|
||||
MutableClosure closure = recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
nameStack.push(name);
|
||||
super.visitNamedFunction(function);
|
||||
nameStack.pop();
|
||||
classStack.pop();
|
||||
|
||||
return closure;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getNameForClassOrPackageMember(@NotNull DeclarationDescriptor descriptor) {
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
|
||||
@@ -66,7 +66,7 @@ public class CodegenBinding {
|
||||
public static final WritableSlice<VariableDescriptor, VariableDescriptor> LOCAL_VARIABLE_PROPERTY_METADATA =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<SimpleFunctionDescriptor, SimpleFunctionDescriptor> SUSPEND_FUNCTION_TO_JVM_VIEW =
|
||||
public static final WritableSlice<FunctionDescriptor, FunctionDescriptor> SUSPEND_FUNCTION_TO_JVM_VIEW =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<ValueParameterDescriptor, ValueParameterDescriptor> PARAMETER_SYNONYM =
|
||||
|
||||
@@ -40,7 +40,8 @@ public final class MutableClosure implements CalculatedClosure {
|
||||
private Map<DeclarationDescriptor, Integer> parameterOffsetInConstructor;
|
||||
private List<Pair<String, Type>> recordedFields;
|
||||
private KotlinType captureReceiverType;
|
||||
private boolean isCoroutine;
|
||||
private boolean isSuspend;
|
||||
private boolean isSuspendLambda;
|
||||
|
||||
MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
|
||||
this.closureClass = classDescriptor;
|
||||
@@ -119,12 +120,21 @@ public final class MutableClosure implements CalculatedClosure {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoroutine() {
|
||||
return isCoroutine;
|
||||
public boolean isSuspend() {
|
||||
return isSuspend;
|
||||
}
|
||||
|
||||
public void setCoroutine(boolean coroutine) {
|
||||
this.isCoroutine = coroutine;
|
||||
public void setSuspend(boolean suspend) {
|
||||
this.isSuspend = suspend;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuspendLambda() {
|
||||
return isSuspendLambda;
|
||||
}
|
||||
|
||||
public void setSuspendLambda() {
|
||||
isSuspendLambda = true;
|
||||
}
|
||||
|
||||
public void recordField(String name, Type type) {
|
||||
|
||||
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.codegen.coroutines
|
||||
import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.backend.common.CONTINUATION_RESUME_METHOD_NAME
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.context.ClosureContext
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -29,9 +31,9 @@ import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtFunctionLiteral
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
@@ -42,6 +44,7 @@ import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
@@ -49,16 +52,20 @@ import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
|
||||
|
||||
class CoroutineCodegen(
|
||||
state: GenerationState,
|
||||
outerExpressionCodegen: ExpressionCodegen,
|
||||
element: KtElement,
|
||||
private val closureContext: ClosureContext,
|
||||
strategy: FunctionGenerationStrategy,
|
||||
parentCodegen: MemberCodegen<*>,
|
||||
classBuilder: ClassBuilder,
|
||||
private val coroutineLambdaDescriptor: FunctionDescriptor
|
||||
) : ClosureCodegen(state, element, null, closureContext, null, strategy, parentCodegen, classBuilder) {
|
||||
private val originalSuspendLambdaDescriptor: FunctionDescriptor?
|
||||
) : ClosureCodegen(
|
||||
outerExpressionCodegen.state,
|
||||
element, null, closureContext, null,
|
||||
FailingFunctionGenerationStrategy,
|
||||
outerExpressionCodegen.parentCodegen, classBuilder
|
||||
) {
|
||||
|
||||
private val classDescriptor = closureContext.contextDescriptor
|
||||
private val builtIns = funDescriptor.builtIns
|
||||
|
||||
private lateinit var constructorToUseFromInvoke: Method
|
||||
|
||||
@@ -75,33 +82,33 @@ class CoroutineCodegen(
|
||||
listOf(
|
||||
ValueParameterDescriptorImpl(
|
||||
this@doResume, null, 0, Annotations.EMPTY, Name.identifier("data"),
|
||||
module.builtIns.nullableAnyType,
|
||||
builtIns.nullableAnyType,
|
||||
/* isDefault = */ false, /* isCrossinline = */ false,
|
||||
/* isNoinline = */ false,
|
||||
/* varargElementType = */ null, SourceElement.NO_SOURCE
|
||||
),
|
||||
ValueParameterDescriptorImpl(
|
||||
this@doResume, null, 1, Annotations.EMPTY, Name.identifier("throwable"),
|
||||
module.builtIns.throwable.defaultType.makeNullable(),
|
||||
builtIns.throwable.defaultType.makeNullable(),
|
||||
/* isDefault = */ false, /* isCrossinline = */ false,
|
||||
/* isNoinline = */ false,
|
||||
/* varargElementType = */ null, SourceElement.NO_SOURCE
|
||||
)
|
||||
),
|
||||
funDescriptor.builtIns.nullableAnyType,
|
||||
builtIns.nullableAnyType,
|
||||
Modality.FINAL,
|
||||
Visibilities.PROTECTED
|
||||
Visibilities.PUBLIC
|
||||
)
|
||||
}
|
||||
|
||||
private val createCoroutineDescriptor =
|
||||
funDescriptor.createCustomCopy {
|
||||
setName(Name.identifier("create"))
|
||||
setName(Name.identifier(SUSPEND_FUNCTION_CREATE_METHOD_NAME))
|
||||
setReturnType(
|
||||
KotlinTypeFactory.simpleNotNullType(
|
||||
Annotations.EMPTY,
|
||||
funDescriptor.builtIns.continuationClassDescriptor,
|
||||
listOf(funDescriptor.builtIns.unitType.asTypeProjection())
|
||||
builtIns.continuationClassDescriptor,
|
||||
listOf(builtIns.unitType.asTypeProjection())
|
||||
)
|
||||
)
|
||||
setVisibility(Visibilities.PUBLIC)
|
||||
@@ -121,9 +128,17 @@ class CoroutineCodegen(
|
||||
generateDoResume()
|
||||
}
|
||||
|
||||
override fun generateBridges() {
|
||||
if (originalSuspendLambdaDescriptor == null) return
|
||||
super.generateBridges()
|
||||
}
|
||||
|
||||
override fun generateBody() {
|
||||
super.generateBody()
|
||||
|
||||
if (originalSuspendLambdaDescriptor == null) return
|
||||
|
||||
// create() = ...
|
||||
functionCodegen.generateMethod(JvmDeclarationOrigin.NO_ORIGIN, createCoroutineDescriptor,
|
||||
object : FunctionGenerationStrategy.CodegenBased(state) {
|
||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||
@@ -182,7 +197,6 @@ class CoroutineCodegen(
|
||||
areturn(AsmTypes.OBJECT_TYPE)
|
||||
}
|
||||
|
||||
|
||||
override fun generateConstructor(): Method {
|
||||
val args = calculateConstructorParameters(typeMapper, closure, asmType)
|
||||
val argTypes = args.map { it.fieldType }.plus(AsmTypes.CONTINUATION).toTypedArray()
|
||||
@@ -217,6 +231,7 @@ class CoroutineCodegen(
|
||||
}
|
||||
|
||||
private fun generateCreateCoroutineMethod(codegen: ExpressionCodegen) {
|
||||
assert(originalSuspendLambdaDescriptor != null) { "create method should only be generated for suspend lambdas" }
|
||||
val classDescriptor = closureContext.contextDescriptor
|
||||
val owner = typeMapper.mapClass(classDescriptor)
|
||||
|
||||
@@ -265,7 +280,7 @@ class CoroutineCodegen(
|
||||
}
|
||||
|
||||
private fun allLambdaParameters() =
|
||||
coroutineLambdaDescriptor.extensionReceiverParameter.singletonOrEmptyList() + coroutineLambdaDescriptor.valueParameters
|
||||
originalSuspendLambdaDescriptor?.extensionReceiverParameter.singletonOrEmptyList() + originalSuspendLambdaDescriptor?.valueParameters.orEmpty()
|
||||
|
||||
private fun ExpressionCodegen.generateLoadField(fieldInfo: FieldInfo) {
|
||||
StackValue.field(fieldInfo, generateThisOrOuter(context.thisDescriptor, false)).put(fieldInfo.fieldType, v)
|
||||
@@ -298,7 +313,7 @@ class CoroutineCodegen(
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun create(
|
||||
fun createByLambda(
|
||||
expressionCodegen: ExpressionCodegen,
|
||||
originalCoroutineLambdaDescriptor: FunctionDescriptor,
|
||||
declaration: KtElement,
|
||||
@@ -307,21 +322,52 @@ class CoroutineCodegen(
|
||||
if (declaration !is KtFunctionLiteral) return null
|
||||
if (!originalCoroutineLambdaDescriptor.isSuspendLambda) return null
|
||||
|
||||
val descriptorWithContinuationReturnType = createJvmSuspendFunctionView(originalCoroutineLambdaDescriptor)
|
||||
|
||||
val state = expressionCodegen.state
|
||||
return CoroutineCodegen(
|
||||
state,
|
||||
expressionCodegen,
|
||||
declaration,
|
||||
expressionCodegen.context.intoCoroutineClosure(
|
||||
descriptorWithContinuationReturnType, originalCoroutineLambdaDescriptor, expressionCodegen, state.typeMapper
|
||||
createJvmSuspendFunctionView(originalCoroutineLambdaDescriptor),
|
||||
originalCoroutineLambdaDescriptor, expressionCodegen, expressionCodegen.state.typeMapper
|
||||
),
|
||||
FunctionGenerationStrategy.FunctionDefault(state, declaration),
|
||||
expressionCodegen.parentCodegen, classBuilder,
|
||||
classBuilder,
|
||||
originalCoroutineLambdaDescriptor
|
||||
)
|
||||
}
|
||||
|
||||
fun create(
|
||||
expressionCodegen: ExpressionCodegen,
|
||||
originalSuspendDescriptor: FunctionDescriptor,
|
||||
declaration: KtFunction,
|
||||
state: GenerationState
|
||||
): CoroutineCodegen {
|
||||
val cv = state.factory.newVisitor(
|
||||
OtherOrigin(declaration, originalSuspendDescriptor),
|
||||
CodegenBinding.asmTypeForAnonymousClass(state.bindingContext, originalSuspendDescriptor),
|
||||
declaration.containingFile
|
||||
)
|
||||
|
||||
return CoroutineCodegen(
|
||||
expressionCodegen, declaration,
|
||||
expressionCodegen.context.intoClosure(
|
||||
originalSuspendDescriptor, expressionCodegen, expressionCodegen.state.typeMapper
|
||||
),
|
||||
cv,
|
||||
originalSuspendLambdaDescriptor = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val COROUTINE_LAMBDA_PARAMETER_PREFIX = "p$"
|
||||
|
||||
private object FailingFunctionGenerationStrategy : FunctionGenerationStrategy() {
|
||||
override fun generateBody(
|
||||
mv: MethodVisitor,
|
||||
frameMap: FrameMap,
|
||||
signature: JvmMethodSignature,
|
||||
context: MethodContext,
|
||||
parentCodegen: MemberCodegen<*>
|
||||
) {
|
||||
error("This functions must not be called")
|
||||
}
|
||||
}
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
class SuspendFunctionGenerationStrategy(
|
||||
state: GenerationState,
|
||||
private val originalSuspendDescriptor: FunctionDescriptor,
|
||||
private val declaration: KtFunction
|
||||
) : FunctionGenerationStrategy.CodegenBased(state) {
|
||||
|
||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||
if (!originalSuspendDescriptor.containsNonTailSuspensionCalls(state.bindingContext)) {
|
||||
return codegen.returnExpression(declaration.bodyExpression)
|
||||
}
|
||||
|
||||
val coroutineCodegen = CoroutineCodegen.create(codegen, originalSuspendDescriptor, declaration, state)
|
||||
coroutineCodegen.generate()
|
||||
|
||||
codegen.putClosureInstanceOnStack(coroutineCodegen, null).put(Type.getObjectType(coroutineCodegen.className), codegen.v)
|
||||
|
||||
with(codegen.v) {
|
||||
invokeDoResumeWithUnit(coroutineCodegen.v.thisName)
|
||||
|
||||
codegen.markLineNumber(declaration, true)
|
||||
|
||||
areturn(AsmTypes.OBJECT_TYPE)
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
-4
@@ -20,8 +20,10 @@ import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.backend.common.SUSPENDED_MARKER_NAME
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineOrReturn
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
@@ -55,6 +57,8 @@ const val AFTER_SUSPENSION_POINT_MARKER_NAME = "afterSuspensionPoint"
|
||||
const val ACTUAL_COROUTINE_START_MARKER_NAME = "actualCoroutineStart"
|
||||
|
||||
const val COROUTINE_LABEL_FIELD_NAME = "label"
|
||||
const val SUSPEND_FUNCTION_CREATE_METHOD_NAME = "create"
|
||||
const val DO_RESUME_METHOD_NAME = "doResume"
|
||||
|
||||
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeContinuationExpression: KtExpression)
|
||||
|
||||
@@ -118,9 +122,18 @@ fun ResolvedCall<*>.replaceSuspensionFunctionWithRealDescriptor(
|
||||
return ResolvedCallWithRealDescriptor(newCall, thisExpression)
|
||||
}
|
||||
|
||||
fun ResolvedCall<*>.isSuspensionPoint(bindingContext: BindingContext) =
|
||||
bindingContext[BindingContext.ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, call] != null
|
||||
fun ResolvedCall<*>.isSuspensionPointInStateMachine(bindingContext: BindingContext): Boolean {
|
||||
if (resultingDescriptor.safeAs<FunctionDescriptor>()?.isSuspend != true) return false
|
||||
val enclosingSuspendFunction = bindingContext[BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, call] ?: return false
|
||||
|
||||
return enclosingSuspendFunction.isStateMachineNeeded(bindingContext)
|
||||
}
|
||||
|
||||
fun FunctionDescriptor.isStateMachineNeeded(bindingContext: BindingContext) =
|
||||
isSuspendLambda || containsNonTailSuspensionCalls(bindingContext)
|
||||
|
||||
fun FunctionDescriptor.containsNonTailSuspensionCalls(bindingContext: BindingContext) =
|
||||
bindingContext[BindingContext.CONTAINS_NON_TAIL_SUSPEND_CALLS, original] == true
|
||||
// Suspend functions have irregular signatures on JVM, containing an additional last parameter with type `Continuation<return-type>`,
|
||||
// and return type Any?
|
||||
// This function returns a function descriptor reflecting how the suspend function looks from point of view of JVM
|
||||
@@ -207,8 +220,9 @@ fun createMethodNodeForSuspendCoroutineOrReturn(
|
||||
return node
|
||||
}
|
||||
|
||||
fun CallableDescriptor?.unwrapInitialDescriptorForSuspendFunction() =
|
||||
(this as? SimpleFunctionDescriptor)?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) ?: this
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <D : CallableDescriptor?> D.unwrapInitialDescriptorForSuspendFunction(): D =
|
||||
this.safeAs<SimpleFunctionDescriptor>()?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) as D ?: this
|
||||
|
||||
fun InstructionAdapter.loadSuspendMarker() {
|
||||
invokestatic(
|
||||
@@ -218,3 +232,17 @@ fun InstructionAdapter.loadSuspendMarker() {
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) {
|
||||
// .doResume(Unit, null)
|
||||
StackValue.putUnitInstance(this)
|
||||
|
||||
aconst(null)
|
||||
|
||||
invokevirtual(
|
||||
thisName,
|
||||
DO_RESUME_METHOD_NAME,
|
||||
Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE, AsmTypes.JAVA_THROWABLE_TYPE),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
|
||||
import org.jetbrains.kotlin.codegen.*;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
@@ -601,6 +602,14 @@ public class InlineCodegen extends CallGenerator {
|
||||
else if (expression instanceof KtFunctionLiteral) {
|
||||
strategy = new ClosureGenerationStrategy(state, (KtDeclarationWithBody) expression);
|
||||
}
|
||||
else if (descriptor.isSuspend() && expression instanceof KtFunction) {
|
||||
strategy =
|
||||
new SuspendFunctionGenerationStrategy(
|
||||
state,
|
||||
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(descriptor),
|
||||
(KtFunction) expression
|
||||
);
|
||||
}
|
||||
else {
|
||||
strategy = new FunctionGenerationStrategy.FunctionDefault(state, (KtDeclarationWithBody) expression);
|
||||
}
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
class Controller {
|
||||
var log = ""
|
||||
var resumeIndex = 0
|
||||
|
||||
suspend fun <T> suspendWithValue(value: T): T = suspendCoroutineOrReturn { continuation ->
|
||||
log += "suspend($value);"
|
||||
continuation.resume(value)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(value: String): Unit = suspendCoroutineOrReturn { continuation ->
|
||||
log += "error($value);"
|
||||
continuation.resumeWithException(RuntimeException(value))
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
}
|
||||
|
||||
fun test(c: suspend Controller.() -> Unit): String {
|
||||
val controller = Controller()
|
||||
c.startCoroutine(controller, EmptyContinuation, object: ContinuationDispatcher {
|
||||
private fun dispatchResume(block: () -> Unit) {
|
||||
val id = controller.resumeIndex++
|
||||
controller.log += "before $id;"
|
||||
block()
|
||||
controller.log += "after $id;"
|
||||
}
|
||||
|
||||
override fun <P> dispatchResume(data: P, continuation: Continuation<P>): Boolean {
|
||||
dispatchResume {
|
||||
continuation.resume(data)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun dispatchResumeWithException(exception: Throwable, continuation: Continuation<*>): Boolean {
|
||||
dispatchResume {
|
||||
continuation.resumeWithException(exception)
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
return controller.log
|
||||
}
|
||||
|
||||
suspend fun Controller.foo() = suspendWithValue("") + suspendWithValue("O")
|
||||
|
||||
suspend fun Controller.test1() {
|
||||
val o = foo()
|
||||
val k = suspendWithValue("K")
|
||||
log += "$o$k;"
|
||||
}
|
||||
|
||||
suspend fun Controller.test2() {
|
||||
try {
|
||||
foo()
|
||||
|
||||
suspendWithException("OK")
|
||||
log += "ignore;"
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
log += "${e.message};"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = test {
|
||||
test1()
|
||||
}
|
||||
if (result != "before 0;suspend();before 1;suspend(O);before 2;before 3;suspend(K);before 4;OK;before 5;after 5;after 4;after 3;after 2;after 1;after 0;") return "fail1: $result"
|
||||
|
||||
result = test {
|
||||
test2()
|
||||
}
|
||||
if (result != "before 0;suspend();before 1;suspend(O);before 2;before 3;error(OK);before 4;OK;before 5;after 5;after 4;after 3;after 2;after 1;after 0;") return "fail2: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
class Controller {
|
||||
var exception: Throwable? = null
|
||||
val postponedActions = ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception): String = suspendCoroutineOrReturn { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
fun run(c: suspend Controller.() -> Unit) {
|
||||
c.startCoroutine(this, handleExceptionContinuation {
|
||||
exception = it
|
||||
})
|
||||
while (postponedActions.isNotEmpty()) {
|
||||
postponedActions[0]()
|
||||
postponedActions.removeAt(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(c: suspend Controller.() -> Unit) {
|
||||
val controller = Controller()
|
||||
controller.run(c)
|
||||
|
||||
if (controller.exception?.message != "OK") {
|
||||
throw RuntimeException("Unexpected result: ${controller.exception?.message}")
|
||||
}
|
||||
}
|
||||
|
||||
fun commonThrow(t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
|
||||
suspend fun justContinue(): Unit = suspendCoroutineOrReturn { x ->
|
||||
x.resume(Unit)
|
||||
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun Controller.test1() {
|
||||
justContinue()
|
||||
throw RuntimeException("OK")
|
||||
}
|
||||
|
||||
suspend fun Controller.test2() {
|
||||
justContinue()
|
||||
commonThrow(RuntimeException("OK"))
|
||||
}
|
||||
|
||||
suspend fun Controller.test3() {
|
||||
justContinue()
|
||||
suspendWithException(RuntimeException("OK"))
|
||||
}
|
||||
|
||||
suspend fun Controller.test4() {
|
||||
justContinue()
|
||||
try {
|
||||
suspendWithException(RuntimeException("fail 1"))
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithException(RuntimeException("OK"))
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun Controller.test5() {
|
||||
justContinue()
|
||||
try {
|
||||
suspendWithException(Exception("OK"))
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithException(RuntimeException("fail 3"))
|
||||
throw RuntimeException("fail 4")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
test1()
|
||||
}
|
||||
|
||||
builder {
|
||||
test2()
|
||||
}
|
||||
|
||||
builder {
|
||||
test3()
|
||||
}
|
||||
|
||||
builder {
|
||||
test4()
|
||||
}
|
||||
|
||||
builder {
|
||||
test5()
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend inline fun suspendHere(crossinline block: () -> String): String {
|
||||
return suspendThere(block()) + suspendThere(block())
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
var q = "O"
|
||||
result = suspendHere {
|
||||
val r = q
|
||||
q = "K"
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
class A(val v: String) {
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): String = suspendThere("O") + suspendThere(v)
|
||||
}
|
||||
|
||||
fun builder(c: suspend A.() -> Unit) {
|
||||
c.startCoroutine(A("K"), EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result = suspendHere()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendHere(suspend: Boolean): String {
|
||||
if (!suspend) return "O"
|
||||
|
||||
return suspendThere("") + suspendThere("K")
|
||||
}
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result = suspendHere(false) + suspendHere(true)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): String = suspendThere("O") + suspendThere("K")
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result = suspendHere()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
SUSPENDED_MARKER
|
||||
}
|
||||
|
||||
suspend fun suspendHere(): String {
|
||||
val k = "K"
|
||||
val x = suspendThere("O")
|
||||
val y = x + suspendThere(k)
|
||||
|
||||
return y
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result = suspendHere()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -5,6 +5,21 @@ class Controller {
|
||||
suspend fun suspendHere() = suspendCoroutineOrReturn<String> { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
suspend fun tailCall(): String {
|
||||
return suspendHere()
|
||||
}
|
||||
|
||||
suspend fun nonTailCall(): String {
|
||||
suspendHere()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
suspend fun multipleSuspensions(): String {
|
||||
suspendHere()
|
||||
return suspendHere()
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(c: suspend Controller.() -> Unit) {
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
final class Controller$multipleSuspensions$1 {
|
||||
synthetic final field this$0: Controller
|
||||
inner class Controller$multipleSuspensions$1
|
||||
method <init>(p0: Controller, p1: kotlin.coroutines.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
}
|
||||
|
||||
final class Controller$nonTailCall$1 {
|
||||
synthetic final field this$0: Controller
|
||||
inner class Controller$nonTailCall$1
|
||||
method <init>(p0: Controller, p1: kotlin.coroutines.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Controller {
|
||||
inner class Controller$multipleSuspensions$1
|
||||
inner class Controller$nonTailCall$1
|
||||
public method <init>(): void
|
||||
public final @org.jetbrains.annotations.Nullable method multipleSuspensions(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method nonTailCall(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method tailCall(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
@@ -15,7 +34,7 @@ final class CoroutineFieldsKt$box$1 {
|
||||
method <init>(p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.coroutines.Continuation): void
|
||||
public final @org.jetbrains.annotations.NotNull method create(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): kotlin.coroutines.Continuation
|
||||
public synthetic method create(p0: java.lang.Object, p1: kotlin.coroutines.Continuation): kotlin.coroutines.Continuation
|
||||
protected final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public synthetic method invoke(p0: java.lang.Object, p1: java.lang.Object): java.lang.Object
|
||||
}
|
||||
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
@kotlin.Metadata
|
||||
public final class Controller {
|
||||
private @org.jetbrains.annotations.NotNull field log: java.lang.String
|
||||
private field resumeIndex: int
|
||||
public method <init>(): void
|
||||
public final @org.jetbrains.annotations.NotNull method getLog(): java.lang.String
|
||||
public final method getResumeIndex(): int
|
||||
public final method setLog(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
public final method setResumeIndex(p0: int): void
|
||||
public final @org.jetbrains.annotations.Nullable method suspendWithException(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method suspendWithValue(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class CoroutineUtilKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class DispatchResumeKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.Nullable method foo(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.NotNull method test(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function2): java.lang.String
|
||||
public final static @org.jetbrains.annotations.Nullable method test1(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method test2(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
|
||||
}
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
@kotlin.Metadata
|
||||
public final class Controller {
|
||||
private @org.jetbrains.annotations.Nullable field exception: java.lang.Throwable
|
||||
private final @org.jetbrains.annotations.NotNull field postponedActions: java.util.ArrayList
|
||||
public method <init>(): void
|
||||
public final @org.jetbrains.annotations.Nullable method getException(): java.lang.Throwable
|
||||
public final @org.jetbrains.annotations.NotNull method getPostponedActions(): java.util.ArrayList
|
||||
public final method run(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function2): void
|
||||
public final method setException(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||
public final @org.jetbrains.annotations.Nullable method suspendWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Exception, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method suspendWithValue(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class CoroutineUtilKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class HandleExceptionKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function2): void
|
||||
public final static method commonThrow(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
|
||||
public final static @org.jetbrains.annotations.Nullable method justContinue(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method test1(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method test2(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method test3(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method test4(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method test5(@org.jetbrains.annotations.NotNull p0: Controller, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
@kotlin.Metadata
|
||||
public final class CoroutineUtilKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class InlineKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
@kotlin.Metadata
|
||||
public final class A {
|
||||
private final @org.jetbrains.annotations.NotNull field v: java.lang.String
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
public final @org.jetbrains.annotations.NotNull method getV(): java.lang.String
|
||||
public final @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class CoroutineUtilKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class MemberKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function2): void
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
@kotlin.Metadata
|
||||
public final class CoroutineUtilKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class ReturnNoSuspendKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendHere(p0: boolean, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
@kotlin.Metadata
|
||||
public final class CoroutineUtilKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class SimpleKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
@kotlin.Metadata
|
||||
public final class CoroutineUtilKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.Continuation
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class EmptyContinuation {
|
||||
public final static field INSTANCE: EmptyContinuation
|
||||
private method <init>(): void
|
||||
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class WithVariablesKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
+51
@@ -5057,6 +5057,57 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SuspendFunctionAsCoroutine extends AbstractIrBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInSuspendFunctionAsCoroutine() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("dispatchResume.kt")
|
||||
public void testDispatchResume() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/dispatchResume.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("handleException.kt")
|
||||
public void testHandleException() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/handleException.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inline.kt")
|
||||
public void testInline() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/inline.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("member.kt")
|
||||
public void testMember() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/member.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("returnNoSuspend.kt")
|
||||
public void testReturnNoSuspend() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/returnNoSuspend.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("withVariables.kt")
|
||||
public void testWithVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/withVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionTypeCall")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -5057,6 +5057,57 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SuspendFunctionAsCoroutine extends AbstractBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInSuspendFunctionAsCoroutine() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("dispatchResume.kt")
|
||||
public void testDispatchResume() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/dispatchResume.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("handleException.kt")
|
||||
public void testHandleException() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/handleException.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inline.kt")
|
||||
public void testInline() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/inline.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("member.kt")
|
||||
public void testMember() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/member.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("returnNoSuspend.kt")
|
||||
public void testReturnNoSuspend() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/returnNoSuspend.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("withVariables.kt")
|
||||
public void testWithVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/withVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionTypeCall")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+51
@@ -5057,6 +5057,57 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SuspendFunctionAsCoroutine extends AbstractLightAnalysisModeCodegenTest {
|
||||
public void testAllFilesPresentInSuspendFunctionAsCoroutine() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("dispatchResume.kt")
|
||||
public void testDispatchResume() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/dispatchResume.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("handleException.kt")
|
||||
public void testHandleException() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/handleException.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inline.kt")
|
||||
public void testInline() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/inline.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("member.kt")
|
||||
public void testMember() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/member.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("returnNoSuspend.kt")
|
||||
public void testReturnNoSuspend() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/returnNoSuspend.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("withVariables.kt")
|
||||
public void testWithVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/withVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionTypeCall")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+51
@@ -5784,6 +5784,57 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SuspendFunctionAsCoroutine extends AbstractJsCodegenBoxTest {
|
||||
public void testAllFilesPresentInSuspendFunctionAsCoroutine() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("dispatchResume.kt")
|
||||
public void testDispatchResume() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/dispatchResume.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("handleException.kt")
|
||||
public void testHandleException() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/handleException.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inline.kt")
|
||||
public void testInline() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/inline.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("member.kt")
|
||||
public void testMember() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/member.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("returnNoSuspend.kt")
|
||||
public void testReturnNoSuspend() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/returnNoSuspend.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("withVariables.kt")
|
||||
public void testWithVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/withVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionTypeCall")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user