Add mechanism for type coercion in JS
Use it for char boxing/unboxing and unit materialization. Possible to use for other purposes, for example, to add type checks to dynamics. See KT-18793, KT-17915, KT-19081, KT-18216, KT-12970, KT-17014, KT-13932, KT-13930
This commit is contained in:
+11
-1
@@ -9,5 +9,15 @@ fun box(): String {
|
||||
assertEquals(false, 'A'== 'B')
|
||||
assertEquals(false, ('A' as Any) == (65 as Any))
|
||||
|
||||
assertTrue(bar('Q'))
|
||||
assertFalse(bar('W'))
|
||||
|
||||
assertTrue(baz('Q'))
|
||||
assertFalse(baz('W'))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun bar(x: Char) = x.equals('Q')
|
||||
|
||||
fun baz(x: Any) = x.equals('Q')
|
||||
@@ -0,0 +1,18 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
class A {
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo()"
|
||||
}
|
||||
|
||||
val bar: Any = foo()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = A()
|
||||
if (a.bar != Unit) return "fail1: ${a.bar}"
|
||||
if (a.log != "foo()") return "fail2: ${a.log}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1006
|
||||
abstract class A<out T> {
|
||||
abstract fun foo(): T
|
||||
}
|
||||
|
||||
class B() : A<Char>() {
|
||||
override fun foo() = 'Q'
|
||||
}
|
||||
|
||||
private fun typeOf(x: dynamic) = js("typeof x")
|
||||
|
||||
fun box(): String {
|
||||
val a: A<Any> = B()
|
||||
if (typeOf(a.foo()) != "object") return "fail1"
|
||||
if (typeOf(B().foo()) != "number") return "fail2"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1012
|
||||
var log = ""
|
||||
|
||||
abstract class A<out T> {
|
||||
abstract fun foo(): T
|
||||
}
|
||||
|
||||
class B() : A<Unit>() {
|
||||
override fun foo() {
|
||||
log += "B.foo()"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a: A<Any> = B()
|
||||
if (a.foo() != Unit) return "fail1"
|
||||
if (log != "B.foo()") return "fail2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1006
|
||||
var log = ""
|
||||
|
||||
class A {
|
||||
operator fun component1() {
|
||||
log += "A.component1()"
|
||||
}
|
||||
|
||||
operator fun component2() = 23
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val (x: Any, y) = A()
|
||||
|
||||
if (x != Unit) return "fail1: $x"
|
||||
if (y != 23) return "fail2: $y"
|
||||
if (log != "A.component1()") return "fail3: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// EXPECTED_REACHABLE_NODES: 996
|
||||
fun box(): String {
|
||||
val a = 'Q'.foo()
|
||||
if (a != "number") return "fail1: $a"
|
||||
|
||||
val b = 'W'.bar()
|
||||
if (b != "object") return "fail2: $b"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun Char.foo() = jsTypeOf(this.asDynamic())
|
||||
|
||||
fun Any.bar() = jsTypeOf(this.asDynamic())
|
||||
@@ -0,0 +1,19 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1005
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo()"
|
||||
}
|
||||
|
||||
fun test(x: Int) = if (x < 10) foo() else 55
|
||||
|
||||
fun box(): String {
|
||||
val a = test(20)
|
||||
if (a !is Int) return "fail1: $a"
|
||||
|
||||
val b = test(5)
|
||||
if (b !is Unit) return "fail2: $b"
|
||||
if (log != "foo()") return "fail3: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1000
|
||||
inline fun foo(i : Int) = if (i % 2 == 0) {} else i
|
||||
|
||||
fun box(): String {
|
||||
val a = foo(1)
|
||||
if (a != 1) return "fail1: $a"
|
||||
|
||||
val b = foo(2)
|
||||
if (b != Unit) return "fail2: $b"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// EXPECTED_REACHABLE_NODES: 997
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: function=toBoxedChar scope=box$lambda
|
||||
// CHECK_CALLED_IN_SCOPE: function=unboxChar scope=box$lambda
|
||||
// CHECK_CALLED_IN_SCOPE: function=toBoxedChar scope=box
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: function=unboxChar scope=box
|
||||
|
||||
fun <T> bar(x: T, y: (T) -> Boolean): Boolean = y(x) && jsTypeOf(x.asDynamic()) != "number"
|
||||
|
||||
fun typeOf(x: dynamic) = js("typeof x")
|
||||
|
||||
fun box(): String {
|
||||
val f = { x: Char ->
|
||||
val a: Char = x
|
||||
val b: Any = x
|
||||
typeOf(a) == "number" && typeOf(b) == "object"
|
||||
}
|
||||
|
||||
if (!f('Q')) return "fail1"
|
||||
if (!bar('W', f)) return "fail2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1009
|
||||
class A {
|
||||
operator fun iterator() = B()
|
||||
}
|
||||
|
||||
class B() {
|
||||
private var count = 0
|
||||
|
||||
operator fun next() {
|
||||
count++
|
||||
}
|
||||
|
||||
operator fun hasNext() = count < 5
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var i = 0
|
||||
for (x: Any in A()) {
|
||||
if (x != Unit) return "fail1: $x"
|
||||
i++
|
||||
}
|
||||
if (i != 5) return "fail2: $i"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// EXPECTED_REACHABLE_NODES: 997
|
||||
fun foo(x: Any): String {
|
||||
return when (x) {
|
||||
is Char -> "char: ${x.toInt()}"
|
||||
else -> "other: $x"
|
||||
}
|
||||
}
|
||||
|
||||
fun bar(x: Any): String {
|
||||
return when (x) {
|
||||
is Char -> "char: ${x.baz()}"
|
||||
else -> "other: $x"
|
||||
}
|
||||
}
|
||||
|
||||
fun Char.baz(): Boolean = jsTypeOf(asDynamic()) == "number"
|
||||
|
||||
fun box(): String {
|
||||
val a = foo('0')
|
||||
if (a != "char: 48") return "fail1: $a"
|
||||
|
||||
val b = foo(23)
|
||||
if (b != "other: 23") return "fail2: $b"
|
||||
|
||||
val c = bar('0')
|
||||
if (c != "char: true") return "fail3: $c"
|
||||
|
||||
val d = bar(23)
|
||||
if (d != "other: 23") return "fail4: $d"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
var log = ""
|
||||
|
||||
fun test(param: Any?) {
|
||||
param?.let {
|
||||
log += "test($param);"
|
||||
} ?: run {
|
||||
log += "test-null;"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
test(null)
|
||||
test(23)
|
||||
|
||||
if (log != "test-null;test(23);") return "fail: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1003
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo()"
|
||||
}
|
||||
|
||||
val bar: Any = foo()
|
||||
|
||||
fun box(): String {
|
||||
if (bar != Unit) return "fail1: $bar"
|
||||
if (log != "foo()") return "fail2: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
fun test(x: Int): Any {
|
||||
return try {
|
||||
if (x % 2 == 0) throw RuntimeException()
|
||||
x
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = test(1)
|
||||
if (a != 1) return "fail1: $a"
|
||||
|
||||
val b = test(2)
|
||||
if (b != Unit) return "fail2: $b"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo"
|
||||
}
|
||||
|
||||
fun Unit.bar() = jsTypeOf(this.asDynamic()) == "undefined"
|
||||
|
||||
fun Any.baz() = jsTypeOf(this.asDynamic()) == "object"
|
||||
|
||||
fun box(): String {
|
||||
if (!foo().bar()) return "fail1"
|
||||
if (!foo().baz()) return "fail2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1002
|
||||
var log = ""
|
||||
|
||||
fun foo(): Unit {
|
||||
log += "foo();"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (foo() !is Any) return "fail1"
|
||||
if (foo() as Any != Unit) return "fail2"
|
||||
if (log != "foo();foo();") return "fail3: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
class C {
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a: C? = C()
|
||||
val b: C? = null
|
||||
|
||||
if (a?.foo() != Unit) return "fail1: ${a?.foo()}"
|
||||
if (b?.foo() != null) return "fail2: ${b?.foo()}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1005
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo()"
|
||||
}
|
||||
|
||||
fun test(x: Int) = when (x) {
|
||||
in 0..10 -> foo()
|
||||
else -> 55
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = test(20)
|
||||
if (a !is Int) return "fail1: $a"
|
||||
|
||||
val b = test(5)
|
||||
if (b !is Unit) return "fail2: $b"
|
||||
if (log != "foo()") return "fail3: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
// FILE: lib.kt
|
||||
package lib
|
||||
|
||||
external fun bar()
|
||||
external fun bar(): Int
|
||||
|
||||
val bar = 32
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// EXPECTED_REACHABLE_NODES: 997
|
||||
fun box(): String {
|
||||
val a = CharArray(1)
|
||||
val aType = jsTypeOf(a.asDynamic()[0])
|
||||
if (aType != "number") return "fail1: $aType"
|
||||
|
||||
a[0] = 'Q'
|
||||
val aType2 = jsTypeOf(a.asDynamic()[0])
|
||||
if (aType2 != "number") return "fail2: $aType2"
|
||||
|
||||
val aType3 = jsTypeOf(a[0].asDynamic())
|
||||
if (aType3 != "number") return "fail3: $aType3"
|
||||
|
||||
val b = Array<Char>(1) { 'Q' }
|
||||
val bType = jsTypeOf(b.asDynamic()[0])
|
||||
if (bType != "object") return "fail4: $bType"
|
||||
|
||||
b[0] = 'W'
|
||||
val bType2 = jsTypeOf(b.asDynamic()[0])
|
||||
if (bType2 != "object") return "fail5: $bType2"
|
||||
|
||||
val bType3 = jsTypeOf(b[0].asDynamic())
|
||||
if (bType3 != "number") return "fail6: $bType3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user