[Wasm] Restrict types allowed in JS interop

- Prohibit Any, Array and other unsupported non-external types in JS
  interop context
- Add K1 diagnostic
- Update BE testdata

^KT-57136 Fixed
This commit is contained in:
Svyatoslav Kuzmich
2023-02-28 10:16:13 +01:00
committed by Space Team
parent bb05c8528f
commit 1e91fe155b
15 changed files with 299 additions and 121 deletions
@@ -53,7 +53,7 @@ external class C {
val x1: Int
val x2: Int
fun foo(x3: Int = definedExternally, x4: Int = definedExternally): String
fun bar(x5: C = definedExternally, x6: Any = definedExternally) : String
fun bar(x5: C = definedExternally, x6: C = definedExternally) : String
}
open external class Writable: WritableStream {
+15 -13
View File
@@ -88,7 +88,7 @@ function createJsLambda() {
// FILE: externals.kt
external fun createJsLambda(): (Boolean, Byte, Short, Char, Int, Long, Float, Double, String, EI, DC, (DC) -> Int) -> Int
external fun createJsLambda(): (Boolean, Byte, Short, Char, Int, Long, Float, Double, String, EI, JSDC, (JSDC) -> Int) -> Int
external fun apply7(f: (String) -> ((String) -> ((String) -> ((String) -> ((String) -> ((String) -> ((String) -> String))))))): String
@@ -98,10 +98,11 @@ external fun is123Array(x: EI): Boolean
external fun create123Array(): EI
data class DC(val x: Int, val y: Int)
typealias JSDC = JsHandle<DC>
external fun extenalWithLambda(
x: (Boolean, Byte, Short, Char, Int, Long, Float, Double, String, EI, DC) -> Unit,
dc: DC,
x: (Boolean, Byte, Short, Char, Int, Long, Float, Double, String, EI, JSDC) -> Unit,
dc: JSDC,
)
external fun externalWithLambdas2(
@@ -115,8 +116,8 @@ external fun externalWithLambdas2(
double: () -> Double,
string: () -> String,
ei: () -> EI,
dc: () -> DC,
dcGetY: (DC) -> Int,
dc: () -> JSDC,
dcGetY: (JSDC) -> Int,
): Int
@JsExport
@@ -165,7 +166,8 @@ fun box(): String {
double: Double,
string: String,
ei: EI,
dc: DC ->
jsdc: JSDC ->
val dc = jsdc.get()
test(bool == true)
test(byte == 1.toByte())
test(short == 2.toShort())
@@ -177,7 +179,7 @@ fun box(): String {
test(string == "S")
test(is123Array(ei))
test(dc.x == 100 && dc.y == 200)
}, DC(100, 200))
}, DC(100, 200).toJsHandle())
if (extenalWithLambdasCount != 11) return "Fail 1"
@@ -193,8 +195,8 @@ fun box(): String {
double = { 600.5 },
string = { "700" },
ei = { create123Array() },
dc = { DC(800, 800) },
dcGetY = { it.y }
dc = { DC(800, 800).toJsHandle() },
dcGetY = { it.get().y }
)
if (externalWithLambdas2Count != 11) return "Fail externalWithLambdas2"
@@ -210,8 +212,8 @@ fun box(): String {
{ 600.5 },
{ "700" },
{ create123Array() },
{ DC(800, 800) },
{ it.y }
{ DC(800, 800).toJsHandle() },
{ it.get().y }
)
if (externalWithLambdas2RefCount != 11) return "Fail externalWithLambdas2"
@@ -228,8 +230,8 @@ fun box(): String {
600.5,
"700",
create123Array(),
DC(800, 800),
{ it.y }
DC(800, 800).toJsHandle(),
{ it.get().y }
)
if (jsLambdaCount != 11)
return "Fail 3"
+5 -4
View File
@@ -1,13 +1,14 @@
// TARGET_BACKEND: WASM
// MODULE: main
// FILE: externals.kt
class C(val x: Int)
@JsExport
fun makeC(x: Int): C = C(x)
fun makeC(x: Int): JsHandle<C> = C(x).toJsHandle()
@JsExport
fun getX(c: C): Int = c.x
fun getX(c: JsHandle<C>): Int = c.get().x
@JsExport
fun getString(s: String): String = "Test string $s";
@@ -18,10 +19,10 @@ fun isEven(x: Int): Boolean = x % 2 == 0
external interface EI
@JsExport
fun eiAsAny(ei: EI): Any = ei
fun eiAsAny(ei: EI): JsHandle<Any> = ei.toJsHandle()
@JsExport
fun anyAsEI(any: Any): EI = any as EI
fun anyAsEI(any: JsHandle<Any>): EI = any.get() as EI
fun box(): String = "OK"
@@ -43,7 +43,8 @@ fun testExterRef() {
check(null2ExternRef() == null)
}
class DataRef
class DataRefImpl
typealias DataRef = JsHandle<DataRefImpl>
fun notNullDataRef(x: DataRef): DataRef = js("x")
@@ -54,7 +55,7 @@ fun nullDataRef(x: DataRef): DataRef? = js("x")
fun null2DataRef(x: DataRef): DataRef? = js("null")
fun testDataRef() {
val dataRef = DataRef()
val dataRef = DataRefImpl().toJsHandle()
check(notNullDataRef(dataRef) == dataRef)
checkNPE { notNull2DataRef(dataRef) }
check (nullDataRef(dataRef) == dataRef)
@@ -121,22 +122,6 @@ fun testFloat() {
check(null2Float() == null)
}
fun notNullNumber(): Number = js("123.5")
fun notNull2Number(): Number = js("null")
fun nullNumber(): Number? = js("123.5")
fun null2Number(): Number? = js("null")
fun testNumber() {
check(notNullNumber() == 123.5)
check(notNull2Number() == 0.0)
check(nullNumber() == 123.5)
check(null2Number() == null)
}
fun box(): String {
testString()
testExterRef()
@@ -145,6 +130,5 @@ fun box(): String {
testBoolean()
testShort()
testFloat()
testNumber()
return "OK"
}
@@ -40,27 +40,6 @@ fun testExterRef() {
null2ExternRef(null)
}
class DataRef
fun notNullDataRef(x: DataRef) {
js("if (x === null) throw 'error'")
}
fun nullDataRef(x: DataRef?) {
js("if (x === null) throw 'error'")
}
fun null2DataRef(x: DataRef?) {
js("if (x !== null) throw 'error'")
}
fun testDataRef() {
val dataRef = DataRef()
notNullDataRef(dataRef)
nullDataRef(dataRef)
null2DataRef(null)
}
fun notNullInt(x: Int) {
js("if (x !== 123) throw 'error'")
}
@@ -133,47 +112,12 @@ fun testFloat() {
null2Float(null)
}
fun notNullNumber(x: Number) {
js("if (x !== 123.5) throw 'error'")
}
fun nullNumber(x: Number?) {
js("if (x !== 123.5) throw 'error'")
}
fun null2Number(x: Number?) {
js("if (x !== null) throw 'error'")
}
fun byte2Number(x: Number) {
js("if (x !== 123) throw 'error'")
}
fun notNullByte2Number(x: Number?) {
js("if (x !== 123) throw 'error'")
}
fun nullByte2Number(x: Number?) {
js("if (x !== null) throw 'error'")
}
fun testNumber() {
notNullNumber(123.5)
nullNumber(123.5)
null2Number(null)
byte2Number(123)
notNullByte2Number(123)
nullByte2Number(null)
}
fun box(): String {
testString()
testExterRef()
testDataRef()
testInt()
testBoolean()
testShort()
testFloat()
testNumber()
return "OK"
}
-11
View File
@@ -72,10 +72,8 @@ external fun getFalseBoolean(): Boolean
external interface EI
external fun createJsObjectAsAny(): Any
external fun createJsObjectAsExternalInterface(): EI
external fun getObjectValueEI(x: EI): String
external fun getObjectValueAny(x: Any): String
fun box(): String {
// Strings
@@ -98,15 +96,6 @@ fun box(): String {
val objAsEI: EI = createJsObjectAsExternalInterface()
if (getObjectValueEI(objAsEI) != "object created by createJsObjectAsExternalInterface")
return "Fail createJsObjectAsExternalInterface + getObjectValueEI"
if (getObjectValueAny(objAsEI) != "object created by createJsObjectAsExternalInterface")
return "Fail createJsObjectAsExternalInterface + getObjectValueAny"
// Any
val objAsAny: Any = createJsObjectAsAny()
if (getObjectValueAny(objAsAny) != "object created by createJsObjectAsAny")
return "Fail createJsObjectAsAny + getObjectValueAny"
if (getObjectValueEI(objAsAny as EI) != "object created by createJsObjectAsAny")
return "Fail createJsObjectAsAny + getObjectValueEI"
return "OK"
}