diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 92e3d4b954f..877a7761dbe 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -198,7 +198,7 @@ class K2Native : CLICompiler() { } override fun createArguments(): K2NativeCompilerArguments { - return K2NativeCompilerArguments().apply { coroutinesState = "enable" } + return K2NativeCompilerArguments() } override fun executableScriptFileName() = "kotlinc-native" diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index fece1508f7b..6bc268cada5 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -18,8 +18,6 @@ package org.jetbrains.kotlin.cli.bc import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.Argument -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.config.LanguageFeature class K2NativeCompilerArguments : CommonCompilerArguments() { // First go the options interesting to the general public. @@ -149,10 +147,5 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { description = "Paths to friend modules" ) var friendModules: String? = null - - override fun configureLanguageFeatures(collector: MessageCollector) = super.configureLanguageFeatures(collector).also { - it[LanguageFeature.InlineClasses] = LanguageFeature.State.ENABLED // TODO: remove after updating to 1.3. - it[LanguageFeature.ReleaseCoroutines] = LanguageFeature.State.DISABLED - } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 0cc6251020d..f666ddbfcb1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -327,9 +327,6 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val val getContinuation = symbolTable.referenceSimpleFunction( context.getInternalFunctions("getContinuation").single()) - val konanIntercepted = symbolTable.referenceSimpleFunction( - context.getInternalFunctions("intercepted").single()) - val konanSuspendCoroutineUninterceptedOrReturn = symbolTable.referenceSimpleFunction( context.getInternalFunctions("suspendCoroutineUninterceptedOrReturn").single()) @@ -347,7 +344,22 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val .single() .getter!! - override val coroutineImpl = symbolTable.referenceClass(context.getInternalClass("CoroutineImpl")) + override val coroutineImpl get() = TODO() + + val baseContinuationImpl = symbolTable.referenceClass( + builtIns.builtInsModule.findClassAcrossModuleDependencies( + ClassId.topLevel(FqName("kotlin.coroutines.native.internal.BaseContinuationImpl")))!! + ) + + val restrictedContinuationImpl = symbolTable.referenceClass( + builtIns.builtInsModule.findClassAcrossModuleDependencies( + ClassId.topLevel(FqName("kotlin.coroutines.native.internal.RestrictedContinuationImpl")))!! + ) + + val continuationImpl = symbolTable.referenceClass( + builtIns.builtInsModule.findClassAcrossModuleDependencies( + ClassId.topLevel(FqName("kotlin.coroutines.native.internal.ContinuationImpl")))!! + ) override val coroutineSuspendedGetter = symbolTable.referenceSimpleFunction( coroutinesIntrinsicsPackage @@ -355,6 +367,11 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val .filterNot { it.isExpect }.single().getter!! ) + val successOrFailure = symbolTable.referenceClass( + builtIns.builtInsModule.findClassAcrossModuleDependencies( + ClassId.topLevel(FqName("kotlin.SuccessOrFailure")))!! + ) + val refClass = symbolTable.referenceClass(context.getInternalClass("Ref")) val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 00cd8590077..daf253a34c6 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1920,19 +1920,18 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map().single { it.name.asString() == "doResume" } + private val invokeSuspendFunction = context.ir.symbols.baseContinuationImpl.owner.declarations + .filterIsInstance().single { it.name.asString() == "invokeSuspend" } private fun getContinuation(): LLVMValueRef { val caller = functionGenerationContext.functionDescriptor!! return if (caller.isSuspend) codegen.param(caller, caller.allParameters.size) // The last argument. else { - // Suspend call from non-suspend function - must be [CoroutineImpl]. - assert (doResumeFunctionDescriptor.symbol in (caller as IrSimpleFunction).overriddenSymbols, - { "Expected 'CoroutineImpl.doResume' but was '$caller'" }) - currentCodeContext.genGetValue(caller.dispatchReceiverParameter!!) // Coroutine itself is a continuation. + // Suspend call from non-suspend function - must be [BaseContinuationImpl]. + assert ((caller as IrSimpleFunction).overrides(invokeSuspendFunction), + { "Expected 'BaseContinuationImpl.invokeSuspend' but was '$caller'" }) + currentCodeContext.genGetValue(caller.dispatchReceiverParameter!!) } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt index 22004c09042..dafa6121ab0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt @@ -99,7 +99,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW descriptor.resolveFakeOverride().original.let { when { it.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) -> - getFunctionDeclaration(context.ir.symbols.konanIntercepted.descriptor) + error("Continuation.intercepted is not available with release coroutines") it.isBuiltInSuspendCoroutineUninterceptedOrReturn(context.config.configuration.languageVersionSettings) -> getFunctionDeclaration(context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.descriptor) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt index 2bb6847722b..b138fd35763 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt @@ -18,11 +18,11 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.descriptors.getFunction -import org.jetbrains.kotlin.backend.common.ir.createOverriddenDescriptor import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith +import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl @@ -242,7 +242,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass val irBuilder = context.createIrBuilder(irFunction.symbol, irFunction.startOffset, irFunction.endOffset) irFunction.body = irBuilder.irBlockBody(irFunction) { +irReturn( - irCall(coroutine.doResumeFunction.symbol).apply { + irCall(coroutine.invokeSuspendFunction.symbol).apply { dispatchReceiver = irCall(coroutine.coroutineConstructor.symbol).apply { val functionParameters = irFunction.explicitParameters functionParameters.forEachIndexed { index, argument -> @@ -251,8 +251,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass putValueArgument(functionParameters.size, irCall(getContinuation, listOf(irFunction.returnType))) } - putValueArgument(0, irGetObject(symbols.unit)) // value - putValueArgument(1, irNull()) // exception + putValueArgument(0, irSuccess(irGetObject(symbols.unit))) }) } } @@ -262,7 +261,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass private class BuiltCoroutine(val coroutineClass: IrClass, val coroutineConstructor: IrConstructor, - val doResumeFunction: IrFunction) + val invokeSuspendFunction: IrFunction) private var coroutineId = 0 @@ -280,26 +279,28 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass private var tempIndex = 0 private var suspensionPointIdIndex = 0 + private lateinit var labelField: IrField private lateinit var suspendResult: IrVariable - private lateinit var dataArgument: IrValueParameter - private lateinit var exceptionArgument: IrValueParameter + private lateinit var resultArgument: IrValueParameter private lateinit var coroutineClassDescriptor: ClassDescriptorImpl private lateinit var coroutineClass: IrClassImpl private lateinit var coroutineClassThis: IrValueParameter private lateinit var argumentToPropertiesMap: Map - private val coroutineImplSymbol = symbols.coroutineImpl - private val coroutineImplConstructorSymbol = coroutineImplSymbol.constructors.single() - private val coroutineImplClassDescriptor = coroutineImplSymbol.descriptor - private val create1Function = coroutineImplSymbol.owner.simpleFunctions() + private val baseClass = + (if (irFunction.isRestrictedSuspendFunction(context.config.configuration.languageVersionSettings)) { + symbols.restrictedContinuationImpl + } else { + symbols.continuationImpl + }).owner + + private val baseClassConstructor = baseClass.constructors.single { it.valueParameters.size == 1 } + private val create1Function = baseClass.simpleFunctions() .single { it.name.asString() == "create" && it.valueParameters.size == 1 } private val create1CompletionParameter = create1Function.valueParameters[0] - private val coroutineImplLabelGetterSymbol = coroutineImplSymbol.getPropertyGetter("label")!! - private val coroutineImplLabelSetterSymbol = coroutineImplSymbol.getPropertySetter("label")!! - fun build(): BuiltCoroutine { - val superTypes = mutableListOf(coroutineImplSymbol.owner.defaultType) + val superTypes = mutableListOf(baseClass.defaultType) var suspendFunctionClass: IrClass? = null var functionClass: IrClass? = null var suspendFunctionClassTypeArguments: List? = null @@ -340,16 +341,27 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass coroutineClass.createParameterDeclarations() coroutineClassThis = coroutineClass.thisReceiver!! + labelField = createField( + irFunction.startOffset, + irFunction.endOffset, + symbols.nativePtrType, + Name.identifier("label"), + true, + IrDeclarationOrigin.DEFINED, + coroutineClass.descriptor + ) + coroutineClass.addChild(labelField) + val overriddenMap = mutableMapOf() val coroutineConstructorBuilder = createConstructorBuilder() coroutineConstructorBuilder.initialize() - val doResumeFunction = coroutineImplSymbol.owner.simpleFunctions() - .single { it.name.asString() == "doResume" } - val doResumeMethodBuilder = createDoResumeMethodBuilder(doResumeFunction, coroutineClass) - doResumeMethodBuilder.initialize() - overriddenMap += doResumeFunction.descriptor to doResumeMethodBuilder.symbol.descriptor + val invokeSuspendFunction = baseClass.simpleFunctions() + .single { it.name.asString() == "invokeSuspend" } + val invokeSuspendMethodBuilder = createInvokeSuspendMethodBuilder(invokeSuspendFunction, coroutineClass) + invokeSuspendMethodBuilder.initialize() + overriddenMap += invokeSuspendFunction.descriptor to invokeSuspendMethodBuilder.symbol.descriptor var coroutineFactoryConstructorBuilder: SymbolWithIrBuilder? = null var createMethodBuilder: SymbolWithIrBuilder? = null @@ -358,7 +370,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass // Suspend lambda - create factory methods. coroutineFactoryConstructorBuilder = createFactoryConstructorBuilder(boundFunctionParameters!!) - val createFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope + val createFunctionDescriptor = baseClass.descriptor.unsubstitutedMemberScope .getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND) .atMostOne { it.valueParameters.size == unboundFunctionParameters!!.size + 1 } createMethodBuilder = createCreateMethodBuilder( @@ -378,7 +390,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor, functionInvokeFunctionDescriptor = invokeFunctionDescriptor, createFunction = createMethodBuilder.ir, - doResumeFunction = doResumeMethodBuilder.ir, + invokeSuspendFunction = invokeSuspendMethodBuilder.ir, coroutineClass = coroutineClass) } @@ -398,7 +410,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass coroutineClass.addChild(it.ir) } - coroutineClass.addChild(doResumeMethodBuilder.ir) + coroutineClass.addChild(invokeSuspendMethodBuilder.ir) coroutineClass.setSuperSymbolsAndAddFakeOverrides(superTypes) @@ -406,7 +418,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass coroutineClass = coroutineClass, coroutineConstructor = coroutineFactoryConstructorBuilder?.ir ?: coroutineConstructorBuilder.ir, - doResumeFunction = doResumeMethodBuilder.ir) + invokeSuspendFunction = invokeSuspendMethodBuilder.ir) } private fun createConstructorBuilder() @@ -427,7 +439,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl constructorParameters = ( functionParameters - + coroutineImplConstructorSymbol.owner.valueParameters[0] // completion. + + baseClassConstructor.valueParameters[0] // completion. ).mapIndexed { index, parameter -> val parameterDescriptor = parameter.descriptor.copyAsValueParameter(descriptor, index) @@ -464,10 +476,13 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass val completionParameter = valueParameters.last() +IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType, - coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply { + baseClassConstructor.symbol, baseClassConstructor.descriptor).apply { putValueArgument(0, irGet(completionParameter)) } +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, context.irBuiltIns.unitType) + + +irSetField(irGet(coroutineClassThis), labelField, irCall(symbols.getNativeNullPtr.owner)) + functionParameters.forEachIndexed { index, parameter -> +irSetField( irGet(coroutineClassThis), @@ -523,7 +538,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) body = irBuilder.irBlockBody { +IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType, - coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply { + baseClassConstructor.symbol, baseClassConstructor.descriptor).apply { putValueArgument(0, irNull()) // Completion. } +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, @@ -573,8 +588,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass /* modality = */ Modality.FINAL, /* visibility = */ Visibilities.PRIVATE).apply { if (superFunctionDescriptor != null) { - overriddenDescriptors += superFunctionDescriptor.overriddenDescriptors - overriddenDescriptors += superFunctionDescriptor + overriddenDescriptors = listOf(superFunctionDescriptor) } } } @@ -622,7 +636,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass private fun createInvokeMethodBuilder(suspendFunctionInvokeFunctionDescriptor: FunctionDescriptor, functionInvokeFunctionDescriptor: FunctionDescriptor, createFunction: IrFunction, - doResumeFunction: IrFunction, + invokeSuspendFunction: IrFunction, coroutineClass: IrClass) = object: SymbolWithIrBuilder() { @@ -679,7 +693,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) body = irBuilder.irBlockBody(startOffset, endOffset) { +irReturn( - irCall(doResumeFunction).apply { + irCall(invokeSuspendFunction).apply { dispatchReceiver = irCall(createFunction).apply { dispatchReceiver = irGet(thisReceiver) valueParameters.forEachIndexed { index, parameter -> @@ -688,8 +702,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass putValueArgument(valueParameters.size, irCall(getContinuation, listOf(returnType))) } - putValueArgument(0, irGetObject(symbols.unit)) // value - putValueArgument(1, irNull()) // exception + putValueArgument(0, irSuccess(irGetObject(symbols.unit))) } ) } @@ -709,11 +722,11 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass coroutineClass.addChild(it) } - private fun createDoResumeMethodBuilder(doResumeFunction: IrFunction, coroutineClass: IrClass) + private fun createInvokeSuspendMethodBuilder(invokeSuspendFunction: IrFunction, coroutineClass: IrClass) = object: SymbolWithIrBuilder() { override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - doResumeFunction.descriptor.createOverriddenDescriptor(coroutineClassDescriptor) + invokeSuspendFunction.descriptor.createOverriddenDescriptor(coroutineClassDescriptor) ) override fun doInitialize() { } @@ -733,17 +746,13 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass this.createDispatchReceiverParameter() - doResumeFunction.valueParameters.mapIndexedTo(this.valueParameters) { index, it -> + invokeSuspendFunction.valueParameters.mapIndexedTo(this.valueParameters) { index, it -> it.copy(descriptor.valueParameters[index]) } } - dataArgument = function.valueParameters[0] - exceptionArgument = function.valueParameters[1] - - val label = coroutineImplSymbol.owner.declarations.filterIsInstance() - .single { it.name.asString() == "label" } + resultArgument = function.valueParameters.single() val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) function.body = irBuilder.irBlockBody(startOffset, endOffset) { @@ -756,7 +765,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass , context.irBuiltIns.anyNType) // Extract all suspend calls to temporaries in order to make correct jumps to them. - originalBody.transformChildrenVoid(ExpressionSlicer(label.getter!!.returnType)) + originalBody.transformChildrenVoid(ExpressionSlicer(labelField.type)) val liveLocals = computeLivenessAtSuspensionPoints(originalBody) @@ -837,10 +846,11 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass val variable = localsMap[it.descriptor] ?: it +irSetField(irGet(thisReceiver), localToPropertyMap[it.symbol]!!, irGet(variable)) } - +irCall(coroutineImplLabelSetterSymbol).apply { - dispatchReceiver = irGet(thisReceiver) - putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter)) - } + +irSetField( + irGet(thisReceiver), + labelField, + irGet(suspensionPoint.suspensionPointIdParameter) + ) } } restoreState.symbol -> { @@ -865,11 +875,9 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass startOffset = startOffset, endOffset = endOffset, type = context.irBuiltIns.unitType, - suspensionPointId = irCall(coroutineImplLabelGetterSymbol).apply { - dispatchReceiver = irGet(function.dispatchReceiverParameter!!) - }, + suspensionPointId = irGetField(irGet(function.dispatchReceiverParameter!!), labelField), result = irBlock(startOffset, endOffset) { - +irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception. + +irThrowIfNotNull(irExceptionOrNull(irGet(resultArgument))) // Coroutine might start with an exception. statements.forEach { +it } }) if (irFunction.returnType.isUnit()) @@ -1107,8 +1115,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass }, resumeResult = irBlock(startOffset, endOffset) { +irCall(restoreState) - +irThrowIfNotNull(exceptionArgument) - +irGet(dataArgument) + +irGetOrThrow(irGet(resultArgument)) }) val expressionResult = when { suspendCall.type.isUnit() -> irImplicitCoercionToUnit(suspensionPoint) @@ -1188,7 +1195,11 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass irIfThen(irEqeqeq(irGet(value), irCall(symbols.coroutineSuspendedGetter)), irReturn(irGet(value))) - private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueDeclaration) = + private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrExpression) = irLetS(exception) { + irThrowIfNotNull(it.owner) + } + + fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueDeclaration) = irIfThen(irNot(irEqeqeq(irGet(exception), irNull())), irThrow(irImplicitCast(irGet(exception), exception.type.makeNotNull()))) @@ -1200,6 +1211,30 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass } } + private fun IrBuilderWithScope.irGetOrThrow(successOrFailure: IrExpression): IrExpression { + // TODO: consider inlining getOrThrow function body here. + val successOrFailureClass = symbols.successOrFailure.owner + val getOrThrow = successOrFailureClass.simpleFunctions().single { it.name.asString() == "getOrThrow" } + return irCall(getOrThrow).apply { + dispatchReceiver = successOrFailure + } + } + + private fun IrBuilderWithScope.irExceptionOrNull(successOrFailure: IrExpression): IrExpression { + val successOrFailureClass = symbols.successOrFailure.owner + val exceptionOrNull = successOrFailureClass.simpleFunctions().single { it.name.asString() == "exceptionOrNull" } + return irCall(exceptionOrNull).apply { + dispatchReceiver = successOrFailure + } + } + + fun IrBlockBodyBuilder.irSuccess(value: IrExpression): IrCall { + val createSuccessOrFailure = symbols.successOrFailure.owner.constructors.single { it.isPrimary } + return irCall(createSuccessOrFailure).apply { + putValueArgument(0, value) + } + } + private open class VariablesScopeTracker: IrElementVisitorVoid { protected val scopeStack = mutableListOf>(mutableSetOf()) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt index d324cce85c3..f0d8bc89429 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt @@ -403,9 +403,9 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag } } - private val doResumeFunctionSymbol = - context.ir.symbols.coroutineImpl.owner.declarations - .filterIsInstance().single { it.name.asString() == "doResume" }.symbol + private val invokeSuspendFunctionSymbol = + context.ir.symbols.baseContinuationImpl.owner.declarations + .filterIsInstance().single { it.name.asString() == "invokeSuspend" }.symbol private val getContinuationSymbol = context.ir.symbols.getContinuation private val continuationType = getContinuationSymbol.owner.returnType @@ -439,7 +439,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag descriptor.isSuspend -> DataFlowIR.Node.Parameter(allParameters.size) - doResumeFunctionSymbol in descriptor.overriddenSymbols -> // is a CoroutineImpl inheritor. + descriptor.overrides(invokeSuspendFunctionSymbol.owner) -> // is a ContinuationImpl inheritor. templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation. else -> null diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanDescriptorSerializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanDescriptorSerializer.kt index d5e7c34dd4d..b6c81da32bb 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanDescriptorSerializer.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanDescriptorSerializer.kt @@ -259,7 +259,7 @@ class KonanDescriptorSerializer private constructor( if (requirement != null) { builder.addAllVersionRequirement(requirement) } - else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { + if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion()) } @@ -342,7 +342,7 @@ class KonanDescriptorSerializer private constructor( if (requirement != null) { builder.addAllVersionRequirement(requirement) } - else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { + if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion()) } @@ -380,7 +380,7 @@ class KonanDescriptorSerializer private constructor( if (requirement != null) { builder.addAllVersionRequirement(requirement) } - else if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { + if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion()) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializerExtension.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializerExtension.kt index d2c3c8826b6..131f898e794 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializerExtension.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializerExtension.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.backend.konan.serialization import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.ProtoBuf @@ -102,6 +104,9 @@ internal class KonanSerializerExtension(val context: Context, override val metad return IrSerializer( context, inlineDescriptorTable, stringTable, serializer, descriptor).serializeInlineBody() } + + override fun releaseCoroutines(): Boolean = + context.config.configuration.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) } internal interface IrAwareExtension { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt index bd1405d7b6d..9ab603a91b4 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.konan.KonanBackendContext import org.jetbrains.kotlin.backend.konan.KonanCompilationException import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.irasdescriptors.* +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor @@ -50,6 +51,8 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.OverridingStrategy import org.jetbrains.kotlin.resolve.OverridingUtil +import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes @@ -721,3 +724,17 @@ val IrType.isSimpleTypeWithQuestionMark: Boolean fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) = if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType + +fun FunctionDescriptor.createOverriddenDescriptor(owner: ClassDescriptor, final: Boolean = true): FunctionDescriptor { + return this.newCopyBuilder() + .setOwner(owner) + .setCopyOverrides(true) + .setModality(if (final) Modality.FINAL else Modality.OPEN) + .setDispatchReceiverParameter(owner.thisAsReceiverParameter) + .build()!!.apply { + overriddenDescriptors = listOf(this@createOverriddenDescriptor) + } +} + +fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean = + this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 8ee72b9afdb..0cb04e50587 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -1329,16 +1329,19 @@ task coroutines_controlFlow_finally4(type: RunKonanTest) { } task coroutines_controlFlow_finally5(type: RunKonanTest) { + expectedFail = (project.testTarget == 'wasm32') // Uses exceptions. goldValue = "s1\nf2\nfinally\n1\n" source = "codegen/coroutines/controlFlow_finally5.kt" } task coroutines_controlFlow_finally6(type: RunKonanTest) { + expectedFail = (project.testTarget == 'wasm32') // Uses exceptions. goldValue = "s1\nfinally\nerror\n0\n" source = "codegen/coroutines/controlFlow_finally6.kt" } task coroutines_controlFlow_finally7(type: RunKonanTest) { + expectedFail = (project.testTarget == 'wasm32') // Uses exceptions. goldValue = "s1\nf2\nfinally1\ns2\nfinally2\n42\n" source = "codegen/coroutines/controlFlow_finally7.kt" } @@ -1364,21 +1367,25 @@ task coroutines_controlFlow_tryCatch1(type: RunKonanTest) { } task coroutines_controlFlow_tryCatch2(type: RunKonanTest) { + expectedFail = (project.testTarget == 'wasm32') // Uses exceptions. goldValue = "s1\n42\n" source = "codegen/coroutines/controlFlow_tryCatch2.kt" } task coroutines_controlFlow_tryCatch3(type: RunKonanTest) { + expectedFail = (project.testTarget == 'wasm32') // Uses exceptions. goldValue = "s2\nf2\n1\n" source = "codegen/coroutines/controlFlow_tryCatch3.kt" } task coroutines_controlFlow_tryCatch4(type: RunKonanTest) { + expectedFail = (project.testTarget == 'wasm32') // Uses exceptions. goldValue = "s2\nf2\n1\n" source = "codegen/coroutines/controlFlow_tryCatch4.kt" } task coroutines_controlFlow_tryCatch5(type: RunKonanTest) { + expectedFail = (project.testTarget == 'wasm32') // Uses exceptions. goldValue = "s2\ns1\nError\n42\n" source = "codegen/coroutines/controlFlow_tryCatch5.kt" } diff --git a/backend.native/tests/codegen/controlflow/for_loops_coroutines.kt b/backend.native/tests/codegen/controlflow/for_loops_coroutines.kt index ddf3ee60c54..c1231216274 100644 --- a/backend.native/tests/codegen/controlflow/for_loops_coroutines.kt +++ b/backend.native/tests/codegen/controlflow/for_loops_coroutines.kt @@ -2,7 +2,7 @@ package codegen.controlflow.for_loops_coroutines import kotlin.test.* -import kotlin.coroutines.experimental.* +import kotlin.coroutines.* @Test fun runTest() { val sq = buildSequence { diff --git a/backend.native/tests/codegen/coroutines/anonymousObject.kt b/backend.native/tests/codegen/coroutines/anonymousObject.kt index 32eed804d4c..0406b2be2d3 100644 --- a/backend.native/tests/codegen/coroutines/anonymousObject.kt +++ b/backend.native/tests/codegen/coroutines/anonymousObject.kt @@ -2,16 +2,15 @@ package codegen.coroutines.anonymousObject import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun suspendHere(): Int = suspendCoroutineOrReturn { x -> +suspend fun suspendHere(): Int = suspendCoroutineUninterceptedOrReturn { x -> x.resume(42) COROUTINE_SUSPENDED } diff --git a/backend.native/tests/codegen/coroutines/controlFlow_finally1.kt b/backend.native/tests/codegen/coroutines/controlFlow_finally1.kt index 62b8b9db00b..ddf474d6cc4 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_finally1.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_finally1.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally1 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_finally2.kt b/backend.native/tests/codegen/coroutines/controlFlow_finally2.kt index 9b3af544ac6..122a5429fd2 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_finally2.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_finally2.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally2 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_finally3.kt b/backend.native/tests/codegen/coroutines/controlFlow_finally3.kt index 5cce005c1b4..523aa899eb9 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_finally3.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_finally3.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally3 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_finally4.kt b/backend.native/tests/codegen/coroutines/controlFlow_finally4.kt index ce628743c22..e1f929454b1 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_finally4.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_finally4.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally4 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_finally5.kt b/backend.native/tests/codegen/coroutines/controlFlow_finally5.kt index 4aea23fffac..c66e5528b62 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_finally5.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_finally5.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally5 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resumeWithException(Error()) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_finally6.kt b/backend.native/tests/codegen/coroutines/controlFlow_finally6.kt index eaa125c30f3..2e9b7820eee 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_finally6.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_finally6.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_finally6 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resumeWithException(Error("error")) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_finally7.kt b/backend.native/tests/codegen/coroutines/controlFlow_finally7.kt index 32edb245142..e7096af0d06 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_finally7.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_finally7.kt @@ -2,22 +2,21 @@ package codegen.coroutines.controlFlow_finally7 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resumeWithException(Error()) COROUTINE_SUSPENDED } -suspend fun s2(): Int = suspendCoroutineOrReturn { x -> +suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s2") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_if1.kt b/backend.native/tests/codegen/coroutines/controlFlow_if1.kt index c6f0f7ce2dc..0908d793407 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_if1.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_if1.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_if1 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_if2.kt b/backend.native/tests/codegen/coroutines/controlFlow_if2.kt index a296ffbfdb2..d8e908b6bff 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_if2.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_if2.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_if2 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_inline1.kt b/backend.native/tests/codegen/coroutines/controlFlow_inline1.kt index 59deae37108..6a97d912367 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_inline1.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_inline1.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_inline1 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_inline2.kt b/backend.native/tests/codegen/coroutines/controlFlow_inline2.kt index 1c17e540d96..03b100feb46 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_inline2.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_inline2.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_inline2 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_inline3.kt b/backend.native/tests/codegen/coroutines/controlFlow_inline3.kt index 71e802c451e..fb3a43c3a4b 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_inline3.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_inline3.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_inline3 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch1.kt b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch1.kt index 9864d513077..0d1679e11a3 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch1.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch1.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_tryCatch1 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch2.kt b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch2.kt index a7ee9d951f4..b1f31de7eed 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch2.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch2.kt @@ -2,16 +2,15 @@ package codegen.coroutines.controlFlow_tryCatch2 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch3.kt b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch3.kt index 43f21f07726..70d35fdbc24 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch3.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch3.kt @@ -2,22 +2,21 @@ package codegen.coroutines.controlFlow_tryCatch3 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED } -suspend fun s2(): Int = suspendCoroutineOrReturn { x -> +suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s2") x.resumeWithException(Error()) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch4.kt b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch4.kt index 38f7a25e49d..42a0f1a61aa 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch4.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch4.kt @@ -2,22 +2,21 @@ package codegen.coroutines.controlFlow_tryCatch4 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED } -suspend fun s2(): Int = suspendCoroutineOrReturn { x -> +suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s2") x.resumeWithException(Error()) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch5.kt b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch5.kt index 8a094d789d1..70f85a53232 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_tryCatch5.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_tryCatch5.kt @@ -2,22 +2,21 @@ package codegen.coroutines.controlFlow_tryCatch5 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED } -suspend fun s2(): Int = suspendCoroutineOrReturn { x -> +suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s2") x.resumeWithException(Error("Error")) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_while1.kt b/backend.native/tests/codegen/coroutines/controlFlow_while1.kt index 5e687a98f5c..71a9c4649cc 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_while1.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_while1.kt @@ -2,28 +2,27 @@ package codegen.coroutines.controlFlow_while1 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED } -suspend fun s2(): Int = suspendCoroutineOrReturn { x -> +suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s2") x.resumeWithException(Error("Error")) COROUTINE_SUSPENDED } -suspend fun s3(value: Int): Int = suspendCoroutineOrReturn { x -> +suspend fun s3(value: Int): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s3") x.resume(value) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/controlFlow_while2.kt b/backend.native/tests/codegen/coroutines/controlFlow_while2.kt index 29b9da722d2..b0bc496cba7 100644 --- a/backend.native/tests/codegen/coroutines/controlFlow_while2.kt +++ b/backend.native/tests/codegen/coroutines/controlFlow_while2.kt @@ -2,28 +2,27 @@ package codegen.coroutines.controlFlow_while2 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED } -suspend fun s2(): Int = suspendCoroutineOrReturn { x -> +suspend fun s2(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s2") x.resumeWithException(Error("Error")) COROUTINE_SUSPENDED } -suspend fun s3(value: Int): Int = suspendCoroutineOrReturn { x -> +suspend fun s3(value: Int): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s3") x.resume(value) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/coroutineContext1.kt b/backend.native/tests/codegen/coroutines/coroutineContext1.kt index 774499926a8..d3969737f2a 100644 --- a/backend.native/tests/codegen/coroutines/coroutineContext1.kt +++ b/backend.native/tests/codegen/coroutines/coroutineContext1.kt @@ -2,13 +2,12 @@ package codegen.coroutines.coroutineContext1 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } fun builder(c: suspend () -> Unit) { diff --git a/backend.native/tests/codegen/coroutines/coroutineContext2.kt b/backend.native/tests/codegen/coroutines/coroutineContext2.kt index 178241502f2..c4021212e10 100644 --- a/backend.native/tests/codegen/coroutines/coroutineContext2.kt +++ b/backend.native/tests/codegen/coroutines/coroutineContext2.kt @@ -2,13 +2,12 @@ package codegen.coroutines.coroutineContext2 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } fun builder(c: suspend () -> Unit) { diff --git a/backend.native/tests/codegen/coroutines/correctOrder1.kt b/backend.native/tests/codegen/coroutines/correctOrder1.kt index c37379bfa30..6614b1ccf37 100644 --- a/backend.native/tests/codegen/coroutines/correctOrder1.kt +++ b/backend.native/tests/codegen/coroutines/correctOrder1.kt @@ -2,16 +2,15 @@ package codegen.coroutines.correctOrder1 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Int = suspendCoroutineOrReturn { x -> +suspend fun s1(): Int = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(42) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/degenerate1.kt b/backend.native/tests/codegen/coroutines/degenerate1.kt index db9203aad40..f1fb7055d47 100644 --- a/backend.native/tests/codegen/coroutines/degenerate1.kt +++ b/backend.native/tests/codegen/coroutines/degenerate1.kt @@ -2,13 +2,12 @@ package codegen.coroutines.degenerate1 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } suspend fun s1() { diff --git a/backend.native/tests/codegen/coroutines/degenerate2.kt b/backend.native/tests/codegen/coroutines/degenerate2.kt index 20c0ca6faed..5414014a493 100644 --- a/backend.native/tests/codegen/coroutines/degenerate2.kt +++ b/backend.native/tests/codegen/coroutines/degenerate2.kt @@ -2,16 +2,15 @@ package codegen.coroutines.degenerate2 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Unit = suspendCoroutineOrReturn { x -> +suspend fun s1(): Unit = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(Unit) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/returnsUnit1.kt b/backend.native/tests/codegen/coroutines/returnsUnit1.kt index 6dd74705d57..b4e4c73fb1a 100644 --- a/backend.native/tests/codegen/coroutines/returnsUnit1.kt +++ b/backend.native/tests/codegen/coroutines/returnsUnit1.kt @@ -2,16 +2,15 @@ package codegen.coroutines.returnsUnit1 import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun s1(): Unit = suspendCoroutineOrReturn { x -> +suspend fun s1(): Unit = suspendCoroutineUninterceptedOrReturn { x -> println("s1") x.resume(Unit) COROUTINE_SUSPENDED diff --git a/backend.native/tests/codegen/coroutines/simple.kt b/backend.native/tests/codegen/coroutines/simple.kt index 70156a3e259..3636b28b8e6 100644 --- a/backend.native/tests/codegen/coroutines/simple.kt +++ b/backend.native/tests/codegen/coroutines/simple.kt @@ -2,16 +2,15 @@ package codegen.coroutines.simple import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } -suspend fun suspendHere(): Int = suspendCoroutineOrReturn { x -> +suspend fun suspendHere(): Int = suspendCoroutineUninterceptedOrReturn { x -> x.resume(42) COROUTINE_SUSPENDED } diff --git a/backend.native/tests/codegen/coroutines/withReceiver.kt b/backend.native/tests/codegen/coroutines/withReceiver.kt index a41bbb4a60a..7b5c85cb6a7 100644 --- a/backend.native/tests/codegen/coroutines/withReceiver.kt +++ b/backend.native/tests/codegen/coroutines/withReceiver.kt @@ -2,17 +2,16 @@ package codegen.coroutines.withReceiver import kotlin.test.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } class Controller { - suspend fun suspendHere(): Int = suspendCoroutineOrReturn { x -> + suspend fun suspendHere(): Int = suspendCoroutineUninterceptedOrReturn { x -> x.resume(42) COROUTINE_SUSPENDED } diff --git a/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy b/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy index e68089388d7..4ff2317e63e 100644 --- a/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy +++ b/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy @@ -151,59 +151,47 @@ abstract class KonanTest extends JavaExec { } void createCoroutineUtil(String file) { - StringBuilder text = new StringBuilder("import kotlin.coroutines.experimental.*\n") + StringBuilder text = new StringBuilder("import kotlin.coroutines.*\n") text.append( """ open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } fun handleResultContinuation(x: (T) -> Unit): Continuation = object: Continuation { override val context = EmptyCoroutineContext - override fun resumeWithException(exception: Throwable) { - throw exception - } - - override fun resume(data: T) = x(data) + override fun resumeWith(result: SuccessOrFailure) { x(result.getOrThrow()) } } fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation = object: Continuation { override val context = EmptyCoroutineContext - override fun resumeWithException(exception: Throwable) { + override fun resumeWith(result: SuccessOrFailure) { + val exception = result.exceptionOrNull() ?: return x(exception) } - - override fun resume(data: Any?) { } } """ ) createFile(file, text.toString()) } String createTextForHelpers() { - def coroutinesPackage = "kotlin.coroutines.experimental" + def coroutinesPackage = "kotlin.coroutines" def emptyContinuationBody = """ - |override fun resume(data: Any?) {} - |override fun resumeWithException(exception: Throwable) { throw exception } + |override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } """.stripMargin() def handleResultContinuationBody = """ - |override fun resumeWithException(exception: Throwable) { - | throw exception - |} - | - |override fun resume(data: T) = x(data) + |override fun resumeWith(result: SuccessOrFailure) { x(result.getOrThrow()) } """.stripMargin() def handleExceptionContinuationBody = """ - |override fun resumeWithException(exception: Throwable) { - | x(exception) + |override fun resumeWith(result: SuccessOrFailure) { + | val exception = result.exceptionOrNull() ?: return + | x(exception) |} - | - |override fun resume(data: Any?) {} """.stripMargin() return """ @@ -228,6 +216,16 @@ fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation = ob | |abstract class ContinuationAdapter : Continuation { | override val context: CoroutineContext = EmptyCoroutineContext + | override fun resumeWith(result: SuccessOrFailure) { + | if (result.isSuccess) { + | resume(result.getOrThrow()) + | } else { + | resumeWithException(result.exceptionOrNull()!!) + | } + | } + | + | abstract fun resumeWithException(exception: Throwable) + | abstract fun resume(value: T) |} """.stripMargin() } @@ -741,7 +739,7 @@ class RunExternalTestGroup extends RunStandaloneKonanTest { for (String filePath : result) { def text = project.file(filePath).text if (text.contains('COROUTINES_PACKAGE')) { - text = text.replace('COROUTINES_PACKAGE', 'kotlin.coroutines.experimental') + text = text.replace('COROUTINES_PACKAGE', 'kotlin.coroutines') } def pkg = null if (text =~ packagePattern) { diff --git a/runtime/src/main/kotlin/kotlin/coroutines/ContinuationImpl.kt b/runtime/src/main/kotlin/kotlin/coroutines/ContinuationImpl.kt new file mode 100644 index 00000000000..60234c47924 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/coroutines/ContinuationImpl.kt @@ -0,0 +1,133 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.coroutines.native.internal + +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.CoroutineSingletons + +@SinceKotlin("1.3") +internal abstract class BaseContinuationImpl( + // This is `public val` so that it is private on JVM and cannot be modified by untrusted code, yet + // it has a public getter (since even untrusted code is allowed to inspect its call stack). + public val completion: Continuation? +) : Continuation, Serializable { + // This implementation is final. This fact is used to unroll resumeWith recursion. + public final override fun resumeWith(result: SuccessOrFailure) { + // Invoke "resume" debug probe only once, even if previous frames are "resumed" in the loop below, too + probeCoroutineResumed(this) + // This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume + var current = this + var param = result + while (true) { + with(current) { + val completion = completion!! // fail fast when trying to resume continuation without completion + val outcome: SuccessOrFailure = + try { + val outcome = invokeSuspend(param) + if (outcome === CoroutineSingletons.COROUTINE_SUSPENDED) return + SuccessOrFailure.success(outcome) + } catch (exception: Throwable) { + SuccessOrFailure.failure(exception) + } + releaseIntercepted() // this state machine instance is terminating + if (completion is BaseContinuationImpl) { + // unrolling recursion via loop + current = completion + param = outcome + } else { + // top-level completion reached -- invoke and return + completion.resumeWith(outcome) + return + } + } + } + } + + protected abstract fun invokeSuspend(result: SuccessOrFailure): Any? + + protected open fun releaseIntercepted() { + // does nothing here, overridden in ContinuationImpl + } + + public open fun create(completion: Continuation<*>): Continuation { + throw UnsupportedOperationException("create(Continuation) has not been overridden") + } + + public open fun create(value: Any?, completion: Continuation<*>): Continuation { + throw UnsupportedOperationException("create(Any?;Continuation) has not been overridden") + } + + public override fun toString(): String { + // todo: how continuation shall be rendered? + return "Continuation @ ${this::class.simpleName}" + } +} + +@SinceKotlin("1.3") +// State machines for named restricted suspend functions extend from this class +internal abstract class RestrictedContinuationImpl( + completion: Continuation? +) : BaseContinuationImpl(completion) { + init { + completion?.let { + require(it.context === EmptyCoroutineContext) { + "Coroutines with restricted suspension must have EmptyCoroutineContext" + } + } + } + + public override val context: CoroutineContext + get() = EmptyCoroutineContext +} + +@SinceKotlin("1.3") +// State machines for named suspend functions extend from this class +internal abstract class ContinuationImpl( + completion: Continuation?, + private val _context: CoroutineContext? +) : BaseContinuationImpl(completion) { + constructor(completion: Continuation?) : this(completion, completion?.context) + + public override val context: CoroutineContext + get() = _context!! + + private var intercepted: Continuation? = null + + public fun intercepted(): Continuation = + intercepted + ?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this) + .also { intercepted = it } + + protected override fun releaseIntercepted() { + val intercepted = intercepted + if (intercepted != null && intercepted !== this) { + context[ContinuationInterceptor]!!.releaseInterceptedContinuation(intercepted) + } + this.intercepted = CompletedContinuation // just in case + } +} + +internal object CompletedContinuation : Continuation { + override val context: CoroutineContext + get() = error("This continuation is already complete") + + override fun resumeWith(result: SuccessOrFailure) { + error("This continuation is already complete") + } + + override fun toString(): String = "This continuation is already complete" +} diff --git a/runtime/src/main/kotlin/kotlin/coroutines/DebugProbes.kt b/runtime/src/main/kotlin/kotlin/coroutines/DebugProbes.kt new file mode 100644 index 00000000000..cb0c97dad8d --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/coroutines/DebugProbes.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.coroutines.native.internal + +// TODO: support coroutines debugging in Kotlin/Native. + +import kotlin.coroutines.Continuation +import kotlin.coroutines.intrinsics.* + +/** + * This probe is invoked when coroutine is being created and it can replace completion + * with its own wrapped object to intercept completion of this coroutine. + * + * This probe is invoked from stdlib implementation of [createCoroutineUnintercepted] function. + * + * Once created, coroutine is repeatedly [resumed][probeCoroutineResumed] and [suspended][probeCoroutineSuspended], + * until it is complete. On completion, the object that was returned by this probe is invoked. + * + * ``` + * +-------+ probeCoroutineCreated +-----------+ + * | START | ---------------------->| SUSPENDED | + * +-------+ +-----------+ + * probeCoroutineResumed | ^ probeCoroutineSuspended + * V | + * +------------+ completion invoked +-----------+ + * | RUNNING | ------------------->| COMPLETED | + * +------------+ +-----------+ + * ``` + * + * While the coroutine is resumed and suspended, it is represented by the pointer to its `frame` + * which always extends [BaseContinuationImpl] and represents a pointer to the topmost frame of the + * coroutine. Each [BaseContinuationImpl] object has [completion][BaseContinuationImpl.completion] reference + * that points either to another frame (extending [BaseContinuationImpl]) or to the completion object + * that was returned by this `probeCoroutineCreated` function. + * + * When coroutine is [suspended][probeCoroutineSuspended], then it is later [resumed][probeCoroutineResumed] + * with a reference to the same frame. However, while coroutine is running it can unwind its frames and + * invoke other suspending functions, so its next suspension can happen with a different frame pointer. + */ +@SinceKotlin("1.3") +internal fun probeCoroutineCreated(completion: Continuation): Continuation { + return completion +} + +/** + * This probe is invoked when coroutine is resumed using [Continuation.resumeWith]. + * + * This probe is invoked from stdlib implementation of [BaseContinuationImpl.resumeWith] function. + * + * Coroutines machinery implementation guarantees that the actual [frame] instance extends + * [BaseContinuationImpl] class, despite the fact that the declared type of [frame] + * parameter in this function is `Continuation<*>`. See [probeCoroutineCreated] for details. + */ +@SinceKotlin("1.3") +internal fun probeCoroutineResumed(frame: Continuation<*>) { +} + +/** + * This probe is invoked when coroutine is suspended using [suspendCoroutineUninterceptedOrReturn], that is + * when the corresponding `block` returns [COROUTINE_SUSPENDED]. + * + * This probe is invoked from compiler-generated intrinsic for [suspendCoroutineUninterceptedOrReturn] function. + * + * Coroutines machinery implementation guarantees that the actual [frame] instance extends + * [BaseContinuationImpl] class, despite the fact that the declared type of [frame] + * parameter in this function is `Continuation<*>`. See [probeCoroutineCreated] for details. + */ +@SinceKotlin("1.3") +internal fun probeCoroutineSuspended(frame: Continuation<*>) { +} + diff --git a/runtime/src/main/kotlin/kotlin/coroutines/SafeContinuationNative.kt b/runtime/src/main/kotlin/kotlin/coroutines/SafeContinuationNative.kt index 9863654aafb..876c95a550a 100644 --- a/runtime/src/main/kotlin/kotlin/coroutines/SafeContinuationNative.kt +++ b/runtime/src/main/kotlin/kotlin/coroutines/SafeContinuationNative.kt @@ -16,7 +16,9 @@ package kotlin.coroutines -// TODO: implement them right. +import kotlin.* +import kotlin.coroutines.intrinsics.CoroutineSingletons.* + @PublishedApi @SinceKotlin("1.3") internal actual class SafeContinuation @@ -24,14 +26,37 @@ internal actual constructor( private val delegate: Continuation, initialResult: Any? ) : Continuation { - - actual override val context: CoroutineContext - get() = TODO("unimplemented") @PublishedApi - internal actual constructor(delegate: Continuation) : this(delegate, /*UNDECIDED*/ null) + internal actual constructor(delegate: Continuation) : this(delegate, UNDECIDED) + + public actual override val context: CoroutineContext + get() = delegate.context + + private var result: Any? = initialResult + + public actual override fun resumeWith(result: SuccessOrFailure) { + val cur = this.result + when { + cur === UNDECIDED -> this.result = result.value + cur === COROUTINE_SUSPENDED -> { + this.result = RESUMED + delegate.resumeWith(result) + } + else -> throw IllegalStateException("Already resumed") + } + } @PublishedApi - internal actual fun getOrThrow(): Any? = TODO("unimplemented") - - actual override fun resumeWith(result: SuccessOrFailure):Unit = TODO("unimplemented") + internal actual fun getOrThrow(): Any? { + val result = this.result + if (result === UNDECIDED) { + this.result = COROUTINE_SUSPENDED + return COROUTINE_SUSPENDED + } + return when { + result === RESUMED -> COROUTINE_SUSPENDED // already called continuation, indicate COROUTINE_SUSPENDED upstream + result is SuccessOrFailure.Failure -> throw result.exception + else -> result // either COROUTINE_SUSPENDED or data + } + } } \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/coroutines/experimental/Intrinsics.kt b/runtime/src/main/kotlin/kotlin/coroutines/experimental/Intrinsics.kt index 05c8581b697..76ae89ac29c 100644 --- a/runtime/src/main/kotlin/kotlin/coroutines/experimental/Intrinsics.kt +++ b/runtime/src/main/kotlin/kotlin/coroutines/experimental/Intrinsics.kt @@ -17,9 +17,6 @@ package kotlin.coroutines.experimental.intrinsics import kotlin.coroutines.experimental.Continuation -import kotlin.coroutines.experimental.CoroutineContext -import kotlin.coroutines.experimental.processBareContinuationResume -import kotlin.native.internal.* /** @@ -34,13 +31,7 @@ import kotlin.native.internal.* */ public actual fun (suspend () -> T).createCoroutineUnchecked( completion: Continuation -): Continuation = - if (this !is CoroutineImpl) - buildContinuationByInvokeCall(completion) { - @Suppress("UNCHECKED_CAST") (this as Function1, Any?>).invoke(completion) - } - else - (this.create(completion) as CoroutineImpl).facade +): Continuation = errorExperimentalCoroutinesAreNoLongerSupported() /** * Creates a coroutine with receiver type [R] and result type [T]. @@ -55,35 +46,7 @@ public actual fun (suspend () -> T).createCoroutineUnchecked( public actual fun (suspend R.() -> T).createCoroutineUnchecked( receiver: R, completion: Continuation -): Continuation = - if (this !is CoroutineImpl) - buildContinuationByInvokeCall(completion) { - @Suppress("UNCHECKED_CAST") (this as Function2, Any?>).invoke(receiver, completion) - } - else - (this.create(receiver, completion) as CoroutineImpl).facade - -// INTERNAL DEFINITIONS -private inline fun buildContinuationByInvokeCall( - completion: Continuation, - crossinline block: () -> Any? -): Continuation { - val continuation = - object : Continuation { - override val context: CoroutineContext - get() = completion.context - - override fun resume(value: Unit) { - processBareContinuationResume(completion, block) - } - - override fun resumeWithException(exception: Throwable) { - completion.resumeWithException(exception) - } - } - - return interceptContinuationIfNeeded(completion.context, continuation) -} +): Continuation = errorExperimentalCoroutinesAreNoLongerSupported() /** * Starts unintercepted coroutine without receiver and with result type [T] and executes it until its first suspension. @@ -96,7 +59,7 @@ private inline fun buildContinuationByInvokeCall( @kotlin.internal.InlineOnly public actual inline fun (suspend () -> T).startCoroutineUninterceptedOrReturn( completion: Continuation -): Any? = (this as Function1, Any?>).invoke(completion) +): Any? = errorExperimentalCoroutinesAreNoLongerSupported() /** * Starts unintercepted coroutine with receiver type [R] and result type [T] and executes it until its first suspension. @@ -110,7 +73,7 @@ public actual inline fun (suspend () -> T).startCoroutineUninterceptedOrRetu public actual inline fun (suspend R.() -> T).startCoroutineUninterceptedOrReturn( receiver: R, completion: Continuation -): Any? = (this as Function2, Any?>).invoke(receiver, completion) +): Any? = errorExperimentalCoroutinesAreNoLongerSupported() @@ -119,6 +82,8 @@ public actual inline fun (suspend R.() -> T).startCoroutineUninterceptedO * the execution was suspended and will not return any result immediately. */ @SinceKotlin("1.1") -public actual val COROUTINE_SUSPENDED: Any = CoroutineSuspendedMarker +public actual val COROUTINE_SUSPENDED: Any get() = errorExperimentalCoroutinesAreNoLongerSupported() -private object CoroutineSuspendedMarker \ No newline at end of file +@PublishedApi +internal fun errorExperimentalCoroutinesAreNoLongerSupported(): Nothing = + error("kotlin.coroutines.experimental is no longer supported, please migrate to kotlin.coroutines") diff --git a/runtime/src/main/kotlin/kotlin/coroutines/intrinsics/IntrinsicsNative.kt b/runtime/src/main/kotlin/kotlin/coroutines/intrinsics/IntrinsicsNative.kt index 7148dc2f846..eeb7013b90a 100644 --- a/runtime/src/main/kotlin/kotlin/coroutines/intrinsics/IntrinsicsNative.kt +++ b/runtime/src/main/kotlin/kotlin/coroutines/intrinsics/IntrinsicsNative.kt @@ -17,35 +17,178 @@ package kotlin.coroutines.intrinsics import kotlin.coroutines.* -// TODO: implement them right. +import kotlin.coroutines.native.internal.* +import kotlin.native.internal.* +/** + * Starts unintercepted coroutine without receiver and with result type [T] and executes it until its first suspension. + * Returns the result of the coroutine or throws its exception if it does not suspend or [COROUTINE_SUSPENDED] if it suspends. + * In the later case, the [completion] continuation is invoked when coroutine completes with result or exception. + * This function is designed to be used from inside of [suspendCoroutineOrReturn] to resume the execution of suspended + * coroutine using a reference to the suspending function. + */ +@Suppress("UNCHECKED_CAST") +@kotlin.internal.InlineOnly public actual inline fun (suspend () -> T).startCoroutineUninterceptedOrReturn( completion: Continuation -): Any? { - TODO("Unimplemented") -} +): Any? = (this as Function1, Any?>).invoke(completion) +/** + * Starts unintercepted coroutine with receiver type [R] and result type [T] and executes it until its first suspension. + * Returns the result of the coroutine or throws its exception if it does not suspend or [COROUTINE_SUSPENDED] if it suspends. + * In the later case, the [completion] continuation is invoked when coroutine completes with result or exception. + * This function is designed to be used from inside of [suspendCoroutineOrReturn] to resume the execution of suspended + * coroutine using a reference to the suspending function. + */ +@Suppress("UNCHECKED_CAST") +@kotlin.internal.InlineOnly public actual inline fun (suspend R.() -> T).startCoroutineUninterceptedOrReturn( receiver: R, completion: Continuation -): Any? { - TODO("Unimplemented") -} +): Any? = (this as Function2, Any?>).invoke(receiver, completion) +private object CoroutineSuspendedMarker + + +/** + * Creates unintercepted coroutine without receiver and with result type [T]. + * This function creates a new, fresh instance of suspendable computation every time it is invoked. + * + * To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance. + * The [completion] continuation is invoked when coroutine completes with result or exception. + * + * This function returns unintercepted continuation. + * Invocation of `resume(Unit)` starts coroutine immediately in the invoker's call stack without going through the + * [ContinuationInterceptor] that might be present in the completion's [CoroutineContext]. + * It is invoker's responsibility to ensure that the proper invocation context is established. + * Note that [completion] of this function may get invoked in an arbitrary context. + * + * [Continuation.intercepted] can be used to acquire the intercepted continuation. + * Invocation of `resume(Unit)` on intercepted continuation guarantees that execution of + * both the coroutine and [completion] happens in the invocation context established by + * [ContinuationInterceptor]. + * + * Repeated invocation of any resume function on the resulting continuation corrupts the + * state machine of the coroutine and may result in arbitrary behaviour or exception. + */ @SinceKotlin("1.3") public actual fun (suspend () -> T).createCoroutineUnintercepted( completion: Continuation ): Continuation { - TODO("Unimplemented") + val probeCompletion = probeCoroutineCreated(completion) + return if (this is BaseContinuationImpl) + create(probeCompletion) + else + createCoroutineFromSuspendFunction(probeCompletion) { + (this as Function1, Any?>).invoke(it) + } } +/** + * Creates unintercepted coroutine with receiver type [R] and result type [T]. + * This function creates a new, fresh instance of suspendable computation every time it is invoked. + * + * To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance. + * The [completion] continuation is invoked when coroutine completes with result or exception. + * + * This function returns unintercepted continuation. + * Invocation of `resume(Unit)` starts coroutine immediately in the invoker's call stack without going through the + * [ContinuationInterceptor] that might be present in the completion's [CoroutineContext]. + * It is invoker's responsibility to ensure that the proper invocation context is established. + * Note that [completion] of this function may get invoked in an arbitrary context. + * + * [Continuation.intercepted] can be used to acquire the intercepted continuation. + * Invocation of `resume(Unit)` on intercepted continuation guarantees that execution of + * both the coroutine and [completion] happens in the invocation context established by + * [ContinuationInterceptor]. + * + * Repeated invocation of any resume function on the resulting continuation corrupts the + * state machine of the coroutine and may result in arbitrary behaviour or exception. + */ @SinceKotlin("1.3") public actual fun (suspend R.() -> T).createCoroutineUnintercepted( receiver: R, completion: Continuation ): Continuation { - TODO("Unimplemented") + val probeCompletion = probeCoroutineCreated(completion) + return if (this is BaseContinuationImpl) + create(receiver, probeCompletion) + else { + createCoroutineFromSuspendFunction(probeCompletion) { + (this as Function2, Any?>).invoke(receiver, it) + } + } } +/** + * Intercepts this continuation with [ContinuationInterceptor]. + * + * This function shall be used on the immediate result of [createCoroutineUnintercepted] or [suspendCoroutineUninterceptedOrReturn], + * in which case it checks for [ContinuationInterceptor] in the continuation's [context][Continuation.context], + * invokes [ContinuationInterceptor.interceptContinuation], caches and returns result. + * + * If this function is invoked on other [Continuation] instances it returns `this` continuation unchanged. + */ @SinceKotlin("1.3") -public actual fun Continuation.intercepted(): Continuation = TODO("unimplemented") +public actual fun Continuation.intercepted(): Continuation = + (this as? ContinuationImpl)?.intercepted() ?: this + +// INTERNAL DEFINITIONS + +/** + * This function is used when [createCoroutineUnintercepted] encounters suspending lambda that does not extend BaseContinuationImpl. + * + * It happens in two cases: + * 1. Callable reference to suspending function, + * 2. Suspending function reference implemented by Java code. + * + * We must wrap it into an instance that extends [BaseContinuationImpl], because that is an expectation of all coroutines machinery. + * As an optimization we use lighter-weight [RestrictedContinuationImpl] base class (it has less fields) if the context is + * [EmptyCoroutineContext], and a full-blown [ContinuationImpl] class otherwise. + * + * The instance of [BaseContinuationImpl] is passed to the [block] so that it can be passed to the corresponding invocation. + */ +@SinceKotlin("1.3") +private inline fun createCoroutineFromSuspendFunction( + completion: Continuation, + crossinline block: (Continuation) -> Any? +): Continuation { + val context = completion.context + // label == 0 when coroutine is not started yet (initially) or label == 1 when it was + return if (context === EmptyCoroutineContext) + object : RestrictedContinuationImpl(completion as Continuation) { + private var label = 0 + + override fun invokeSuspend(result: SuccessOrFailure): Any? = + when (label) { + 0 -> { + label = 1 + result.getOrThrow() // Rethrow exception if trying to start with exception (will be caught by BaseContinuationImpl.resumeWith + block(this) // run the block, may return or suspend + } + 1 -> { + label = 2 + result.getOrThrow() // this is the result if the block had suspended + } + else -> error("This coroutine had already completed") + } + } + else + object : ContinuationImpl(completion as Continuation, context) { + private var label = 0 + + override fun invokeSuspend(result: SuccessOrFailure): Any? = + when (label) { + 0 -> { + label = 1 + result.getOrThrow() // Rethrow exception if trying to start with exception (will be caught by BaseContinuationImpl.resumeWith + block(this) // run the block, may return or suspend + } + 1 -> { + label = 2 + result.getOrThrow() // this is the result if the block had suspended + } + else -> error("This coroutine had already completed") + } + } +} diff --git a/runtime/src/main/kotlin/kotlin/native/internal/Coroutines.kt b/runtime/src/main/kotlin/kotlin/native/internal/Coroutines.kt index e2e15c910a0..e34df6d21f1 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/Coroutines.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/Coroutines.kt @@ -16,19 +16,14 @@ package kotlin.native.internal -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* @kotlin.internal.InlineOnly @PublishedApi internal inline suspend fun suspendCoroutineUninterceptedOrReturn(crossinline block: (Continuation) -> Any?): T = returnIfSuspended(block(getContinuation())) -@kotlin.internal.InlineOnly -@PublishedApi -internal inline fun Continuation.intercepted(): Continuation = - normalizeContinuation(this) - @Intrinsic @PublishedApi internal external fun getContinuation(): Continuation @@ -41,65 +36,3 @@ internal inline suspend fun getCoroutineContext(): CoroutineContext = @Intrinsic @PublishedApi internal external suspend fun returnIfSuspended(@Suppress("UNUSED_PARAMETER") argument: Any?): T - - -@ExportForCompiler -internal fun interceptContinuationIfNeeded( - context: CoroutineContext, - continuation: Continuation -) = context[ContinuationInterceptor]?.interceptContinuation(continuation) ?: continuation - -/** - * @suppress - */ -@ExportForCompiler -@PublishedApi -internal fun normalizeContinuation(continuation: Continuation): Continuation = - (continuation as? CoroutineImpl)?.facade ?: continuation - -/** - * @suppress - */ -@ExportForCompiler -abstract internal class CoroutineImpl( - protected var completion: Continuation? -) : Continuation { - - // label == -1 when coroutine cannot be started (it is just a factory object) or has already finished execution - // label == 0 in initial part of the coroutine - protected var label: NativePtr = if (completion != null) NativePtr.NULL else NativePtr.NULL + (-1L) - - private val _context: CoroutineContext? = completion?.context - - override val context: CoroutineContext - get() = _context!! - - private var _facade: Continuation? = null - - val facade: Continuation get() { - if (_facade == null) _facade = interceptContinuationIfNeeded(_context!!, this) - return _facade!! - } - - override fun resume(value: Any?) { - processBareContinuationResume(completion!!) { - doResume(value, null) - } - } - - override fun resumeWithException(exception: Throwable) { - processBareContinuationResume(completion!!) { - doResume(null, exception) - } - } - - protected abstract fun doResume(data: Any?, exception: Throwable?): Any? - - open fun create(completion: Continuation<*>): Continuation { - throw IllegalStateException("create(Continuation) has not been overridden") - } - - open fun create(value: Any?, completion: Continuation<*>): Continuation { - throw IllegalStateException("create(Any?;Continuation) has not been overridden") - } -} diff --git a/samples/nonBlockingEchoServer/src/main/kotlin/EchoServer.kt b/samples/nonBlockingEchoServer/src/main/kotlin/EchoServer.kt index b6a62096dff..1c3cf659986 100644 --- a/samples/nonBlockingEchoServer/src/main/kotlin/EchoServer.kt +++ b/samples/nonBlockingEchoServer/src/main/kotlin/EchoServer.kt @@ -16,8 +16,8 @@ import kotlinx.cinterop.* import platform.posix.* -import kotlin.coroutines.experimental.* -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* fun main(args: Array) { if (args.size < 1) { @@ -96,9 +96,8 @@ class Client(val clientFd: Int, val waitingList: MutableMap) { if (posix_errno() != EWOULDBLOCK) throw IOException(getUnixError()) // Save continuation and suspend. - return suspendCoroutineOrReturn { continuation -> + return suspendCoroutine { continuation -> waitingList.put(clientFd, WaitingFor.Read(data, dataLength, continuation)) - COROUTINE_SUSPENDED } } @@ -109,17 +108,15 @@ class Client(val clientFd: Int, val waitingList: MutableMap) { if (posix_errno() != EWOULDBLOCK) throw IOException(getUnixError()) // Save continuation and suspend. - return suspendCoroutineOrReturn { continuation -> + return suspendCoroutine { continuation -> waitingList.put(clientFd, WaitingFor.Write(data, length, continuation)) - COROUTINE_SUSPENDED } } } open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation { companion object : EmptyContinuation() - override fun resume(value: Any?) {} - override fun resumeWithException(exception: Throwable) { throw exception } + override fun resumeWith(result: SuccessOrFailure) { result.getOrThrow() } } fun acceptClientsAndRun(serverFd: Int, block: suspend Client.() -> Unit) {