[JS IR BE] Implement type check for SuspendFunctionN

This commit is contained in:
Roman Artemev
2019-05-16 16:43:44 +03:00
committed by romanart
parent 9894c216c1
commit 9c7d47789c
8 changed files with 36 additions and 5 deletions
@@ -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")
@@ -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
@@ -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,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -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)