From 33e96fcb9acfde60cbcafafe924871ebfa6cc198 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Mon, 15 Aug 2016 22:23:42 +0300 Subject: [PATCH] JS: fix runtime type checking for native non-fake interfaces on WebKit (JavaScriptCore); add tests for object and object expressions. --- .../js/test/semantics/RttiTestGenerated.java | 18 +++++++++++ js/js.translator/testData/kotlin_lib_ecma5.js | 25 ++++++++------- .../testData/rtti/cases/isObject.kt | 12 +++++++ .../testData/rtti/cases/objectExpression.kt | 32 +++++++++++++++++++ .../testData/rtti/cases/onNativeObject.kt | 18 +++++++++++ 5 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 js/js.translator/testData/rtti/cases/isObject.kt create mode 100644 js/js.translator/testData/rtti/cases/objectExpression.kt create mode 100644 js/js.translator/testData/rtti/cases/onNativeObject.kt diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/RttiTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/RttiTestGenerated.java index b3b23ffa802..d5b29b39de7 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/RttiTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/RttiTestGenerated.java @@ -53,6 +53,12 @@ public class RttiTestGenerated extends AbstractRttiTest { doTest(fileName); } + @TestMetadata("isObject.kt") + public void testIsObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/rtti/cases/isObject.kt"); + doTest(fileName); + } + @TestMetadata("isSameClass.kt") public void testIsSameClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/rtti/cases/isSameClass.kt"); @@ -65,6 +71,18 @@ public class RttiTestGenerated extends AbstractRttiTest { doTest(fileName); } + @TestMetadata("objectExpression.kt") + public void testObjectExpression() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/rtti/cases/objectExpression.kt"); + doTest(fileName); + } + + @TestMetadata("onNativeObject.kt") + public void testOnNativeObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/rtti/cases/onNativeObject.kt"); + doTest(fileName); + } + @TestMetadata("rttiForClass.kt") public void testRttiForClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/rtti/cases/rttiForClass.kt"); diff --git a/js/js.translator/testData/kotlin_lib_ecma5.js b/js/js.translator/testData/kotlin_lib_ecma5.js index 6d1b30776fe..2d7f51e09bc 100644 --- a/js/js.translator/testData/kotlin_lib_ecma5.js +++ b/js/js.translator/testData/kotlin_lib_ecma5.js @@ -376,18 +376,21 @@ if (object == null || klass == null || (typeof object !== 'object' && typeof object !== 'function')) { return false; } - else { - if (typeof klass === "function" && object instanceof klass) { - return true; - } - else if (isNativeClass(klass) || klass.$metadata$.type == Kotlin.TYPE.CLASS) { - return false; - } - else { - var metadata = "$metadata$" in object ? object.$metadata$ : object.constructor.$metadata$; - return isInheritanceFromTrait(metadata, klass); - } + + if (typeof klass === "function") { + return object instanceof klass; } + + // In WebKit (JavaScriptCore) for some interfaces from DOM typeof returns "object", nevertheless they can be used in RHS of instanceof + if (isNativeClass(klass)) { + return object instanceof klass; + } + + if (object.constructor != null) { + return isInheritanceFromTrait(object.constructor.$metadata$, klass); + } + + return false; }; // TODO Store callable references for members in class diff --git a/js/js.translator/testData/rtti/cases/isObject.kt b/js/js.translator/testData/rtti/cases/isObject.kt new file mode 100644 index 00000000000..b76176bc171 --- /dev/null +++ b/js/js.translator/testData/rtti/cases/isObject.kt @@ -0,0 +1,12 @@ +package foo + +object Obj + +fun box(): String { + val r: Any = Obj + +// TODO: fix KT-13465 +// if (r !is Obj) return "r !is Obj" + + return "OK" +} diff --git a/js/js.translator/testData/rtti/cases/objectExpression.kt b/js/js.translator/testData/rtti/cases/objectExpression.kt new file mode 100644 index 00000000000..f5fb5182aad --- /dev/null +++ b/js/js.translator/testData/rtti/cases/objectExpression.kt @@ -0,0 +1,32 @@ +package foo + +interface A +interface B +open class C +open class D + +fun box(): String { + + if ((object {} as Any) is A) return "object {} is A" + if ((object {} as Any) is C) return "object {} is C" + + if ((object : A {} as Any) !is A) return "object : A {} !is A" + if ((object : A {} as Any) is B) return "object : A {} is B" + if ((object : A {} as Any) is C) return "object : A {} is C" + + if ((object : C() {} as Any) is A) return "object : C() {} is A" + if ((object : C() {} as Any) !is C) return "object : C() {} !is C" + if ((object : C() {} as Any) is D) return "object : C() {} is D" + + if ((object : B, D() {} as Any) is A) return "object : B, D() {} is A" + if ((object : B, D() {} as Any) !is B) return "object : B, D() {} !is B" + if ((object : B, D() {} as Any) is C) return "object : B, D() {} is C" + if ((object : B, D() {} as Any) !is D) return "object : B, D() {} !is D" + + if ((object : D(), B {} as Any) is A) return "object : D(), B {} is A" + if ((object : D(), B {} as Any) !is B) return "object : D(), B {} !is B" + if ((object : D(), B {} as Any) is C) return "object : D(), B {} is C" + if ((object : D(), B {} as Any) !is D) return "object : D(), B {} !is D" + + return "OK" +} diff --git a/js/js.translator/testData/rtti/cases/onNativeObject.kt b/js/js.translator/testData/rtti/cases/onNativeObject.kt new file mode 100644 index 00000000000..c611f17b338 --- /dev/null +++ b/js/js.translator/testData/rtti/cases/onNativeObject.kt @@ -0,0 +1,18 @@ +package foo + +class C +interface I + +fun box(): String { + val obj: Any = js("({})") + + if (obj is C) return "obj is C" + if (obj is I) return "obj is I" + + val obj2: Any = js("Object.create(null)") + + if (obj2 is C) return "obj2 is C" + if (obj2 is I) return "obj2 is I" + + return "OK" +}