[WASM] Support nullable types for external functions

This commit is contained in:
Igor Yakovlev
2022-09-13 20:37:06 +02:00
parent dc57ccdf76
commit 081cd4a4a8
8 changed files with 519 additions and 24 deletions
@@ -0,0 +1,161 @@
// IGNORE_BACKEND: JS_IR, JS
inline fun checkNPE(body: () -> Unit) {
var throwed = false
try {
body()
} catch (e: NullPointerException) {
throwed = true
}
check(throwed)
}
@JsFun("() => 'abc'")
external fun notNullString(): String
@JsFun("() => null")
external fun notNull2String(): String
@JsFun("() => 'abc'")
external fun nullString(): String?
@JsFun("() => null")
external fun null2String(): String?
fun testString() {
check(notNullString() == "abc")
checkNPE { notNull2String() }
check(nullString() == "abc")
check(null2String() == null)
}
external interface ExternRef
@JsFun("() => 'abc'")
external fun notNullExternRef(): ExternRef
@JsFun("() => null")
external fun notNull2ExternRef(): ExternRef
@JsFun("() => 'abc'")
external fun nullExternRef(): ExternRef?
@JsFun("() => null")
external fun null2ExternRef(): ExternRef?
fun testExterRef() {
check(notNullExternRef() != null)
checkNPE { notNull2ExternRef() }
check(nullExternRef() != null)
check(null2ExternRef() == null)
}
class DataRef
@JsFun("(x) => x")
external fun notNullDataRef(x: DataRef): DataRef
@JsFun("(x) => null")
external fun notNull2DataRef(x: DataRef): DataRef
@JsFun("(x) => x")
external fun nullDataRef(x: DataRef): DataRef?
@JsFun("(x) => null")
external fun null2DataRef(x: DataRef): DataRef?
fun testDataRef() {
val dataRef = DataRef()
check(notNullDataRef(dataRef) == dataRef)
checkNPE { notNull2DataRef(dataRef) }
check (nullDataRef(dataRef) == dataRef)
check (null2DataRef(dataRef) == null)
}
@JsFun("() => 123")
external fun notNullInt(): Int
@JsFun("() => null")
external fun notNull2Int(): Int
@JsFun("() => 123")
external fun nullInt(): Int?
@JsFun("() => null")
external fun null2Int(): Int?
fun testInt() {
check(notNullInt() == 123)
check(notNull2Int() == 0)
check(nullInt() == 123)
check(null2Int() == null)
}
@JsFun("() => true")
external fun notNullBoolean(): Boolean
@JsFun("() => null")
external fun notNull2Boolean(): Boolean
@JsFun("() => true")
external fun nullBoolean(): Boolean?
@JsFun("() => null")
external fun null2Boolean(): Boolean?
fun testBoolean() {
check(notNullBoolean() == true)
check(notNull2Boolean() == false)
check(nullBoolean() == true)
check(null2Boolean() == null)
}
@JsFun("() => 123")
external fun notNullShort(): Short
@JsFun("() => null")
external fun notNull2Short(): Short
@JsFun("() => 123")
external fun nullShort(): Short?
@JsFun("() => null")
external fun null2Short(): Short?
fun testShort() {
check(notNullShort() == 123.toShort())
check(notNull2Short() == 0.toShort())
check(nullShort() == 123.toShort())
check(null2Short() == null)
}
@JsFun("() => 123.5")
external fun notNullFloat(): Float
@JsFun("() => null")
external fun notNull2Float(): Float
@JsFun("() => 123.5")
external fun nullFloat(): Float?
@JsFun("() => null")
external fun null2Float(): Float?
fun testFloat() {
check(notNullFloat() == 123.5f)
check(notNull2Float() == 0.0f)
check(nullFloat() == 123.5f)
check(null2Float() == null)
}
fun box(): String {
testString()
testExterRef()
testDataRef()
testInt()
testBoolean()
testShort()
testFloat()
return "OK"
}
@@ -0,0 +1,126 @@
// IGNORE_BACKEND: JS_IR, JS
@JsFun("(x) => { if (x !== 'abc') throw 'error' }")
external fun notNullString(x: String)
@JsFun("(x) => { if (x !== 'abc') throw 'error' }")
external fun nullString(x: String?)
@JsFun("(x) => { if (x !== null) throw 'error' }")
external fun null2String(x: String?)
fun testString() {
notNullString("abc")
nullString("abc")
null2String(null)
}
external interface ExternRef
@JsFun("(x) => { if (x !== 'abc') throw 'error' }")
external fun notNullExternRef(x: ExternRef)
@JsFun("(x) => { if (x !== 'abc') throw 'error' }")
external fun nullExternRef(x: ExternRef?)
@JsFun("(x) => { if (x !== null) throw 'error' }")
external fun null2ExternRef(x: ExternRef?)
@JsFun("() => 'abc'")
external fun getExternRef(): ExternRef
fun testExterRef() {
val externRef = getExternRef()
notNullExternRef(externRef)
nullExternRef(externRef)
null2ExternRef(null)
}
class DataRef
@JsFun("(x, y) => { if (x === null) throw 'error' }")
external fun notNullDataRef(x: DataRef)
@JsFun("(x, y) => { if (x === null) throw 'error' }")
external fun nullDataRef(x: DataRef?)
@JsFun("(x, y) => { if (x !== null) throw 'error' }")
external fun null2DataRef(x: DataRef?)
fun testDataRef() {
val dataRef = DataRef()
notNullDataRef(dataRef)
nullDataRef(dataRef)
null2DataRef(null)
}
@JsFun("(x) => { if (x !== 123) throw 'error' }")
external fun notNullInt(x: Int)
@JsFun("(x) => { if (x !== 123) throw 'error' }")
external fun nullInt(x: Int?)
@JsFun("(x) => { if (x !== null) throw 'error' }")
external fun null2Int(x: Int?)
fun testInt() {
notNullInt(123)
nullInt(123)
null2Int(null)
}
@JsFun("(x) => { if (x !== true) throw 'error' }")
external fun notNullBoolean(x: Boolean)
@JsFun("(x) => { if (x !== true) throw 'error' }")
external fun nullBoolean(x: Boolean?)
@JsFun("(x) => { if (x !== null) throw 'error' }")
external fun null2Boolean(x: Boolean?)
fun testBoolean() {
notNullBoolean(true)
nullBoolean(true)
null2Boolean(null)
}
@JsFun("(x) => { x == 123 }")
external fun notNullShort(x: Short)
@JsFun("(x) => { if (x !== 123) throw 'error' }")
external fun nullShort(x: Short?)
@JsFun("(x) => { if (x !== null) throw 'error' }")
external fun null2Short(x: Short?)
fun testShort() {
notNullShort(123.toShort())
nullShort(123.toShort())
null2Short(null)
}
@JsFun("(x) => { if (x !== 123.5) throw 'error' }")
external fun notNullFloat(x: Float)
@JsFun("(x) => { if (x !== 123.5) throw 'error' }")
external fun nullFloat(x: Float?)
@JsFun("(x) => { if (x !== null) throw 'error' }")
external fun null2Float(x: Float?)
fun testFloat() {
notNullFloat(123.5f)
nullFloat(123.5f)
null2Float(null)
}
fun box(): String {
testString()
testExterRef()
testDataRef()
testInt()
testBoolean()
testShort()
testFloat()
return "OK"
}
@@ -37,6 +37,16 @@ external fun getJsNullAsNonNullable(): EI
@JsFun("() => undefined")
external fun getJsUndefinedAsNonNullable(): EI
inline fun checkNPE(body: () -> Unit) {
var throwed = false
try {
body()
} catch (e: NullPointerException) {
throwed = true
}
assertTrue(throwed)
}
fun box(): String {
val jsNull = getNull()
val jsUndefined = getUndefined()
@@ -55,11 +65,8 @@ fun box(): String {
assertFalse(isJsUndefined(null))
assertTrue(isJsUndefined(jsUndefined))
// TODO: Should these fail?
val n2 = getJsNullAsNonNullable()
val ud2 = getJsUndefinedAsNonNullable()
assertTrue(isJsNull(n2))
assertTrue(isJsUndefined(ud2))
checkNPE(::getJsNullAsNonNullable)
checkNPE(::getJsUndefinedAsNonNullable)
return "OK"
}