Support new suspend convention in JVM backend partially
Stack-unwinding does not work yet #KT-14924 In Progress
This commit is contained in:
@@ -78,6 +78,7 @@ import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluatorKt;
|
||||
import org.jetbrains.kotlin.resolve.coroutine.CoroutineReceiverValue;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||
@@ -1900,15 +1901,29 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
@NotNull
|
||||
public StackValue genCoroutineInstanceValueFromResolvedCall(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
ExtensionReceiver controllerReceiver = getControllerReceiverFromResolvedCall(resolvedCall);
|
||||
ClassDescriptor coroutineClassDescriptor =
|
||||
bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, controllerReceiver.getDeclarationDescriptor());
|
||||
assert coroutineClassDescriptor != null : "Coroutine class descriptor should not be null";
|
||||
return getCoroutineInstanceValueByReceiver(getControllerReceiverFromResolvedCall(resolvedCall));
|
||||
}
|
||||
|
||||
// second argument for handleResult is always Continuation<T> ('this'-object in current implementation)
|
||||
@NotNull
|
||||
private StackValue getCoroutineInstanceValueByReceiver(
|
||||
@NotNull ExtensionReceiver descriptor
|
||||
) {
|
||||
ClassDescriptor coroutineClassDescriptor =
|
||||
bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, descriptor.getDeclarationDescriptor());
|
||||
assert coroutineClassDescriptor != null : "Coroutine class descriptor should not be null";
|
||||
return StackValue.thisOrOuter(this, coroutineClassDescriptor, false, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private StackValue getCoroutineInstanceValueForSuspensionPoint(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
CoroutineReceiverValue coroutineReceiverValue =
|
||||
bindingContext.get(COROUTINE_RECEIVER_FOR_SUSPENSION_POINT, resolvedCall.getCall());
|
||||
|
||||
if (coroutineReceiverValue == null) return null;
|
||||
|
||||
return getCoroutineInstanceValueByReceiver(coroutineReceiverValue);
|
||||
}
|
||||
|
||||
private static ExtensionReceiver getControllerReceiverFromResolvedCall(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
ReceiverValue controllerReceiver =
|
||||
resolvedCall.getDispatchReceiver() != null
|
||||
@@ -2515,7 +2530,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
public int lookupLocalIndex(DeclarationDescriptor descriptor) {
|
||||
return myFrameMap.getIndex(descriptor);
|
||||
return myFrameMap.getIndex(getParameterSynonymOrThis(descriptor));
|
||||
}
|
||||
|
||||
private DeclarationDescriptor getParameterSynonymOrThis(DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ValueParameterDescriptor)) return descriptor;
|
||||
|
||||
DeclarationDescriptor synonym = bindingContext.get(CodegenBinding.PARAMETER_SYNONYM, (ValueParameterDescriptor) descriptor);
|
||||
return synonym != null ? synonym : descriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -2754,9 +2776,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
@NotNull
|
||||
public StackValue invokeFunction(@NotNull Call call, @NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) {
|
||||
ResolvedCallWithRealDescriptor callWithRealDescriptor =
|
||||
CoroutineCodegenUtilKt.replaceSuspensionFunctionViewWithRealDescriptor(resolvedCall, state.getProject());
|
||||
CoroutineCodegenUtilKt.replaceSuspensionFunctionWithRealDescriptor(
|
||||
resolvedCall, state.getProject(), state.getBindingContext()
|
||||
);
|
||||
if (callWithRealDescriptor != null) {
|
||||
tempVariables.put(callWithRealDescriptor.getFakeThisExpression(), genCoroutineInstanceValueFromResolvedCall(resolvedCall));
|
||||
StackValue coroutineInstanceValueForSuspensionPoint = getCoroutineInstanceValueForSuspensionPoint(resolvedCall);
|
||||
StackValue coroutineInstanceValue =
|
||||
coroutineInstanceValueForSuspensionPoint != null
|
||||
? coroutineInstanceValueForSuspensionPoint
|
||||
: getContinuationParameterFromEnclosingSuspendFunction(resolvedCall);
|
||||
tempVariables.put(callWithRealDescriptor.getFakeContinuationExpression(), coroutineInstanceValue);
|
||||
|
||||
return invokeFunction(callWithRealDescriptor.getResolvedCall(), receiver);
|
||||
}
|
||||
FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall);
|
||||
@@ -2778,7 +2808,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
StackValue result = callable.invokeMethodWithArguments(resolvedCall, receiver, this);
|
||||
|
||||
if (CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall)) {
|
||||
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());
|
||||
}
|
||||
@@ -2786,6 +2816,25 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return result;
|
||||
}
|
||||
|
||||
private StackValue getContinuationParameterFromEnclosingSuspendFunction(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
SimpleFunctionDescriptor 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 =
|
||||
bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, enclosingSuspendFunction);
|
||||
|
||||
assert enclosingSuspendFunctionJvmView != null : "No JVM view function found for " + enclosingSuspendFunction;
|
||||
|
||||
ValueParameterDescriptor continuationParameter =
|
||||
enclosingSuspendFunctionJvmView.getValueParameters()
|
||||
.get(enclosingSuspendFunctionJvmView.getValueParameters().size() - 1);
|
||||
|
||||
return findLocalOrCapturedValue(continuationParameter);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
// Find the first parent of the current context which corresponds to a subclass of a given class
|
||||
public static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
|
||||
@@ -2838,7 +2887,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
@NotNull CallGenerator callGenerator,
|
||||
@NotNull ArgumentGenerator argumentGenerator
|
||||
) {
|
||||
boolean isSuspensionPoint = CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall);
|
||||
boolean isSuspensionPoint = CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, bindingContext);
|
||||
if (isSuspensionPoint) {
|
||||
// Inline markers are used to spill the stack before coroutine suspension
|
||||
addInlineMarker(v, true);
|
||||
@@ -2876,11 +2925,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
if (isSuspensionPoint) {
|
||||
v.aconst(getSuspensionReturnTypeByResolvedCall(resolvedCall).getDescriptor());
|
||||
v.tconst(getSuspensionReturnTypeByResolvedCall(resolvedCall));
|
||||
v.invokestatic(
|
||||
CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
|
||||
CoroutineCodegenUtilKt.BEFORE_SUSPENSION_POINT_MARKER_NAME,
|
||||
"(Ljava/lang/String;)V", false);
|
||||
"(Ljava/lang/Class;)V", false);
|
||||
}
|
||||
|
||||
callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this);
|
||||
@@ -2905,8 +2954,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
assert resolvedCall.getResultingDescriptor() instanceof SimpleFunctionDescriptor
|
||||
: "Suspension point resolved call should be built on SimpleFunctionDescriptor";
|
||||
|
||||
KotlinType returnType = org.jetbrains.kotlin.resolve.coroutine.CoroutineUtilKt
|
||||
.getSuspensionPointReturnType((SimpleFunctionDescriptor) resolvedCall.getResultingDescriptor());
|
||||
FunctionDescriptor initialSignature =
|
||||
((SimpleFunctionDescriptor) resolvedCall.getResultingDescriptor())
|
||||
.getUserData(CoroutineCodegenUtilKt.INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION);
|
||||
|
||||
assert initialSignature != null : "Initial signature must be not null for suspension point";
|
||||
|
||||
KotlinType returnType = initialSignature.getReturnType();
|
||||
|
||||
assert returnType != null : "Return type of suspension point should not be null";
|
||||
return typeMapper.mapType(returnType);
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.Unit;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import kotlin.text.StringsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge;
|
||||
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.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
@@ -81,9 +82,7 @@ import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isAnnotationOrJvm6Interface;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8Interface;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceMember;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION;
|
||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
|
||||
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*;
|
||||
@@ -128,6 +127,10 @@ public class FunctionCodegen {
|
||||
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));
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.coroutines.continuationClassDescriptor
|
||||
import org.jetbrains.kotlin.codegen.coroutines.hasNoinlineInterceptResume
|
||||
import org.jetbrains.kotlin.coroutines.controllerTypeIfCoroutine
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -24,7 +25,6 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.util.createFunctionType
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -59,7 +59,7 @@ class JvmRuntimeTypes(module: ModuleDescriptor) {
|
||||
* @return `Continuation<Any?>` type
|
||||
*/
|
||||
private fun createNullableAnyContinuation(module: ModuleDescriptor): KotlinType {
|
||||
val classDescriptor = module.builtIns.getBuiltInClassByFqName(DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME)
|
||||
val classDescriptor = module.builtIns.continuationClassDescriptor
|
||||
|
||||
return TypeConstructorSubstitution.createByParametersMap(
|
||||
mapOf(classDescriptor.declaredTypeParameters.single() to TypeProjectionImpl(module.builtIns.nullableAnyType))
|
||||
|
||||
+29
@@ -20,6 +20,8 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import kotlin.Pair;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -432,6 +434,33 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
// working around a problem with shallow analysis
|
||||
if (functionDescriptor == null) return;
|
||||
|
||||
if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend()) {
|
||||
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
||||
CoroutineCodegenUtilKt.createJvmSuspendFunctionView(
|
||||
(SimpleFunctionDescriptor) functionDescriptor
|
||||
);
|
||||
|
||||
// This is a very subtle place (hack).
|
||||
// When generating bytecode of some suspend function, we replace the original descriptor
|
||||
// with one that reflects how it should look on JVM.
|
||||
// But the problem is that the function may contain resolved calls referencing original parameters, that are recreated
|
||||
// in jvmSuspendFunctionView.
|
||||
// So we remember the relation between the old and the new parameter descriptors and use it when looking for their indices
|
||||
// in ExpressionCodegen.
|
||||
for (Pair<ValueParameterDescriptor, ValueParameterDescriptor> parameterDescriptorPair : CollectionsKt
|
||||
.zip(functionDescriptor.getValueParameters(), jvmSuspendFunctionView.getValueParameters())) {
|
||||
bindingTrace.record(
|
||||
CodegenBinding.PARAMETER_SYNONYM, parameterDescriptorPair.getFirst(), parameterDescriptorPair.getSecond()
|
||||
);
|
||||
}
|
||||
|
||||
bindingTrace.record(
|
||||
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
|
||||
(SimpleFunctionDescriptor) functionDescriptor,
|
||||
jvmSuspendFunctionView
|
||||
);
|
||||
}
|
||||
|
||||
String nameForClassOrPackageMember = getNameForClassOrPackageMember(functionDescriptor);
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.push(nameForClassOrPackageMember);
|
||||
|
||||
@@ -71,6 +71,12 @@ public class CodegenBinding {
|
||||
public static final WritableSlice<KtElement, FunctionGenerationStrategy> CUSTOM_STRATEGY_FOR_INLINE_LAMBDA = Slices.createSimpleSlice();
|
||||
public static final WritableSlice<KtElement, FunctionDescriptor> CUSTOM_DESCRIPTOR_FOR_INLINE_LAMBDA = Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<SimpleFunctionDescriptor, SimpleFunctionDescriptor> SUSPEND_FUNCTION_TO_JVM_VIEW =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<ValueParameterDescriptor, ValueParameterDescriptor> PARAMETER_SYNONYM =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
static {
|
||||
BasicWritableSlice.initSliceDebugNames(CodegenBinding.class);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.codegen.JvmCodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.OwnerKind;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -79,7 +80,10 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
|
||||
|
||||
@Nullable
|
||||
public StackValue generateReceiver(@NotNull CallableDescriptor descriptor, @NotNull GenerationState state, boolean ignoreNoOuter) {
|
||||
if (getCallableDescriptorWithReceiver() == descriptor) {
|
||||
// When generating bytecode of some suspend function, we replace the original descriptor with one that reflects how it should look on JVM.
|
||||
// But when we looking for receiver parameter in resolved call, it still references the initial function, so we unwrap it here
|
||||
// before comparision.
|
||||
if (CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(getCallableDescriptorWithReceiver()) == descriptor) {
|
||||
return getReceiverExpression(state.getTypeMapper());
|
||||
}
|
||||
ReceiverParameterDescriptor parameter = descriptor.getExtensionReceiverParameter();
|
||||
|
||||
+1
-1
@@ -171,7 +171,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
suspensionCallBegin = beforeSuspensionPointMarker,
|
||||
suspensionCallEnd = methodInsn,
|
||||
fakeReturnValueInsns = fakeReturnValueInsns,
|
||||
returnType = Type.getType((beforeSuspensionPointMarker.previous as LdcInsnNode).cst as String))
|
||||
returnType = (beforeSuspensionPointMarker.previous as LdcInsnNode).cst as Type)
|
||||
suspensionPoints.add(suspensionPoint)
|
||||
|
||||
// Drop type info from marker
|
||||
|
||||
+114
-26
@@ -17,13 +17,19 @@
|
||||
package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
@@ -32,13 +38,16 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
||||
import org.jetbrains.kotlin.resolve.coroutine.REPLACED_SUSPENSION_POINT_KEY
|
||||
import org.jetbrains.kotlin.resolve.coroutine.SUSPENSION_POINT_KEY
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
// These classes do not actually exist at runtime
|
||||
val CONTINUATION_METHOD_ANNOTATION_DESC = "Lkotlin/ContinuationMethod;"
|
||||
@@ -54,30 +63,26 @@ const val COROUTINE_CONTROLLER_FIELD_NAME = "_controller"
|
||||
const val COROUTINE_CONTROLLER_GETTER_NAME = "getController"
|
||||
const val COROUTINE_LABEL_FIELD_NAME = "label"
|
||||
|
||||
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeThisExpression: KtExpression)
|
||||
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeContinuationExpression: KtExpression)
|
||||
|
||||
@JvmField
|
||||
val INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION = object : FunctionDescriptor.UserDataKey<FunctionDescriptor> {}
|
||||
// Resolved calls to suspension function contain descriptors as they visible within coroutines:
|
||||
// E.g. `fun <V> await(f: CompletableFuture<V>): V` instead of `fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>): Unit`
|
||||
// See `createCoroutineSuspensionFunctionView` and it's usages for clarification
|
||||
// See `createJvmSuspendFunctionView` and it's usages for clarification
|
||||
// But for call generation it's convenient to have `machine` (continuation) parameter/argument within resolvedCall.
|
||||
// So this function returns resolved call with descriptor looking like `fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>): Unit`
|
||||
// and fake `this` expression that used as argument for second parameter
|
||||
fun ResolvedCall<*>.replaceSuspensionFunctionViewWithRealDescriptor(
|
||||
project: Project
|
||||
fun ResolvedCall<*>.replaceSuspensionFunctionWithRealDescriptor(
|
||||
project: Project,
|
||||
bindingContext: BindingContext
|
||||
): ResolvedCallWithRealDescriptor? {
|
||||
val function = candidateDescriptor as? FunctionDescriptor ?: return null
|
||||
if (!isSuspensionPoint()) return null
|
||||
|
||||
val initialSignatureDescriptor = function.initialSignatureDescriptor ?: return null
|
||||
if (function.getUserData(REPLACED_SUSPENSION_POINT_KEY) == true) return null
|
||||
val function = candidateDescriptor as? SimpleFunctionDescriptor ?: return null
|
||||
if (!function.isSuspend || function.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) != null) return null
|
||||
|
||||
val newCandidateDescriptor =
|
||||
initialSignatureDescriptor.createCustomCopy {
|
||||
setPreserveSourceElement()
|
||||
setSignatureChange()
|
||||
putUserData(SUSPENSION_POINT_KEY, true)
|
||||
putUserData(REPLACED_SUSPENSION_POINT_KEY, true)
|
||||
}
|
||||
bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, function)
|
||||
?: createJvmSuspendFunctionView(function)
|
||||
|
||||
val newCall = ResolvedCallImpl(
|
||||
call,
|
||||
@@ -180,13 +185,35 @@ fun createResolvedCallForInterceptResume(
|
||||
return InterceptResumeCallContext(resolvedCall, thisExpression)
|
||||
}
|
||||
|
||||
fun ResolvedCall<*>.isSuspensionPoint() =
|
||||
(candidateDescriptor as? FunctionDescriptor)?.let { it.isSuspend && it.getUserData(SUSPENSION_POINT_KEY) ?: false }
|
||||
?: false
|
||||
fun ResolvedCall<*>.isSuspensionPoint(bindingContext: BindingContext) =
|
||||
bindingContext[BindingContext.COROUTINE_RECEIVER_FOR_SUSPENSION_POINT, call] != null
|
||||
|
||||
private fun FunctionDescriptor.createCustomCopy(
|
||||
copySettings: FunctionDescriptor.CopyBuilder<out FunctionDescriptor>.(FunctionDescriptor) -> FunctionDescriptor.CopyBuilder<out FunctionDescriptor>
|
||||
): FunctionDescriptor {
|
||||
// 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?')
|
||||
// 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(
|
||||
function, null, function.valueParameters.size, Annotations.EMPTY, Name.identifier("\$continuation"),
|
||||
function.getContinuationParameterTypeOfSuspendFunction(),
|
||||
/* declaresDefaultValue = */ false, /* isCrossinline = */ false,
|
||||
/* isNoinline = */ false, /* isCoroutine = */ false, /* varargElementType = */ null, SourceElement.NO_SOURCE
|
||||
)
|
||||
|
||||
return function.createCustomCopy {
|
||||
setPreserveSourceElement()
|
||||
setReturnType(function.builtIns.unitType)
|
||||
setValueParameters(it.valueParameters + continuationParameter)
|
||||
putUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION, it)
|
||||
}
|
||||
}
|
||||
|
||||
typealias FunctionDescriptorCopyBuilderToFunctionDescriptorCopyBuilder =
|
||||
FunctionDescriptor.CopyBuilder<out FunctionDescriptor>.(FunctionDescriptor)
|
||||
-> FunctionDescriptor.CopyBuilder<out FunctionDescriptor>
|
||||
|
||||
private fun <D : FunctionDescriptor> D.createCustomCopy(
|
||||
copySettings: FunctionDescriptorCopyBuilderToFunctionDescriptorCopyBuilder
|
||||
): D {
|
||||
|
||||
val newOriginal =
|
||||
if (original !== this)
|
||||
@@ -198,9 +225,18 @@ private fun FunctionDescriptor.createCustomCopy(
|
||||
|
||||
result.overriddenDescriptors = this.overriddenDescriptors.map { it.createCustomCopy(copySettings) }
|
||||
|
||||
return result
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return result as D
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction() =
|
||||
KotlinTypeFactory.simpleType(
|
||||
builtIns.continuationClassDescriptor.defaultType,
|
||||
arguments = listOf(returnType!!.asTypeProjection())
|
||||
)
|
||||
|
||||
val KotlinBuiltIns.continuationClassDescriptor get() = getBuiltInClassByFqName(DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME)
|
||||
|
||||
fun KotlinType.hasInlineInterceptResume() =
|
||||
findOperatorInController(this, OperatorNameConventions.COROUTINE_INTERCEPT_RESUME)?.isInline == true
|
||||
|
||||
@@ -209,3 +245,55 @@ fun KotlinType.hasNoinlineInterceptResume() =
|
||||
|
||||
fun findOperatorInController(controllerType: KotlinType, name: Name): SimpleFunctionDescriptor? =
|
||||
controllerType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).singleOrNull { it.isOperator }
|
||||
|
||||
val SUSPEND_WITH_CURRENT_CONTINUATION_NAME = Name.identifier("suspendWithCurrentContinuation")
|
||||
|
||||
fun FunctionDescriptor.isBuiltInSuspendWithCurrentContinuation(): Boolean {
|
||||
if (name != SUSPEND_WITH_CURRENT_CONTINUATION_NAME) return false
|
||||
|
||||
val originalDeclaration =
|
||||
builtIns.builtInsPackageFragments.singleOrNull { it.fqName == KotlinBuiltIns.COROUTINES_PACKAGE_FQ_NAME }
|
||||
?.getMemberScope()
|
||||
?.getContributedFunctions(SUSPEND_WITH_CURRENT_CONTINUATION_NAME, NoLookupLocation.FROM_BACKEND)
|
||||
?.singleOrNull()
|
||||
?: return false
|
||||
|
||||
return DescriptorEquivalenceForOverrides.areEquivalent(
|
||||
originalDeclaration, this.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)
|
||||
)
|
||||
}
|
||||
|
||||
fun createMethodNodeForSuspendWithCurrentContinuation(
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
typeMapper: KotlinTypeMapper
|
||||
): MethodNode {
|
||||
assert(functionDescriptor.isBuiltInSuspendWithCurrentContinuation()) {
|
||||
"functionDescriptor must be kotlin.coroutines.suspendWithCurrentContinuation"
|
||||
}
|
||||
|
||||
val node =
|
||||
MethodNode(
|
||||
Opcodes.ASM5,
|
||||
Opcodes.ACC_STATIC,
|
||||
"fake",
|
||||
typeMapper.mapAsmMethod(functionDescriptor).descriptor, null, null
|
||||
)
|
||||
|
||||
node.visitVarInsn(Opcodes.ALOAD, 0)
|
||||
node.visitVarInsn(Opcodes.ALOAD, 1)
|
||||
node.visitMethodInsn(
|
||||
Opcodes.INVOKEINTERFACE,
|
||||
typeMapper.mapType(functionDescriptor.valueParameters[0]).internalName,
|
||||
OperatorNameConventions.INVOKE.identifier,
|
||||
"(${AsmTypes.OBJECT_TYPE})${AsmTypes.OBJECT_TYPE}",
|
||||
true
|
||||
)
|
||||
node.visitInsn(Opcodes.POP)
|
||||
node.visitInsn(Opcodes.RETURN)
|
||||
node.visitMaxs(2, 2)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
fun CallableDescriptor?.unwrapInitialDescriptorForSuspendFunction() =
|
||||
(this as? SimpleFunctionDescriptor)?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) ?: this
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
|
||||
import org.jetbrains.kotlin.codegen.*;
|
||||
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.intrinsics.IntrinsicArrayConstructorsKt;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
@@ -246,6 +247,14 @@ public class InlineCodegen extends CallGenerator {
|
||||
);
|
||||
return new SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1));
|
||||
}
|
||||
else if (CoroutineCodegenUtilKt.isBuiltInSuspendWithCurrentContinuation(functionDescriptor)) {
|
||||
return new SMAPAndMethodNode(
|
||||
CoroutineCodegenUtilKt.createMethodNodeForSuspendWithCurrentContinuation(
|
||||
functionDescriptor, codegen.getState().getTypeMapper()
|
||||
),
|
||||
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
|
||||
);
|
||||
}
|
||||
|
||||
final GenerationState state = codegen.getState();
|
||||
final Method asmMethod =
|
||||
|
||||
@@ -6,7 +6,7 @@ class Controller {
|
||||
exception = t
|
||||
}
|
||||
|
||||
suspend fun suspendHere(x: Continuation<Any>) {}
|
||||
suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x ->}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Any>) {}
|
||||
suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x ->}
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ class Controller {
|
||||
result = "OK"
|
||||
}
|
||||
|
||||
suspend fun <T> await(t: T, c: Continuation<T>) {
|
||||
suspend fun <T> await(t: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(t)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendAndLog(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
result += "suspend($value);"
|
||||
c.resume(value)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
result += "["
|
||||
c.resume(value)
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendAndLog(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
result += "suspend($value);"
|
||||
c.resume(value)
|
||||
}
|
||||
|
||||
suspend fun suspendLogAndThrow(exception: Throwable, c: Continuation<Nothing>) {
|
||||
suspend fun suspendLogAndThrow(exception: Throwable): Nothing = suspendWithCurrentContinuation { c ->
|
||||
result += "throw(${exception.message});"
|
||||
c.resumeWithException(exception)
|
||||
}
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendAndLog(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
result += "suspend($value);"
|
||||
c.resume(value)
|
||||
}
|
||||
@@ -35,4 +35,4 @@ fun box(): String {
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
|
||||
suspend fun <T> suspendWithResult(value: T, c: Continuation<T>) {
|
||||
suspend fun <T> suspendWithResult(value: T): T = suspendWithCurrentContinuation { c ->
|
||||
c.resume(value)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
class Controller {
|
||||
var result = false
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(a: String = "abc", i: Int = 2, x: Continuation<String>) {
|
||||
suspend fun suspendHere(a: String = "abc", i: Int = 2): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(a + "#" + (i + 1))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var result = 0
|
||||
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
result++
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun <T> suspendHere(v: T, x: Continuation<T>) {
|
||||
suspend fun <T> suspendHere(v: T): T = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ class GeneratorController<T>() : AbstractIterator<T>() {
|
||||
this.nextStep = step
|
||||
}
|
||||
|
||||
suspend fun yield(value: T, c: Continuation<Unit>) {
|
||||
suspend fun yield(value: T): Unit = suspendWithCurrentContinuation { c ->
|
||||
setNext(value)
|
||||
setNextStep(c)
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@ class Controller {
|
||||
var exception: Throwable? = null
|
||||
val postponedActions = ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Controller {
|
||||
var isCompleted = false
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Controller {
|
||||
var log = ""
|
||||
|
||||
suspend fun <T> suspendAndLog(value: T, x: Continuation<T>) {
|
||||
suspend fun <T> suspendAndLog(value: T): T = suspendWithCurrentContinuation { x ->
|
||||
log += "suspend($value);"
|
||||
x.resume(value)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// NO_INTERCEPT_RESUME_TESTS
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,17 +8,13 @@ class Controller {
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
suspend inline fun suspendInline(v: String, x: Continuation<String>) {
|
||||
suspend inline fun suspendInline(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
withValue(v, x)
|
||||
}
|
||||
|
||||
suspend inline fun suspendInline(crossinline b: () -> String, x: Continuation<String>) {
|
||||
suspendInline(b(), x)
|
||||
}
|
||||
suspend inline fun suspendInline(crossinline b: () -> String): String = suspendInline(b())
|
||||
|
||||
suspend inline fun <reified T : Any> suspendInline(x: Continuation<String>) {
|
||||
suspendInline({ T::class.simpleName!! }, x)
|
||||
}
|
||||
suspend inline fun <reified T : Any> suspendInline(): String = suspendInline({ T::class.simpleName!! })
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = mutableListOf<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Controller {
|
||||
var i = 0
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume((i++).toString())
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
// WITH_REFLECT
|
||||
|
||||
class Controller {
|
||||
suspend fun runInstanceOf(x: Continuation<Boolean>) {
|
||||
suspend fun runInstanceOf(): Boolean = suspendWithCurrentContinuation { x ->
|
||||
val y: Any = x
|
||||
x.resume(x is Continuation<*>)
|
||||
}
|
||||
|
||||
suspend fun runCast(x: Continuation<Boolean>) {
|
||||
suspend fun runCast(): Boolean = suspendWithCurrentContinuation { x ->
|
||||
val y: Any = x
|
||||
x.resume(Continuation::class.isInstance(y as Continuation<*>))
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
class Controller {
|
||||
var result = "fail"
|
||||
suspend fun <V> suspendHere(v: V, x: Continuation<V>) {
|
||||
suspend fun <V> suspendHere(v: V): V = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Controller {
|
||||
var result = ""
|
||||
var ok = false
|
||||
suspend fun suspendHere(v: String, x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x ->
|
||||
result += v
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Controller {
|
||||
var wasHandleResultCalled = false
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Controller {
|
||||
var wasHandleResultCalled = false
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Controller {
|
||||
var ok = false
|
||||
var v = "fail"
|
||||
suspend fun suspendHere(v: String, x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x ->
|
||||
this.v = v
|
||||
x.resume(Unit)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
@@ -13,11 +14,11 @@ fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
fun box(): String {
|
||||
var result = "fail"
|
||||
|
||||
val lambda: Controller.() -> Continuation<Unit> = {
|
||||
val lambda: Controller.() -> Continuation<Unit> = l1@{
|
||||
object : Continuation<Any?> {
|
||||
override fun resume(data: Any?) {
|
||||
if (data == Unit) {
|
||||
suspendHere(this)
|
||||
this@l1.javaClass.getMethod("suspendHere", Continuation::class.java).invoke(this@l1, this)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
package lib
|
||||
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
@@ -4,36 +4,26 @@ package lib
|
||||
|
||||
@AllowSuspendExtensions
|
||||
class Controller {
|
||||
suspend fun String.suspendHere(x: Continuation<String>) {
|
||||
suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(this)
|
||||
}
|
||||
|
||||
inline suspend fun String.inlineSuspendHere(x: Continuation<String>) {
|
||||
suspendHere(x)
|
||||
}
|
||||
inline suspend fun String.inlineSuspendHere(): String = suspendHere()
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
}
|
||||
|
||||
suspend fun Controller.suspendExtension(v: String, x: Continuation<String>) {
|
||||
v.suspendHere(x)
|
||||
}
|
||||
suspend fun Controller.suspendExtension(v: String): String = v.suspendHere()
|
||||
|
||||
inline suspend fun Controller.inlineSuspendExtension(v: String, x: Continuation<String>) {
|
||||
v.inlineSuspendHere(x)
|
||||
}
|
||||
inline suspend fun Controller.inlineSuspendExtension(v: String) = v.inlineSuspendHere()
|
||||
|
||||
// MODULE: main(controller)
|
||||
// FILE: main.kt
|
||||
import lib.*
|
||||
|
||||
suspend fun Controller.localSuspendExtension(v: String, x: Continuation<String>) {
|
||||
v.suspendHere(x)
|
||||
}
|
||||
suspend fun Controller.localSuspendExtension(v: String) = v.suspendHere()
|
||||
|
||||
inline suspend fun Controller.localInlineSuspendExtension(v: String, x: Continuation<String>) {
|
||||
v.inlineSuspendHere(x)
|
||||
}
|
||||
inline suspend fun Controller.localInlineSuspendExtension(v: String) = v.inlineSuspendHere()
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
class Controller {
|
||||
var lastSuspension: Continuation<String>? = null
|
||||
var result = "fail"
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
lastSuspension = x
|
||||
Unit
|
||||
}
|
||||
|
||||
fun hasNext() = lastSuspension != null
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
class Controller {
|
||||
var lastSuspension: Continuation<String>? = null
|
||||
var result = "fail"
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
lastSuspension = x
|
||||
Unit
|
||||
}
|
||||
|
||||
fun hasNext() = lastSuspension != null
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
class Controller {
|
||||
var lastSuspension: Continuation<String>? = null
|
||||
var result = "fail"
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
lastSuspension = x
|
||||
Unit
|
||||
}
|
||||
|
||||
fun hasNext() = lastSuspension != null
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
class Controller {
|
||||
var lastSuspension: Continuation<String>? = null
|
||||
var result = "fail"
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
lastSuspension = x
|
||||
Unit
|
||||
}
|
||||
|
||||
fun hasNext() = lastSuspension != null
|
||||
|
||||
@@ -4,13 +4,13 @@ var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Controller {
|
||||
var cResult = 0
|
||||
suspend fun suspendHere(v: Int, x: Continuation<Int>) {
|
||||
suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v * 2)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
class Controller {
|
||||
var cResult = 0
|
||||
suspend fun suspendHere(v: Int, x: Continuation<Int>) {
|
||||
suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v * 2)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Controller {
|
||||
var res = 0
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resumeWithException(RuntimeException("OK"))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Controller {
|
||||
var res = 0
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
var globalResult = ""
|
||||
class Controller {
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspendThere(x)
|
||||
}
|
||||
suspend fun suspendHere(): String = suspendThere()
|
||||
|
||||
suspend fun suspendThere(x: Continuation<String>) {
|
||||
suspend fun suspendThere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
@AllowSuspendExtensions
|
||||
class Controller {
|
||||
suspend fun String.suspendHere(x: Continuation<String>) {
|
||||
suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(this)
|
||||
}
|
||||
|
||||
inline suspend fun String.inlineSuspendHere(x: Continuation<String>) {
|
||||
suspendHere(x)
|
||||
}
|
||||
inline suspend fun String.inlineSuspendHere(): String = suspendHere()
|
||||
|
||||
// INTERCEPT_RESUME_PLACEHOLDER
|
||||
}
|
||||
|
||||
suspend fun Controller.suspendExtension(v: String, x: Continuation<String>) {
|
||||
v.suspendHere(x)
|
||||
}
|
||||
suspend fun Controller.suspendExtension(v: String): String = v.suspendHere()
|
||||
|
||||
inline suspend fun Controller.inlineSuspendExtension(v: String, x: Continuation<String>) {
|
||||
v.inlineSuspendHere(x)
|
||||
}
|
||||
inline suspend fun Controller.inlineSuspendExtension(v: String): String = v.inlineSuspendHere()
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(v: Int, x: Continuation<Int>) {
|
||||
suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v * 2)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
class Controller {
|
||||
var i = 0
|
||||
suspend fun suspendHere(x: Continuation<Int>) {
|
||||
suspend fun suspendHere(): Int = suspendWithCurrentContinuation { x ->
|
||||
x.resume(i++)
|
||||
}
|
||||
suspend fun suspendThere(x: Continuation<String>) {
|
||||
suspend fun suspendThere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("?")
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("K")
|
||||
}
|
||||
|
||||
suspend fun suspendWithArgument(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendWithArgument(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
suspend fun suspendWithDouble(v: Double, x: Continuation<Double>) {
|
||||
suspend fun suspendWithDouble(v: Double): Double = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -4,13 +4,13 @@ var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume(v)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = mutableListOf<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x ->
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ inline fun inline() {}
|
||||
class External { external fun external() }
|
||||
operator fun Unit.invoke() {}
|
||||
infix fun Unit.infix(unit: Unit) {}
|
||||
class Suspend { suspend fun suspend(c: Continuation<Unit>) {} }
|
||||
// TODO: support or prohibit references to suspend functions
|
||||
// class Suspend { suspend fun suspend(c: Continuation<Unit>) {} }
|
||||
|
||||
val externalGetter = Unit
|
||||
external get
|
||||
@@ -44,11 +45,11 @@ fun box(): String {
|
||||
assertTrue(Unit::infix.isInfix)
|
||||
assertFalse(Unit::infix.isSuspend)
|
||||
|
||||
assertFalse(Suspend::suspend.isInline)
|
||||
assertFalse(Suspend::suspend.isExternal)
|
||||
assertFalse(Suspend::suspend.isOperator)
|
||||
assertFalse(Suspend::suspend.isInfix)
|
||||
assertTrue(Suspend::suspend.isSuspend)
|
||||
// assertFalse(Suspend::suspend.isInline)
|
||||
// assertFalse(Suspend::suspend.isExternal)
|
||||
// assertFalse(Suspend::suspend.isOperator)
|
||||
// assertFalse(Suspend::suspend.isInfix)
|
||||
// assertTrue(Suspend::suspend.isSuspend)
|
||||
|
||||
assertTrue(::externalGetter.getter.isExternal)
|
||||
assertFalse(::externalGetter.getter.isInline)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere() = suspendWithCurrentContinuation<String> { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
}
|
||||
suspend fun suspendHere() = ""
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x ->
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere(): String = suspendWithCurrentContinuation { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ class FutureController<T> {
|
||||
val future = CompletableFuture<T>()
|
||||
|
||||
|
||||
suspend fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>) {
|
||||
suspend fun <V> await(f: CompletableFuture<V>) = suspendWithCurrentContinuation<V> { machine ->
|
||||
f.whenComplete { value, throwable ->
|
||||
if (throwable == null)
|
||||
machine.resume(value)
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ fun <T> async(coroutine c: FutureController<T>.() -> Continuation<Unit>): Comple
|
||||
class FutureController<T> {
|
||||
val future = CompletableFuture<T>()
|
||||
|
||||
suspend fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>) {
|
||||
suspend fun <V> await(f: CompletableFuture<V>) = suspendWithCurrentContinuation<V> { machine ->
|
||||
f.whenComplete { value, throwable ->
|
||||
if (throwable == null)
|
||||
machine.resume(value)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// FILE: A.kt
|
||||
package a
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
suspend fun suspendHere() = suspendWithCurrentContinuation<String> { x ->
|
||||
x.resume("OK")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ fun async(coroutine x: Controller.() -> Continuation<Unit>) {
|
||||
}
|
||||
|
||||
class Controller {
|
||||
suspend fun step(param: Int, next: Continuation<Int>) {
|
||||
suspend fun step(param: Int) = suspendWithCurrentContinuation<Int> { next ->
|
||||
next.resume(param + 1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user