Support suspendCoroutineUninterceptedOrReturn intrinsic

KT-17336: Fixed
This commit is contained in:
Ilmir Usmanov
2017-10-27 21:03:17 +03:00
parent 4c583c5a61
commit 0fbbe10143
13 changed files with 420 additions and 8 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -26,11 +27,23 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
val SUSPEND_COROUTINE_OR_RETURN_NAME = Name.identifier("suspendCoroutineOrReturn")
val INTERCEPTED_NAME = Name.identifier("intercepted")
val COROUTINE_SUSPENDED_NAME = Name.identifier("COROUTINE_SUSPENDED")
val COROUTINES_INTRINSICS_PACKAGE_FQ_NAME = DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("intrinsics"))
val COROUTINE_CONTEXT_FQ_NAME = COROUTINES_INTRINSICS_PACKAGE_FQ_NAME.child(Name.identifier("coroutineContext"))
val SUSPEND_COROUTINE_UNINTERCEPTED_OR_RETURN_NAME = Name.identifier("suspendCoroutineUninterceptedOrReturn")
fun FunctionDescriptor.isBuiltInIntercepted(): Boolean {
if (name != INTERCEPTED_NAME) return false
val original =
module.getPackage(COROUTINES_INTRINSICS_PACKAGE_FQ_NAME).memberScope
.getContributedFunctions(INTERCEPTED_NAME, NoLookupLocation.FROM_BACKEND)
.singleOrNull() as CallableDescriptor
return DescriptorEquivalenceForOverrides.areEquivalent(original, this)
}
fun FunctionDescriptor.isBuiltInSuspendCoroutineOrReturn(): Boolean {
if (name != SUSPEND_COROUTINE_OR_RETURN_NAME) return false
@@ -49,3 +62,10 @@ fun FunctionDescriptor.getBuiltInSuspendCoroutineOrReturn() =
fun FunctionDescriptor.isBuiltInCoroutineContext() =
(this as? PropertyGetterDescriptor)?.correspondingProperty?.fqNameSafe == COROUTINE_CONTEXT_FQ_NAME
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(): Boolean {
if (name != SUSPEND_COROUTINE_UNINTERCEPTED_OR_RETURN_NAME) return false
val original = module.getPackage(COROUTINES_INTRINSICS_PACKAGE_FQ_NAME).memberScope
.getContributedFunctions(SUSPEND_COROUTINE_UNINTERCEPTED_OR_RETURN_NAME, NoLookupLocation.FROM_BACKEND)
.singleOrNull() as CallableDescriptor
return DescriptorEquivalenceForOverrides.areEquivalent(original, this)
}
@@ -172,7 +172,7 @@ private fun NewResolvedCallImpl<VariableDescriptor>.asDummyOldResolvedCall(bindi
fun ResolvedCall<*>.isSuspendNoInlineCall() =
resultingDescriptor.safeAs<FunctionDescriptor>()
?.let {
it.isSuspend && (!it.isInline || it.isBuiltInSuspendCoroutineOrReturnInJvm())
it.isSuspend && (!it.isInline || it.isBuiltInSuspendCoroutineOrReturnInJvm() || it.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm())
} == true
fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean {
@@ -245,7 +245,6 @@ fun ModuleDescriptor.getContinuationOfTypeOrAny(kotlinType: KotlinType) =
)
} ?: module.builtIns.nullableAnyType
fun FunctionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm() =
getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineOrReturn() == true
@@ -289,6 +288,40 @@ fun createMethodNodeForSuspendCoroutineOrReturn(
return node
}
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm() =
getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineUninterceptedOrReturn() == true
fun createMethodNodeForIntercepted(
functionDescriptor: FunctionDescriptor,
typeMapper: KotlinTypeMapper
): MethodNode {
assert(functionDescriptor.isBuiltInIntercepted()) {
"functionDescriptor must be kotlin.coroutines.intrinsics.intercepted"
}
val node =
MethodNode(
Opcodes.ASM5,
Opcodes.ACC_STATIC,
"fake",
typeMapper.mapAsmMethod(functionDescriptor).descriptor, null, null
)
node.visitVarInsn(Opcodes.ALOAD, 0)
node.visitMethodInsn(
Opcodes.INVOKESTATIC,
INTERNAL_COROUTINE_INTRINSICS_OWNER_INTERNAL_NAME,
NORMALIZE_CONTINUATION_METHOD_NAME,
Type.getMethodDescriptor(CONTINUATION_ASM_TYPE, CONTINUATION_ASM_TYPE),
false
)
node.visitInsn(Opcodes.ARETURN)
node.visitMaxs(1, 1)
return node
}
fun createMethodNodeForCoroutineContext(functionDescriptor: FunctionDescriptor): MethodNode {
assert(functionDescriptor.isBuiltInCoroutineContext()) {
"functionDescriptor must be kotlin.coroutines.intrinsics.coroutineContext property getter"
@@ -318,6 +351,39 @@ fun createMethodNodeForCoroutineContext(functionDescriptor: FunctionDescriptor):
return node
}
fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(
functionDescriptor: FunctionDescriptor,
typeMapper: KotlinTypeMapper
): MethodNode {
assert(functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm()) {
"functionDescriptor must be kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn"
}
val node =
MethodNode(
Opcodes.ASM5,
Opcodes.ACC_STATIC,
"fake",
typeMapper.mapAsmMethod(functionDescriptor).descriptor, null, null
)
node.visitVarInsn(Opcodes.ALOAD, 0)
node.visitVarInsn(Opcodes.ALOAD, 1)
node.visitMethodInsn(
Opcodes.INVOKEINTERFACE,
typeMapper.mapType(functionDescriptor.valueParameters[0]).internalName,
OperatorNameConventions.INVOKE.identifier,
"(${AsmTypes.OBJECT_TYPE})${AsmTypes.OBJECT_TYPE}",
true
)
node.visitInsn(Opcodes.ARETURN)
node.visitMaxs(2, 2)
return node
}
@Suppress("UNCHECKED_CAST")
fun <D : CallableDescriptor?> D.unwrapInitialDescriptorForSuspendFunction(): D =
this.safeAs<SimpleFunctionDescriptor>()?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) as D ?: this
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.inline
import com.intellij.psi.PsiElement
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.backend.common.isBuiltInCoroutineContext
import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags
@@ -490,13 +491,23 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
}
functionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm() ->
return SMAPAndMethodNode(
createMethodNodeForSuspendCoroutineOrReturn(functionDescriptor, state.typeMapper),
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
createMethodNodeForSuspendCoroutineOrReturn(functionDescriptor, state.typeMapper),
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
)
functionDescriptor.isBuiltInIntercepted() ->
return SMAPAndMethodNode(
createMethodNodeForIntercepted(functionDescriptor, state.typeMapper),
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
)
functionDescriptor.isBuiltInCoroutineContext() ->
return SMAPAndMethodNode(
createMethodNodeForCoroutineContext(functionDescriptor),
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
createMethodNodeForCoroutineContext(functionDescriptor),
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
)
functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm() ->
return SMAPAndMethodNode(
createMethodNodeForSuspendCoroutineUninterceptedOrReturn(functionDescriptor, state.typeMapper),
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
)
}
@@ -0,0 +1,82 @@
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
import kotlin.test.assertEquals
suspend fun suspendHereUnintercepted(): String = suspendCoroutineUninterceptedOrReturn { x ->
x.resume("OK")
COROUTINE_SUSPENDED
}
suspend fun suspendWithExceptionUnintercepted(): String = suspendCoroutineUninterceptedOrReturn { x ->
x.resumeWithException(RuntimeException("OK"))
COROUTINE_SUSPENDED
}
suspend fun suspendHereIntercepted(): String = suspendCoroutineUninterceptedOrReturn { x ->
x.intercepted().resume("OK")
COROUTINE_SUSPENDED
}
suspend fun suspendWithExceptionIntercepted(): String = suspendCoroutineUninterceptedOrReturn { x ->
x.intercepted().resumeWithException(RuntimeException("OK"))
COROUTINE_SUSPENDED
}
fun builder(expectedCount: Int, c: suspend () -> String): String {
var fromSuspension: String? = null
var counter = 0
val result = try {
c.startCoroutineUninterceptedOrReturn(object: Continuation<String> {
override val context: CoroutineContext
get() = ContinuationDispatcher { counter++ }
override fun resumeWithException(exception: Throwable) {
fromSuspension = "Exception: " + exception.message!!
}
override fun resume(value: String) {
fromSuspension = value
}
})
} catch (e: Exception) {
"Exception: ${e.message}"
}
if (counter != expectedCount) throw RuntimeException("fail 0")
return fromSuspension!!
}
class ContinuationDispatcher(val dispatcher: () -> Unit) : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> = DispatchedContinuation(dispatcher, continuation)
}
private class DispatchedContinuation<T>(
val dispatcher: () -> Unit,
val continuation: Continuation<T>
): Continuation<T> {
override val context: CoroutineContext = continuation.context
override fun resume(value: T) {
dispatcher()
continuation.resume(value)
}
override fun resumeWithException(exception: Throwable) {
dispatcher()
continuation.resumeWithException(exception)
}
}
fun box(): String {
if (builder(0) { suspendHereUnintercepted() } != "OK") return "fail 2"
if (builder(1) { suspendHereIntercepted() } != "OK") return "fail 3"
if (builder(0) { suspendWithExceptionUnintercepted() } != "Exception: OK") return "fail 4"
if (builder(1) { suspendWithExceptionIntercepted() } != "Exception: OK") return "fail 5"
return "OK"
}
@@ -0,0 +1,80 @@
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
import kotlin.test.assertEquals
suspend fun suspendHere(): String = suspendCoroutineUninterceptedOrReturn { x ->
x.resume("OK")
COROUTINE_SUSPENDED
}
suspend fun suspendWithException(): String = suspendCoroutineUninterceptedOrReturn { x ->
x.resumeWithException(RuntimeException("OK"))
COROUTINE_SUSPENDED
}
fun builder(shouldSuspend: Boolean, c: suspend () -> String): String {
var fromSuspension: String? = null
var counter = 0
val result = try {
c.startCoroutineUninterceptedOrReturn(object: Continuation<String> {
override val context: CoroutineContext
get() = ContinuationDispatcher { counter++ }
override fun resumeWithException(exception: Throwable) {
fromSuspension = "Exception: " + exception.message!!
}
override fun resume(value: String) {
fromSuspension = value
}
})
} catch (e: Exception) {
"Exception: ${e.message}"
}
if (counter != 0) throw RuntimeException("fail 0 $counter")
if (shouldSuspend) {
if (result !== COROUTINE_SUSPENDED) throw RuntimeException("fail 1")
if (fromSuspension == null) throw RuntimeException("fail 2")
return fromSuspension!!
}
if (result === COROUTINE_SUSPENDED) throw RuntimeException("fail 3")
return result as String
}
class ContinuationDispatcher(val dispatcher: () -> Unit) : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> = DispatchedContinuation(dispatcher, continuation)
}
private class DispatchedContinuation<T>(
val dispatcher: () -> Unit,
val continuation: Continuation<T>
): Continuation<T> {
override val context: CoroutineContext = continuation.context
override fun resume(value: T) {
dispatcher()
continuation.resume(value)
}
override fun resumeWithException(exception: Throwable) {
dispatcher()
continuation.resumeWithException(exception)
}
}
fun box(): String {
if (builder(false) { "OK" } != "OK") return "fail 4"
if (builder(true) { suspendHere() } != "OK") return "fail 5"
if (builder(false) { throw RuntimeException("OK") } != "Exception: OK") return "fail 6"
if (builder(true) { suspendWithException() } != "Exception: OK") return "fail 7"
return "OK"
}
@@ -6064,6 +6064,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("intercepted.kt")
public void testIntercepted() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/intercepted.kt");
doTest(fileName);
}
@TestMetadata("startCoroutine.kt")
public void testStartCoroutine() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutine.kt");
@@ -6081,6 +6087,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutineUninterceptedOrReturnInterception.kt");
doTest(fileName);
}
@TestMetadata("suspendCoroutineUninterceptedOrReturn.kt")
public void testSuspendCoroutineUninterceptedOrReturn() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/suspendCoroutineUninterceptedOrReturn.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/multiModule")
@@ -6064,6 +6064,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("intercepted.kt")
public void testIntercepted() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/intercepted.kt");
doTest(fileName);
}
@TestMetadata("startCoroutine.kt")
public void testStartCoroutine() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutine.kt");
@@ -6081,6 +6087,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutineUninterceptedOrReturnInterception.kt");
doTest(fileName);
}
@TestMetadata("suspendCoroutineUninterceptedOrReturn.kt")
public void testSuspendCoroutineUninterceptedOrReturn() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/suspendCoroutineUninterceptedOrReturn.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/multiModule")
@@ -6064,6 +6064,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("intercepted.kt")
public void testIntercepted() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/intercepted.kt");
doTest(fileName);
}
@TestMetadata("startCoroutine.kt")
public void testStartCoroutine() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutine.kt");
@@ -6081,6 +6087,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutineUninterceptedOrReturnInterception.kt");
doTest(fileName);
}
@TestMetadata("suspendCoroutineUninterceptedOrReturn.kt")
public void testSuspendCoroutineUninterceptedOrReturn() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/suspendCoroutineUninterceptedOrReturn.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/multiModule")
@@ -6628,6 +6628,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("intercepted.kt")
public void testIntercepted() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/intercepted.kt");
doTest(fileName);
}
@TestMetadata("startCoroutine.kt")
public void testStartCoroutine() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutine.kt");
@@ -6645,6 +6651,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutineUninterceptedOrReturnInterception.kt");
doTest(fileName);
}
@TestMetadata("suspendCoroutineUninterceptedOrReturn.kt")
public void testSuspendCoroutineUninterceptedOrReturn() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/suspendCoroutineUninterceptedOrReturn.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/multiModule")
@@ -52,6 +52,8 @@ public final class FunctionIntrinsics {
register(ExceptionPropertyIntrinsicFactory.INSTANCE);
register(AsDynamicFIF.INSTANCE);
register(CoroutineContextFIF.INSTANCE);
register(SuspendCoroutineUninterceptedOrReturnFIF.INSTANCE);
register(InterceptedFIF.INSTANCE);
}
private void register(@NotNull FunctionIntrinsicFactory instance) {
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories
import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
object InterceptedFIF: FunctionIntrinsicFactory {
override fun getIntrinsic(descriptor: FunctionDescriptor): FunctionIntrinsic? {
if (!descriptor.isBuiltInIntercepted()) return null
return Intrinsic
}
object Intrinsic: FunctionIntrinsic() {
override fun apply(callInfo: CallInfo, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
val continuation = callInfo.extensionReceiver ?: error("intercepted shall be extension function")
val facadeName = context.getNameForDescriptor(TranslationUtils.getCoroutineProperty(context, "facade"))
return JsAstUtils.pureFqn(facadeName, continuation)
}
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsInvocation
import org.jetbrains.kotlin.js.backend.ast.metadata.isSuspend
import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic
object SuspendCoroutineUninterceptedOrReturnFIF: FunctionIntrinsicFactory {
override fun getIntrinsic(descriptor: FunctionDescriptor): FunctionIntrinsic? {
if (!descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn()) return null
return Intrinsic
}
object Intrinsic: FunctionIntrinsic() {
override fun apply(callInfo: CallInfo, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
val lambda = arguments.first()
val continuation = arguments.last()
val invocation = JsInvocation(lambda, continuation)
invocation.isSuspend = true
return invocation
}
}
}
@@ -23,8 +23,8 @@ import kotlin.coroutines.experimental.CoroutineContext
import kotlin.coroutines.experimental.processBareContinuationResume
/**
* Obtains the current continuation instance inside suspend functions and either suspend
* currently running coroutine or return result immediately without suspension.
* Obtains the current continuation instance inside suspend functions and either suspends
* currently running coroutine or returns result immediately without suspension.
*
* If the [block] returns the special [COROUTINE_SUSPENDED] value, it means that suspend function did suspend the execution and will
* not return any result immediately. In this case, the [Continuation] provided to the [block] shall be invoked at some moment in the
@@ -42,9 +42,29 @@ import kotlin.coroutines.experimental.processBareContinuationResume
@SinceKotlin("1.1")
@kotlin.internal.InlineOnly
@Suppress("UNUSED_PARAMETER")
// todo: this shall be ordinary function, but, unfortunately, bootstrap compiler does not have suspendCoroutineUninterceptedOrReturn and intercepted intrinsics
public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T =
throw NotImplementedError("Implementation is intrinsic")
/**
* Obtains the current continuation instance inside suspend functions and either suspends
* currently running coroutine or returns result immediately without suspension.
*
* Unlike [suspendCoroutineOrReturn] it does not intercept continuation.
*/
@SinceKotlin("1.2")
@kotlin.internal.InlineOnly
public inline suspend fun <T> suspendCoroutineUninterceptedOrReturn(crossinline block: (Continuation<T>) -> Any?): T =
throw NotImplementedError("Implementation of suspendCoroutineUninterceptedOrReturn is intrinsic")
/**
* Intercept continuation with [ContinuationInterceptor].
*/
@SinceKotlin("1.2")
@kotlin.internal.InlineOnly
public inline fun <T> Continuation<T>.intercepted(): Continuation<T> =
throw NotImplementedError("Implementation of intercepted is intrinsic")
/**
* Continuation context of current coroutine.
*