From 2b92b1d8803f405b4d3f6db6f0b1f3d56015a4d8 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Thu, 27 Apr 2017 17:02:12 +0300 Subject: [PATCH] Added coroutines stdlib classes --- .../main/kotlin/konan/internal/Coroutines.kt | 118 +++++++++++++++ .../experimental/ContinuationInterceptor.kt | 40 +++++ .../experimental/CoroutineContext.kt | 66 +++++++++ .../coroutines/experimental/Coroutines.kt | 47 ++++++ .../experimental/CoroutinesLibrary.kt | 103 +++++++++++++ .../experimental/EmptyCoroutineContext.kt | 128 ++++++++++++++++ .../experimental/intrinsics/Intrinsics.kt | 139 ++++++++++++++++++ 7 files changed, 641 insertions(+) create mode 100644 runtime/src/main/kotlin/konan/internal/Coroutines.kt create mode 100644 runtime/src/main/kotlin/kotlin/coroutines/experimental/ContinuationInterceptor.kt create mode 100644 runtime/src/main/kotlin/kotlin/coroutines/experimental/CoroutineContext.kt create mode 100644 runtime/src/main/kotlin/kotlin/coroutines/experimental/Coroutines.kt create mode 100644 runtime/src/main/kotlin/kotlin/coroutines/experimental/CoroutinesLibrary.kt create mode 100644 runtime/src/main/kotlin/kotlin/coroutines/experimental/EmptyCoroutineContext.kt create mode 100644 runtime/src/main/kotlin/kotlin/coroutines/experimental/intrinsics/Intrinsics.kt diff --git a/runtime/src/main/kotlin/konan/internal/Coroutines.kt b/runtime/src/main/kotlin/konan/internal/Coroutines.kt new file mode 100644 index 00000000000..6db4ec794ce --- /dev/null +++ b/runtime/src/main/kotlin/konan/internal/Coroutines.kt @@ -0,0 +1,118 @@ +package konan.internal + +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +// Single-threaded continuation. +class SafeContinuation +constructor( + private val delegate: Continuation, + initialResult: Any? +) : Continuation { + + constructor(delegate: Continuation) : this(delegate, UNDECIDED) + + public override val context: CoroutineContext + get() = delegate.context + + private var result: Any? = initialResult + + companion object { + private val UNDECIDED: Any? = Any() + private val RESUMED: Any? = Any() + } + + private class Fail(val exception: Throwable) + + override fun resume(value: T) { + when { + result === UNDECIDED -> result = value + result === COROUTINE_SUSPENDED -> { + result = RESUMED + delegate.resume(value) + } + else -> throw IllegalStateException("Already resumed") + } + } + + override fun resumeWithException(exception: Throwable) { + when { + result === UNDECIDED -> result = Fail(exception) + result === COROUTINE_SUSPENDED -> { + result = RESUMED + delegate.resumeWithException(exception) + } + else -> throw IllegalStateException("Already resumed") + } + } + + fun getResult(): Any? { + if (this.result === UNDECIDED) this.result = COROUTINE_SUSPENDED + val result = this.result + when { + result === RESUMED -> return COROUTINE_SUSPENDED // already called continuation, indicate COROUTINE_SUSPENDED upstream + result is Fail -> throw result.exception + else -> return result // either COROUTINE_SUSPENDED or data + } + } +} + +@ExportForCompiler +internal fun interceptContinuationIfNeeded( + context: CoroutineContext, + continuation: Continuation +) = context[ContinuationInterceptor]?.interceptContinuation(continuation) ?: continuation + +/** + * @suppress + */ +@ExportForCompiler +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: Int = if (completion != null) 0L else -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/runtime/src/main/kotlin/kotlin/coroutines/experimental/ContinuationInterceptor.kt b/runtime/src/main/kotlin/kotlin/coroutines/experimental/ContinuationInterceptor.kt new file mode 100644 index 00000000000..6bc31a1d1af --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/coroutines/experimental/ContinuationInterceptor.kt @@ -0,0 +1,40 @@ +/* + * 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 kotlin.coroutines.experimental + +/** + * Marks coroutine context element that intercepts coroutine continuations. + * The coroutines framework uses [ContinuationInterceptor.Key] to retrieve the interceptor and + * intercepts all coroutine continuations with [interceptContinuation] invocations. + */ +public interface ContinuationInterceptor : CoroutineContext.Element { + /** + * The key that defines *the* context interceptor. + */ + companion object Key : CoroutineContext.Key + + /** + * Returns continuation that wraps the original [continuation], thus intercepting all resumptions. + * This function is invoked by coroutines framework when needed and the resulting continuations are + * cached internally per each instance of the original [continuation]. + * + * By convention, implementations that install themselves as *the* interceptor in the context with + * the [Key] shall also scan the context for other element that implement [ContinuationInterceptor] interface + * and use their [interceptContinuation] functions, too. + */ + public fun interceptContinuation(continuation: Continuation): Continuation +} diff --git a/runtime/src/main/kotlin/kotlin/coroutines/experimental/CoroutineContext.kt b/runtime/src/main/kotlin/kotlin/coroutines/experimental/CoroutineContext.kt new file mode 100644 index 00000000000..836b23f3435 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/coroutines/experimental/CoroutineContext.kt @@ -0,0 +1,66 @@ +/* + * 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 kotlin.coroutines.experimental + +/** + * Persistent context for the coroutine. It is an indexed set of [Element] instances. + * An indexed set is a mix between a set and a map. + * Every element in this set has a unique [Key]. Keys are compared _by reference_. + */ +public interface CoroutineContext { + /** + * Returns the element with the given [key] from this context or `null`. + * Keys are compared _by reference_, that is to get an element from the context the reference to its actual key + * object must be presented to this function. + */ + public operator fun get(key: Key): E? + + /** + * Accumulates entries of this context starting with [initial] value and applying [operation] + * from left to right to current accumulator value and each element of this context. + */ + public fun fold(initial: R, operation: (R, Element) -> R): R + + /** + * Returns a context containing elements from this context and elements from other [context]. + * The elements from this context with the same key as in the other one are dropped. + */ + public operator fun plus(context: CoroutineContext): CoroutineContext + + /** + * Returns a context containing elements from this context, but without an element with + * the specified [key]. Keys are compared _by reference_, that is to remove an element from the context + * the reference to its actual key object must be presented to this function. + */ + public fun minusKey(key: Key<*>): CoroutineContext + + /** + * An element of the [CoroutineContext]. An element of the coroutine context is a singleton context by itself. + */ + public interface Element : CoroutineContext { + /** + * A key of this coroutine context element. + */ + public val key: Key<*> + } + + /** + * Key for the elements of [CoroutineContext]. [E] is a type of element with this key. + * Keys in the context are compared _by reference_. + */ + public interface Key +} diff --git a/runtime/src/main/kotlin/kotlin/coroutines/experimental/Coroutines.kt b/runtime/src/main/kotlin/kotlin/coroutines/experimental/Coroutines.kt new file mode 100644 index 00000000000..0fa1fb02dc3 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/coroutines/experimental/Coroutines.kt @@ -0,0 +1,47 @@ +/* + * 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 kotlin.coroutines.experimental + +/** + * Interface representing a continuation after a suspension point that returns value of type `T`. + */ +public interface Continuation { + /** + * Context of the coroutine that corresponds to this continuation. + */ + public val context: CoroutineContext + + /** + * Resumes the execution of the corresponding coroutine passing [value] as the return value of the last suspension point. + */ + public fun resume(value: T) + + /** + * Resumes the execution of the corresponding coroutine so that the [exception] is re-thrown right after the + * last suspension point. + */ + public fun resumeWithException(exception: Throwable) +} + +/** + * Classes and interfaces marked with this annotation are restricted when used as receivers for extension + * `suspend` functions. These `suspend` extensions can only invoke other member or extension `suspend` functions on this particular + * receiver only and are restricted from calling arbitrary suspension functions. + */ +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.BINARY) +public annotation class RestrictsSuspension diff --git a/runtime/src/main/kotlin/kotlin/coroutines/experimental/CoroutinesLibrary.kt b/runtime/src/main/kotlin/kotlin/coroutines/experimental/CoroutinesLibrary.kt new file mode 100644 index 00000000000..c5860db8cea --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/coroutines/experimental/CoroutinesLibrary.kt @@ -0,0 +1,103 @@ +/* + * 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 kotlin.coroutines.experimental + +import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED +import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn +import kotlin.coroutines.experimental.intrinsics.createCoroutineUnchecked +import konan.internal.SafeContinuation + +/** + * Starts coroutine with receiver type [R] and result type [T]. + * This function creates and start a new, fresh instance of suspendable computation every time it is invoked. + * The [completion] continuation is invoked when coroutine completes with result or exception. + */ +@Suppress("UNCHECKED_CAST") +public fun (suspend R.() -> T).startCoroutine( + receiver: R, + completion: Continuation +) { + createCoroutineUnchecked(receiver, completion).resume(Unit) +} + +/** + * Starts coroutine without receiver and with result type [T]. + * This function creates and start a new, fresh instance of suspendable computation every time it is invoked. + * The [completion] continuation is invoked when coroutine completes with result or exception. + */ +@Suppress("UNCHECKED_CAST") +public fun (suspend () -> T).startCoroutine( + completion: Continuation +) { + createCoroutineUnchecked(completion).resume(Unit) +} + +/** + * Creates a 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. + * Repeated invocation of any resume function on the resulting continuation produces [IllegalStateException]. + */ +@Suppress("UNCHECKED_CAST") +public fun (suspend R.() -> T).createCoroutine( + receiver: R, + completion: Continuation +): Continuation = SafeContinuation(createCoroutineUnchecked(receiver, completion), COROUTINE_SUSPENDED) + +/** + * Creates a 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. + * Repeated invocation of any resume function on the resulting continuation produces [IllegalStateException]. + */ +@Suppress("UNCHECKED_CAST") +public fun (suspend () -> T).createCoroutine( + completion: Continuation +): Continuation = SafeContinuation(createCoroutineUnchecked(completion), COROUTINE_SUSPENDED) + +/** + * Obtains the current continuation instance inside suspend functions and suspends + * currently running coroutine. + * + * In this function both [Continuation.resume] and [Continuation.resumeWithException] can be used either synchronously in + * the same stack-frame where suspension function is run or asynchronously later in the same thread or + * from a different thread of execution. Repeated invocation of any resume function produces [IllegalStateException]. + */ +public inline suspend fun suspendCoroutine(crossinline block: (Continuation) -> Unit): T = + suspendCoroutineOrReturn { c: Continuation -> + val safe = SafeContinuation(c) + block(safe) + safe.getResult() + } + +// INTERNAL DECLARATIONS + +@kotlin.internal.InlineOnly +internal inline fun processBareContinuationResume(completion: Continuation<*>, block: () -> Any?) { + try { + val result = block() + if (result !== COROUTINE_SUSPENDED) { + (completion as Continuation).resume(result) + } + } catch (t: Throwable) { + completion.resumeWithException(t) + } +} diff --git a/runtime/src/main/kotlin/kotlin/coroutines/experimental/EmptyCoroutineContext.kt b/runtime/src/main/kotlin/kotlin/coroutines/experimental/EmptyCoroutineContext.kt new file mode 100644 index 00000000000..76bc6f2312e --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/coroutines/experimental/EmptyCoroutineContext.kt @@ -0,0 +1,128 @@ +/* + * 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 kotlin.coroutines.experimental + +import kotlin.coroutines.experimental.CoroutineContext.* + +/** + * Base class for [CoroutineContext.Element] implementations. + */ +public abstract class AbstractCoroutineContextElement(public override val key: Key<*>) : Element { + @Suppress("UNCHECKED_CAST") + public override operator fun get(key: Key): E? = + if (this.key === key) this as E else null + + public override fun fold(initial: R, operation: (R, Element) -> R): R = + operation(initial, this) + + public override operator fun plus(context: CoroutineContext): CoroutineContext = + plusImpl(context) + + public override fun minusKey(key: Key<*>): CoroutineContext = + if (this.key === key) EmptyCoroutineContext else this +} + +/** + * An empty coroutine context. + */ +public object EmptyCoroutineContext : CoroutineContext { + public override fun get(key: Key): E? = null + public override fun fold(initial: R, operation: (R, Element) -> R): R = initial + public override fun plus(context: CoroutineContext): CoroutineContext = context + public override fun minusKey(key: Key<*>): CoroutineContext = this + public override fun hashCode(): Int = 0 + public override fun toString(): String = "EmptyCoroutineContext" +} + +//--------------------- private impl --------------------- + +// this class is not exposed, but is hidden inside implementations +// this is a left-biased list, so that `plus` works naturally +private class CombinedContext(val left: CoroutineContext, val element: Element) : CoroutineContext { + override fun get(key: Key): E? { + var cur = this + while (true) { + cur.element[key]?.let { return it } + val next = cur.left + if (next is CombinedContext) { + cur = next + } else { + return next[key] + } + } + } + + public override fun fold(initial: R, operation: (R, Element) -> R): R = + operation(left.fold(initial, operation), element) + + public override operator fun plus(context: CoroutineContext): CoroutineContext = + plusImpl(context) + + public override fun minusKey(key: Key<*>): CoroutineContext { + element[key]?.let { return left } + val newLeft = left.minusKey(key) + return when { + newLeft === left -> this + newLeft === EmptyCoroutineContext -> element + else -> CombinedContext(newLeft, element) + } + } + + private fun size(): Int = + if (left is CombinedContext) left.size() + 1 else 2 + + private fun contains(element: Element): Boolean = + get(element.key) == element + + private fun containsAll(context: CombinedContext): Boolean { + var cur = context + while (true) { + if (!contains(cur.element)) return false + val next = cur.left + if (next is CombinedContext) { + cur = next + } else { + return contains(next as Element) + } + } + } + + override fun equals(other: Any?): Boolean = + this === other || other is CombinedContext && other.size() == size() && other.containsAll(this) + + override fun hashCode(): Int = left.hashCode() + element.hashCode() + + override fun toString(): String = + "[" + fold("") { acc, element -> + if (acc.isEmpty()) element.toString() else acc + ", " + element + } + "]" +} + +private fun CoroutineContext.plusImpl(context: CoroutineContext): CoroutineContext = + if (context === EmptyCoroutineContext) this else // fast path -- avoid lambda creation + context.fold(this) { acc, element -> + val removed = acc.minusKey(element.key) + if (removed === EmptyCoroutineContext) element else { + // make sure interceptor is always last in the context (and thus is fast to get when present) + val interceptor = removed[ContinuationInterceptor] + if (interceptor == null) CombinedContext(removed, element) else { + val left = removed.minusKey(ContinuationInterceptor) + if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else + CombinedContext(CombinedContext(left, element), interceptor) + } + } + } diff --git a/runtime/src/main/kotlin/kotlin/coroutines/experimental/intrinsics/Intrinsics.kt b/runtime/src/main/kotlin/kotlin/coroutines/experimental/intrinsics/Intrinsics.kt new file mode 100644 index 00000000000..8867a619b00 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/coroutines/experimental/intrinsics/Intrinsics.kt @@ -0,0 +1,139 @@ +/* + * 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 kotlin.coroutines.experimental.intrinsics + +import kotlin.coroutines.experimental.Continuation +import kotlin.coroutines.experimental.CoroutineContext +import kotlin.coroutines.experimental.processBareContinuationResume +import konan.internal.interceptContinuationIfNeeded +import konan.internal.CoroutineImpl + +/** + * Obtains the current continuation instance inside suspend functions and either suspend + * currently running coroutine or return 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 + * future when the result becomes available to resume the computation. + * + * Otherwise, the return value of the [block] must have a type assignable to [T] and represents the result of this suspend function. + * It means that the execution was not suspended and the [Continuation] provided to the [block] shall not be invoked. + * As the result type of the [block] is declared as `Any?` and cannot be correctly type-checked, + * its proper return type remains on the conscience of the suspend function's author. + * + * Note that it is not recommended to call either [Continuation.resume] nor [Continuation.resumeWithException] functions synchronously + * in the same stackframe where suspension function is run. Use [suspendCoroutine] as a safer way to obtain current + * continuation instance. + */ +@kotlin.internal.InlineOnly +public inline suspend fun suspendCoroutineOrReturn(crossinline block: (Continuation) -> Any?): T = throw Error("Should've been intrinsified") + +/** + * This value is used as a return value of [suspendCoroutineOrReturn] `block` argument to state that + * the execution was suspended and will not return any result immediately. + */ +public val COROUTINE_SUSPENDED: Any = Any() + +/** + * Creates a 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 is _unchecked_. 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. + */ +public fun (suspend () -> T).createCoroutineUnchecked( + completion: Continuation +): Continuation = + if (this !is CoroutineImpl) + buildContinuationByInvokeCall(completion) { + (this as Function1, Any?>).invoke(completion) + } + else + (this.create(completion) as CoroutineImpl).facade + +/** + * Creates a 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 is _unchecked_. 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. + */ +public fun (suspend R.() -> T).createCoroutineUnchecked( + receiver: R, + completion: Continuation +): Continuation = + if (this !is CoroutineImpl) + buildContinuationByInvokeCall(completion) { + (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) +} + +/** + * 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 inline fun (suspend () -> T).startCoroutineUninterceptedOrReturn( + completion: Continuation +): 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 inline fun (suspend R.() -> T).startCoroutineUninterceptedOrReturn( + receiver: R, + completion: Continuation +): Any? = (this as Function2, Any?>).invoke(receiver, completion)