[JS IR BE] Implement type check for SuspendFunctionN
This commit is contained in:
@@ -54,6 +54,7 @@ fun IrType.typeParameterSuperTypes(): List<IrType> {
|
||||
}
|
||||
|
||||
fun IrType.isFunctionTypeOrSubtype(): Boolean = DFS.ifAny(listOf(this), { it.superTypes() }, { it.isFunction() })
|
||||
fun IrType.isSuspendFunctionTypeOrSubtype(): Boolean = DFS.ifAny(listOf(this), { it.superTypes() }, { it.isSuspendFunction() })
|
||||
|
||||
fun IrType.isTypeParameter() = classifierOrNull is IrTypeParameterSymbol
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val isArraySymbol = getInternalFunction("isArray")
|
||||
// val isCharSymbol = getInternalFunction("isChar")
|
||||
val isObjectSymbol = getInternalFunction("isObject")
|
||||
val isSuspendFunctionSymbol = getInternalFunction("isSuspendFunction")
|
||||
|
||||
val isNumberSymbol = getInternalFunction("isNumber")
|
||||
val isComparableSymbol = getInternalFunction("isComparable")
|
||||
|
||||
+12
@@ -42,6 +42,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
|
||||
private val isInterfaceSymbol get() = context.intrinsics.isInterfaceSymbol
|
||||
private val isArraySymbol get() = context.intrinsics.isArraySymbol
|
||||
private val isSuspenfFunctionSymbol = context.intrinsics.isSuspendFunctionSymbol
|
||||
// private val isCharSymbol get() = context.intrinsics.isCharSymbol
|
||||
private val isObjectSymbol get() = context.intrinsics.isObjectSymbol
|
||||
|
||||
@@ -209,6 +210,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
return when {
|
||||
toType.isAny() -> generateIsObjectCheck(argument)
|
||||
toType.isNothing() -> JsIrBuilder.buildComposite(context.irBuiltIns.booleanType, listOf(argument, litFalse))
|
||||
toType.isSuspendFunctionTypeOrSubtype() -> generateSuspendFunctionCheck(argument, toType)
|
||||
isTypeOfCheckingType(toType) -> generateTypeOfCheck(argument, toType)
|
||||
// toType.isChar() -> generateCheckForChar(argument)
|
||||
toType.isNumber() -> generateNumberCheck(argument)
|
||||
@@ -254,6 +256,16 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
// private fun generateCheckForChar(argument: IrExpression) =
|
||||
// JsIrBuilder.buildCall(isCharSymbol).apply { dispatchReceiver = argument }
|
||||
|
||||
private fun generateSuspendFunctionCheck(argument: IrExpression, toType: IrType): IrExpression {
|
||||
val arity = (toType.classifierOrFail.owner as IrClass).typeParameters.size - 1 // drop return type
|
||||
|
||||
val irBuiltIns = context.irBuiltIns
|
||||
return JsIrBuilder.buildCall(isSuspenfFunctionSymbol, irBuiltIns.booleanType).apply {
|
||||
putValueArgument(0, argument)
|
||||
putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, arity))
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateTypeOfCheck(argument: IrExpression, toType: IrType): IrExpression {
|
||||
val marker = when {
|
||||
toType.isFunctionOrKFunction() -> functionMarker
|
||||
|
||||
+12
@@ -240,9 +240,21 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
metadataLiteral.propertyInitializers += JsPropertyInitializer(JsNameRef(Namer.METADATA_CLASS_KIND), classKind)
|
||||
|
||||
metadataLiteral.propertyInitializers += generateSuperClasses()
|
||||
|
||||
if (isCoroutineClass()) {
|
||||
metadataLiteral.propertyInitializers += generateSuspendArity()
|
||||
}
|
||||
|
||||
return jsAssignment(JsNameRef(Namer.METADATA, classNameRef), metadataLiteral).makeStmt()
|
||||
}
|
||||
|
||||
private fun isCoroutineClass(): Boolean = irClass.superTypes.any { it.isSuspendFunctionTypeOrSubtype() }
|
||||
|
||||
private fun generateSuspendArity(): JsPropertyInitializer {
|
||||
val arity = irClass.declarations.filterIsInstance<IrSimpleFunction>().first { it.isSuspend }.valueParameters.size
|
||||
return JsPropertyInitializer(JsNameRef(Namer.METADATA_SUSPEND_ARITY), JsIntLiteral(arity))
|
||||
}
|
||||
|
||||
private fun generateSuperClasses(): JsPropertyInitializer {
|
||||
val functionTypeOrSubtype = irClass.defaultType.isFunctionTypeOrSubtype()
|
||||
return JsPropertyInitializer(
|
||||
|
||||
@@ -35,6 +35,7 @@ object Namer {
|
||||
val METADATA_INTERFACES = "interfaces"
|
||||
val METADATA_SIMPLE_NAME = "simpleName"
|
||||
val METADATA_CLASS_KIND = "kind"
|
||||
val METADATA_SUSPEND_ARITY = "suspendArity"
|
||||
|
||||
val KCALLABLE_GET_NAME = "<get-name>"
|
||||
val KCALLABLE_NAME = "callableName"
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// COMMON_COROUTINES_TEST
|
||||
|
||||
Vendored
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
|
||||
@@ -7,6 +7,7 @@ package kotlin.js
|
||||
|
||||
private external interface Metadata {
|
||||
val interfaces: Array<Ctor>
|
||||
val suspendArity: Int?
|
||||
}
|
||||
|
||||
private external interface Ctor {
|
||||
@@ -33,9 +34,7 @@ private fun isInterfaceImpl(ctor: Ctor, iface: dynamic): Boolean {
|
||||
}
|
||||
|
||||
public fun isInterface(obj: dynamic, iface: dynamic): Boolean {
|
||||
val ctor = obj.constructor
|
||||
|
||||
if (ctor == null) return false
|
||||
val ctor = obj.constructor ?: return false
|
||||
|
||||
return isInterfaceImpl(ctor, iface)
|
||||
}
|
||||
@@ -75,6 +74,13 @@ public fun isInterface(ctor: dynamic, IType: dynamic): Boolean {
|
||||
}
|
||||
*/
|
||||
|
||||
internal fun isSuspendFunction(obj: dynamic, arity: Int): Boolean {
|
||||
val ctor = obj.constructor?.unsafeCast<Ctor>() ?: return false
|
||||
|
||||
val metadata = ctor.`$metadata$`?.unsafeCast<Metadata>() ?: return false
|
||||
|
||||
return metadata.suspendArity === arity
|
||||
}
|
||||
|
||||
fun isObject(obj: dynamic): Boolean {
|
||||
val objTypeOf = jsTypeOf(obj)
|
||||
|
||||
Reference in New Issue
Block a user