[JS IR] Add intrinsic to call suspend functions as super type
^KT-46204 fixed
This commit is contained in:
@@ -163,6 +163,9 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
|||||||
get() = context.ir.symbols.coroutineContextGetter
|
get() = context.ir.symbols.coroutineContextGetter
|
||||||
|
|
||||||
val jsGetContinuation = getInternalFunction("getContinuation")
|
val jsGetContinuation = getInternalFunction("getContinuation")
|
||||||
|
val jsInvokeSuspendFunction = getInternalWithoutPackage("kotlin.coroutines.intrinsics.invokeSuspendFunction")
|
||||||
|
val jsInvokeSuspendFunctionWithReceiver = getInternalWithoutPackage("kotlin.coroutines.intrinsics.invokeSuspendFunctionWithReceiver")
|
||||||
|
val jsInvokeSuspendFunctionWithReceiverAndParam = getInternalWithoutPackage("kotlin.coroutines.intrinsics.invokeSuspendFunctionWithReceiverAndParam")
|
||||||
val jsGetKClass = getInternalWithoutPackage("getKClass")
|
val jsGetKClass = getInternalWithoutPackage("getKClass")
|
||||||
val jsGetKClassFromExpression = getInternalWithoutPackage("getKClassFromExpression")
|
val jsGetKClassFromExpression = getInternalWithoutPackage("getKClassFromExpression")
|
||||||
|
|
||||||
|
|||||||
+57
@@ -8,12 +8,14 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getClassRef
|
import org.jetbrains.kotlin.ir.backend.js.utils.getClassRef
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrGetField
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||||
@@ -226,6 +228,61 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
|||||||
add(intrinsics.jsUndefined) { _, _ ->
|
add(intrinsics.jsUndefined) { _, _ ->
|
||||||
JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
|
JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val suspendInvokeTransform: (IrCall, JsGenerationContext) -> JsExpression = { call, context: JsGenerationContext ->
|
||||||
|
// Because it is intrinsic, we know everything about this function
|
||||||
|
// There is callable reference as extension receiver
|
||||||
|
val invokeFun = (call.extensionReceiver as IrCall)
|
||||||
|
// Single parameter is field
|
||||||
|
.getValueArgument(0)
|
||||||
|
.let { it as IrGetField }
|
||||||
|
.symbol
|
||||||
|
.owner
|
||||||
|
// It should be SuspendFunctionN
|
||||||
|
.type
|
||||||
|
.classifierOrFail
|
||||||
|
.owner
|
||||||
|
.let { it as IrClass }
|
||||||
|
.declarations
|
||||||
|
.filterIsInstance<IrSimpleFunction>()
|
||||||
|
.single { it.name.asString() == "invoke" }
|
||||||
|
|
||||||
|
val jsInvokeFunName = context.getNameForMemberFunction(invokeFun)
|
||||||
|
|
||||||
|
val jsExtensionReceiver = call.extensionReceiver?.accept(IrElementToJsExpressionTransformer(), context)!! as JsInvocation
|
||||||
|
val args = translateCallArguments(call, context)
|
||||||
|
val jsArgsForClosureFun = args.mapIndexed { index, _ -> JsName("${"$"}p$index") }
|
||||||
|
|
||||||
|
// Function to make closure for invoke to avoid losing this
|
||||||
|
jsExtensionReceiver.arguments[0] = JsInvocation(
|
||||||
|
JsNameRef(
|
||||||
|
Namer.BIND_FUNCTION,
|
||||||
|
JsFunction(
|
||||||
|
emptyScope,
|
||||||
|
JsBlock(
|
||||||
|
JsReturn(
|
||||||
|
JsInvocation(
|
||||||
|
JsNameRef(
|
||||||
|
jsInvokeFunName,
|
||||||
|
jsExtensionReceiver.arguments[0]
|
||||||
|
),
|
||||||
|
jsArgsForClosureFun.map { it.makeRef() }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"Function to make closure for invoke to avoid losing this"
|
||||||
|
).also { func ->
|
||||||
|
func.parameters.addAll(jsArgsForClosureFun.map { JsParameter(it) })
|
||||||
|
}
|
||||||
|
), JsThisRef()
|
||||||
|
)
|
||||||
|
|
||||||
|
JsInvocation(jsExtensionReceiver, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
add(intrinsics.jsInvokeSuspendFunction, suspendInvokeTransform)
|
||||||
|
add(intrinsics.jsInvokeSuspendFunctionWithReceiver, suspendInvokeTransform)
|
||||||
|
add(intrinsics.jsInvokeSuspendFunctionWithReceiverAndParam, suspendInvokeTransform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,30 @@ package kotlin.coroutines.intrinsics
|
|||||||
import kotlin.coroutines.*
|
import kotlin.coroutines.*
|
||||||
import kotlin.internal.InlineOnly
|
import kotlin.internal.InlineOnly
|
||||||
|
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
public fun <T> (suspend () -> T).invokeSuspendFunction(
|
||||||
|
completion: Continuation<T>
|
||||||
|
): Any? {
|
||||||
|
throw NotImplementedError("It is intrinsic method")
|
||||||
|
}
|
||||||
|
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
public fun <R, T> (suspend R.() -> T).invokeSuspendFunctionWithReceiver(
|
||||||
|
receiver: R,
|
||||||
|
completion: Continuation<T>
|
||||||
|
): Any? {
|
||||||
|
throw NotImplementedError("It is intrinsic method")
|
||||||
|
}
|
||||||
|
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
public fun <R, P, T> (suspend R.(P) -> T).invokeSuspendFunctionWithReceiverAndParam(
|
||||||
|
receiver: R,
|
||||||
|
param: P,
|
||||||
|
completion: Continuation<T>
|
||||||
|
): Any? {
|
||||||
|
throw NotImplementedError("It is intrinsic method")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts unintercepted coroutine without receiver and with result type [T] and executes it until its first suspension.
|
* 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.
|
* Returns the result of the coroutine or throws its exception if it does not suspend or [COROUTINE_SUSPENDED] if it suspends.
|
||||||
@@ -29,7 +53,7 @@ public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrRetu
|
|||||||
): Any? {
|
): Any? {
|
||||||
val a = this.asDynamic()
|
val a = this.asDynamic()
|
||||||
return if (jsTypeOf(a) == "function") a(completion)
|
return if (jsTypeOf(a) == "function") a(completion)
|
||||||
else ::invoke.asDynamic()(completion)
|
else ::invoke.invokeSuspendFunction(completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +76,7 @@ public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedO
|
|||||||
): Any? {
|
): Any? {
|
||||||
val a = this.asDynamic()
|
val a = this.asDynamic()
|
||||||
return if (jsTypeOf(a) == "function") a(receiver, completion)
|
return if (jsTypeOf(a) == "function") a(receiver, completion)
|
||||||
else ::invoke.asDynamic()(receiver, completion)
|
else ::invoke.invokeSuspendFunctionWithReceiver(receiver, completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
@InlineOnly
|
@InlineOnly
|
||||||
@@ -63,7 +87,7 @@ internal actual inline fun <R, P, T> (suspend R.(P) -> T).startCoroutineUninterc
|
|||||||
): Any? {
|
): Any? {
|
||||||
val a = this.asDynamic()
|
val a = this.asDynamic()
|
||||||
return if (jsTypeOf(a) == "function") a(receiver, param, completion)
|
return if (jsTypeOf(a) == "function") a(receiver, param, completion)
|
||||||
else ::invoke.asDynamic()(receiver, param, completion)
|
else ::invoke.invokeSuspendFunctionWithReceiverAndParam(receiver, param, completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,7 +113,7 @@ public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
|
|||||||
createCoroutineFromSuspendFunction(completion) {
|
createCoroutineFromSuspendFunction(completion) {
|
||||||
val a = this.asDynamic()
|
val a = this.asDynamic()
|
||||||
if (jsTypeOf(a) == "function") a(completion)
|
if (jsTypeOf(a) == "function") a(completion)
|
||||||
else ::invoke.asDynamic()(completion)
|
else ::invoke.invokeSuspendFunction(completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,7 +140,7 @@ public actual fun <R, T> (suspend R.() -> T).createCoroutineUnintercepted(
|
|||||||
createCoroutineFromSuspendFunction(completion) {
|
createCoroutineFromSuspendFunction(completion) {
|
||||||
val a = this.asDynamic()
|
val a = this.asDynamic()
|
||||||
if (jsTypeOf(a) == "function") a(receiver, completion)
|
if (jsTypeOf(a) == "function") a(receiver, completion)
|
||||||
else ::invoke.asDynamic()(receiver, completion)
|
else ::invoke.invokeSuspendFunctionWithReceiver(receiver, completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user