diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/commonCoroutineCodegenUtil.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/commonCoroutineCodegenUtil.kt index 2ec90ef7072..bdedbb359b8 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/commonCoroutineCodegenUtil.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/commonCoroutineCodegenUtil.kt @@ -18,12 +18,9 @@ package org.jetbrains.kotlin.backend.common import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.util.OperatorNameConventions val SUSPEND_WITH_CURRENT_CONTINUATION_NAME = Name.identifier("suspendWithCurrentContinuation") @@ -32,8 +29,3 @@ fun FunctionDescriptor.getBuiltInSuspendWithCurrentContinuation() = ?.getMemberScope() ?.getContributedFunctions(SUSPEND_WITH_CURRENT_CONTINUATION_NAME, NoLookupLocation.FROM_BACKEND) ?.singleOrNull() - -fun KotlinType.findInterceptResume() = findOperatorInController(this, OperatorNameConventions.COROUTINE_INTERCEPT_RESUME) - -fun findOperatorInController(controllerType: KotlinType, name: Name): SimpleFunctionDescriptor? = - controllerType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).singleOrNull { it.isOperator } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 609c105410c..f196ef48cc9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -457,9 +457,18 @@ public class AsmUtil { } public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) { + return genAssignInstanceFieldFromParam(info, index, iv, 0); + } + + public static int genAssignInstanceFieldFromParam( + FieldInfo info, + int index, + InstructionAdapter iv, + int ownerIndex + ) { assert !info.isStatic(); Type fieldType = info.getFieldType(); - iv.load(0, info.getOwnerType());//this + iv.load(ownerIndex, info.getOwnerType());//this iv.load(index, fieldType); //param iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor()); index += fieldType.getSize(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index 3405ff4d21c..a3c81484d10 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -77,12 +77,12 @@ public class ClosureCodegen extends MemberCodegen { private final FunctionDescriptor functionReferenceTarget; private final FunctionGenerationStrategy strategy; protected final CalculatedClosure closure; - private final Type asmType; - private final int visibilityFlag; + protected final Type asmType; + protected final int visibilityFlag; private final boolean shouldHaveBoundReferenceReceiver; private Method constructor; - private Type superClassAsmType; + protected Type superClassAsmType; public ClosureCodegen( @NotNull GenerationState state, @@ -406,7 +406,7 @@ public class ClosureCodegen extends MemberCodegen { } @NotNull - private Method generateConstructor() { + protected Method generateConstructor() { List args = calculateConstructorParameters(typeMapper, closure, asmType); Type[] argTypes = fieldListToTypeArray(args); @@ -430,9 +430,7 @@ public class ClosureCodegen extends MemberCodegen { String superClassConstructorDescriptor; if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE) || superClassAsmType.equals(COROUTINE_IMPL)) { - int arity = funDescriptor.getValueParameters().size(); - if (funDescriptor.getExtensionReceiverParameter() != null) arity++; - if (funDescriptor.getDispatchReceiverParameter() != null) arity++; + int arity = calculateArity(); iv.iconst(arity); if (shouldHaveBoundReferenceReceiver) { CallableReferenceUtilKt.loadBoundReferenceReceiverParameter(iv, boundReferenceReceiverParameterIndex, boundReferenceReceiverType); @@ -455,6 +453,13 @@ public class ClosureCodegen extends MemberCodegen { return constructor; } + protected int calculateArity() { + int arity = funDescriptor.getValueParameters().size(); + if (funDescriptor.getExtensionReceiverParameter() != null) arity++; + if (funDescriptor.getDispatchReceiverParameter() != null) arity++; + return arity; + } + @NotNull public static List calculateConstructorParameters( @NotNull KotlinTypeMapper typeMapper, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 3e67158f21b..e0e1924c883 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -50,8 +50,8 @@ import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.when.SwitchCodegen; import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil; -import org.jetbrains.kotlin.coroutines.CoroutineUtilKt; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor; import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor; @@ -78,7 +78,6 @@ import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.constants.ConstantValue; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluatorKt; -import org.jetbrains.kotlin.resolve.coroutine.CoroutineReceiverValue; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.inline.InlineUtil; import org.jetbrains.kotlin.resolve.jvm.AsmTypes; @@ -128,6 +127,7 @@ public class ExpressionCodegen extends KtVisitor impleme public final FrameMap myFrameMap; public final MethodContext context; private final Type returnType; + private final Type boxedReturnTypeForCoroutine; private final CodegenStatementVisitor statementVisitor = new CodegenStatementVisitor(this); private final MemberCodegen parentCodegen; @@ -160,11 +160,37 @@ public class ExpressionCodegen extends KtVisitor impleme this.v = new InstructionAdapter(mv); this.myFrameMap = frameMap; this.context = context; - this.returnType = returnType; + + FunctionDescriptor descriptorForCoroutine = getOriginalLambdaDescriptorForCoroutine(context); + if (descriptorForCoroutine != null && descriptorForCoroutine.getReturnType() != null) { + this.returnType = typeMapper.mapReturnType(descriptorForCoroutine); + this.boxedReturnTypeForCoroutine = getBoxedReturnTypeForCoroutine(descriptorForCoroutine); + } + else { + this.returnType = returnType; + this.boxedReturnTypeForCoroutine = null; + } + this.parentCodegen = parentCodegen; this.tailRecursionCodegen = new TailRecursionCodegen(context, this, this.v, state); } + @NotNull + private Type getBoxedReturnTypeForCoroutine(FunctionDescriptor descriptorForCoroutine) { + assert descriptorForCoroutine.getReturnType() != null : "Uninitialized coroutine return type"; + return AsmUtil.boxType(typeMapper.mapType(descriptorForCoroutine.getReturnType())); + } + + @Nullable + private static FunctionDescriptor getOriginalLambdaDescriptorForCoroutine(MethodContext context) { + if ((context.getParentContext() instanceof ClosureContext) && + (context.getParentContext().closure != null) && + context.getParentContext().closure.isCoroutine()) { + return ((ClosureContext) context.getParentContext()).getCoroutineDescriptor(); + } + return null; + } + static class BlockStackElement { } @@ -569,7 +595,7 @@ public class ExpressionCodegen extends KtVisitor impleme statements.add(condition); //Need to split leave task and condition cause otherwise BranchedValue optimizations wouldn't work - leaveTask = generateBlock((KtBlockExpression) body, statements, false, continueLabel, null); + leaveTask = generateBlock(statements, false, continueLabel, null); conditionValue = leaveTask.getStackValue(); } else { @@ -1718,10 +1744,9 @@ public class ExpressionCodegen extends KtVisitor impleme KotlinType captureReceiver = closure.getCaptureReceiverType(); if (captureReceiver != null) { - Type asmType = typeMapper.mapType(captureReceiver); StackValue capturedReceiver = functionReferenceReceiver != null ? functionReferenceReceiver : - StackValue.local(AsmUtil.getReceiverIndex(context, context.getContextDescriptor()), asmType); + generateExtensionReceiver(unwrapOriginalLambdaDescriptorForCoroutine(context)); callGenerator.putCapturedValueOnStack(capturedReceiver, capturedReceiver.type, paramIndex++); } @@ -1741,14 +1766,26 @@ public class ExpressionCodegen extends KtVisitor impleme superClass, putThis && closure.getCaptureThis() == null, callGenerator, /* functionReferenceReceiver = */ null ); } + + if (closure.isCoroutine()) { + // resultContinuation + v.aconst(null); + } + } + + @NotNull + private static CallableDescriptor unwrapOriginalLambdaDescriptorForCoroutine(@NotNull MethodContext context) { + FunctionDescriptor coroutine = getOriginalLambdaDescriptorForCoroutine(context); + if (coroutine != null) return coroutine; + return context.getFunctionDescriptor(); } /* package */ StackValue generateBlock(@NotNull KtBlockExpression expression, boolean isStatement) { if (expression.getParent() instanceof KtNamedFunction) { // For functions end of block should be end of function label - return generateBlock(expression, expression.getStatements(), isStatement, null, context.getMethodEndLabel()); + return generateBlock(expression.getStatements(), isStatement, null, context.getMethodEndLabel()); } - return generateBlock(expression, expression.getStatements(), isStatement, null, null); + return generateBlock(expression.getStatements(), isStatement, null, null); } @NotNull @@ -1763,7 +1800,6 @@ public class ExpressionCodegen extends KtVisitor impleme } private StackValueWithLeaveTask generateBlock( - @NotNull KtBlockExpression block, @NotNull List statements, boolean isStatement, @Nullable Label labelBeforeLastExpression, @@ -1800,13 +1836,7 @@ public class ExpressionCodegen extends KtVisitor impleme StackValue statementResult = isExpression ? gen(possiblyLabeledStatement) : genStatement(possiblyLabeledStatement); if (!iterator.hasNext()) { - StackValue handleResultValue = genControllerHandleResultForLastStatementInCoroutine(block, possiblyLabeledStatement); - if (handleResultValue != null) { - blockResult = handleResultValue; - } - else { - blockResult = statementResult; - } + blockResult = statementResult; } else { statementResult.put(Type.VOID_TYPE, v); @@ -1816,13 +1846,7 @@ public class ExpressionCodegen extends KtVisitor impleme } if (statements.isEmpty()) { - StackValue handleResultValue = genControllerHandleResultForLastStatementInCoroutine(block, null); - if (handleResultValue != null) { - blockResult = handleResultValue; - } - else { - blockResult = StackValue.none(); - } + blockResult = StackValue.none(); } assert blockResult != null : "Block result should be initialized in the loop or the condition above"; @@ -1841,107 +1865,22 @@ public class ExpressionCodegen extends KtVisitor impleme }); } - @Nullable - private StackValue genControllerHandleResultForLastStatementInCoroutine( - @NotNull KtBlockExpression block, - @Nullable KtExpression lastStatement - ) { - if (!(block.getParent() instanceof KtFunctionLiteral)) return null; - KtFunctionLiteral functionLiteral = (KtFunctionLiteral) block.getParent(); - - return genControllerHandleResultCallIfNeeded(functionLiteral, lastStatement); - } - - @Nullable - private StackValue genControllerHandleResultCallIfNeeded(@NotNull KtExpression callOwner, @Nullable KtExpression returnValue) { - ResolvedCall resolvedCall = bindingContext.get(RETURN_HANDLE_RESULT_RESOLVED_CALL, callOwner); - - if (resolvedCall != null) { - assert resolvedCall.getValueArgumentsByIndex() != null : "Arguments were not resolved for call element: " + callOwner.getText(); - KtExpression argumentExpression = - resolvedCall.getValueArgumentsByIndex().get(0).getArguments().get(0).getArgumentExpression(); - - final StackValue putValueBeforeCall; - // This condition may be true in cases like return-statement without value or for last statement in a lambda block that - // has a type different from Unit, while 'handleResult' method accepts exactly the latter - // (see org.jetbrains.kotlin.coroutines.resolveCoroutineHandleResultCallIfNeeded for clarifications) - if (argumentExpression != returnValue) { - assert KotlinBuiltIns.isUnit(resolvedCall.getResultingDescriptor().getValueParameters().get(0).getType()) - : "If handleResult argument is different from returnValue, handleResult's first parameter must accept Unit, but " + - resolvedCall.getResultingDescriptor() + " was found"; - - // generate last statement in the coroutine lambda - putValueBeforeCall = returnValue != null ? genStatement(returnValue) : null; - - // Here 'argumentExpression' is a special fake one that used as an expression of Unit type - // when 'handleResult' call was resolved - tempVariables.put(argumentExpression, StackValue.unit()); - } - else { - putValueBeforeCall = null; - } - - tempVariables.put( - resolvedCall.getValueArgumentsByIndex().get(1).getArguments().get(0).getArgumentExpression(), - genCoroutineInstanceValueFromResolvedCall(resolvedCall)); - - - final StackValue handleResultCallValue = invokeFunction(resolvedCall, StackValue.none()); - if (putValueBeforeCall == null) return handleResultCallValue; - - return new StackValue(handleResultCallValue.type) { - @Override - public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { - putValueBeforeCall.put(type, v); - handleResultCallValue.putSelector(type, v); - } - - @Override - public void putReceiver(@NotNull InstructionAdapter v, boolean isRead) { - handleResultCallValue.putReceiver(v, isRead); - } - }; - } - return null; - } - - @NotNull - public StackValue genCoroutineInstanceValueFromResolvedCall(@NotNull ResolvedCall resolvedCall) { - return getCoroutineInstanceValueByReceiver(getControllerReceiverFromResolvedCall(resolvedCall)); - } - - @NotNull - private StackValue getCoroutineInstanceValueByReceiver( - @NotNull ExtensionReceiver descriptor - ) { - ClassDescriptor coroutineClassDescriptor = - bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, descriptor.getDeclarationDescriptor()); - assert coroutineClassDescriptor != null : "Coroutine class descriptor should not be null"; - return StackValue.thisOrOuter(this, coroutineClassDescriptor, false, false); - } - @Nullable private StackValue getCoroutineInstanceValueForSuspensionPoint(@NotNull ResolvedCall resolvedCall) { - CoroutineReceiverValue coroutineReceiverValue = - bindingContext.get(COROUTINE_RECEIVER_FOR_SUSPENSION_POINT, resolvedCall.getCall()); + CallableDescriptor enclosingSuspendLambdaForSuspensionPoint = + bindingContext.get(ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, resolvedCall.getCall()); - if (coroutineReceiverValue == null) return null; - - return getCoroutineInstanceValueByReceiver(coroutineReceiverValue); + if (enclosingSuspendLambdaForSuspensionPoint == null) return null; + return genCoroutineInstanceByLambda(enclosingSuspendLambdaForSuspensionPoint); } - private static ExtensionReceiver getControllerReceiverFromResolvedCall(@NotNull ResolvedCall resolvedCall) { - ReceiverValue controllerReceiver = - resolvedCall.getDispatchReceiver() != null - ? resolvedCall.getDispatchReceiver() - : resolvedCall.getExtensionReceiver(); + @NotNull + private StackValue genCoroutineInstanceByLambda(@NotNull CallableDescriptor suspendLambda) { + ClassDescriptor suspendLambdaClassDescriptor = + bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendLambda); + assert suspendLambdaClassDescriptor != null : "Coroutine class descriptor should not be null"; - assert controllerReceiver != null : "Both dispatch and extension receivers are null for handleResult/suspend to " + resolvedCall.getResultingDescriptor(); - assert controllerReceiver instanceof ExtensionReceiver - : "Argument for handleResult call to " + resolvedCall.getResultingDescriptor() + - " should be a coroutine receiver parameter, but " + controllerReceiver + " found"; - - return (ExtensionReceiver) controllerReceiver; + return StackValue.thisOrOuter(this, suspendLambdaClassDescriptor, false, false); } @NotNull @@ -2204,7 +2143,7 @@ public class ExpressionCodegen extends KtVisitor impleme } @Override - public StackValue visitReturnExpression(@NotNull final KtReturnExpression expression, StackValue receiver) { + public StackValue visitReturnExpression(@NotNull final KtReturnExpression expression, final StackValue receiver) { return StackValue.operation(Type.VOID_TYPE, new Function1() { @Override public Unit invoke(InstructionAdapter adapter) { @@ -2221,13 +2160,8 @@ public class ExpressionCodegen extends KtVisitor impleme Type returnType = isNonLocalReturn ? nonLocalReturn.returnType : ExpressionCodegen.this.returnType; StackValue valueToReturn = returnedExpression != null ? gen(returnedExpression) : null; - StackValue handleResultValue = genControllerHandleResultCallIfNeeded(expression, returnedExpression); - if (handleResultValue != null) { - handleResultValue.put(Type.VOID_TYPE, v); - returnType = Type.VOID_TYPE; - } - else if (returnedExpression != null && valueToReturn != null) { + if (returnedExpression != null && valueToReturn != null) { putStackValue(returnedExpression, returnType, valueToReturn); } @@ -2235,9 +2169,18 @@ public class ExpressionCodegen extends KtVisitor impleme generateFinallyBlocksIfNeeded(returnType, afterReturnLabel); if (isNonLocalReturn) { + if (nonLocalReturn.boxedCoroutineReturnType != null && !nonLocalReturn.boxedCoroutineReturnType.equals(returnType)) { + StackValue.coerce(nonLocalReturn.returnType, nonLocalReturn.boxedCoroutineReturnType, v); + returnType = nonLocalReturn.boxedCoroutineReturnType; + } + InlineCodegenUtil.generateGlobalReturnFlag(v, nonLocalReturn.labelName); + v.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); } - v.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); + else { + emitLocalReturnInsn(); + } + v.mark(afterReturnLabel); return Unit.INSTANCE; } @@ -2270,7 +2213,7 @@ public class ExpressionCodegen extends KtVisitor impleme FunctionDescriptor containingFunction = BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst(); //FIRST_FUN_LABEL to prevent clashing with existing labels - return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL); + return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL, null); } else { //local return null; @@ -2282,7 +2225,15 @@ public class ExpressionCodegen extends KtVisitor impleme DeclarationDescriptor elementDescriptor = typeMapper.getBindingContext().get(DECLARATION_TO_DESCRIPTOR, element); assert element != null : "Expression should be not null " + expression.getText(); assert elementDescriptor != null : "Descriptor should be not null: " + element.getText(); - return new NonLocalReturnInfo(typeMapper.mapReturnType((CallableDescriptor) elementDescriptor), expression.getLabelName()); + Type boxedCoroutineReturnType = + elementDescriptor instanceof AnonymousFunctionDescriptor + && ((AnonymousFunctionDescriptor) elementDescriptor).isCoroutine() + ? getBoxedReturnTypeForCoroutine((FunctionDescriptor) elementDescriptor) + : null; + return new NonLocalReturnInfo( + typeMapper.mapReturnType((CallableDescriptor) elementDescriptor), expression.getLabelName(), + boxedCoroutineReturnType + ); } } return null; @@ -2307,6 +2258,16 @@ public class ExpressionCodegen extends KtVisitor impleme StackValue.none().put(returnType, v); } + emitLocalReturnInsn(); + } + } + + private void emitLocalReturnInsn() { + if (boxedReturnTypeForCoroutine != null && !boxedReturnTypeForCoroutine.equals(returnType)) { + StackValue.coerce(returnType, boxedReturnTypeForCoroutine, v); + v.areturn(boxedReturnTypeForCoroutine); + } + else { v.areturn(returnType); } } @@ -3098,46 +3059,11 @@ public class ExpressionCodegen extends KtVisitor impleme @NotNull private StackValue generateExtensionReceiver(@NotNull CallableDescriptor descriptor) { - KotlinType coroutineControllerType = CoroutineUtilKt.getControllerTypeIfCoroutine(descriptor); - if (coroutineControllerType != null) { - ClassDescriptor classDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, descriptor); - assert classDescriptor != null : "class descriptor for coroutine " + descriptor + " should not be null"; - - final StackValue coroutineReceiver = StackValue.thisOrOuter(this, classDescriptor, /* isSuper =*/ false, /* castReceiver */ false); - - StackValue controllerValue; - if (InlineUtil.checkNonLocalReturnUsage( - context.getFunctionDescriptor(), - descriptor, DescriptorToSourceUtils.descriptorToDeclaration(descriptor), bindingContext - )) { - // This branch should work for major part of cases and it's needed mostly for optimizations purpose - // else branch must have just the same semantics - controllerValue = StackValue.field( - FieldInfo.createForHiddenField( - AsmTypes.COROUTINE_IMPL, - AsmTypes.OBJECT_TYPE, - CoroutineCodegenUtilKt.COROUTINE_CONTROLLER_FIELD_NAME - ), - coroutineReceiver - ); - } - else { - controllerValue = StackValue.functionCall(AsmTypes.OBJECT_TYPE, new Function1() { - @Override - public Unit invoke(InstructionAdapter adapter) { - coroutineReceiver.put(AsmTypes.COROUTINE_IMPL, adapter); - adapter.invokevirtual( - AsmTypes.COROUTINE_IMPL.getInternalName(), - CoroutineCodegenUtilKt.COROUTINE_CONTROLLER_GETTER_NAME, - "()" + AsmTypes.OBJECT_TYPE, - false - ); - return Unit.INSTANCE; - } - }); - } - - return StackValue.coercion(controllerValue, typeMapper.mapType(coroutineControllerType)); + if (myFrameMap.getIndex(descriptor.getExtensionReceiverParameter()) != -1) { + return StackValue.local( + myFrameMap.getIndex(descriptor.getExtensionReceiverParameter()), + typeMapper.mapType(descriptor.getExtensionReceiverParameter()) + ); } return context.generateReceiver(descriptor, state, false); @@ -4784,13 +4710,15 @@ The "returned" value of try expression with no finally is either the last expres private static class NonLocalReturnInfo { - final Type returnType; + private final Type returnType; - final String labelName; + private final String labelName; + private final Type boxedCoroutineReturnType; - private NonLocalReturnInfo(Type type, String name) { + private NonLocalReturnInfo(@NotNull Type type, @NotNull String name, @Nullable Type boxedCoroutineReturnType) { returnType = type; labelName = name; + this.boxedCoroutineReturnType = boxedCoroutineReturnType; } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt index 0132f8a840e..b5c3f6d8b83 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt @@ -17,9 +17,8 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.kotlin.builtins.createFunctionType -import org.jetbrains.kotlin.codegen.coroutines.continuationClassDescriptor -import org.jetbrains.kotlin.codegen.coroutines.hasNoinlineInterceptResume -import org.jetbrains.kotlin.coroutines.controllerTypeIfCoroutine +import org.jetbrains.kotlin.codegen.coroutines.createJvmSuspendFunctionView +import org.jetbrains.kotlin.coroutines.isSuspendLambda import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor @@ -28,11 +27,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeConstructorSubstitution -import org.jetbrains.kotlin.types.TypeProjectionImpl -import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils -import org.jetbrains.kotlin.utils.singletonOrEmptyList class JvmRuntimeTypes(module: ModuleDescriptor) { private val kotlinJvmInternalPackage = MutablePackageFragmentDescriptor(module, FqName("kotlin.jvm.internal")) @@ -53,19 +48,6 @@ class JvmRuntimeTypes(module: ModuleDescriptor) { (0..2).map { i -> createClass(kotlinJvmInternalPackage, "MutablePropertyReference$i") } } - val continuationOfAny: KotlinType by lazy { createNullableAnyContinuation(module) } - - /** - * @return `Continuation` type - */ - private fun createNullableAnyContinuation(module: ModuleDescriptor): KotlinType { - val classDescriptor = module.builtIns.continuationClassDescriptor - - return TypeConstructorSubstitution.createByParametersMap( - mapOf(classDescriptor.declaredTypeParameters.single() to TypeProjectionImpl(module.builtIns.nullableAnyType)) - ).buildSubstitutor().substitute(classDescriptor.defaultType, Variance.INVARIANT)!! - } - private fun createClass(packageFragment: PackageFragmentDescriptor, name: String): ClassDescriptor = MutableClassDescriptor(packageFragment, ClassKind.CLASS, /* isInner = */ false, /* isExternal = */ false, Name.identifier(name), SourceElement.NO_SOURCE).apply { @@ -76,33 +58,24 @@ class JvmRuntimeTypes(module: ModuleDescriptor) { } fun getSupertypesForClosure(descriptor: FunctionDescriptor): Collection { + + val actualFunctionDescriptor = + if (descriptor.isSuspendLambda) + createJvmSuspendFunctionView(descriptor) + else + descriptor + val functionType = createFunctionType( descriptor.builtIns, Annotations.EMPTY, - descriptor.extensionReceiverParameter?.type, - ExpressionTypingUtils.getValueParametersTypes(descriptor.valueParameters), + actualFunctionDescriptor.extensionReceiverParameter?.type, + ExpressionTypingUtils.getValueParametersTypes(actualFunctionDescriptor.valueParameters), null, - descriptor.returnType!! + actualFunctionDescriptor.returnType!! ) - val coroutineControllerType = descriptor.controllerTypeIfCoroutine - if (coroutineControllerType != null) { - val additionalType: KotlinType? - if (coroutineControllerType.hasNoinlineInterceptResume()) { - // for non-inline interceptResume we use coroutine instance as an argument for interceptRun call, i.e. it must be a Function0 - // See org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegen.processInterceptResume() for details - additionalType = - createFunctionType( - descriptor.builtIns, Annotations.EMPTY, - /* recieverParameter = */ null, /* parameterTypes = */ emptyList(), /* parameterNames = */ emptyList(), - /* returnType = */ descriptor.builtIns.unitType - ) - } - else { - additionalType = null - } - - return listOf(coroutineImplClass.defaultType, functionType) + additionalType.singletonOrEmptyList() + if (descriptor.isSuspendLambda) { + return listOf(coroutineImplClass.defaultType, functionType) } return listOf(lambda.defaultType, functionType) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java index 8aba287ee5e..182aef58442 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java @@ -33,11 +33,9 @@ import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt; import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil; import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping; -import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.coroutines.CoroutineUtilKt; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; -import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.fileClasses.FileClasses; import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider; @@ -290,31 +288,8 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { classStack.push(classDescriptor); nameStack.push(name); - KotlinType controllerTypeIfCoroutine = CoroutineUtilKt.getControllerTypeIfCoroutine(functionDescriptor); - if (controllerTypeIfCoroutine != null) { + if (CoroutineUtilKt.isSuspendLambda(functionDescriptor)) { closure.setCoroutine(true); - - if (CoroutineCodegenUtilKt.hasInlineInterceptResume(controllerTypeIfCoroutine)) { - // for inline interceptResume we create a descriptor for fake lambda that must be inlined when generating interceptRun call - // See org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegen.processInterceptResume() for details - AnonymousFunctionDescriptor fakeDescriptorForInlineLambda = - new AnonymousFunctionDescriptor(functionDescriptor, Annotations.Companion.getEMPTY(), - CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE, false - ); - - fakeDescriptorForInlineLambda.initialize( - null, null, - Collections.emptyList(), - Collections.emptyList(), - DescriptorUtilsKt.getBuiltIns(functionDescriptor).getUnitType(), - Modality.FINAL, Visibilities.PUBLIC - ); - - bindingTrace.record(CUSTOM_DESCRIPTOR_FOR_INLINE_LAMBDA, functionLiteral, fakeDescriptorForInlineLambda); - - recordClosure(recordClassForCallable(functionLiteral, fakeDescriptorForInlineLambda, supertypes, name), - inventAnonymousClassName()); - } } super.visitLambdaExpression(lambdaExpression); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index e11c68dfb45..6bacbee20d5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -16,17 +16,15 @@ package org.jetbrains.kotlin.codegen.coroutines -import org.jetbrains.kotlin.backend.common.findOperatorInController +import com.intellij.util.ArrayUtil import org.jetbrains.kotlin.codegen.* -import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.context.ClosureContext import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.coroutines.controllerTypeIfCoroutine +import org.jetbrains.kotlin.coroutines.isSuspendLambda import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl -import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtDeclarationWithBody import org.jetbrains.kotlin.psi.KtElement @@ -39,8 +37,8 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.makeNullable -import org.jetbrains.kotlin.util.OperatorNameConventions -import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.kotlin.utils.singletonOrEmptyList import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -54,98 +52,143 @@ class CoroutineCodegen( strategy: FunctionGenerationStrategy, parentCodegen: MemberCodegen<*>, classBuilder: ClassBuilder, - private val coroutineLambdaDescriptor: FunctionDescriptor, - private val controllerType: KotlinType + private val coroutineLambdaDescriptor: FunctionDescriptor ) : ClosureCodegen(state, element, null, closureContext, null, strategy, parentCodegen, classBuilder) { + private val classDescriptor = closureContext.contextDescriptor + + private lateinit var constructorToUseFromInvoke: Method + + // protected fun doResume(result, throwable) + private val doResumeDescriptor = + SimpleFunctionDescriptorImpl.create( + classDescriptor, Annotations.EMPTY, Name.identifier("doResume"), CallableMemberDescriptor.Kind.DECLARATION, + funDescriptor.source + ).apply doResume@{ + initialize( + /* receiverParameterType = */ null, + classDescriptor.thisAsReceiverParameter, + /* typeParameters = */ emptyList(), + listOf( + ValueParameterDescriptorImpl( + this@doResume, null, 0, Annotations.EMPTY, Name.identifier("data"), + module.builtIns.nullableAnyType, + /* isDefault = */ false, /* isCrossinline = */ false, + /* isNoinline = */ false, /* isCoroutine = */ false, + /* varargElementType = */ null, SourceElement.NO_SOURCE + ), + ValueParameterDescriptorImpl( + this@doResume, null, 1, Annotations.EMPTY, Name.identifier("throwable"), + module.builtIns.throwable.defaultType.makeNullable(), + /* isDefault = */ false, /* isCrossinline = */ false, + /* isNoinline = */ false, /* isCoroutine = */ false, + /* varargElementType = */ null, SourceElement.NO_SOURCE + ) + ), + funDescriptor.builtIns.nullableAnyType, + Modality.FINAL, + Visibilities.PROTECTED + ) + } + override fun generateClosureBody() { - for (parameter in funDescriptor.valueParameters) { + for (parameter in allLambdaParameters()) { + val fieldInfo = parameter.getFieldInfoForCoroutineLambdaParameter() v.newField( OtherOrigin(parameter), Opcodes.ACC_PRIVATE, - COROUTINE_LAMBDA_PARAMETER_PREFIX + parameter.index, - typeMapper.mapType(parameter.type).descriptor, null, null) + fieldInfo.fieldName, + fieldInfo.fieldType.descriptor, null, null + ) } generateDoResume() + } + + override fun generateBody() { + super.generateBody() functionCodegen.generateMethod(JvmDeclarationOrigin.NO_ORIGIN, funDescriptor, object : FunctionGenerationStrategy.CodegenBased(state) { override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { - generateInvokeMethod(codegen, signature) + generateInvokeMethod(codegen) } }) } - // invoke for lambda being passes to builder - // fun builder(coroutine c: Controller.() -> Continuation) - // - // This lambda must have a receiver parameter, may have value parameters and returns Continuation (`this` instance or a copy of it) - private fun generateInvokeMethod(codegen: ExpressionCodegen, signature: JvmMethodSignature) { + override fun generateConstructor(): Method { + val args = calculateConstructorParameters(typeMapper, closure, asmType) + val argTypes = args.map { it.fieldType }.plus(AsmTypes.CONTINUATION).toTypedArray() + + val constructor = Method("", Type.VOID_TYPE, argTypes) + val mv = v.newMethod( + OtherOrigin(element, funDescriptor), visibilityFlag, "", constructor.descriptor, null, + ArrayUtil.EMPTY_STRING_ARRAY + ) + + constructorToUseFromInvoke = constructor + + if (state.classBuilderMode.generateBodies) { + mv.visitCode() + val iv = InstructionAdapter(mv) + + iv.generateClosureFieldsInitializationFromParameters(closure, args) + + iv.load(0, AsmTypes.OBJECT_TYPE) + iv.iconst(calculateArity()) + iv.load(argTypes.map { it.size }.sum(), AsmTypes.OBJECT_TYPE) + + val superClassConstructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, AsmTypes.CONTINUATION) + iv.invokespecial(superClassAsmType.internalName, "", superClassConstructorDescriptor, false) + + iv.visitInsn(Opcodes.RETURN) + + FunctionCodegen.endVisit(iv, "constructor", element) + } + + return constructor + } + + private fun generateInvokeMethod(codegen: ExpressionCodegen) { val classDescriptor = closureContext.contextDescriptor val owner = typeMapper.mapClass(classDescriptor) - val controllerFieldInfo = - FieldInfo.createForHiddenField( - AsmTypes.COROUTINE_IMPL, - AsmTypes.OBJECT_TYPE, COROUTINE_CONTROLLER_FIELD_NAME - ) val thisInstance = StackValue.thisOrOuter(codegen, classDescriptor, false, false) with(codegen.v) { - // if (controller != null) - StackValue.field(controllerFieldInfo, thisInstance).put(AsmTypes.OBJECT_TYPE, this) - val repeated = Label() - ifnonnull(repeated) - - // first call - AsmUtil.genAssignInstanceFieldFromParam(controllerFieldInfo, 1, this) - - setLabelValue(LABEL_VALUE_BEFORE_FIRST_SUSPENSION) - - // Save lambda parameters to fields - // 0 - this - // 1 - controller - var index = 2 - for (parameter in funDescriptor.valueParameters) { - val fieldInfoForCoroutineLambdaParameter = parameter.getFieldInfoForCoroutineLambdaParameter() - AsmUtil.genAssignInstanceFieldFromParam( - fieldInfoForCoroutineLambdaParameter, index, this) - index += fieldInfoForCoroutineLambdaParameter.fieldType.size - } - - load(0, AsmTypes.OBJECT_TYPE) - areturn(AsmTypes.OBJECT_TYPE) - - // repeated call - visitLabel(repeated) anew(owner) dup() - // pass closure parameters to constructor + // pass captured closure to constructor val constructorParameters = calculateConstructorParameters(typeMapper, closure, owner) for (parameter in constructorParameters) { StackValue.field(parameter, thisInstance).put(parameter.fieldType, this) } - val constructor = Method("", Type.VOID_TYPE, constructorParameters.map { it.fieldType }.toTypedArray()) - invokespecial(owner.internalName, constructor.name, constructor.descriptor, false) + // load resultContinuation + load(allLambdaParameters().map { typeMapper.mapType(it.type).size }.sum() + 1, AsmTypes.OBJECT_TYPE) + + invokespecial(owner.internalName, constructorToUseFromInvoke.name, constructorToUseFromInvoke.descriptor, false) + + val cloneIndex = codegen.frameMap.enterTemp(AsmTypes.OBJECT_TYPE) + store(cloneIndex, AsmTypes.OBJECT_TYPE) // Pass lambda parameters to 'invoke' call on newly constructed object - index = 1 - for (parameter in signature.valueParameters) { - load(index, parameter.asmType) - index += parameter.asmType.size + var index = 1 + for (parameter in allLambdaParameters()) { + val fieldInfoForCoroutineLambdaParameter = parameter.getFieldInfoForCoroutineLambdaParameter() + load(index, fieldInfoForCoroutineLambdaParameter.fieldType) + AsmUtil.genAssignInstanceFieldFromParam(fieldInfoForCoroutineLambdaParameter, index, this, cloneIndex) + index += fieldInfoForCoroutineLambdaParameter.fieldType.size } - // 'invoke' call on freshly constructed coroutine returns receiver itself - invokevirtual(owner.internalName, signature.asmMethod.name, signature.asmMethod.descriptor, false) + load(cloneIndex, AsmTypes.OBJECT_TYPE) areturn(AsmTypes.OBJECT_TYPE) } } private fun ExpressionCodegen.initializeCoroutineParameters() { - for (parameter in coroutineLambdaDescriptor.valueParameters) { + for (parameter in allLambdaParameters()) { val mappedType = typeMapper.mapType(parameter.type) val newIndex = myFrameMap.enter(parameter, mappedType) @@ -154,12 +197,15 @@ class CoroutineCodegen( } } + private fun allLambdaParameters() = + coroutineLambdaDescriptor.extensionReceiverParameter.singletonOrEmptyList() + private fun ExpressionCodegen.generateLoadField(fieldInfo: FieldInfo) { StackValue.field(fieldInfo, generateThisOrOuter(context.thisDescriptor, false)).put(fieldInfo.fieldType, v) } - private fun ValueParameterDescriptor.getFieldInfoForCoroutineLambdaParameter() = - createHiddenFieldInfo(type, COROUTINE_LAMBDA_PARAMETER_PREFIX + index) + private fun ParameterDescriptor.getFieldInfoForCoroutineLambdaParameter() = + createHiddenFieldInfo(type, COROUTINE_LAMBDA_PARAMETER_PREFIX + (this.safeAs()?.index ?: "")) private fun createHiddenFieldInfo(type: KotlinType, name: String) = FieldInfo.createForHiddenField( @@ -168,243 +214,21 @@ class CoroutineCodegen( name ) - private fun generateExceptionHandlingBlock(codegen: ExpressionCodegen) { - val handleExceptionFunction = findOperatorInController(controllerType, OperatorNameConventions.COROUTINE_HANDLE_EXCEPTION) ?: return - - val (resolvedCall, fakeExceptionExpression, fakeThisContinuationException) = - createResolvedCallForHandleExceptionCall(element, handleExceptionFunction, coroutineLambdaDescriptor) - - codegen.tempVariables.put(fakeExceptionExpression, StackValue.operation(AsmTypes.OBJECT_TYPE) { - codegen.v.invokestatic(COROUTINE_MARKER_OWNER, HANDLE_EXCEPTION_ARGUMENT_MARKER_NAME, "()Ljava/lang/Object;", false) - }) - - codegen.tempVariables.put(fakeThisContinuationException, codegen.genCoroutineInstanceValueFromResolvedCall(resolvedCall)) - - codegen.v.invokestatic(COROUTINE_MARKER_OWNER, HANDLE_EXCEPTION_MARKER_NAME, "()V", false) - codegen.invokeFunction(resolvedCall, StackValue.none()).put(Type.VOID_TYPE, codegen.v) - codegen.v.areturn(Type.VOID_TYPE) - } - private fun generateDoResume() { - val classDescriptor = closureContext.contextDescriptor - - // protected fun doResume(result, throwable) - val doResumeDescriptor = - SimpleFunctionDescriptorImpl.create( - classDescriptor, Annotations.EMPTY, Name.identifier("doResume"), CallableMemberDescriptor.Kind.DECLARATION, - funDescriptor.source - ).apply doResume@{ - initialize( - /* receiverParameterType = */ null, - classDescriptor.thisAsReceiverParameter, - /* typeParameters = */ emptyList(), - listOf( - ValueParameterDescriptorImpl( - this@doResume, null, 0, Annotations.EMPTY, Name.identifier("data"), - module.builtIns.nullableAnyType, - /* isDefault = */ false, /* isCrossinline = */ false, - /* isNoinline = */ false, /* isCoroutine = */ false, - /* varargElementType = */ null, SourceElement.NO_SOURCE - ), - ValueParameterDescriptorImpl( - this@doResume, null, 1, Annotations.EMPTY, Name.identifier("throwable"), - module.builtIns.throwable.defaultType.makeNullable(), - /* isDefault = */ false, /* isCrossinline = */ false, - /* isNoinline = */ false, /* isCoroutine = */ false, - /* varargElementType = */ null, SourceElement.NO_SOURCE - ) - ), - module.builtIns.unitType, - Modality.FINAL, - Visibilities.PROTECTED - ) - } - val interceptResume = findOperatorInController(controllerType, OperatorNameConventions.COROUTINE_INTERCEPT_RESUME) - if (interceptResume != null) { - processInterceptResume(doResumeDescriptor, interceptResume) - } - else { - functionCodegen.generateMethod( - OtherOrigin(element), - doResumeDescriptor, - object : FunctionGenerationStrategy.FunctionDefault(state, element as KtDeclarationWithBody) { - override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { - codegen.v.visitAnnotation(CONTINUATION_METHOD_ANNOTATION_DESC, true).visitEnd() - codegen.initializeCoroutineParameters() - super.doGenerateBody(codegen, signature) - generateExceptionHandlingBlock(codegen) - } - } - ) - } - } - - /** - * If there is defined an interceptResume operator in the controller class (it must have 'fun interceptResume(x: () -> Unit): Unit' signature), - * then continuation resume* operations must behave as they defined like `fun resume(x: T) = controller.interceptResume { doResume(x) }`. - * - * We do it the following way, our doResume implementation is defined as (at least for noinline case): - * fun doResume(v: Any?, t: Throwable?) { - * this.$v = v - * this.$t = t - * controller.interceptResume(this) - * } - * - * override fun invoke() { - * val v = this.$v - * val t = this.$t - * .. // common continuation state machine encoding - * } - * - * And yes, it means that `this`-object (i.e. a Continuation instance) also implements Function0, along with - * FunctionK. - * There are two kinds of interceptResume: - * 1. When the defined as not inline. In that case a continuation object is also implements `Function0` (literally in class-file) and defines - * an `invoke()Lj/l/Object` bridge. - * 2. Otherwise, it's defined as inline and we generate interceptResume call in the following way: - * controller.interceptResume { this.invoke() } - * - * The subtle difference with noinline case is that `this.invoke()` call is devirtualized after inlining - * (so there's no need to literally implement `Function0` nor to generate the bridges) - * - * Note that in the second case there must be created a fake lambda descriptor (and it's done via CodegenAnnotatingVisitor) - */ - private fun processInterceptResume(doResumeDescriptor: SimpleFunctionDescriptor, interceptResume: SimpleFunctionDescriptor) { - val (interceptResumeResolvedCall, lambdaExpressionForInterceptResume) = - createResolvedCallForInterceptResume(element as KtFunctionLiteral, interceptResume, coroutineLambdaDescriptor) - - val fieldInfoForValue = - createHiddenFieldInfo(funDescriptor.builtIns.anyType, COROUTINE_VALUE_FIELD_NAME_FOR_INTERCEPT_RESUME) - - val fieldInfoForThrowable = - createHiddenFieldInfo(funDescriptor.builtIns.throwable.defaultType, COROUTINE_THROWABLE_FIELD_NAME_FOR_INTERCEPT_RESUME) - - v.newField( - JvmDeclarationOrigin.NO_ORIGIN, - Opcodes.ACC_PRIVATE, - fieldInfoForValue.fieldName, - fieldInfoForValue.fieldType.descriptor, null, null) - - v.newField( - JvmDeclarationOrigin.NO_ORIGIN, - Opcodes.ACC_PRIVATE, - fieldInfoForThrowable.fieldName, - fieldInfoForThrowable.fieldType.descriptor, null, null) - - val classDescriptor = closureContext.contextDescriptor - val invokeDescriptor = - SimpleFunctionDescriptorImpl.create( - classDescriptor, Annotations.EMPTY, Name.identifier("invoke"), CallableMemberDescriptor.Kind.DECLARATION, - funDescriptor.source - ).apply { - initialize( - /* receiverParameterType = */ null, classDescriptor.thisAsReceiverParameter, - /* typeParameters = */ emptyList(), emptyList(), - module.builtIns.unitType, - Modality.FINAL, - Visibilities.PUBLIC - ) - - if (!interceptResume.isInline) { - // for generating necessary bridges - overriddenDescriptors = - funDescriptor.builtIns.getFunction(0) - .defaultType.memberScope.getContributedFunctions(Name.identifier("invoke"), - NoLookupLocation.FROM_BACKEND - ) - } - } - - if (interceptResume.isInline) { - state.bindingTrace.record( - CodegenBinding.CUSTOM_STRATEGY_FOR_INLINE_LAMBDA, element, - object : FunctionGenerationStrategy.FunctionDefault(state, element as KtDeclarationWithBody) { - override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { - // ? - val label = Label() - codegen.v.visitLineNumber(1, label) - codegen.v.visitLabel(label) - - codegen.generateThisOrOuter(context.thisDescriptor, false) - .put(Type.getObjectType(this@CoroutineCodegen.v.thisName), codegen.v) - codegen.v.invokevirtual(this@CoroutineCodegen.v.thisName, "invoke", "()V", false) - codegen.v.areturn(Type.VOID_TYPE) - } - } - ) - } - - functionCodegen.generateMethod( - OtherOrigin(element), - invokeDescriptor, - object : FunctionGenerationStrategy.FunctionDefault(state, element) { - override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { - codegen.v.visitAnnotation(CONTINUATION_METHOD_ANNOTATION_DESC, true).visitEnd() - - assert(codegen.frameMap.enterTemp(AsmTypes.OBJECT_TYPE) == COROUTINE_VALUE_PARAMETER_SLOT_IN_DO_RESUME) { - "Next free slot must be $COROUTINE_VALUE_PARAMETER_SLOT_IN_DO_RESUME" - } - assert(codegen.frameMap.enterTemp(AsmTypes.JAVA_THROWABLE_TYPE) == COROUTINE_THROWABLE_PARAMETER_SLOT_IN_DO_RESUME) { - "Next free slot must be $COROUTINE_THROWABLE_PARAMETER_SLOT_IN_DO_RESUME" - } - - codegen.generateLoadField(fieldInfoForValue) - codegen.v.store(COROUTINE_VALUE_PARAMETER_SLOT_IN_DO_RESUME, AsmTypes.OBJECT_TYPE) - - codegen.generateLoadField(fieldInfoForThrowable) - codegen.v.store(COROUTINE_THROWABLE_PARAMETER_SLOT_IN_DO_RESUME, AsmTypes.JAVA_THROWABLE_TYPE) - - codegen.v.invokestatic( - COROUTINE_MARKER_OWNER, ACTUAL_COROUTINE_START_MARKER_NAME, "()V", false - ) - - codegen.initializeCoroutineParameters() - super.doGenerateBody(codegen, signature) - generateExceptionHandlingBlock(codegen) - codegen.v.areturn(Type.VOID_TYPE) - } - } - ) - functionCodegen.generateMethod( OtherOrigin(element), doResumeDescriptor, - object : FunctionGenerationStrategy.CodegenBased(state) { + object : FunctionGenerationStrategy.FunctionDefault(state, element as KtDeclarationWithBody) { override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { - AsmUtil.genAssignInstanceFieldFromParam( - fieldInfoForValue, COROUTINE_VALUE_PARAMETER_SLOT_IN_DO_RESUME, codegen.v - ) - - AsmUtil.genAssignInstanceFieldFromParam( - fieldInfoForThrowable, COROUTINE_THROWABLE_PARAMETER_SLOT_IN_DO_RESUME, codegen.v - ) - - if (!interceptResume.isInline) { - codegen.tempVariables.put( - lambdaExpressionForInterceptResume, - codegen.generateThisOrOuter(context.thisDescriptor, false) - ) - } - - codegen.invokeFunction( - interceptResumeResolvedCall, StackValue.none() - ).put(Type.VOID_TYPE, codegen.v) - - codegen.v.areturn(Type.VOID_TYPE) + codegen.v.visitAnnotation(CONTINUATION_METHOD_ANNOTATION_DESC, true).visitEnd() + codegen.initializeCoroutineParameters() + super.doGenerateBody(codegen, signature) } } ) } - - private fun InstructionAdapter.setLabelValue(value: Int) { - load(0, AsmTypes.OBJECT_TYPE) - iconst(value) - putfield(AsmTypes.COROUTINE_IMPL.internalName, COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor) - } - companion object { - private const val LABEL_VALUE_BEFORE_FIRST_SUSPENSION = 0 @JvmStatic fun create( @@ -414,13 +238,9 @@ class CoroutineCodegen( classBuilder: ClassBuilder ): ClosureCodegen? { if (declaration !is KtFunctionLiteral) return null - val controllerType = originalCoroutineLambdaDescriptor.controllerTypeIfCoroutine ?: return null + if (!originalCoroutineLambdaDescriptor.isSuspendLambda) return null - val descriptorWithContinuationReturnType = - originalCoroutineLambdaDescriptor.newCopyBuilder() - .setPreserveSourceElement() - .setReturnType(expressionCodegen.state.jvmRuntimeTypes.continuationOfAny) - .build()!! + val descriptorWithContinuationReturnType = createJvmSuspendFunctionView(originalCoroutineLambdaDescriptor) val state = expressionCodegen.state return CoroutineCodegen( @@ -431,15 +251,10 @@ class CoroutineCodegen( ), FunctionGenerationStrategy.FunctionDefault(state, declaration), expressionCodegen.parentCodegen, classBuilder, - originalCoroutineLambdaDescriptor, - controllerType + originalCoroutineLambdaDescriptor ) } } } private const val COROUTINE_LAMBDA_PARAMETER_PREFIX = "p$" -private const val COROUTINE_VALUE_FIELD_NAME_FOR_INTERCEPT_RESUME = "v$" -private const val COROUTINE_THROWABLE_FIELD_NAME_FOR_INTERCEPT_RESUME = "throwable$" -private const val COROUTINE_VALUE_PARAMETER_SLOT_IN_DO_RESUME = 1 -private const val COROUTINE_THROWABLE_PARAMETER_SLOT_IN_DO_RESUME = 2 diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformationClassBuilder.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformationClassBuilder.kt index ad8c7275180..09f3ca3a8d9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformationClassBuilder.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformationClassBuilder.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue import org.jetbrains.kotlin.codegen.optimization.common.analyzeLiveness import org.jetbrains.kotlin.codegen.optimization.common.insnListOf import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks -import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.utils.sure @@ -119,17 +118,12 @@ class CoroutineTransformerMethodVisitor( // tableswitch(this.label) insertBefore(firstToInsertBefore, insnListOf( - FieldInsnNode( - Opcodes.GETSTATIC, - AsmTypes.COROUTINES_SUSPEND.internalName, - JvmAbi.INSTANCE_FIELD, - AsmTypes.COROUTINES_SUSPEND.descriptor - ), + *withInstructionAdapter { loadSuspendMarker() }.toArray(), VarInsnNode(Opcodes.ASTORE, suspendMarkerVarIndex), VarInsnNode(Opcodes.ALOAD, 0), FieldInsnNode( Opcodes.GETFIELD, - AsmTypes.COROUTINE_IMPL.internalName, + AsmTypes.RESTRICTED_COROUTINE_IMPL.internalName, COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor ), TableSwitchInsnNode(0, @@ -338,7 +332,7 @@ class CoroutineTransformerMethodVisitor( VarInsnNode(Opcodes.ALOAD, 0), *withInstructionAdapter { iconst(id) }.toArray(), FieldInsnNode( - Opcodes.PUTFIELD, AsmTypes.COROUTINE_IMPL.internalName, COROUTINE_LABEL_FIELD_NAME, + Opcodes.PUTFIELD, AsmTypes.RESTRICTED_COROUTINE_IMPL.internalName, COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor ) ) @@ -349,11 +343,12 @@ class CoroutineTransformerMethodVisitor( insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter { dup() - load(suspendMarkerVarIndex, AsmTypes.COROUTINES_SUSPEND) + load(suspendMarkerVarIndex, AsmTypes.OBJECT_TYPE) ifacmpne(continuationLabelAfterLoadedResult.label) // Exit - areturn(Type.VOID_TYPE) + load(suspendMarkerVarIndex, AsmTypes.OBJECT_TYPE) + areturn(AsmTypes.OBJECT_TYPE) // Mark place for continuation visitLabel(continuationLabel.label) }) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt index 986626f87fb..5eb976bccce 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt @@ -18,20 +18,18 @@ package org.jetbrains.kotlin.codegen.coroutines import com.intellij.openapi.project.Project import org.jetbrains.kotlin.backend.common.SUSPEND_WITH_CURRENT_CONTINUATION_NAME -import org.jetbrains.kotlin.backend.common.findInterceptResume import org.jetbrains.kotlin.backend.common.getBuiltInSuspendWithCurrentContinuation -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor -import org.jetbrains.kotlin.descriptors.SourceElement +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.BindingTraceContext +import org.jetbrains.kotlin.resolve.DelegatingBindingTrace +import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall @@ -42,13 +40,14 @@ import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.jvm.AsmTypes -import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinTypeFactory import org.jetbrains.kotlin.types.TypeConstructorSubstitution import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.tree.MethodNode // These classes do not actually exist at runtime @@ -61,8 +60,6 @@ const val HANDLE_EXCEPTION_MARKER_NAME = "handleException" const val HANDLE_EXCEPTION_ARGUMENT_MARKER_NAME = "handleExceptionArgument" const val ACTUAL_COROUTINE_START_MARKER_NAME = "actualCoroutineStart" -const val COROUTINE_CONTROLLER_FIELD_NAME = "_controller" -const val COROUTINE_CONTROLLER_GETTER_NAME = "getController" const val COROUTINE_LABEL_FIELD_NAME = "label" data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeContinuationExpression: KtExpression) @@ -188,7 +185,7 @@ fun createResolvedCallForInterceptResume( } fun ResolvedCall<*>.isSuspensionPoint(bindingContext: BindingContext) = - bindingContext[BindingContext.COROUTINE_RECEIVER_FOR_SUSPENSION_POINT, call] != null + bindingContext[BindingContext.ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, call] != null // Suspend functions have irregular signatures on JVM, containing an additional last parameter with type `Continuation`, // and return type Any? @@ -237,12 +234,6 @@ private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction() = arguments = listOf(returnType!!.asTypeProjection()) ) -val KotlinBuiltIns.continuationClassDescriptor get() = getBuiltInClassByFqName(DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME) - -fun KotlinType.hasInlineInterceptResume() = findInterceptResume()?.isInline == true - -fun KotlinType.hasNoinlineInterceptResume() = findInterceptResume()?.isInline == false - fun FunctionDescriptor.isBuiltInSuspendWithCurrentContinuation(): Boolean { if (name != SUSPEND_WITH_CURRENT_CONTINUATION_NAME) return false @@ -286,3 +277,10 @@ fun createMethodNodeForSuspendWithCurrentContinuation( fun CallableDescriptor?.unwrapInitialDescriptorForSuspendFunction() = (this as? SimpleFunctionDescriptor)?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) ?: this + +fun InstructionAdapter.loadSuspendMarker() = invokestatic( + AsmTypes.COROUTINES_SUSPEND_MARKER_OWNER.internalName, + "getSUSPENDED", + Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE), + false +) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 68b253ca40b..4b99f3f9643 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -331,11 +331,20 @@ public class KotlinTypeMapper { } private static final ClassId FAKE_CLASS_ID_FOR_BUILTINS = ClassId.topLevel(new FqName("kotlin.KotlinPackage")); + private static final FqName COROUTINE_SUSPENDED_PROPERTY = new FqName("kotlin.coroutines.SUSPENDED"); @Nullable private static ContainingClassesInfo getPackageMemberContainingClassesInfo(@NotNull DeserializedCallableMemberDescriptor descriptor) { DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); if (containingDeclaration instanceof BuiltInsPackageFragment) { + // TODO: Top level callables are not supported in built-ins + // (while they are loaded from .kotlin-builtins files information about the actual file part is lost) + // This must be fixed when built-ins get loaded through their class files + if (DescriptorUtils.getFqName(descriptor).equals(COROUTINE_SUSPENDED_PROPERTY.toUnsafe())) { + ClassId id = ClassId.topLevel(new FqName("kotlin.coroutines.CoroutinesKt")); + return new ContainingClassesInfo(id, id); + } + return new ContainingClassesInfo(FAKE_CLASS_ID_FOR_BUILTINS, FAKE_CLASS_ID_FOR_BUILTINS); } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index 034839f15a3..bee0f118b5f 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -41,7 +41,9 @@ public class AsmTypes { public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1"); public static final Type MUTABLE_PROPERTY_REFERENCE2 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference2"); public static final Type COROUTINE_IMPL = Type.getObjectType("kotlin/jvm/internal/CoroutineImpl"); - public static final Type COROUTINES_SUSPEND = Type.getObjectType("kotlin/coroutines/Suspend"); + public static final Type RESTRICTED_COROUTINE_IMPL = Type.getObjectType("kotlin/jvm/internal/RestrictedCoroutineImpl"); + public static final Type COROUTINES_SUSPEND_MARKER_OWNER = Type.getObjectType("kotlin/coroutines/CoroutinesKt"); + public static final Type CONTINUATION = Type.getObjectType("kotlin/coroutines/Continuation"); public static final Type[] PROPERTY_REFERENCE_IMPL = { diff --git a/compiler/testData/codegen/box/coroutines/await.kt b/compiler/testData/codegen/box/coroutines/await.kt index 79ee8edaa77..33e444197b5 100644 --- a/compiler/testData/codegen/box/coroutines/await.kt +++ b/compiler/testData/codegen/box/coroutines/await.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES // NO_INTERCEPT_RESUME_TESTS // FILE: promise.kt class Promise(private val executor: ((T) -> Unit) -> Unit) { @@ -48,12 +49,6 @@ fun processQueue() { // FILE: await.kt private var log = "" -class Controller(private val resolve: (T) -> Unit) { - operator fun handleResult(result: T, c: Continuation) { - resolve(result) - } -} - private var inAwait = false suspend fun await(value: Promise): S = suspendWithCurrentContinuation { continuation: Continuation -> @@ -67,7 +62,7 @@ suspend fun await(value: Promise): S = suspendWithCurrentContinuation { c } } inAwait = false - Suspend + SUSPENDED } suspend fun awaitAndLog(value: Promise): S { @@ -78,10 +73,9 @@ suspend fun awaitAndLog(value: Promise): S { }) } -fun async(coroutine c: Controller.() -> Continuation): Promise { +fun async(c: @Suspend() (() -> T)): Promise { return Promise { resolve -> - val controller = Controller { resolve(it) } - c(controller).resume(Unit) + c.startCoroutine(handleResultContinuation(resolve)) } } diff --git a/compiler/testData/codegen/box/coroutines/beginWithException.kt b/compiler/testData/codegen/box/coroutines/beginWithException.kt index 01a01c1ab62..7c1935e02f5 100644 --- a/compiler/testData/codegen/box/coroutines/beginWithException.kt +++ b/compiler/testData/codegen/box/coroutines/beginWithException.kt @@ -1,22 +1,22 @@ // WITH_RUNTIME -class Controller { +// WITH_COROUTINES + +suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x -> } + +fun builder(c: @Suspend() (() -> Unit)) { var exception: Throwable? = null - operator fun handleException(t: Throwable, c: Continuation) { - exception = t - } + c.createCoroutine(object : Continuation { + override fun resume(data: Unit) { + } - suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x -> } + override fun resumeWithException(e: Throwable) { + exception = e + } + }).resumeWithException(RuntimeException("OK")) - // INTERCEPT_RESUME_PLACEHOLDER -} - -fun builder(coroutine c: Controller.() -> Continuation) { - val controller = Controller() - c(controller).resumeWithException(RuntimeException("OK")) - - if (controller.exception?.message != "OK") { - throw RuntimeException("Unexpected result: ${controller.exception?.message}") + if (exception?.message != "OK") { + throw RuntimeException("Unexpected result: ${exception?.message}") } } diff --git a/compiler/testData/codegen/box/coroutines/beginWithExceptionNoHandleException.kt b/compiler/testData/codegen/box/coroutines/beginWithExceptionNoHandleException.kt index 101ac232df2..52a58dfe3e6 100644 --- a/compiler/testData/codegen/box/coroutines/beginWithExceptionNoHandleException.kt +++ b/compiler/testData/codegen/box/coroutines/beginWithExceptionNoHandleException.kt @@ -1,14 +1,10 @@ // WITH_RUNTIME -class Controller { - suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x ->} +// WITH_COROUTINES +suspend fun suspendHere(): Any = suspendWithCurrentContinuation { x ->} - // INTERCEPT_RESUME_PLACEHOLDER -} - -fun builder(coroutine c: Controller.() -> Continuation) { +fun builder(c: @Suspend() (() -> Unit)) { try { - val controller = Controller() - c(controller).resumeWithException(RuntimeException("OK")) + c.createCoroutine(EmptyContinuation).resumeWithException(RuntimeException("OK")) } catch(e: Exception) { if (e?.message != "OK") { diff --git a/compiler/testData/codegen/box/coroutines/coercionToUnit.kt b/compiler/testData/codegen/box/coroutines/coercionToUnit.kt index 33a05981afb..39544ed70f6 100644 --- a/compiler/testData/codegen/box/coroutines/coercionToUnit.kt +++ b/compiler/testData/codegen/box/coroutines/coercionToUnit.kt @@ -1,21 +1,17 @@ -class Controller { - var result = "fail" - operator fun handleResult(u: Unit, c: Continuation) { - result = "OK" - } +// WITH_RUNTIME +// WITH_COROUTINES - suspend fun await(t: T): T = suspendWithCurrentContinuation { c -> - c.resume(t) - Suspend - } - - // INTERCEPT_RESUME_PLACEHOLDER +suspend fun await(t: T): T = suspendWithCurrentContinuation { c -> + c.resume(t) + SUSPENDED } -fun builder(coroutine c: Controller.() -> Continuation): String { - val controller = Controller() - c(controller).resume(Unit) - return controller.result +fun builder(c: @Suspend() (() -> Unit)): String { + var result = "fail" + c.startCoroutine(handleResultContinuation { + result = "OK" + }) + return result } var TRUE = true diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/breakFinally.kt b/compiler/testData/codegen/box/coroutines/controlFlow/breakFinally.kt index a754245e1a1..e15b7429d06 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/breakFinally.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/breakFinally.kt @@ -1,18 +1,18 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" suspend fun suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> c.resume(value) - Suspend + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/breakStatement.kt b/compiler/testData/codegen/box/coroutines/controlFlow/breakStatement.kt index 79433ae673b..24dcf7c4c88 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/breakStatement.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/breakStatement.kt @@ -1,18 +1,18 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" suspend fun suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> c.resume(value) - Suspend + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/doWhileStatement.kt b/compiler/testData/codegen/box/coroutines/controlFlow/doWhileStatement.kt index 580c29d4e80..f358a1d2d0b 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/doWhileStatement.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/doWhileStatement.kt @@ -1,18 +1,18 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" suspend fun suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> c.resume(value) - Suspend + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/forContinue.kt b/compiler/testData/codegen/box/coroutines/controlFlow/forContinue.kt index d4d7c1a9d0e..7da06c3032d 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/forContinue.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/forContinue.kt @@ -1,18 +1,18 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" suspend fun suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> c.resume(value) - Suspend + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/forStatement.kt b/compiler/testData/codegen/box/coroutines/controlFlow/forStatement.kt index 6650ac61837..fb5cfe6232d 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/forStatement.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/forStatement.kt @@ -1,18 +1,18 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" suspend fun suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> c.resume(value) - Suspend + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/ifStatement.kt b/compiler/testData/codegen/box/coroutines/controlFlow/ifStatement.kt index d3bc0c92301..798045ef034 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/ifStatement.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/ifStatement.kt @@ -1,18 +1,18 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" suspend fun suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> c.resume(value) - Suspend + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/returnFromFinally.kt b/compiler/testData/codegen/box/coroutines/controlFlow/returnFromFinally.kt index 3155d370f6b..88fc5a9ecbe 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/returnFromFinally.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/returnFromFinally.kt @@ -1,5 +1,5 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES // Does not work in JVM backend, probably due to bug. It's not clear which behaviour is right. // TODO: fix the bug and enable for JVM backend @@ -11,17 +11,15 @@ class Controller { suspend fun suspendAndLog(value: T): T = suspendWithCurrentContinuation { c -> result += "suspend($value);" c.resume(value) - Suspend - } - - operator fun handleResult(value: String, c: Continuation) { - result += "return($value);" + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(coroutine c: () -> String): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(handleResult { + controller.result += "return($value);" + }) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt b/compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt index 81b7f86af73..8403e00fa77 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt @@ -1,5 +1,5 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" @@ -7,13 +7,13 @@ class Controller { suspend fun suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> result += "[" c.resume(value) - Suspend + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt b/compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt index 0e4fde7e3b5..c074286bc38 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt @@ -1,5 +1,5 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" @@ -7,24 +7,29 @@ class Controller { suspend fun suspendAndLog(value: T): T = suspendWithCurrentContinuation { c -> result += "suspend($value);" c.resume(value) - Suspend + SUSPENDED } // Tail calls are not allowed to be Nothing typed. See KT-15051 suspend fun suspendLogAndThrow(exception: Throwable): Any? = suspendWithCurrentContinuation { c -> result += "throw(${exception.message});" c.resumeWithException(exception) - Suspend - } - - operator fun handleException(exception: Throwable, c: Continuation) { - result += "caught(${exception.message});" + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, object : Continuation { + override fun resume(data: Unit) { + + } + + override fun resumeWithException(exception: Throwable) { + controller.result += "caught(${exception.message});" + } + }) + return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt b/compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt index b48a6b4652f..39f808e720e 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt @@ -1,5 +1,5 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" @@ -7,17 +7,19 @@ class Controller { suspend fun suspendAndLog(value: T): T = suspendWithCurrentContinuation { c -> result += "suspend($value);" c.resume(value) - Suspend - } - - operator fun handleException(exception: Throwable, c: Continuation) { - result += "ignoreCaught(${exception.message});" + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, object : Continuation { + override fun resume(data: Unit) {} + + override fun resumeWithException(exception: Throwable) { + controller.result += "ignoreCaught(${exception.message});" + } + }) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/whileStatement.kt b/compiler/testData/codegen/box/coroutines/controlFlow/whileStatement.kt index 8df31af14f6..26a82f6ea00 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/whileStatement.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/whileStatement.kt @@ -1,18 +1,18 @@ // WITH_RUNTIME -// NO_INTERCEPT_RESUME_TESTS +// WITH_COROUTINES class Controller { var result = "" suspend fun suspendWithResult(value: T): T = suspendWithCurrentContinuation { c -> c.resume(value) - Suspend + SUSPENDED } } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation) return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/controllerAccessFromInnerLambda.kt b/compiler/testData/codegen/box/coroutines/controllerAccessFromInnerLambda.kt index ac7d0c7ed9b..f97401fcb0c 100644 --- a/compiler/testData/codegen/box/coroutines/controllerAccessFromInnerLambda.kt +++ b/compiler/testData/codegen/box/coroutines/controllerAccessFromInnerLambda.kt @@ -1,8 +1,10 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var result = false suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> x.resume("OK") - Suspend + SUSPENDED } fun foo() { @@ -12,9 +14,9 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { +fun builder(c: @Suspend() (Controller.() -> Unit)) { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation) if (!controller.result) throw RuntimeException("fail") } diff --git a/compiler/testData/codegen/box/coroutines/defaultParametersInSuspend.kt b/compiler/testData/codegen/box/coroutines/defaultParametersInSuspend.kt index bcaf53064b6..b084ed58a18 100644 --- a/compiler/testData/codegen/box/coroutines/defaultParametersInSuspend.kt +++ b/compiler/testData/codegen/box/coroutines/defaultParametersInSuspend.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(a: String = "abc", i: Int = 2): String = suspendWithCurrentContinuation { x -> x.resume(a + "#" + (i + 1)) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/emptyClosure.kt b/compiler/testData/codegen/box/coroutines/emptyClosure.kt index 94f31caec63..7d61cb6f2ca 100644 --- a/compiler/testData/codegen/box/coroutines/emptyClosure.kt +++ b/compiler/testData/codegen/box/coroutines/emptyClosure.kt @@ -1,18 +1,20 @@ +// WITH_RUNTIME +// WITH_COROUTINES var result = 0 class Controller { suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> result++ x.resume("OK") - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/falseUnitCoercion.kt b/compiler/testData/codegen/box/coroutines/falseUnitCoercion.kt index 40f3eb64a49..9c0a54790eb 100644 --- a/compiler/testData/codegen/box/coroutines/falseUnitCoercion.kt +++ b/compiler/testData/codegen/box/coroutines/falseUnitCoercion.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(v: T): T = suspendWithCurrentContinuation { x -> x.resume(v) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } var result: Any = "" diff --git a/compiler/testData/codegen/box/coroutines/generate.kt b/compiler/testData/codegen/box/coroutines/generate.kt index 99318cd1b29..a1a2a192be7 100644 --- a/compiler/testData/codegen/box/coroutines/generate.kt +++ b/compiler/testData/codegen/box/coroutines/generate.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES // FULL_JDK fun box(): String { @@ -24,35 +25,34 @@ fun gen() = generate { } // LIBRARY CODE -fun generate(coroutine c: GeneratorController.() -> Continuation): Sequence = object : Sequence { - override fun iterator(): Iterator { - val iterator = GeneratorController() - iterator.setNextStep(c(iterator)) - return iterator - } +interface Generator { + suspend fun yield(value: T) } -class GeneratorController() : AbstractIterator() { - private lateinit var nextStep: Continuation +fun generate(block: @Suspend() (Generator.() -> Unit)): Sequence = GeneratedSequence(block) + +class GeneratedSequence(private val block: @Suspend() (Generator.() -> Unit)) : Sequence { + override fun iterator(): Iterator = GeneratedIterator(block) +} + +class GeneratedIterator(block: @Suspend() (Generator.() -> Unit)) : AbstractIterator(), Generator { + private var nextStep: Continuation = block.createCoroutine(this, object : Continuation { + override fun resume(data: Unit) { + done() + } + + override fun resumeWithException(exception: Throwable) { + throw exception + } + }) override fun computeNext() { nextStep.resume(Unit) } - - fun setNextStep(step: Continuation) { - this.nextStep = step - } - - suspend fun yield(value: T): Unit = suspendWithCurrentContinuation { c -> + suspend override fun yield(value: T) = suspendWithCurrentContinuation { c -> setNext(value) - setNextStep(c) + nextStep = c - Suspend + SUSPENDED } - - operator fun handleResult(result: Unit, c: Continuation) { - done() - } - - // INTERCEPT_RESUME_PLACEHOLDER } diff --git a/compiler/testData/codegen/box/coroutines/handleException.kt b/compiler/testData/codegen/box/coroutines/handleException.kt index ae0308c89a8..596d9077e2d 100644 --- a/compiler/testData/codegen/box/coroutines/handleException.kt +++ b/compiler/testData/codegen/box/coroutines/handleException.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES class Controller { var exception: Throwable? = null val postponedActions = ArrayList<() -> Unit>() @@ -8,7 +9,7 @@ class Controller { x.resume(v) } - Suspend + SUSPENDED } suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> @@ -16,25 +17,21 @@ class Controller { x.resumeWithException(e) } - Suspend + SUSPENDED } - operator fun handleException(t: Throwable, c: Continuation) { - exception = t - } - - fun run(c: Controller.() -> Continuation) { - c(this).resume(Unit) + fun run(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(this, handleExceptionContinuation { + exception = it + }) while (postponedActions.isNotEmpty()) { postponedActions[0]() postponedActions.removeAt(0) } } - - // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { +fun builder(c: @Suspend() (Controller.() -> Unit)) { val controller = Controller() controller.run(c) diff --git a/compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt b/compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt index 641ddcb9d8b..45c8bad226d 100644 --- a/compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt +++ b/compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt @@ -1,17 +1,12 @@ -class Controller { +// WITH_RUNTIME +// WITH_COROUTINES + +fun builder(c: @Suspend() (() -> Unit)): String { var ok = false - - operator fun handleResult(u: Unit, v: Continuation) { + c.startCoroutine(handleResultContinuation { ok = true - } - - // INTERCEPT_RESUME_PLACEHOLDER -} - -fun builder(coroutine c: Controller.() -> Continuation): String { - val controller = Controller() - c(controller).resume(Unit) - if (!controller.ok) throw RuntimeException("Was not called") + }) + if (!ok) throw RuntimeException("Was not called") return "OK" } diff --git a/compiler/testData/codegen/box/coroutines/handleResultNonUnitExpression.kt b/compiler/testData/codegen/box/coroutines/handleResultNonUnitExpression.kt index 10a6302bdb1..d78e88bdd0a 100644 --- a/compiler/testData/codegen/box/coroutines/handleResultNonUnitExpression.kt +++ b/compiler/testData/codegen/box/coroutines/handleResultNonUnitExpression.kt @@ -1,21 +1,17 @@ -class Controller { - var isCompleted = false - suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> - x.resume("OK") - Suspend - } +// WITH_RUNTIME +// WITH_COROUTINES - operator fun handleResult(x: Unit, y: Continuation) { - isCompleted = true - } - - // INTERCEPT_RESUME_PLACEHOLDER +suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> + x.resume("OK") + SUSPENDED } -fun builder(coroutine c: Controller.() -> Continuation) { - val controller = Controller() - c(controller).resume(Unit) - if (!controller.isCompleted) throw RuntimeException("fail") +fun builder(c: @Suspend() (() -> Unit)) { + var isCompleted = false + c.startCoroutine(handleResultContinuation { + isCompleted = true + }) + if (!isCompleted) throw RuntimeException("fail") } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/handleResultSuspended.kt b/compiler/testData/codegen/box/coroutines/handleResultSuspended.kt index 07340fadfd2..405da7fb208 100644 --- a/compiler/testData/codegen/box/coroutines/handleResultSuspended.kt +++ b/compiler/testData/codegen/box/coroutines/handleResultSuspended.kt @@ -1,22 +1,20 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var log = "" suspend fun suspendAndLog(value: T): T = suspendWithCurrentContinuation { x -> log += "suspend($value);" x.resume(value) - Suspend + SUSPENDED } - - operator fun handleResult(value: String, y: Continuation) { - log += "return($value);" - } - - // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> String)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, handleResultContinuation { + controller.log += "return($it);" + }) return controller.log } diff --git a/compiler/testData/codegen/box/coroutines/illegalState.kt b/compiler/testData/codegen/box/coroutines/illegalState.kt index 43d6c77a696..6b8f652f953 100644 --- a/compiler/testData/codegen/box/coroutines/illegalState.kt +++ b/compiler/testData/codegen/box/coroutines/illegalState.kt @@ -1,20 +1,19 @@ // WITH_RUNTIME +// WITH_COROUTINES // TARGET_BACKEND: JVM // NO_INTERCEPT_RESUME_TESTS -class Controller { - suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> - x.resume(Unit) - Suspend - } +suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> + x.resume(Unit) + SUSPENDED } -fun builder1(coroutine c: Controller.() -> Continuation) { +fun builder1(c: @Suspend() (() -> Unit)) { (c as Continuation).resume(Unit) } -fun builder2(coroutine c: Controller.() -> Continuation) { - val continuation = c(Controller()) - val declaredField = continuation.javaClass.superclass.getDeclaredField("label") +fun builder2(c: @Suspend() (() -> Unit)) { + val continuation = c.createCoroutine(EmptyContinuation) + val declaredField = continuation.javaClass.superclass.superclass.getDeclaredField("label") declaredField.setAccessible(true) declaredField.set(continuation, -3) continuation.resume(Unit) @@ -27,8 +26,7 @@ fun box(): String { suspendHere() } return "fail 1" - } catch (e: java.lang.IllegalStateException) { - if (e.message != "call to 'resume' before 'invoke' with coroutine") return "fail 2: ${e.message!!}" + } catch (e: kotlin.KotlinNullPointerException) { } try { @@ -47,8 +45,7 @@ fun box(): String { result = "fail 5" } return "fail 6" - } catch (e: java.lang.IllegalStateException) { - if (e.message != "call to 'resume' before 'invoke' with coroutine") return "fail 7: ${e.message!!}" + } catch (e: kotlin.KotlinNullPointerException) { } try { diff --git a/compiler/testData/codegen/box/coroutines/inlineSuspendFunction.kt b/compiler/testData/codegen/box/coroutines/inlineSuspendFunction.kt index 2d506c112f2..b769cdf58bf 100644 --- a/compiler/testData/codegen/box/coroutines/inlineSuspendFunction.kt +++ b/compiler/testData/codegen/box/coroutines/inlineSuspendFunction.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES // WITH_REFLECT // CHECK_NOT_CALLED: suspendInline_61zpoe$ // CHECK_NOT_CALLED: suspendInline_6r51u9$ @@ -10,7 +11,7 @@ class Controller { suspend inline fun suspendInline(v: String): String = suspendWithCurrentContinuation { x -> withValue(v, x) - Suspend + SUSPENDED } suspend inline fun suspendInline(crossinline b: () -> String): String = suspendInline(b()) @@ -20,8 +21,8 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } class OK diff --git a/compiler/testData/codegen/box/coroutines/inlinedTryCatchFinally.kt b/compiler/testData/codegen/box/coroutines/inlinedTryCatchFinally.kt index b2324b90698..ef1386fd903 100644 --- a/compiler/testData/codegen/box/coroutines/inlinedTryCatchFinally.kt +++ b/compiler/testData/codegen/box/coroutines/inlinedTryCatchFinally.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES var globalResult = "" var wasCalled = false class Controller { @@ -9,7 +10,7 @@ class Controller { x.resume(v) } - Suspend + SUSPENDED } suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> @@ -17,25 +18,21 @@ class Controller { x.resumeWithException(e) } - Suspend + SUSPENDED } - operator fun handleResult(x: String, c: Continuation) { - globalResult = x - } - - fun run(c: Controller.() -> Continuation) { - c(this).resume(Unit) + fun run(c: @Suspend() (Controller.() -> String)) { + c.startCoroutine(this, handleResultContinuation { + globalResult = it + }) while (postponedActions.isNotEmpty()) { postponedActions[0]() postponedActions.removeAt(0) } } - - // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation) { +fun builder(expectException: Boolean = false, c: @Suspend() (Controller.() -> String)) { val controller = Controller() globalResult = "#" diff --git a/compiler/testData/codegen/box/coroutines/innerSuspensionCalls.kt b/compiler/testData/codegen/box/coroutines/innerSuspensionCalls.kt index 5855dd9a0cc..107c443f6ea 100644 --- a/compiler/testData/codegen/box/coroutines/innerSuspensionCalls.kt +++ b/compiler/testData/codegen/box/coroutines/innerSuspensionCalls.kt @@ -1,15 +1,17 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var i = 0 suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> x.resume((i++).toString()) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/instanceOfContinuation.kt b/compiler/testData/codegen/box/coroutines/instanceOfContinuation.kt index 04f55879a42..c5c0f30a37c 100644 --- a/compiler/testData/codegen/box/coroutines/instanceOfContinuation.kt +++ b/compiler/testData/codegen/box/coroutines/instanceOfContinuation.kt @@ -1,24 +1,25 @@ // WITH_RUNTIME +// WITH_COROUTINES // WITH_REFLECT class Controller { suspend fun runInstanceOf(): Boolean = suspendWithCurrentContinuation { x -> val y: Any = x x.resume(x is Continuation<*>) - Suspend + SUSPENDED } suspend fun runCast(): Boolean = suspendWithCurrentContinuation { x -> val y: Any = x x.resume(Continuation::class.isInstance(y as Continuation<*>)) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/complicatedMerge.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/complicatedMerge.kt index 00ff4ad03e3..9f3d2aeef40 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/complicatedMerge.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/complicatedMerge.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun foo() = true diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/i2bResult.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/i2bResult.kt index 8be34c56581..4cc60a2bc06 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/i2bResult.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/i2bResult.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } private var byteResult: Byte = 0 diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromBooleanArray.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromBooleanArray.kt index 2e9cb6b7dbe..3501a5f87f4 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromBooleanArray.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromBooleanArray.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } private var booleanResult = false diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromByteArray.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromByteArray.kt index 4334a180fcf..dab629a493c 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromByteArray.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromByteArray.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } private var byteResult: Byte = 0 diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/noVariableInTable.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/noVariableInTable.kt index 006f9e070e0..96319e5c3cb 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/noVariableInTable.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/noVariableInTable.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } private var booleanResult = false diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/sameIconst1ManyVars.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/sameIconst1ManyVars.kt index 90c2454dff1..ba05935c9c2 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/sameIconst1ManyVars.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/sameIconst1ManyVars.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } private var result: String = "" diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInArrayStore.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInArrayStore.kt index 566683be772..83fe4b3f71a 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInArrayStore.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInArrayStore.kt @@ -1,16 +1,17 @@ // WITH_RUNTIME +// WITH_COROUTINES // TARGET_BACKEND: JVM class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } @JvmField diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInMethodCall.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInMethodCall.kt index 357327b29fd..64aa2b45655 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInMethodCall.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInMethodCall.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } private var booleanResult = false diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInPutfield.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInPutfield.kt index 49fc4e94a7f..756c1033c31 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInPutfield.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInPutfield.kt @@ -1,16 +1,17 @@ // WITH_RUNTIME +// WITH_COROUTINES // TARGET_BACKEND: JVM class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } @JvmField diff --git a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInVarStore.kt b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInVarStore.kt index 2a1f342ddeb..2bf268fb84b 100644 --- a/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInVarStore.kt +++ b/compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInVarStore.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): Unit = suspendWithCurrentContinuation { x -> x.resume(Unit) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/interceptResume.kt b/compiler/testData/codegen/box/coroutines/interceptResume.kt index 9b46d4be343..592e3a7b559 100644 --- a/compiler/testData/codegen/box/coroutines/interceptResume.kt +++ b/compiler/testData/codegen/box/coroutines/interceptResume.kt @@ -1,3 +1,5 @@ +// WITH_RUNTIME +// WITH_COROUTINES // NO_INTERCEPT_RESUME_TESTS class Controller { @@ -7,26 +9,40 @@ class Controller { suspend fun suspendWithValue(value: T): T = suspendWithCurrentContinuation { continuation -> log += "suspend($value);" continuation.resume(value) - Suspend + SUSPENDED } suspend fun suspendWithException(value: String): Unit = suspendWithCurrentContinuation { continuation -> log += "error($value);" continuation.resumeWithException(RuntimeException(value)) - Suspend - } - - operator fun interceptResume(block: () -> Unit) { - var id = resumeIndex++ - log += "before $id;" - block() - log += "after $id;" + SUSPENDED } } -fun test(coroutine c: Controller.() -> Continuation): String { +fun test(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, EmptyContinuation, object: ResumeInterceptor { + private fun interceptResume(block: () -> Unit) { + val id = controller.resumeIndex++ + controller.log += "before $id;" + block() + controller.log += "after $id;" + } + + override fun

interceptResume(data: P, continuation: Continuation

): Boolean { + interceptResume { + continuation.resume(data) + } + return true + } + + override fun interceptResumeWithException(exception: Throwable, continuation: Continuation<*>): Boolean { + interceptResume { + continuation.resumeWithException(exception) + } + return true + } + }) return controller.log } @@ -50,4 +66,4 @@ fun box(): String { if (result != "before 0;error(OK);before 1;OK;after 1;after 0;") return "fail2: $result" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/coroutines/iterateOverArray.kt b/compiler/testData/codegen/box/coroutines/iterateOverArray.kt index de46c2646b2..1e81aa355d7 100644 --- a/compiler/testData/codegen/box/coroutines/iterateOverArray.kt +++ b/compiler/testData/codegen/box/coroutines/iterateOverArray.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> x.resume("OK") - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/kt12958.kt b/compiler/testData/codegen/box/coroutines/kt12958.kt index a10b1a0470a..c7c8ff7dd0d 100644 --- a/compiler/testData/codegen/box/coroutines/kt12958.kt +++ b/compiler/testData/codegen/box/coroutines/kt12958.kt @@ -1,22 +1,18 @@ -class Controller { - var result = "fail" - suspend fun suspendHere(v: V): V = suspendWithCurrentContinuation { x -> - x.resume(v) - Suspend - } - - operator fun handleResult(x: String, c: Continuation) { - result = x - } - - // INTERCEPT_RESUME_PLACEHOLDER +// WITH_RUNTIME +// WITH_COROUTINES +// WITH_CONTINUATION +suspend fun suspendHere(v: V): V = suspendWithCurrentContinuation { x -> + x.resume(v) + SUSPENDED } -fun builder(coroutine c: Controller.() -> Continuation): String { - val controller = Controller() - c(controller).resume(Unit) +fun builder(c: @Suspend() (() -> String)): String { + var result = "fail" + c.startCoroutine(handleResultContinuation { + result = it + }) - return controller.result + return result } fun foo(): String = builder { diff --git a/compiler/testData/codegen/box/coroutines/lambdaParameters.kt b/compiler/testData/codegen/box/coroutines/lambdaParameters.kt deleted file mode 100644 index cae64ecf71d..00000000000 --- a/compiler/testData/codegen/box/coroutines/lambdaParameters.kt +++ /dev/null @@ -1,43 +0,0 @@ -class Controller { - suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x -> - x.resume(v) - Suspend - } - - // INTERCEPT_RESUME_PLACEHOLDER -} - -fun builder(coroutine c: Controller.(Long, String) -> Continuation) { - c(Controller(), 56L, "OK").resume(Unit) -} - -fun noinline(l: () -> String) = l() -inline fun inline(l: () -> String) = l() - -fun box(): String { - var result = "" - - builder { l, s -> - result = suspendHere(s + "#" + l) - } - - if (result != "OK#56") return "fail 1: $result" - - builder { l, s -> - result = suspendHere(noinline { - s + "#" + l - }) - } - - if (result != "OK#56") return "fail 2: $result" - - builder { l, s -> - result = suspendHere(inline { - s + "#" + l - }) - } - - if (result != "OK#56") return "fail 3: $result" - - return "OK" -} diff --git a/compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt b/compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt index 2a2d99d6e8e..50a814b15d4 100644 --- a/compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt +++ b/compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt @@ -1,22 +1,20 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var result = "" var ok = false suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x -> result += v x.resume(Unit) - Suspend + SUSPENDED } - - operator fun handleResult(u: Unit, v: Continuation) { - ok = true - } - - // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, handleResultContinuation { + controller.ok = true + }) if (!controller.ok) throw RuntimeException("Fail ok") return controller.result } diff --git a/compiler/testData/codegen/box/coroutines/lastStatementInc.kt b/compiler/testData/codegen/box/coroutines/lastStatementInc.kt index 76b51fa5adc..342fbd5cf33 100644 --- a/compiler/testData/codegen/box/coroutines/lastStatementInc.kt +++ b/compiler/testData/codegen/box/coroutines/lastStatementInc.kt @@ -1,22 +1,17 @@ -class Controller { - var wasHandleResultCalled = false - suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> - x.resume("OK") - Suspend - } - - operator fun handleResult(x: Unit, y: Continuation) { - wasHandleResultCalled = true - } - - // INTERCEPT_RESUME_PLACEHOLDER +// WITH_RUNTIME +// WITH_COROUTINES +suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> + x.resume("OK") + SUSPENDED } -fun builder(coroutine c: Controller.() -> Continuation) { - val controller = Controller() - c(controller).resume(Unit) +fun builder(c: @Suspend() (() -> Unit)) { + var wasHandleResultCalled = false + c.startCoroutine(handleResultContinuation { + wasHandleResultCalled = true + }) - if (!controller.wasHandleResultCalled) throw RuntimeException("fail 1") + if (!wasHandleResultCalled) throw RuntimeException("fail 1") } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/lastStementAssignment.kt b/compiler/testData/codegen/box/coroutines/lastStementAssignment.kt index a240285cc14..3077bf534f6 100644 --- a/compiler/testData/codegen/box/coroutines/lastStementAssignment.kt +++ b/compiler/testData/codegen/box/coroutines/lastStementAssignment.kt @@ -1,22 +1,17 @@ -class Controller { - var wasHandleResultCalled = false - suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> - x.resume("OK") - Suspend - } - - operator fun handleResult(x: Unit, y: Continuation) { - wasHandleResultCalled = true - } - - // INTERCEPT_RESUME_PLACEHOLDER +// WITH_RUNTIME +// WITH_COROUTINES +suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> + x.resume("OK") + SUSPENDED } -fun builder(coroutine c: Controller.() -> Continuation) { - val controller = Controller() - c(controller).resume(Unit) +fun builder(c: @Suspend() (() -> Unit)) { + var wasHandleResultCalled = false + c.startCoroutine(handleResultContinuation { + wasHandleResultCalled = true + }) - if (!controller.wasHandleResultCalled) throw RuntimeException("fail 1") + if (!wasHandleResultCalled) throw RuntimeException("fail 1") } var varWithCustomSetter: String = "" diff --git a/compiler/testData/codegen/box/coroutines/lastUnitExpression.kt b/compiler/testData/codegen/box/coroutines/lastUnitExpression.kt index 297716dd5f5..0baaf48ddf5 100644 --- a/compiler/testData/codegen/box/coroutines/lastUnitExpression.kt +++ b/compiler/testData/codegen/box/coroutines/lastUnitExpression.kt @@ -1,22 +1,20 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var ok = false var v = "fail" suspend fun suspendHere(v: String): Unit = suspendWithCurrentContinuation { x -> this.v = v x.resume(Unit) - Suspend + SUSPENDED } - - operator fun handleResult(u: Unit, v: Continuation) { - ok = true - } - - // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation): String { +fun builder(c: @Suspend() (Controller.() -> Unit)): String { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, handleResultContinuation { + controller.ok = true + }) if (!controller.ok) throw RuntimeException("Fail 1") return controller.v } diff --git a/compiler/testData/codegen/box/coroutines/manualContinuationImpl.kt b/compiler/testData/codegen/box/coroutines/manualContinuationImpl.kt deleted file mode 100644 index dca0deb25bb..00000000000 --- a/compiler/testData/codegen/box/coroutines/manualContinuationImpl.kt +++ /dev/null @@ -1,41 +0,0 @@ -// IGNORE_BACKEND: JS -// WITH_RUNTIME -class Controller { - suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> - x.resume("OK") - Suspend - } - - // INTERCEPT_RESUME_PLACEHOLDER -} - -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) -} - -fun box(): String { - var result = "fail" - - val lambda: Controller.() -> Continuation = l1@{ - object : Continuation { - override fun resume(data: Any?) { - if (data == Unit) { - this@l1.javaClass.getMethod("suspendHere", Continuation::class.java).invoke(this@l1, this) - return - } - - if (data != "OK") { - throw RuntimeException("fail: $data") - } - - result = "OK" - } - - override fun resumeWithException(exception: Throwable) = throw exception - } - } - - builder(lambda) - - return result -} diff --git a/compiler/testData/codegen/box/coroutines/multiModule/simple.kt b/compiler/testData/codegen/box/coroutines/multiModule/simple.kt index a07055245c4..aff532263f2 100644 --- a/compiler/testData/codegen/box/coroutines/multiModule/simple.kt +++ b/compiler/testData/codegen/box/coroutines/multiModule/simple.kt @@ -1,3 +1,5 @@ +// WITH_RUNTIME +// WITH_COROUTINES // MODULE: controller // FILE: controller.kt package lib @@ -5,7 +7,7 @@ package lib class Controller { suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> x.resume("OK") - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER @@ -15,8 +17,8 @@ class Controller { // FILE: main.kt import lib.* -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/multiModule/suspendExtension.kt b/compiler/testData/codegen/box/coroutines/multiModule/suspendExtension.kt index 7d9cbc80b05..70d781d0b63 100644 --- a/compiler/testData/codegen/box/coroutines/multiModule/suspendExtension.kt +++ b/compiler/testData/codegen/box/coroutines/multiModule/suspendExtension.kt @@ -1,3 +1,5 @@ +// WITH_RUNTIME +// WITH_COROUTINES // MODULE: controller // FILE: controller.kt package lib @@ -6,7 +8,7 @@ package lib class Controller { suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x -> x.resume(this) - Suspend + SUSPENDED } inline suspend fun String.inlineSuspendHere(): String = suspendHere() @@ -26,8 +28,8 @@ suspend fun Controller.localSuspendExtension(v: String) = v.suspendHere() inline suspend fun Controller.localInlineSuspendExtension(v: String) = v.inlineSuspendHere() -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt b/compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt index f6ea90373df..932cf29e6e0 100644 --- a/compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt +++ b/compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt @@ -1,9 +1,11 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var lastSuspension: Continuation? = null var result = "fail" suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> lastSuspension = x - Suspend + SUSPENDED } fun hasNext() = lastSuspension != null @@ -16,26 +18,26 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { +fun builder(c: @Suspend() (Controller.() -> Unit)) { val controller1 = Controller() val controller2 = Controller() - c(controller1).resume(Unit) - c(controller2).resume(Unit) - - runControllers(controller1, controller2) -} - -fun builder2(coroutine c: Controller.(Long, String) -> Continuation) { - val controller1 = Controller() - val controller2 = Controller() - - c(controller1, 1234567890123456789L, "Q").resume(Unit) - c(controller2, 1234567890123456789L, "Q").resume(Unit) + c.startCoroutine(controller1, EmptyContinuation) + c.startCoroutine(controller2, EmptyContinuation) runControllers(controller1, controller2) } +// TODO: additional parameters are not supported yet +//fun builder2(coroutine c: Controller.(Long, String) -> Continuation) { +// val controller1 = Controller() +// val controller2 = Controller() +// +// c(controller1, 1234567890123456789L, "Q").resume(Unit) +// c(controller2, 1234567890123456789L, "Q").resume(Unit) +// +// runControllers(controller1, controller2) +//} private fun runControllers(controller1: Controller, controller2: Controller) { while (controller1.hasNext()) { @@ -72,28 +74,25 @@ fun box(): String { result = "OK" } - // with capture and params + // with capture var x = "O" var y = "K" // no suspension - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 + builder { result = x + y } // 1 suspension - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - if (suspendHere() != "56") return@builder2 + builder { + if (suspendHere() != "56") return@builder result = x + y } // 2 suspensions - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - if (suspendHere() != "56") return@builder2 + builder { + if (suspendHere() != "56") return@builder suspendHere() result = x + y } diff --git a/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda1.kt b/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda1.kt index 53055413af8..fd6c758e212 100644 --- a/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda1.kt +++ b/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda1.kt @@ -1,9 +1,11 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var lastSuspension: Continuation? = null var result = "fail" suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> lastSuspension = x - Suspend + SUSPENDED } fun hasNext() = lastSuspension != null @@ -16,26 +18,26 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { +fun builder(c: @Suspend() (Controller.() -> Unit)) { val controller1 = Controller() val controller2 = Controller() - c(controller1).resume(Unit) - c(controller2).resume(Unit) - - runControllers(controller1, controller2) -} - -fun builder2(coroutine c: Controller.(Long, String) -> Continuation) { - val controller1 = Controller() - val controller2 = Controller() - - c(controller1, 1234567890123456789L, "Q").resume(Unit) - c(controller2, 1234567890123456789L, "Q").resume(Unit) + c.startCoroutine(controller1, EmptyContinuation) + c.startCoroutine(controller2, EmptyContinuation) runControllers(controller1, controller2) } +// TODO: additional parameters are not supported yet +//fun builder2(coroutine c: Controller.(Long, String) -> Continuation) { +// val controller1 = Controller() +// val controller2 = Controller() +// +// c(controller1, 1234567890123456789L, "Q").resume(Unit) +// c(controller2, 1234567890123456789L, "Q").resume(Unit) +// +// runControllers(controller1, controller2) +//} private fun runControllers(controller1: Controller, controller2: Controller) { while (controller1.hasNext()) { @@ -66,22 +68,19 @@ fun box(): String { // inlined run { // no suspension - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 + builder { result = x + y } // 1 suspension - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - if (suspendHere() != "56") return@builder2 + builder { + if (suspendHere() != "56") return@builder result = x + y } // 2 suspensions - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - if (suspendHere() != "56") return@builder2 + builder { + if (suspendHere() != "56") return@builder suspendHere() result = x + y } diff --git a/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda2.kt b/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda2.kt index 1e342624390..ca53524524e 100644 --- a/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda2.kt +++ b/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda2.kt @@ -1,9 +1,11 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var lastSuspension: Continuation? = null var result = "fail" suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> lastSuspension = x - Suspend + SUSPENDED } fun hasNext() = lastSuspension != null @@ -16,26 +18,26 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { +fun builder(c: @Suspend() (Controller.() -> Unit)) { val controller1 = Controller() val controller2 = Controller() - c(controller1).resume(Unit) - c(controller2).resume(Unit) - - runControllers(controller1, controller2) -} - -fun builder2(coroutine c: Controller.(Long, String) -> Continuation) { - val controller1 = Controller() - val controller2 = Controller() - - c(controller1, 1234567890123456789L, "Q").resume(Unit) - c(controller2, 1234567890123456789L, "Q").resume(Unit) + c.startCoroutine(controller1, EmptyContinuation) + c.startCoroutine(controller2, EmptyContinuation) runControllers(controller1, controller2) } +// TODO: additional parameters are not supported yet +//fun builder2(coroutine c: Controller.(Long, String) -> Continuation) { +// val controller1 = Controller() +// val controller2 = Controller() +// +// c(controller1, 1234567890123456789L, "Q").resume(Unit) +// c(controller2, 1234567890123456789L, "Q").resume(Unit) +// +// runControllers(controller1, controller2) +//} private fun runControllers(controller1: Controller, controller2: Controller) { while (controller1.hasNext()) { @@ -83,28 +85,6 @@ fun box(): String { suspendHere() result = "OK" } - - // no suspension - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - result = x + y - } - - // 1 suspension - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - if (suspendHere() != "56") return@builder2 - result = x + y - } - - // 2 suspensions - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - if (suspendHere() != "56") return@builder2 - suspendHere() - result = x + y - } - }() } diff --git a/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda3.kt b/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda3.kt index a1d57db5d92..08374f9d07a 100644 --- a/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda3.kt +++ b/compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda3.kt @@ -1,9 +1,11 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var lastSuspension: Continuation? = null var result = "fail" suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> lastSuspension = x - Suspend + SUSPENDED } fun hasNext() = lastSuspension != null @@ -16,26 +18,26 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { +fun builder(c: @Suspend() (Controller.() -> Unit)) { val controller1 = Controller() val controller2 = Controller() - c(controller1).resume(Unit) - c(controller2).resume(Unit) - - runControllers(controller1, controller2) -} - -fun builder2(coroutine c: Controller.(Long, String) -> Continuation) { - val controller1 = Controller() - val controller2 = Controller() - - c(controller1, 1234567890123456789L, "Q").resume(Unit) - c(controller2, 1234567890123456789L, "Q").resume(Unit) + c.startCoroutine(controller1, EmptyContinuation) + c.startCoroutine(controller2, EmptyContinuation) runControllers(controller1, controller2) } +// TODO: additional parameters are not supported yet +//fun builder2(coroutine c: Controller.(Long, String) -> Continuation) { +// val controller1 = Controller() +// val controller2 = Controller() +// +// c(controller1, 1234567890123456789L, "Q").resume(Unit) +// c(controller2, 1234567890123456789L, "Q").resume(Unit) +// +// runControllers(controller1, controller2) +//} private fun runControllers(controller1: Controller, controller2: Controller) { while (controller1.hasNext()) { @@ -81,28 +83,6 @@ fun box(): String { suspendHere() result = "OK" } - - - // no suspension - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - result = x + y - } - - // 1 suspension - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - if (suspendHere() != "56") return@builder2 - result = x + y - } - - // 2 suspensions - builder2 { a, b -> - if (a != 1234567890123456789L || b != "Q" ) return@builder2 - if (suspendHere() != "56") return@builder2 - suspendHere() - result = x + y - } } } () diff --git a/compiler/testData/codegen/box/coroutines/nestedTryCatch.kt b/compiler/testData/codegen/box/coroutines/nestedTryCatch.kt index a265460ed18..ba3cdd00acf 100644 --- a/compiler/testData/codegen/box/coroutines/nestedTryCatch.kt +++ b/compiler/testData/codegen/box/coroutines/nestedTryCatch.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES var globalResult = "" var wasCalled = false class Controller { @@ -9,7 +10,7 @@ class Controller { x.resume(v) } - Suspend + SUSPENDED } suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> @@ -17,15 +18,13 @@ class Controller { x.resumeWithException(e) } - Suspend + SUSPENDED } - operator fun handleResult(x: String, c: Continuation) { - globalResult = x - } - - fun run(c: Controller.() -> Continuation) { - c(this).resume(Unit) + fun run(c: @Suspend() (Controller.() -> String)) { + c.startCoroutine(this, handleResultContinuation { + globalResult = it + }) while (postponedActions.isNotEmpty()) { postponedActions[0]() postponedActions.removeAt(0) @@ -35,7 +34,7 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation) { +fun builder(expectException: Boolean = false, c: @Suspend() (Controller.() -> String)) { val controller = Controller() globalResult = "#" diff --git a/compiler/testData/codegen/box/coroutines/noSuspensionPoints.kt b/compiler/testData/codegen/box/coroutines/noSuspensionPoints.kt index d95c3f839a8..252b3eb1dd0 100644 --- a/compiler/testData/codegen/box/coroutines/noSuspensionPoints.kt +++ b/compiler/testData/codegen/box/coroutines/noSuspensionPoints.kt @@ -1,17 +1,13 @@ -class Controller { +// WITH_RUNTIME +// WITH_COROUTINES + +fun builder(c: @Suspend() (() -> Int)): Int { var res = 0 - operator fun handleResult(x: Int, y: Continuation) { - res = x - } + c.startCoroutine(handleResultContinuation { + res = it + }) - // INTERCEPT_RESUME_PLACEHOLDER -} - -fun builder(coroutine c: Controller.() -> Continuation): Int { - val controller = Controller() - c(controller).resume(Unit) - - return controller.res + return res } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambda.kt b/compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambda.kt index c3878e75817..0daed379a15 100644 --- a/compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambda.kt +++ b/compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambda.kt @@ -1,20 +1,18 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var cResult = 0 suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x -> x.resume(v * 2) - Suspend + SUSPENDED } - - operator fun handleResult(x: Int, y: Continuation) { - cResult = x - } - - // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation): Controller { +fun builder(c: @Suspend() (Controller.() -> Int)): Controller { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, handleResultContinuation { + controller.cResult = it + }) return controller } diff --git a/compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambdaDeep.kt b/compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambdaDeep.kt index 27e8549fe1a..8c37614010e 100644 --- a/compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambdaDeep.kt +++ b/compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambdaDeep.kt @@ -1,22 +1,19 @@ // WITH_RUNTIME +// WITH_COROUTINES class Controller { var cResult = 0 suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x -> x.resume(v * 2) - Suspend + SUSPENDED } - - operator fun handleResult(x: Int, y: Continuation) { - cResult = x - } - - // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation): Controller { +fun builder(c: @Suspend() (Controller.() -> Int)): Controller { val controller = Controller() - c(controller).resume(Unit) + c.startCoroutine(controller, handleResultContinuation { + controller.cResult = it + }) return controller } diff --git a/compiler/testData/codegen/box/coroutines/returnByLabel.kt b/compiler/testData/codegen/box/coroutines/returnByLabel.kt index 9bae929ab2f..1623632cfb8 100644 --- a/compiler/testData/codegen/box/coroutines/returnByLabel.kt +++ b/compiler/testData/codegen/box/coroutines/returnByLabel.kt @@ -1,22 +1,17 @@ -class Controller { - var res = 0 - suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> - x.resume("OK") - Suspend - } - - operator fun handleResult(x: Int, y: Continuation) { - res = x - } - - // INTERCEPT_RESUME_PLACEHOLDER +// WITH_RUNTIME +// WITH_COROUTINES +suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> + x.resume("OK") + SUSPENDED } -fun builder(coroutine c: Controller.() -> Continuation): Int { - val controller = Controller() - c(controller).resume(Unit) +fun builder(c: @Suspend() (() -> Int)): Int { + var res = 0 + c.startCoroutine(handleResultContinuation { + res = it + }) - return controller.res + return res } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/simple.kt b/compiler/testData/codegen/box/coroutines/simple.kt index 8b38d74b036..1471d33785c 100644 --- a/compiler/testData/codegen/box/coroutines/simple.kt +++ b/compiler/testData/codegen/box/coroutines/simple.kt @@ -1,14 +1,14 @@ -class Controller { - suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> - x.resume("OK") - Suspend - } +// IGNORE_BACKEND: JS +// WITH_RUNTIME +// WITH_COROUTINES - // INTERCEPT_RESUME_PLACEHOLDER +suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> + x.resume("OK") + SUSPENDED } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() () -> Unit) { + c.startCoroutine(EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/simpleException.kt b/compiler/testData/codegen/box/coroutines/simpleException.kt index b9b95a5fde7..e854c3ec223 100644 --- a/compiler/testData/codegen/box/coroutines/simpleException.kt +++ b/compiler/testData/codegen/box/coroutines/simpleException.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> x.resumeWithException(RuntimeException("OK")) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/simpleWithHandleResult.kt b/compiler/testData/codegen/box/coroutines/simpleWithHandleResult.kt index 3c294e2badf..b7833c2f0e1 100644 --- a/compiler/testData/codegen/box/coroutines/simpleWithHandleResult.kt +++ b/compiler/testData/codegen/box/coroutines/simpleWithHandleResult.kt @@ -1,23 +1,27 @@ -class Controller { +// WITH_RUNTIME +// WITH_COROUTINES +suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> + x.resume("OK") + SUSPENDED +} + +fun builder(c: @Suspend() () -> Int): Int { var res = 0 - suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> - x.resume("OK") - Suspend - } - operator fun handleResult(x: Int, y: Continuation) { - res = x - } + c.createCoroutine(object : Continuation { + override fun resume(data: Int) { + res = data + } - // INTERCEPT_RESUME_PLACEHOLDER + override fun resumeWithException(exception: Throwable) { + throw exception + } + }).resume(Unit) + + return res } -fun builder(coroutine c: Controller.() -> Continuation): Int { - val controller = Controller() - c(controller).resume(Unit) - return controller.res -} fun box(): String { var result = "" diff --git a/compiler/testData/codegen/box/coroutines/stackUnwinding/exception.kt b/compiler/testData/codegen/box/coroutines/stackUnwinding/exception.kt index 0c9e2b02253..c92aeb0692f 100644 --- a/compiler/testData/codegen/box/coroutines/stackUnwinding/exception.kt +++ b/compiler/testData/codegen/box/coroutines/stackUnwinding/exception.kt @@ -1,11 +1,13 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): String = throw RuntimeException("OK") // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/stackUnwinding/inlineSuspendFunction.kt b/compiler/testData/codegen/box/coroutines/stackUnwinding/inlineSuspendFunction.kt index 4151881f7c7..a6265b30eb0 100644 --- a/compiler/testData/codegen/box/coroutines/stackUnwinding/inlineSuspendFunction.kt +++ b/compiler/testData/codegen/box/coroutines/stackUnwinding/inlineSuspendFunction.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES // WITH_REFLECT // CHECK_NOT_CALLED: suspendInline_61zpoe$ // CHECK_NOT_CALLED: suspendInline_6r51u9$ @@ -13,8 +14,8 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } class OK diff --git a/compiler/testData/codegen/box/coroutines/stackUnwinding/simple.kt b/compiler/testData/codegen/box/coroutines/stackUnwinding/simple.kt index 611c333d5ee..9a10acb0603 100644 --- a/compiler/testData/codegen/box/coroutines/stackUnwinding/simple.kt +++ b/compiler/testData/codegen/box/coroutines/stackUnwinding/simple.kt @@ -1,11 +1,13 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere() = "OK" // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/stackUnwinding/suspendInCycle.kt b/compiler/testData/codegen/box/coroutines/stackUnwinding/suspendInCycle.kt index 26a71f2756a..35e46f55c65 100644 --- a/compiler/testData/codegen/box/coroutines/stackUnwinding/suspendInCycle.kt +++ b/compiler/testData/codegen/box/coroutines/stackUnwinding/suspendInCycle.kt @@ -1,3 +1,5 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): Int = suspendWithCurrentContinuation { x -> 1 @@ -9,8 +11,8 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/statementLikeLastExpression.kt b/compiler/testData/codegen/box/coroutines/statementLikeLastExpression.kt index a5a70f472d6..663591b3a6e 100644 --- a/compiler/testData/codegen/box/coroutines/statementLikeLastExpression.kt +++ b/compiler/testData/codegen/box/coroutines/statementLikeLastExpression.kt @@ -1,19 +1,15 @@ +// WITH_RUNTIME +// WITH_COROUTINES var globalResult = "" -class Controller { - suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x -> - x.resume(v) - Suspend - } - - operator fun handleResult(x: String, c: Continuation) { - globalResult = x - } - - // INTERCEPT_RESUME_PLACEHOLDER +suspend fun suspendWithValue(v: String): String = suspendWithCurrentContinuation { x -> + x.resume(v) + SUSPENDED } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (() -> String)) { + c.startCoroutine(handleResultContinuation { + globalResult = it + }) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/suspendDelegation.kt b/compiler/testData/codegen/box/coroutines/suspendDelegation.kt index 8688459a4ca..da6cf8cfad1 100644 --- a/compiler/testData/codegen/box/coroutines/suspendDelegation.kt +++ b/compiler/testData/codegen/box/coroutines/suspendDelegation.kt @@ -1,16 +1,18 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): String = suspendThere() suspend fun suspendThere(): String = suspendWithCurrentContinuation { x -> x.resume("OK") - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/suspendExtension.kt b/compiler/testData/codegen/box/coroutines/suspendExtension.kt index afcbc35a234..aded3f16ba3 100644 --- a/compiler/testData/codegen/box/coroutines/suspendExtension.kt +++ b/compiler/testData/codegen/box/coroutines/suspendExtension.kt @@ -1,8 +1,10 @@ +// WITH_RUNTIME +// WITH_COROUTINES @AllowSuspendExtensions class Controller { suspend fun String.suspendHere(): String = suspendWithCurrentContinuation { x -> x.resume(this) - Suspend + SUSPENDED } inline suspend fun String.inlineSuspendHere(): String = suspendHere() @@ -14,8 +16,8 @@ suspend fun Controller.suspendExtension(v: String): String = v.suspendHere() inline suspend fun Controller.inlineSuspendExtension(v: String): String = v.inlineSuspendHere() -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/suspendFromInlineLambda.kt b/compiler/testData/codegen/box/coroutines/suspendFromInlineLambda.kt index 03d0b769085..4ff4124e9eb 100644 --- a/compiler/testData/codegen/box/coroutines/suspendFromInlineLambda.kt +++ b/compiler/testData/codegen/box/coroutines/suspendFromInlineLambda.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(v: Int): Int = suspendWithCurrentContinuation { x -> x.resume(v * 2) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } inline fun foo(x: (Int) -> Unit) { diff --git a/compiler/testData/codegen/box/coroutines/suspendInCycle.kt b/compiler/testData/codegen/box/coroutines/suspendInCycle.kt index 0f648491144..a9b120d9a47 100644 --- a/compiler/testData/codegen/box/coroutines/suspendInCycle.kt +++ b/compiler/testData/codegen/box/coroutines/suspendInCycle.kt @@ -1,19 +1,21 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { var i = 0 suspend fun suspendHere(): Int = suspendWithCurrentContinuation { x -> x.resume(i++) - Suspend + SUSPENDED } suspend fun suspendThere(): String = suspendWithCurrentContinuation { x -> x.resume("?") - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstruction.kt b/compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstruction.kt index 8e37b6fa37b..ba4c388b85f 100644 --- a/compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstruction.kt +++ b/compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstruction.kt @@ -1,24 +1,26 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> x.resume("K") - Suspend + SUSPENDED } suspend fun suspendWithArgument(v: String): String = suspendWithCurrentContinuation { x -> x.resume(v) - Suspend + SUSPENDED } suspend fun suspendWithDouble(v: Double): Double = suspendWithCurrentContinuation { x -> x.resume(v) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } class A(val first: String, val second: String) { diff --git a/compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt b/compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt index 41929a3692b..7c09b2f982b 100644 --- a/compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt +++ b/compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES var globalResult = "" var wasCalled = false class Controller { @@ -9,7 +10,7 @@ class Controller { x.resume(v) } - Suspend + SUSPENDED } suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> @@ -17,15 +18,13 @@ class Controller { x.resumeWithException(e) } - Suspend + SUSPENDED } - operator fun handleResult(x: String, c: Continuation) { - globalResult = x - } - - fun run(c: Controller.() -> Continuation) { - c(this).resume(Unit) + fun run(c: @Suspend() (Controller.() -> String)) { + c.startCoroutine(this, handleResultContinuation { + globalResult = it + }) while (postponedActions.isNotEmpty()) { postponedActions[0]() postponedActions.removeAt(0) @@ -35,7 +34,7 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation) { +fun builder(expectException: Boolean = false, c: @Suspend() (Controller.() -> String)) { val controller = Controller() globalResult = "#" diff --git a/compiler/testData/codegen/box/coroutines/tryCatchWithHandleResult.kt b/compiler/testData/codegen/box/coroutines/tryCatchWithHandleResult.kt index 0011192d8aa..2752e3d5ced 100644 --- a/compiler/testData/codegen/box/coroutines/tryCatchWithHandleResult.kt +++ b/compiler/testData/codegen/box/coroutines/tryCatchWithHandleResult.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES var globalResult = "" var wasCalled = false class Controller { @@ -9,7 +10,7 @@ class Controller { x.resume(v) } - Suspend + SUSPENDED } suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> @@ -17,25 +18,21 @@ class Controller { x.resumeWithException(e) } - Suspend + SUSPENDED } - operator fun handleResult(x: String, c: Continuation) { - globalResult = x - } - - fun run(c: Controller.() -> Continuation) { - c(this).resume(Unit) + fun run(c: @Suspend() (Controller.() -> String)) { + c.startCoroutine(this, handleResultContinuation { + globalResult = it + }) while (postponedActions.isNotEmpty()) { postponedActions[0]() postponedActions.removeAt(0) } } - - // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation) { +fun builder(expectException: Boolean = false, c: @Suspend() (Controller.() -> String)) { val controller = Controller() globalResult = "#" diff --git a/compiler/testData/codegen/box/coroutines/tryFinallyInsideInlineLambda.kt b/compiler/testData/codegen/box/coroutines/tryFinallyInsideInlineLambda.kt index c5ca7cc1be0..492f6426eb2 100644 --- a/compiler/testData/codegen/box/coroutines/tryFinallyInsideInlineLambda.kt +++ b/compiler/testData/codegen/box/coroutines/tryFinallyInsideInlineLambda.kt @@ -1,15 +1,17 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(v: String): String = suspendWithCurrentContinuation { x -> x.resume(v) - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } inline fun run(block: () -> Unit) { diff --git a/compiler/testData/codegen/box/coroutines/tryFinallyWithHandleResult.kt b/compiler/testData/codegen/box/coroutines/tryFinallyWithHandleResult.kt index eb4d4049805..53d22676229 100644 --- a/compiler/testData/codegen/box/coroutines/tryFinallyWithHandleResult.kt +++ b/compiler/testData/codegen/box/coroutines/tryFinallyWithHandleResult.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// WITH_COROUTINES var globalResult = "" var wasCalled = false class Controller { @@ -9,7 +10,7 @@ class Controller { x.resume(v) } - Suspend + SUSPENDED } suspend fun suspendWithException(e: Exception): String = suspendWithCurrentContinuation { x -> @@ -17,15 +18,13 @@ class Controller { x.resumeWithException(e) } - Suspend + SUSPENDED } - operator fun handleResult(x: String, c: Continuation) { - globalResult = x - } - - fun run(c: Controller.() -> Continuation) { - c(this).resume(Unit) + fun run(c: @Suspend() (Controller.() -> String)) { + c.startCoroutine(this, handleResultContinuation { + globalResult = it + }) while (postponedActions.isNotEmpty()) { postponedActions[0]() postponedActions.removeAt(0) @@ -35,7 +34,7 @@ class Controller { // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation) { +fun builder(expectException: Boolean = false, c: @Suspend() (Controller.() -> String)) { val controller = Controller() globalResult = "#" diff --git a/compiler/testData/codegen/box/coroutines/varValueConflictsWithTable.kt b/compiler/testData/codegen/box/coroutines/varValueConflictsWithTable.kt index 171b563c516..6ade0df22fb 100644 --- a/compiler/testData/codegen/box/coroutines/varValueConflictsWithTable.kt +++ b/compiler/testData/codegen/box/coroutines/varValueConflictsWithTable.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> x.resume("OK") - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/box/coroutines/varValueConflictsWithTableSameSort.kt b/compiler/testData/codegen/box/coroutines/varValueConflictsWithTableSameSort.kt index dfdc3699a5d..7b89257b7fb 100644 --- a/compiler/testData/codegen/box/coroutines/varValueConflictsWithTableSameSort.kt +++ b/compiler/testData/codegen/box/coroutines/varValueConflictsWithTableSameSort.kt @@ -1,14 +1,16 @@ +// WITH_RUNTIME +// WITH_COROUTINES class Controller { suspend fun suspendHere(): String = suspendWithCurrentContinuation { x -> x.resume("OK") - Suspend + SUSPENDED } // INTERCEPT_RESUME_PLACEHOLDER } -fun builder(coroutine c: Controller.() -> Continuation) { - c(Controller()).resume(Unit) +fun builder(c: @Suspend() (Controller.() -> Unit)) { + c.startCoroutine(Controller(), EmptyContinuation) } fun box(): String { diff --git a/compiler/testData/codegen/java8/box/async.kt b/compiler/testData/codegen/java8/box/async.kt index 506398dea51..c62f08a70f0 100644 --- a/compiler/testData/codegen/java8/box/async.kt +++ b/compiler/testData/codegen/java8/box/async.kt @@ -43,32 +43,26 @@ fun box(): String { // LIBRARY CODE -fun async(coroutine c: FutureController.() -> Continuation): CompletableFuture { - val controller = FutureController() - c(controller).resume(Unit) - return controller.future -} - -class FutureController { +fun async(c: @Suspend() (() -> T)): CompletableFuture { val future = CompletableFuture() - - - suspend fun await(f: CompletableFuture) = suspendWithCurrentContinuation { machine -> - f.whenComplete { value, throwable -> - if (throwable == null) - machine.resume(value) - else - machine.resumeWithException(throwable) + c.startCoroutine(object : Continuation { + override fun resume(data: T) { + future.complete(data) } - Suspend - } - - operator fun handleResult(value: T, c: Continuation) { - future.complete(value) - } - - fun handleException(t: Throwable, c: Continuation) { - future.completeExceptionally(t) - } + override fun resumeWithException(exception: Throwable) { + future.completeExceptionally(exception) + } + }) + return future +} + +suspend fun await(f: CompletableFuture) = suspendWithCurrentContinuation { machine -> + f.whenComplete { value, throwable -> + if (throwable == null) + machine.resume(value) + else + machine.resumeWithException(throwable) + } + SUSPENDED } diff --git a/compiler/testData/codegen/java8/box/asyncException.kt b/compiler/testData/codegen/java8/box/asyncException.kt index 02aeb7af5e0..8af186c8b66 100644 --- a/compiler/testData/codegen/java8/box/asyncException.kt +++ b/compiler/testData/codegen/java8/box/asyncException.kt @@ -40,31 +40,26 @@ fun box(): String { return "No exception" } -fun async(coroutine c: FutureController.() -> Continuation): CompletableFuture { - val controller = FutureController() - c(controller).resume(Unit) - return controller.future -} - -class FutureController { +fun async(c: @Suspend() (() -> T)): CompletableFuture { val future = CompletableFuture() - - suspend fun await(f: CompletableFuture) = suspendWithCurrentContinuation { machine -> - f.whenComplete { value, throwable -> - if (throwable == null) - machine.resume(value) - else - machine.resumeWithException(throwable) + c.startContinuation(object : Continuation { + override fun resume(data: T) { + future.complete(data) } - Suspend - } - - operator fun handleResult(value: T, c: Continuation) { - future.complete(value) - } - - operator fun handleException(t: Throwable, c: Continuation) { - future.completeExceptionally(t) - } + override fun resumeWithException(exception: Throwable) { + future.completeExceptionally(exception) + } + }) + return future +} + +suspend fun await(f: CompletableFuture) = suspendWithCurrentContinuation { machine -> + f.whenComplete { value, throwable -> + if (throwable == null) + machine.resume(value) + else + machine.resumeWithException(throwable) + } + SUSPENDED } diff --git a/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java b/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java index 1803c872ca4..43e6bf9418d 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java +++ b/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java @@ -92,6 +92,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import static org.jetbrains.kotlin.test.InTextDirectivesUtils.isCompatibleTarget; +import static org.jetbrains.kotlin.test.InTextDirectivesUtils.isDirectiveDefined; public class KotlinTestUtils { public static String TEST_MODULE_NAME = "test-module"; @@ -639,6 +640,37 @@ public class KotlinTestUtils { " to " + (expectedText.length() - 1); } + + if (isDirectiveDefined(expectedText, "WITH_COROUTINES")) { + testFiles.add(factory.createFile(null, + "CoroutineUtil.kt", + "fun handleResultContinuation(x: (T) -> Unit): Continuation = object: Continuation {\n" + + " override fun resumeWithException(exception: Throwable) {\n" + + " throw exception\n" + + " }\n" + + "\n" + + " override fun resume(data: T) = x(data)\n" + + "}\n" + + "\n" + + "fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation = object: Continuation {\n" + + " override fun resumeWithException(exception: Throwable) {\n" + + " x(exception)\n" + + " }\n" + + "\n" + + " override fun resume(data: Any?) { }\n" + + "}\n" + + "\n" + + "object EmptyContinuation : Continuation {\n" + + " override fun resume(data: Any?) {}\n" + + "\n" + + " override fun resumeWithException(exception: Throwable) {\n" + + " throw exception\n" + + " }\n" + + "}", + directives + )); + } + return testFiles; } diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 0b34093800c..f43b75ca8ed 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -4619,12 +4619,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } - @TestMetadata("lambdaParameters.kt") - public void testLambdaParameters() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lambdaParameters.kt"); - doTest(fileName); - } - @TestMetadata("lastExpressionIsLoop.kt") public void testLastExpressionIsLoop() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt"); @@ -4649,12 +4643,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } - @TestMetadata("manualContinuationImpl.kt") - public void testManualContinuationImpl() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/manualContinuationImpl.kt"); - doTest(fileName); - } - @TestMetadata("multipleInvokeCalls.kt") public void testMultipleInvokeCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java index 58c2108e44c..2e21997c2cb 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java @@ -144,12 +144,6 @@ public class AdditionalCoroutineBlackBoxCodegenTestGenerated extends AbstractAdd doTest(fileName); } - @TestMetadata("lambdaParameters.kt") - public void testLambdaParameters() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lambdaParameters.kt"); - doTest(fileName); - } - @TestMetadata("lastExpressionIsLoop.kt") public void testLastExpressionIsLoop() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt"); @@ -174,12 +168,6 @@ public class AdditionalCoroutineBlackBoxCodegenTestGenerated extends AbstractAdd doTest(fileName); } - @TestMetadata("manualContinuationImpl.kt") - public void testManualContinuationImpl() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/manualContinuationImpl.kt"); - doTest(fileName); - } - @TestMetadata("multipleInvokeCalls.kt") public void testMultipleInvokeCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt"); @@ -332,6 +320,71 @@ public class AdditionalCoroutineBlackBoxCodegenTestGenerated extends AbstractAdd KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/controlFlow"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("breakFinally.kt") + public void testBreakFinally() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/breakFinally.kt"); + doTest(fileName); + } + + @TestMetadata("breakStatement.kt") + public void testBreakStatement() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/breakStatement.kt"); + doTest(fileName); + } + + @TestMetadata("doWhileStatement.kt") + public void testDoWhileStatement() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/doWhileStatement.kt"); + doTest(fileName); + } + + @TestMetadata("forContinue.kt") + public void testForContinue() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/forContinue.kt"); + doTest(fileName); + } + + @TestMetadata("forStatement.kt") + public void testForStatement() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/forStatement.kt"); + doTest(fileName); + } + + @TestMetadata("ifStatement.kt") + public void testIfStatement() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/ifStatement.kt"); + doTest(fileName); + } + + @TestMetadata("returnFromFinally.kt") + public void testReturnFromFinally() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/returnFromFinally.kt"); + doTest(fileName); + } + + @TestMetadata("switchLikeWhen.kt") + public void testSwitchLikeWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt"); + doTest(fileName); + } + + @TestMetadata("throwFromCatch.kt") + public void testThrowFromCatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt"); + doTest(fileName); + } + + @TestMetadata("throwInTryWithHandleResult.kt") + public void testThrowInTryWithHandleResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt"); + doTest(fileName); + } + + @TestMetadata("whileStatement.kt") + public void testWhileStatement() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/whileStatement.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 672c3d54265..fd5cb72ca43 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4619,12 +4619,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } - @TestMetadata("lambdaParameters.kt") - public void testLambdaParameters() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lambdaParameters.kt"); - doTest(fileName); - } - @TestMetadata("lastExpressionIsLoop.kt") public void testLastExpressionIsLoop() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt"); @@ -4649,12 +4643,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } - @TestMetadata("manualContinuationImpl.kt") - public void testManualContinuationImpl() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/manualContinuationImpl.kt"); - doTest(fileName); - } - @TestMetadata("multipleInvokeCalls.kt") public void testMultipleInvokeCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java index c68f5f23732..4a627200c30 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java @@ -4619,12 +4619,6 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis doTest(fileName); } - @TestMetadata("lambdaParameters.kt") - public void testLambdaParameters() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lambdaParameters.kt"); - doTest(fileName); - } - @TestMetadata("lastExpressionIsLoop.kt") public void testLastExpressionIsLoop() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt"); @@ -4649,12 +4643,6 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis doTest(fileName); } - @TestMetadata("manualContinuationImpl.kt") - public void testManualContinuationImpl() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/manualContinuationImpl.kt"); - doTest(fileName); - } - @TestMetadata("multipleInvokeCalls.kt") public void testMultipleInvokeCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt index 03aef0ad3e3..fc0650bf01d 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt @@ -16,16 +16,21 @@ package org.jetbrains.kotlin.load.kotlin -import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.* import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations import org.jetbrains.kotlin.load.java.typeEnhancement.hasEnhancedNullability import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.platform.JavaToKotlinClassMap +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.asTypeProjection +import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections import org.jetbrains.kotlin.utils.DO_NOTHING_3 @@ -65,6 +70,26 @@ fun mapType( descriptorTypeWriter: JvmDescriptorTypeWriter?, writeGenericType: (KotlinType, T, TypeMappingMode) -> Unit = DO_NOTHING_3 ): T { + if (kotlinType.isSuspendFunctionType) { + return mapType( + createFunctionType( + kotlinType.builtIns, + FilteredAnnotations(kotlinType.annotations) { it != DescriptorUtils.SUSPEND_ANNOTATION_FQ_NAME }, + kotlinType.getReceiverTypeFromFunctionType(), + kotlinType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) + + KotlinTypeFactory.simpleType( + Annotations.EMPTY, kotlinType.builtIns.continuationClassDescriptor.typeConstructor, + listOf(kotlinType.getReturnTypeFromFunctionType().asTypeProjection()), nullable = false + ), + // TODO: names + null, + kotlinType.builtIns.nullableAnyType + ), + factory, mode, typeMappingConfiguration, descriptorTypeWriter, + writeGenericType + ) + } + mapBuiltInType(kotlinType, factory, typeMappingConfiguration)?.let { builtInType -> val jvmType = factory.boxTypeIfNeeded(builtInType, mode.needPrimitiveBoxing) writeGenericType(kotlinType, jvmType, mode)