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;
|
FunctionDescriptor erasedInterfaceFunction;
|
||||||
if (samType == null) {
|
if (samType == null) {
|
||||||
erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor);
|
erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor);
|
||||||
@@ -233,7 +233,10 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
|||||||
protected void generateKotlinMetadataAnnotation() {
|
protected void generateKotlinMetadataAnnotation() {
|
||||||
FunctionDescriptor freeLambdaDescriptor = createFreeLambdaDescriptor(funDescriptor);
|
FunctionDescriptor freeLambdaDescriptor = createFreeLambdaDescriptor(funDescriptor);
|
||||||
Method method = v.getSerializationBindings().get(METHOD_FOR_FUNCTION, 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);
|
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, freeLambdaDescriptor, method);
|
||||||
|
|
||||||
final DescriptorSerializer serializer =
|
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.SwitchCodegen;
|
||||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
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.LocalVariableDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
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 (originalCoroutineDescriptor != null) return originalCoroutineDescriptor;
|
||||||
|
|
||||||
if (context.getFunctionDescriptor().isSuspend()) {
|
if (context.getFunctionDescriptor().isSuspend()) {
|
||||||
return (FunctionDescriptor) CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(context.getFunctionDescriptor());
|
return CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(context.getFunctionDescriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -192,7 +191,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
private static FunctionDescriptor getOriginalCoroutineDescriptor(MethodContext context) {
|
private static FunctionDescriptor getOriginalCoroutineDescriptor(MethodContext context) {
|
||||||
if ((context.getParentContext() instanceof ClosureContext) &&
|
if ((context.getParentContext() instanceof ClosureContext) &&
|
||||||
(context.getParentContext().closure != null) &&
|
(context.getParentContext().closure != null) &&
|
||||||
context.getParentContext().closure.isCoroutine()) {
|
context.getParentContext().closure.isSuspend()) {
|
||||||
return ((ClosureContext) context.getParentContext()).getCoroutineDescriptor();
|
return ((ClosureContext) context.getParentContext()).getCoroutineDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1650,7 +1649,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
declaration.getContainingFile()
|
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(
|
ClosureCodegen closureCodegen = coroutineCodegen != null ? coroutineCodegen : new ClosureCodegen(
|
||||||
state, declaration, samType, context.intoClosure(descriptor, this, typeMapper),
|
state, declaration, samType, context.intoClosure(descriptor, this, typeMapper),
|
||||||
functionReferenceTarget, strategy, parentCodegen, cv
|
functionReferenceTarget, strategy, parentCodegen, cv
|
||||||
@@ -1658,6 +1657,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
|
|
||||||
closureCodegen.generate();
|
closureCodegen.generate();
|
||||||
|
|
||||||
|
return putClosureInstanceOnStack(closureCodegen, functionReferenceReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public StackValue putClosureInstanceOnStack(
|
||||||
|
@NotNull ClosureCodegen closureCodegen,
|
||||||
|
@Nullable StackValue functionReferenceReceiver
|
||||||
|
) {
|
||||||
if (closureCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
|
if (closureCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
|
||||||
ReifiedTypeInliner.putNeedClassReificationMarker(v);
|
ReifiedTypeInliner.putNeedClassReificationMarker(v);
|
||||||
propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages());
|
propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages());
|
||||||
@@ -1770,9 +1777,20 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (closure.isCoroutine()) {
|
if (closure.isSuspend()) {
|
||||||
// resultContinuation
|
// 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
|
@Nullable
|
||||||
private StackValue getCoroutineInstanceValueForSuspensionPoint(@NotNull ResolvedCall<?> resolvedCall) {
|
private StackValue getCoroutineInstanceValueForSuspensionPoint(@NotNull ResolvedCall<?> resolvedCall) {
|
||||||
CallableDescriptor enclosingSuspendLambdaForSuspensionPoint =
|
FunctionDescriptor enclosingSuspendLambdaForSuspensionPoint =
|
||||||
bindingContext.get(ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, resolvedCall.getCall());
|
bindingContext.get(ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
|
||||||
|
|
||||||
if (enclosingSuspendLambdaForSuspensionPoint == null) return null;
|
if (enclosingSuspendLambdaForSuspensionPoint == null) return null;
|
||||||
return genCoroutineInstanceByLambda(enclosingSuspendLambdaForSuspensionPoint);
|
return genCoroutineInstanceBySuspendFunction(enclosingSuspendLambdaForSuspensionPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@Nullable
|
||||||
private StackValue genCoroutineInstanceByLambda(@NotNull CallableDescriptor suspendLambda) {
|
private StackValue genCoroutineInstanceBySuspendFunction(@NotNull FunctionDescriptor suspendFunction) {
|
||||||
ClassDescriptor suspendLambdaClassDescriptor =
|
if (!CoroutineCodegenUtilKt.isStateMachineNeeded(suspendFunction, bindingContext)) return null;
|
||||||
bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendLambda);
|
ClassDescriptor suspendLambdaClassDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendFunction);
|
||||||
assert suspendLambdaClassDescriptor != null : "Coroutine class descriptor should not be null";
|
assert suspendLambdaClassDescriptor != null : "Coroutine class descriptor should not be null";
|
||||||
|
|
||||||
return StackValue.thisOrOuter(this, suspendLambdaClassDescriptor, false, false);
|
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);
|
StackValue result = callable.invokeMethodWithArguments(resolvedCall, receiver, this);
|
||||||
|
|
||||||
if (bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall()) != null) {
|
if (resolvedCall.getResultingDescriptor() instanceof FunctionDescriptor &&
|
||||||
// Suspend function's calls inside another suspend function should behave like they leave values of correct type,
|
((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.
|
// while real methods return java/lang/Object.
|
||||||
// NB: They are always in return position at the moment.
|
// 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
|
// 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) {
|
private StackValue getContinuationParameterFromEnclosingSuspendFunction(@NotNull ResolvedCall<?> resolvedCall) {
|
||||||
SimpleFunctionDescriptor enclosingSuspendFunction =
|
FunctionDescriptor enclosingSuspendFunction =
|
||||||
bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
|
bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
|
||||||
|
|
||||||
assert enclosingSuspendFunction != null
|
assert enclosingSuspendFunction != null
|
||||||
: "Suspend functions may be called either as suspension points or from another suspend function";
|
: "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);
|
bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, enclosingSuspendFunction);
|
||||||
|
|
||||||
assert enclosingSuspendFunctionJvmView != null : "No JVM view function found for " + 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 CallGenerator callGenerator,
|
||||||
@NotNull ArgumentGenerator argumentGenerator
|
@NotNull ArgumentGenerator argumentGenerator
|
||||||
) {
|
) {
|
||||||
boolean isSuspensionPoint = CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, bindingContext);
|
boolean isSuspensionPoint = CoroutineCodegenUtilKt.isSuspensionPointInStateMachine(resolvedCall, bindingContext);
|
||||||
if (isSuspensionPoint) {
|
if (isSuspensionPoint) {
|
||||||
// Inline markers are used to spill the stack before coroutine suspension
|
// Inline markers are used to spill the stack before coroutine suspension
|
||||||
addInlineMarker(v, true);
|
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.annotation.AnnotatedWithOnlyTargetedAnnotations;
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||||
import org.jetbrains.kotlin.codegen.context.*;
|
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.GenerationState;
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
@@ -119,17 +121,29 @@ public class FunctionCodegen {
|
|||||||
|
|
||||||
public void gen(@NotNull KtNamedFunction function) {
|
public void gen(@NotNull KtNamedFunction function) {
|
||||||
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, 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) {
|
if (functionDescriptor == null) {
|
||||||
throw ExceptionLogger.logDescriptorNotFound("No descriptor for function " + function.getName(), function);
|
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()) {
|
if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) {
|
||||||
generateMethod(JvmDeclarationOriginKt.OtherOrigin(function, functionDescriptor), functionDescriptor,
|
FunctionGenerationStrategy strategy;
|
||||||
new FunctionGenerationStrategy.FunctionDefault(state, function));
|
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(),
|
generateDefaultIfNeeded(owner.intoFunction(functionDescriptor, true), functionDescriptor, owner.getContextKind(),
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public class JvmCodegenUtil {
|
|||||||
return closure.getCaptureThis() == null &&
|
return closure.getCaptureThis() == null &&
|
||||||
closure.getCaptureReceiverType() == null &&
|
closure.getCaptureReceiverType() == null &&
|
||||||
closure.getCaptureVariables().isEmpty() &&
|
closure.getCaptureVariables().isEmpty() &&
|
||||||
!closure.isCoroutine();
|
!closure.isSuspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isCallInsideSameClassAsDeclared(@NotNull CallableMemberDescriptor descriptor, @NotNull CodegenContext context) {
|
private static boolean isCallInsideSameClassAsDeclared(@NotNull CallableMemberDescriptor descriptor, @NotNull CodegenContext context) {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class JvmRuntimeTypes(module: ModuleDescriptor) {
|
|||||||
fun getSupertypesForClosure(descriptor: FunctionDescriptor): Collection<KotlinType> {
|
fun getSupertypesForClosure(descriptor: FunctionDescriptor): Collection<KotlinType> {
|
||||||
|
|
||||||
val actualFunctionDescriptor =
|
val actualFunctionDescriptor =
|
||||||
if (descriptor.isSuspendLambda)
|
if (descriptor.isSuspend)
|
||||||
createJvmSuspendFunctionView(descriptor)
|
createJvmSuspendFunctionView(descriptor)
|
||||||
else
|
else
|
||||||
descriptor
|
descriptor
|
||||||
@@ -84,15 +84,17 @@ class JvmRuntimeTypes(module: ModuleDescriptor) {
|
|||||||
actualFunctionDescriptor.returnType!!
|
actualFunctionDescriptor.returnType!!
|
||||||
)
|
)
|
||||||
|
|
||||||
if (descriptor.isSuspendLambda) {
|
if (descriptor.isSuspend) {
|
||||||
return mutableListOf<KotlinType>().apply {
|
return mutableListOf<KotlinType>().apply {
|
||||||
add(coroutineImplClass.defaultType)
|
add(coroutineImplClass.defaultType)
|
||||||
add(functionType)
|
|
||||||
|
|
||||||
val parametersNumber =
|
if (descriptor.isSuspendLambda) {
|
||||||
descriptor.valueParameters.size + (if (functionType.isExtensionFunctionType) 1 else 0)
|
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
|
@NotNull
|
||||||
List<Pair<String, Type>> getRecordedFields();
|
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 CallableDescriptor callableDescriptor,
|
||||||
@NotNull Collection<KotlinType> supertypes,
|
@NotNull Collection<KotlinType> supertypes,
|
||||||
@NotNull String name
|
@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);
|
String simpleName = name.substring(name.lastIndexOf('/') + 1);
|
||||||
ClassDescriptor classDescriptor = new SyntheticClassDescriptorForLambda(
|
ClassDescriptor classDescriptor = new SyntheticClassDescriptorForLambda(
|
||||||
correctContainerForLambda(callableDescriptor, element),
|
customContainer != null ? customContainer : correctContainerForLambda(callableDescriptor, element),
|
||||||
Name.special("<closure-" + simpleName + ">"),
|
Name.special("<closure-" + simpleName + ">"),
|
||||||
supertypes,
|
supertypes,
|
||||||
element
|
element
|
||||||
@@ -289,7 +300,8 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
nameStack.push(name);
|
nameStack.push(name);
|
||||||
|
|
||||||
if (CoroutineUtilKt.isSuspendLambda(functionDescriptor)) {
|
if (CoroutineUtilKt.isSuspendLambda(functionDescriptor)) {
|
||||||
closure.setCoroutine(true);
|
closure.setSuspend(true);
|
||||||
|
closure.setSuspendLambda();
|
||||||
}
|
}
|
||||||
|
|
||||||
super.visitLambdaExpression(lambdaExpression);
|
super.visitLambdaExpression(lambdaExpression);
|
||||||
@@ -415,6 +427,8 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
// working around a problem with shallow analysis
|
// working around a problem with shallow analysis
|
||||||
if (functionDescriptor == null) return;
|
if (functionDescriptor == null) return;
|
||||||
|
|
||||||
|
String nameForClassOrPackageMember = getNameForClassOrPackageMember(functionDescriptor);
|
||||||
|
|
||||||
if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend()) {
|
if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend()) {
|
||||||
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
||||||
CoroutineCodegenUtilKt.createJvmSuspendFunctionView(
|
CoroutineCodegenUtilKt.createJvmSuspendFunctionView(
|
||||||
@@ -437,31 +451,53 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
|
|
||||||
bindingTrace.record(
|
bindingTrace.record(
|
||||||
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
|
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
|
||||||
(SimpleFunctionDescriptor) functionDescriptor,
|
functionDescriptor,
|
||||||
jvmSuspendFunctionView
|
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) {
|
if (nameForClassOrPackageMember != null) {
|
||||||
nameStack.push(nameForClassOrPackageMember);
|
nameStack.push(nameForClassOrPackageMember);
|
||||||
super.visitNamedFunction(function);
|
super.visitNamedFunction(function);
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String name = inventAnonymousClassName();
|
processNamedFunctionWithClosure(function, functionDescriptor, null);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@Nullable
|
||||||
private String getNameForClassOrPackageMember(@NotNull DeclarationDescriptor descriptor) {
|
private String getNameForClassOrPackageMember(@NotNull DeclarationDescriptor descriptor) {
|
||||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class CodegenBinding {
|
|||||||
public static final WritableSlice<VariableDescriptor, VariableDescriptor> LOCAL_VARIABLE_PROPERTY_METADATA =
|
public static final WritableSlice<VariableDescriptor, VariableDescriptor> LOCAL_VARIABLE_PROPERTY_METADATA =
|
||||||
Slices.createSimpleSlice();
|
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();
|
Slices.createSimpleSlice();
|
||||||
|
|
||||||
public static final WritableSlice<ValueParameterDescriptor, ValueParameterDescriptor> PARAMETER_SYNONYM =
|
public static final WritableSlice<ValueParameterDescriptor, ValueParameterDescriptor> PARAMETER_SYNONYM =
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ public final class MutableClosure implements CalculatedClosure {
|
|||||||
private Map<DeclarationDescriptor, Integer> parameterOffsetInConstructor;
|
private Map<DeclarationDescriptor, Integer> parameterOffsetInConstructor;
|
||||||
private List<Pair<String, Type>> recordedFields;
|
private List<Pair<String, Type>> recordedFields;
|
||||||
private KotlinType captureReceiverType;
|
private KotlinType captureReceiverType;
|
||||||
private boolean isCoroutine;
|
private boolean isSuspend;
|
||||||
|
private boolean isSuspendLambda;
|
||||||
|
|
||||||
MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
|
MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
|
||||||
this.closureClass = classDescriptor;
|
this.closureClass = classDescriptor;
|
||||||
@@ -119,12 +120,21 @@ public final class MutableClosure implements CalculatedClosure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCoroutine() {
|
public boolean isSuspend() {
|
||||||
return isCoroutine;
|
return isSuspend;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCoroutine(boolean coroutine) {
|
public void setSuspend(boolean suspend) {
|
||||||
this.isCoroutine = coroutine;
|
this.isSuspend = suspend;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuspendLambda() {
|
||||||
|
return isSuspendLambda;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuspendLambda() {
|
||||||
|
isSuspendLambda = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void recordField(String name, Type type) {
|
public void recordField(String name, Type type) {
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.codegen.coroutines
|
|||||||
import com.intellij.util.ArrayUtil
|
import com.intellij.util.ArrayUtil
|
||||||
import org.jetbrains.kotlin.backend.common.CONTINUATION_RESUME_METHOD_NAME
|
import org.jetbrains.kotlin.backend.common.CONTINUATION_RESUME_METHOD_NAME
|
||||||
import org.jetbrains.kotlin.codegen.*
|
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.ClosureContext
|
||||||
|
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
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.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtFunction
|
||||||
import org.jetbrains.kotlin.psi.KtFunctionLiteral
|
import org.jetbrains.kotlin.psi.KtFunctionLiteral
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
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.AsmTypes
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
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.types.typeUtil.makeNullable
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
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.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
@@ -49,16 +52,20 @@ import org.jetbrains.org.objectweb.asm.commons.Method
|
|||||||
|
|
||||||
|
|
||||||
class CoroutineCodegen(
|
class CoroutineCodegen(
|
||||||
state: GenerationState,
|
outerExpressionCodegen: ExpressionCodegen,
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
private val closureContext: ClosureContext,
|
private val closureContext: ClosureContext,
|
||||||
strategy: FunctionGenerationStrategy,
|
|
||||||
parentCodegen: MemberCodegen<*>,
|
|
||||||
classBuilder: ClassBuilder,
|
classBuilder: ClassBuilder,
|
||||||
private val coroutineLambdaDescriptor: FunctionDescriptor
|
private val originalSuspendLambdaDescriptor: FunctionDescriptor?
|
||||||
) : ClosureCodegen(state, element, null, closureContext, null, strategy, parentCodegen, classBuilder) {
|
) : ClosureCodegen(
|
||||||
|
outerExpressionCodegen.state,
|
||||||
|
element, null, closureContext, null,
|
||||||
|
FailingFunctionGenerationStrategy,
|
||||||
|
outerExpressionCodegen.parentCodegen, classBuilder
|
||||||
|
) {
|
||||||
|
|
||||||
private val classDescriptor = closureContext.contextDescriptor
|
private val classDescriptor = closureContext.contextDescriptor
|
||||||
|
private val builtIns = funDescriptor.builtIns
|
||||||
|
|
||||||
private lateinit var constructorToUseFromInvoke: Method
|
private lateinit var constructorToUseFromInvoke: Method
|
||||||
|
|
||||||
@@ -75,33 +82,33 @@ class CoroutineCodegen(
|
|||||||
listOf(
|
listOf(
|
||||||
ValueParameterDescriptorImpl(
|
ValueParameterDescriptorImpl(
|
||||||
this@doResume, null, 0, Annotations.EMPTY, Name.identifier("data"),
|
this@doResume, null, 0, Annotations.EMPTY, Name.identifier("data"),
|
||||||
module.builtIns.nullableAnyType,
|
builtIns.nullableAnyType,
|
||||||
/* isDefault = */ false, /* isCrossinline = */ false,
|
/* isDefault = */ false, /* isCrossinline = */ false,
|
||||||
/* isNoinline = */ false,
|
/* isNoinline = */ false,
|
||||||
/* varargElementType = */ null, SourceElement.NO_SOURCE
|
/* varargElementType = */ null, SourceElement.NO_SOURCE
|
||||||
),
|
),
|
||||||
ValueParameterDescriptorImpl(
|
ValueParameterDescriptorImpl(
|
||||||
this@doResume, null, 1, Annotations.EMPTY, Name.identifier("throwable"),
|
this@doResume, null, 1, Annotations.EMPTY, Name.identifier("throwable"),
|
||||||
module.builtIns.throwable.defaultType.makeNullable(),
|
builtIns.throwable.defaultType.makeNullable(),
|
||||||
/* isDefault = */ false, /* isCrossinline = */ false,
|
/* isDefault = */ false, /* isCrossinline = */ false,
|
||||||
/* isNoinline = */ false,
|
/* isNoinline = */ false,
|
||||||
/* varargElementType = */ null, SourceElement.NO_SOURCE
|
/* varargElementType = */ null, SourceElement.NO_SOURCE
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
funDescriptor.builtIns.nullableAnyType,
|
builtIns.nullableAnyType,
|
||||||
Modality.FINAL,
|
Modality.FINAL,
|
||||||
Visibilities.PROTECTED
|
Visibilities.PUBLIC
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val createCoroutineDescriptor =
|
private val createCoroutineDescriptor =
|
||||||
funDescriptor.createCustomCopy {
|
funDescriptor.createCustomCopy {
|
||||||
setName(Name.identifier("create"))
|
setName(Name.identifier(SUSPEND_FUNCTION_CREATE_METHOD_NAME))
|
||||||
setReturnType(
|
setReturnType(
|
||||||
KotlinTypeFactory.simpleNotNullType(
|
KotlinTypeFactory.simpleNotNullType(
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
funDescriptor.builtIns.continuationClassDescriptor,
|
builtIns.continuationClassDescriptor,
|
||||||
listOf(funDescriptor.builtIns.unitType.asTypeProjection())
|
listOf(builtIns.unitType.asTypeProjection())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
setVisibility(Visibilities.PUBLIC)
|
setVisibility(Visibilities.PUBLIC)
|
||||||
@@ -121,9 +128,17 @@ class CoroutineCodegen(
|
|||||||
generateDoResume()
|
generateDoResume()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun generateBridges() {
|
||||||
|
if (originalSuspendLambdaDescriptor == null) return
|
||||||
|
super.generateBridges()
|
||||||
|
}
|
||||||
|
|
||||||
override fun generateBody() {
|
override fun generateBody() {
|
||||||
super.generateBody()
|
super.generateBody()
|
||||||
|
|
||||||
|
if (originalSuspendLambdaDescriptor == null) return
|
||||||
|
|
||||||
|
// create() = ...
|
||||||
functionCodegen.generateMethod(JvmDeclarationOrigin.NO_ORIGIN, createCoroutineDescriptor,
|
functionCodegen.generateMethod(JvmDeclarationOrigin.NO_ORIGIN, createCoroutineDescriptor,
|
||||||
object : FunctionGenerationStrategy.CodegenBased(state) {
|
object : FunctionGenerationStrategy.CodegenBased(state) {
|
||||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||||
@@ -182,7 +197,6 @@ class CoroutineCodegen(
|
|||||||
areturn(AsmTypes.OBJECT_TYPE)
|
areturn(AsmTypes.OBJECT_TYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun generateConstructor(): Method {
|
override fun generateConstructor(): Method {
|
||||||
val args = calculateConstructorParameters(typeMapper, closure, asmType)
|
val args = calculateConstructorParameters(typeMapper, closure, asmType)
|
||||||
val argTypes = args.map { it.fieldType }.plus(AsmTypes.CONTINUATION).toTypedArray()
|
val argTypes = args.map { it.fieldType }.plus(AsmTypes.CONTINUATION).toTypedArray()
|
||||||
@@ -217,6 +231,7 @@ class CoroutineCodegen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateCreateCoroutineMethod(codegen: ExpressionCodegen) {
|
private fun generateCreateCoroutineMethod(codegen: ExpressionCodegen) {
|
||||||
|
assert(originalSuspendLambdaDescriptor != null) { "create method should only be generated for suspend lambdas" }
|
||||||
val classDescriptor = closureContext.contextDescriptor
|
val classDescriptor = closureContext.contextDescriptor
|
||||||
val owner = typeMapper.mapClass(classDescriptor)
|
val owner = typeMapper.mapClass(classDescriptor)
|
||||||
|
|
||||||
@@ -265,7 +280,7 @@ class CoroutineCodegen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun allLambdaParameters() =
|
private fun allLambdaParameters() =
|
||||||
coroutineLambdaDescriptor.extensionReceiverParameter.singletonOrEmptyList() + coroutineLambdaDescriptor.valueParameters
|
originalSuspendLambdaDescriptor?.extensionReceiverParameter.singletonOrEmptyList() + originalSuspendLambdaDescriptor?.valueParameters.orEmpty()
|
||||||
|
|
||||||
private fun ExpressionCodegen.generateLoadField(fieldInfo: FieldInfo) {
|
private fun ExpressionCodegen.generateLoadField(fieldInfo: FieldInfo) {
|
||||||
StackValue.field(fieldInfo, generateThisOrOuter(context.thisDescriptor, false)).put(fieldInfo.fieldType, v)
|
StackValue.field(fieldInfo, generateThisOrOuter(context.thisDescriptor, false)).put(fieldInfo.fieldType, v)
|
||||||
@@ -298,7 +313,7 @@ class CoroutineCodegen(
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun create(
|
fun createByLambda(
|
||||||
expressionCodegen: ExpressionCodegen,
|
expressionCodegen: ExpressionCodegen,
|
||||||
originalCoroutineLambdaDescriptor: FunctionDescriptor,
|
originalCoroutineLambdaDescriptor: FunctionDescriptor,
|
||||||
declaration: KtElement,
|
declaration: KtElement,
|
||||||
@@ -307,21 +322,52 @@ class CoroutineCodegen(
|
|||||||
if (declaration !is KtFunctionLiteral) return null
|
if (declaration !is KtFunctionLiteral) return null
|
||||||
if (!originalCoroutineLambdaDescriptor.isSuspendLambda) return null
|
if (!originalCoroutineLambdaDescriptor.isSuspendLambda) return null
|
||||||
|
|
||||||
val descriptorWithContinuationReturnType = createJvmSuspendFunctionView(originalCoroutineLambdaDescriptor)
|
|
||||||
|
|
||||||
val state = expressionCodegen.state
|
|
||||||
return CoroutineCodegen(
|
return CoroutineCodegen(
|
||||||
state,
|
expressionCodegen,
|
||||||
declaration,
|
declaration,
|
||||||
expressionCodegen.context.intoCoroutineClosure(
|
expressionCodegen.context.intoCoroutineClosure(
|
||||||
descriptorWithContinuationReturnType, originalCoroutineLambdaDescriptor, expressionCodegen, state.typeMapper
|
createJvmSuspendFunctionView(originalCoroutineLambdaDescriptor),
|
||||||
|
originalCoroutineLambdaDescriptor, expressionCodegen, expressionCodegen.state.typeMapper
|
||||||
),
|
),
|
||||||
FunctionGenerationStrategy.FunctionDefault(state, declaration),
|
classBuilder,
|
||||||
expressionCodegen.parentCodegen, classBuilder,
|
|
||||||
originalCoroutineLambdaDescriptor
|
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 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.SUSPENDED_MARKER_NAME
|
||||||
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineOrReturn
|
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineOrReturn
|
||||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||||
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
|
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
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 ACTUAL_COROUTINE_START_MARKER_NAME = "actualCoroutineStart"
|
||||||
|
|
||||||
const val COROUTINE_LABEL_FIELD_NAME = "label"
|
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)
|
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeContinuationExpression: KtExpression)
|
||||||
|
|
||||||
@@ -118,9 +122,18 @@ fun ResolvedCall<*>.replaceSuspensionFunctionWithRealDescriptor(
|
|||||||
return ResolvedCallWithRealDescriptor(newCall, thisExpression)
|
return ResolvedCallWithRealDescriptor(newCall, thisExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ResolvedCall<*>.isSuspensionPoint(bindingContext: BindingContext) =
|
fun ResolvedCall<*>.isSuspensionPointInStateMachine(bindingContext: BindingContext): Boolean {
|
||||||
bindingContext[BindingContext.ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, call] != null
|
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>`,
|
// Suspend functions have irregular signatures on JVM, containing an additional last parameter with type `Continuation<return-type>`,
|
||||||
// and return type Any?
|
// and return type Any?
|
||||||
// This function returns a function descriptor reflecting how the suspend function looks from point of view of JVM
|
// This function returns a function descriptor reflecting how the suspend function looks from point of view of JVM
|
||||||
@@ -207,8 +220,9 @@ fun createMethodNodeForSuspendCoroutineOrReturn(
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CallableDescriptor?.unwrapInitialDescriptorForSuspendFunction() =
|
@Suppress("UNCHECKED_CAST")
|
||||||
(this as? SimpleFunctionDescriptor)?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) ?: this
|
fun <D : CallableDescriptor?> D.unwrapInitialDescriptorForSuspendFunction(): D =
|
||||||
|
this.safeAs<SimpleFunctionDescriptor>()?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) as D ?: this
|
||||||
|
|
||||||
fun InstructionAdapter.loadSuspendMarker() {
|
fun InstructionAdapter.loadSuspendMarker() {
|
||||||
invokestatic(
|
invokestatic(
|
||||||
@@ -218,3 +232,17 @@ fun InstructionAdapter.loadSuspendMarker() {
|
|||||||
false
|
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.*;
|
||||||
import org.jetbrains.kotlin.codegen.context.*;
|
import org.jetbrains.kotlin.codegen.context.*;
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
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.intrinsics.IntrinsicArrayConstructorsKt;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||||
@@ -601,6 +602,14 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
else if (expression instanceof KtFunctionLiteral) {
|
else if (expression instanceof KtFunctionLiteral) {
|
||||||
strategy = new ClosureGenerationStrategy(state, (KtDeclarationWithBody) expression);
|
strategy = new ClosureGenerationStrategy(state, (KtDeclarationWithBody) expression);
|
||||||
}
|
}
|
||||||
|
else if (descriptor.isSuspend() && expression instanceof KtFunction) {
|
||||||
|
strategy =
|
||||||
|
new SuspendFunctionGenerationStrategy(
|
||||||
|
state,
|
||||||
|
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(descriptor),
|
||||||
|
(KtFunction) expression
|
||||||
|
);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
strategy = new FunctionGenerationStrategy.FunctionDefault(state, (KtDeclarationWithBody) expression);
|
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 ->
|
suspend fun suspendHere() = suspendCoroutineOrReturn<String> { x ->
|
||||||
x.resume("OK")
|
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) {
|
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
|
@kotlin.Metadata
|
||||||
public final class Controller {
|
public final class Controller {
|
||||||
|
inner class Controller$multipleSuspensions$1
|
||||||
|
inner class Controller$nonTailCall$1
|
||||||
public method <init>(): void
|
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 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
|
@kotlin.Metadata
|
||||||
@@ -15,7 +34,7 @@ final class CoroutineFieldsKt$box$1 {
|
|||||||
method <init>(p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.coroutines.Continuation): void
|
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 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
|
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 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
|
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")
|
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionTypeCall")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionTypeCall")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionTypeCall")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionTypeCall")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user