| // TARGET_BACKEND: WASM |
| // MODULE: main |
| // LANGUAGE: +TurnTypeCheckWarningsIntoErrors |
| |
| // FILE: jsType.js |
| |
| class MyJsClass { |
| constructor() { |
| this.value = 41; |
| } |
| |
| // Increment the counter by 1 (or a custom step) |
| increment() { |
| this.value += 1; |
| return this.value; |
| } |
| } |
| |
| |
| // FILE: jsReferenceCasts.kt |
| |
| class C(val x: Int) |
| |
| val c = C(1) |
| |
| fun testTypeOperations(obj: JsReference<C>) : String? { |
| if (obj !is Any) |
| return "!is Any" |
| if (obj !is Any?) |
| return "!is Any?" |
| if (obj !is C) |
| return "!is C" |
| if (obj !is C?) |
| return "!is C" |
| if (obj != c) |
| return "!= C" |
| if (obj !== c) |
| return "!== C" |
| return null |
| } |
| |
| // similar checks as above, but with another formal type of the object |
| fun testTypeOperations(obj: JsReference<String>) : String? { |
| if (obj !is Any) |
| return "!is Any" |
| if (obj !is Any?) |
| return "!is Any" |
| if (obj is String) |
| return "is String" |
| // these checks are forbidden by FE checks, although actual runtime code would return 'true' due |
| // to previous unsafe casts |
| // if (obj != c) |
| // return "!= C" |
| // if (obj !is C) |
| // return "!is C" |
| // if (obj !== c) |
| // return "!== C" |
| return null |
| } |
| |
| fun testTypeOperations(obj: JsAny) : String? { |
| if (obj !is Any) |
| return "!is Any" |
| if (obj !is Any?) |
| return "!is Any" |
| if (obj !is C) |
| return "!is C" |
| if (obj !is C?) |
| return "!is C" |
| if (obj is String) |
| return "is String" |
| if (obj != c) |
| return "!= C" |
| if (obj !== c) |
| return "!== C" |
| return null |
| } |
| |
| // same as above, but for nullable JsAny |
| fun testTypeOperationsNullable(obj: JsAny?) : String? { |
| if (obj !is Any) |
| return "!is Any" |
| if (obj !is Any?) |
| return "!is Any" |
| if (obj !is C) |
| return "!is C" |
| if (obj !is C?) |
| return "!is C" |
| if (obj is String) |
| return "is String" |
| if (obj != c) |
| return "!= C" |
| if (obj !== c) |
| return "!== C" |
| return null |
| } |
| |
| external class MyJsClass() { |
| fun increment(): Int |
| } |
| |
| fun createExtTypeInstance(): MyJsClass = js("new MyJsClass()") |
| |
| fun testJsReferenceToExtType(): String? { |
| val extInstance: MyJsClass = createExtTypeInstance() // externref |
| val extInstanceAsAny: Any = extInstance // JsExternalBox(extInstance) |
| val jsReferenceToExtInstanceAsAny: JsReference<Any> = extInstanceAsAny.toJsReference() // JsExternalBox(extInstance) as externref |
| val a: Any = jsReferenceToExtInstanceAsAny // JsExternalBox(extInstance) |
| val b = a as MyJsClass // unwraps && checks external type |
| if (extInstance !== b) return "Fail: extInstance !== b" |
| if (a !== b) return "Fail: a !== b" |
| |
| val result = a.increment() // smart casted |
| if (result != 42) return "Fail: $result != 42" |
| return null |
| } |
| |
| fun box(): String { |
| val jsReference: JsReference<C> = c.toJsReference() |
| testTypeOperations(jsReference)?.let { return "Fail: JsReference<C> $it"} |
| |
| val jsReferenceWithIncorrectType: JsReference<String> = jsReference.unsafeCast<JsReference<String>>() |
| testTypeOperations(jsReferenceWithIncorrectType)?.let { return "Fail: JsReference<C>.unsafeCast<JsReference<String>>() $it"} |
| |
| val jsReferenceAsJsAny: JsAny = jsReference |
| testTypeOperations(jsReferenceAsJsAny)?.let { return "Fail: (JsReference<C> as JsAny) $it"} |
| |
| val jsReferenceAsNullableJsAny: JsAny? = jsReference |
| testTypeOperationsNullable(jsReferenceAsNullableJsAny)?.let { return "Fail: (JsReference<C> as JsAny?) $it"} |
| |
| val c2 : C = jsReference as Any as C |
| if (c !== c2) |
| return "Fail: implicit cast of JsReference<C>->Any->C shall result in the original object" |
| |
| val c3 : C = jsReference as Any? as C |
| if (c !== c3) |
| return "Fail: implicit cast of JsReference<C>->Any?->C shall result in the original object" |
| |
| val c4 : C = jsReference as C |
| if (c !== c4) |
| return "Fail: implicit restoration of JsReference<C>->C shall result in the original object" |
| |
| val c5 : C? = jsReference as C? |
| if (c !== c5) |
| return "Fail: implicit restoration of JsReference<C>->C? shall result in the original object" |
| |
| testJsReferenceToExtType()?.let { return it } |
| |
| return "OK" |
| } |