[K/JS] Add ability to use is checks on external objects
This commit is contained in:
@@ -95,6 +95,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
val jsInstanceOf = getInternalFunction("jsInstanceOfIntrinsic")
|
||||
val jsTypeOf = getInternalFunction("jsTypeOf")
|
||||
val isExternalObject = getInternalFunction("isExternalObject")
|
||||
|
||||
// Number conversions:
|
||||
|
||||
|
||||
+10
@@ -53,6 +53,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val isObjectSymbol get() = context.intrinsics.isObjectSymbol
|
||||
|
||||
private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf
|
||||
private val isExternalObjectSymbol = context.intrinsics.isExternalObject
|
||||
private val typeOfIntrinsicSymbol = context.intrinsics.jsTypeOf
|
||||
private val jsClassIntrinsicSymbol = context.intrinsics.jsClass
|
||||
|
||||
@@ -270,6 +271,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
generateInterfaceCheck(argument, toType)
|
||||
}
|
||||
}
|
||||
toType.isExternalObject() -> generateIsExternalObject(argument, toType)
|
||||
else -> generateNativeInstanceOf(argument, toType)
|
||||
}
|
||||
}
|
||||
@@ -360,6 +362,14 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateIsExternalObject(argument: IrExpression, toType: IrType): IrExpression {
|
||||
val irType = wrapTypeReference(toType)
|
||||
return JsIrBuilder.buildCall(isExternalObjectSymbol).apply {
|
||||
putValueArgument(0, argument)
|
||||
putValueArgument(1, irType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateNativeInstanceOf(argument: IrExpression, toType: IrType): IrExpression {
|
||||
val irType = wrapTypeReference(toType)
|
||||
return JsIrBuilder.buildCall(instanceOfIntrinsicSymbol).apply {
|
||||
|
||||
@@ -57,6 +57,8 @@ fun IrType.isTypeParameter() = classifierOrNull is IrTypeParameterSymbol
|
||||
|
||||
fun IrType.isInterface() = classOrNull?.owner?.kind == ClassKind.INTERFACE
|
||||
|
||||
fun IrType.isExternalObject() = classOrNull?.owner.let { it?.kind == ClassKind.OBJECT && it.isExternal }
|
||||
|
||||
fun IrType.isAnnotation() = classOrNull?.owner?.kind == ClassKind.ANNOTATION_CLASS
|
||||
|
||||
fun IrType.isFunctionOrKFunction() = isFunction() || isKFunction()
|
||||
|
||||
@@ -3824,6 +3824,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
public void testSimpleIsInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/simpleIsInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIsObject.kt")
|
||||
public void testSimpleIsObject() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/simpleIsObject.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+6
@@ -4440,6 +4440,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
|
||||
public void testSimpleIsInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/simpleIsInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIsObject.kt")
|
||||
public void testSimpleIsObject() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/simpleIsObject.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+6
@@ -4546,6 +4546,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
|
||||
public void testSimpleIsInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/simpleIsInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIsObject.kt")
|
||||
public void testSimpleIsObject() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/simpleIsObject.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+6
@@ -4440,6 +4440,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
public void testSimpleIsInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/simpleIsInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIsObject.kt")
|
||||
public void testSimpleIsObject() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/simpleIsObject.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1403
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
package foo
|
||||
|
||||
object RegularKotlinObject
|
||||
|
||||
@JsName("Array")
|
||||
external object JsArray
|
||||
|
||||
@JsName("Math")
|
||||
external object JsMath
|
||||
|
||||
fun box(): String {
|
||||
if (js("[]") !is JsArray) return "fail1"
|
||||
if (js("[]") is JsMath) return "fail2"
|
||||
if (js("[]") is RegularKotlinObject) return "fail3"
|
||||
if (JsMath !is JsMath) return "fail4"
|
||||
if (RegularKotlinObject !is RegularKotlinObject) return "fail5"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -239,3 +239,8 @@ internal fun isComparable(value: dynamic): Boolean {
|
||||
@OptIn(JsIntrinsic::class)
|
||||
internal fun isCharSequence(value: dynamic): Boolean =
|
||||
jsTypeOf(value) == "string" || isInterface(value, jsClassIntrinsic<CharSequence>())
|
||||
|
||||
|
||||
@OptIn(JsIntrinsic::class)
|
||||
internal fun isExternalObject(value: dynamic, ktExternalObject: dynamic) =
|
||||
jsEqeqeq(value, ktExternalObject) || (jsTypeOf(ktExternalObject) == "function" && jsInstanceOf(value, ktExternalObject))
|
||||
Reference in New Issue
Block a user