Native: don't expect that startCoroutineUninterceptedOrReturn receiver is FunctionN+1
Previous implementation of startCoroutineUninterceptedOrReturn expected that the receiver (i.e. the suspend function object to start) of type SuspendFunctionN (i.e. suspend function type with arity = N) is also an instance of FunctionN+1 (i.e. regular function type with arity = N + 1) with proper convention. While compiler tries to achieve that (for better compatibility with Kotlin/JVM, by generating additional supertypes and methods for classes implementing suspend function types), this doesn't work e.g. for implementations defined in Swift. Fix this by adding fallbacks for cases when the receiver is not a FunctionN+1, while keeping the fastpath for default FunctionN+1 cases. ^KT-51043 Fixed
This commit is contained in:
committed by
Space
parent
15fe2c2c5c
commit
728fe918fe
+59
-3
@@ -25,7 +25,25 @@ import kotlin.native.internal.*
|
||||
@kotlin.internal.InlineOnly
|
||||
public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrReturn(
|
||||
completion: Continuation<T>
|
||||
): Any? = (this as Function1<Continuation<T>, Any?>).invoke(completion)
|
||||
): Any? {
|
||||
val function = this as? Function1<Continuation<T>, Any?>
|
||||
return if (function != null)
|
||||
function.invoke(completion)
|
||||
else
|
||||
startCoroutineUninterceptedOrReturnFallback(this, completion)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@PublishedApi
|
||||
internal fun <T> startCoroutineUninterceptedOrReturnFallback(
|
||||
function: suspend () -> T,
|
||||
completion: Continuation<T>
|
||||
): Any? {
|
||||
// Unlike `function`, `wrapper` class is generated and lowered entirely by Kotlin compiler,
|
||||
// so the cast below will succeed.
|
||||
val wrapper: suspend () -> T = { function() }
|
||||
return (wrapper as Function1<Continuation<T>, Any?>).invoke(completion)
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an unintercepted coroutine with receiver type [R] and result type [T] and executes it until its first suspension.
|
||||
@@ -44,7 +62,26 @@ public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrRetu
|
||||
public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedOrReturn(
|
||||
receiver: R,
|
||||
completion: Continuation<T>
|
||||
): Any? = (this as Function2<R, Continuation<T>, Any?>).invoke(receiver, completion)
|
||||
): Any? {
|
||||
val function = this as? Function2<R, Continuation<T>, Any?>
|
||||
return if (function != null)
|
||||
function.invoke(receiver, completion)
|
||||
else
|
||||
startCoroutineUninterceptedOrReturnFallback(this, receiver, completion)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@PublishedApi
|
||||
internal fun <R, T> startCoroutineUninterceptedOrReturnFallback(
|
||||
function: suspend R.() -> T,
|
||||
receiver: R,
|
||||
completion: Continuation<T>
|
||||
): Any? {
|
||||
// Unlike `function`, `wrapper` class is generated and lowered entirely by Kotlin compiler,
|
||||
// so the cast below will succeed.
|
||||
val wrapper: suspend R.() -> T = { this.function() }
|
||||
return (wrapper as Function2<R, Continuation<T>, Any?>).invoke(receiver, completion)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@kotlin.internal.InlineOnly
|
||||
@@ -52,7 +89,26 @@ internal actual inline fun <R, P, T> (suspend R.(P) -> T).startCoroutineUninterc
|
||||
receiver: R,
|
||||
param: P,
|
||||
completion: Continuation<T>
|
||||
): Any? = (this as Function3<R, P, Continuation<T>, Any?>).invoke(receiver, param, completion)
|
||||
): Any? {
|
||||
val function = this as? Function3<R, P, Continuation<T>, Any?>
|
||||
return if (function != null)
|
||||
function.invoke(receiver, param, completion)
|
||||
else
|
||||
startCoroutineUninterceptedOrReturnFallback(this, receiver, param, completion)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal fun <R, P, T> startCoroutineUninterceptedOrReturnFallback(
|
||||
function: suspend R.(P) -> T,
|
||||
receiver: R,
|
||||
param: P,
|
||||
completion: Continuation<T>
|
||||
): Any? {
|
||||
// Unlike `function`, `wrapper` class is generated and lowered entirely by Kotlin compiler,
|
||||
// so the cast below will succeed.
|
||||
val wrapper: suspend R.(P) -> T = { this.function(it) }
|
||||
return (wrapper as Function3<R, P, Continuation<T>, Any?>).invoke(receiver, param, completion)
|
||||
}
|
||||
|
||||
private object CoroutineSuspendedMarker
|
||||
|
||||
|
||||
Reference in New Issue
Block a user