[JS IR] Make Char a value class (again)

#KT-35100 Fixed
This commit is contained in:
Sergej Jaskiewicz
2021-12-01 16:22:09 +03:00
committed by Space
parent 599f705842
commit 67dfe7bed1
19 changed files with 226 additions and 51 deletions
@@ -216,6 +216,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
runTest("js/js.translator/testData/box/char/charEquals.kt");
}
@Test
@TestMetadata("charInExternalDecl.kt")
public void testCharInExternalDecl() throws Exception {
runTest("js/js.translator/testData/box/char/charInExternalDecl.kt");
}
@Test
@TestMetadata("charInStringTemplate.kt")
public void testCharInStringTemplate() throws Exception {
@@ -216,6 +216,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/char/charEquals.kt");
}
@Test
@TestMetadata("charInExternalDecl.kt")
public void testCharInExternalDecl() throws Exception {
runTest("js/js.translator/testData/box/char/charInExternalDecl.kt");
}
@Test
@TestMetadata("charInStringTemplate.kt")
public void testCharInStringTemplate() throws Exception {
@@ -0,0 +1,69 @@
function actualTypeOfChar(x) {
return typeof x;
}
function actualTypeOfMaybeChar(x) {
return actualTypeOfChar(x);
}
function getSomeChar() {
return 'a'.charCodeAt(0);
}
function getMaybeChar() {
return getSomeChar();
}
function getCharNull() {
return null;
}
var charVal = getSomeChar();
var maybeCharVal = getMaybeChar();
var charNullVal = getCharNull();
var charVar = getSomeChar();
var maybeCharVar = null;
function A(c) {
this.c = c;
this._baz = 'q'.charCodeAt(0);
this._nullableBaz = null;
}
A.prototype.foo = function () {
return this.c;
};
A.prototype.maybeFoo = A.prototype.foo;
A.prototype.fooNull = getCharNull;
A.prototype.actualTypeOfChar = actualTypeOfChar
A.prototype.actualTypeOfMaybeChar = actualTypeOfMaybeChar
Object.defineProperty(A.prototype, 'bar', {
configurable: true,
get: A.prototype.foo
});
Object.defineProperty(A.prototype, 'maybeBar', {
configurable: true,
get: A.prototype.maybeFoo
});
Object.defineProperty(A.prototype, 'barNull', {
configurable: true,
get: A.prototype.fooNull
});
Object.defineProperty(A.prototype, 'baz', {
configurable: true,
get: function () { return this._baz; },
set: function (v) { this._baz = v; }
});
Object.defineProperty(A.prototype, 'maybeBaz', {
configurable: true,
get: function () { return this._nullableBaz; },
set: function (v) { this._nullableBaz = v; }
});
+121
View File
@@ -0,0 +1,121 @@
// See KT-43224
external fun actualTypeOfChar(x: Char): String
external fun actualTypeOfMaybeChar(x: Char?): String
external fun getSomeChar(): Char
external fun getMaybeChar(): Char?
external fun getCharNull(): Char?
external val charVal: Char
external val maybeCharVal: Char?
external val charNullVal: Char?
external var charVar: Char
external var maybeCharVar: Char?
external interface I {
fun foo(): Char
fun maybeFoo(): Char?
fun fooNull(): Char?
fun actualTypeOfChar(x: Char): String
fun actualTypeOfMaybeChar(x: Char?): String
val bar: Char
val maybeBar: Char?
val barNull: Char?
var baz: Char
var maybeBaz: Char?
}
external class A(c: Char): I {
override fun foo(): Char
override fun maybeFoo(): Char?
override fun fooNull(): Char?
override fun actualTypeOfChar(x: Char): String
override fun actualTypeOfMaybeChar(x: Char?): String
override val bar: Char
override val maybeBar: Char?
override val barNull: Char?
override var baz: Char
override var maybeBaz: Char?
}
val expectedCharRepresentationInProperty = if (testUtils.isLegacyBackend()) "object" else "number"
fun box(): String {
if (actualTypeOfChar('a') != "number") return "Fail (actualTypeOfChar)"
if (actualTypeOfMaybeChar('a') != "number") return "Fail (actualTypeOfMaybeChar with nonnull arg)"
if (actualTypeOfMaybeChar(null) != "object") return "Fail (actualTypeOfMaybeChar with null arg)"
if (getSomeChar() != 'a') return "Fail (getSomeChar)"
if (getMaybeChar() != 'a') return "Fail (getMaybeChar)"
if (getCharNull() != null) return "Fail (getCharNull)"
if (charVal != 'a') return "Fail (charVal)"
if (maybeCharVal != 'a') return "Fail (maybeCharVal)"
if (charNullVal != null) return "Fail (charNullVal)"
if (charVar != 'a') return "Fail (charVar initial value)"
charVar = 'b'
if (js("typeof charVar") != "number") return "Fail (typeof charVar after modification)"
if (charVar != 'b') return "Fail (charVar after modification)"
if (maybeCharVar != null) return "Fail (maybeCharVar initial value)"
maybeCharVar = 'a'
if (js("typeof maybeCharVar") != "number") return "Fail (typeof maybeCharVar after 1st modification)"
if (maybeCharVar != 'a') return "Fail (maybeCharVar after 1st modification)"
maybeCharVar = null
if (js("typeof maybeCharVar") != "object") return "Fail (typeof maybeCharVar after 2nd modification)"
if (maybeCharVar != null) return "Fail (maybeCharVar after 2nd modification)"
val a = A('b')
if (a.foo() != 'b') return "Fail (a.foo())"
if (a.maybeFoo() != 'b') return "Fail (a.maybeFoo())"
if (a.fooNull() != null) return "Fail (a.fooNull())"
if (a.actualTypeOfChar('a') != "number") return "Fail (a.actualTypeOfChar())"
if (a.actualTypeOfMaybeChar('a') != "number") return "Fail (a.actualTypeOfMaybeChar() with nonnull arg)"
if (a.actualTypeOfMaybeChar(null) != "object") return "Fail (a.actualTypeOfMaybeChar() with null arg)"
if (a.bar != 'b') return "Fail (a.bar)"
if (a.maybeBar != 'b') return "Fail (a.maybeBar)"
if (a.barNull != null) return "Fail (a.barNull)"
if (a.baz != 'q') return "Fail (a.baz initial value)"
a.baz = 'r'
if (js("typeof a._baz") != expectedCharRepresentationInProperty) return "Fail (typeof a._baz after modification)"
if (a.baz != 'r') return "Fail (a.baz after modification)"
if (a.maybeBaz != null) return "Fail (a.maybeBaz initial value)"
a.maybeBaz = 's'
if (js("typeof a._nullableBaz") != expectedCharRepresentationInProperty) return "Fail (typeof a._nullableBaz after 1st modification)"
if (a.maybeBaz != 's') return "Fail (a.maybeBaz after 1st modification)"
a.maybeBaz = null
if (js("typeof a._nullableBaz") != "object") return "Fail (typeof a._nullableBaz after 2nd modification)"
if (a.maybeBaz != null) return "Fail (a.maybeBaz after 2nd modification)"
val b: I = A('e')
if (b.foo() != 'e') return "Fail (b.foo())"
if (b.maybeFoo() != 'e') return "Fail (b.maybeFoo())"
if (b.fooNull() != null) return "Fail (b.fooNull())"
if (b.actualTypeOfChar('a') != "number") return "Fail (b.actualTypeOfChar())"
if (b.actualTypeOfMaybeChar('a') != "number") return "Fail (b.actualTypeOfMaybeChar() with nonnull arg)"
if (b.actualTypeOfMaybeChar(null) != "object") return "Fail (b.actualTypeOfMaybeChar() with null arg)"
if (b.bar != 'e') return "Fail (b.bar)"
if (b.maybeBar != 'e') return "Fail (b.maybeBar)"
if (b.barNull != null) return "Fail (b.barNull)"
if (b.baz != 'q') return "Fail (b.baz initial value)"
b.baz = 'r'
if (js("typeof b._baz") != expectedCharRepresentationInProperty) return "Fail (typeof b._baz after modification)"
if (b.baz != 'r') return "Fail (b.baz after modification)"
if (b.maybeBaz != null) return "Fail (b.maybeBaz initial value)"
b.maybeBaz = 's'
if (js("typeof b._nullableBaz") != expectedCharRepresentationInProperty) return "Fail (typeof b._nullableBaz after 1st modification)"
if (b.maybeBaz != 's') return "Fail (b.maybeBaz after 1st modification)"
b.maybeBaz = null
if (js("typeof b._nullableBaz") != "object") return "Fail (typeof b._nullableBaz after 2nd modification)"
if (b.maybeBaz != null) return "Fail (b.maybeBaz after 2nd modification)"
return "OK"
}
+4 -5
View File
@@ -1,16 +1,15 @@
// SKIP_MINIFICATION
// Exported declaration uses non-exportable return type: Char
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
@JsName("foo")
@JsExport
fun foo(): Char = '1'
@JsExport
val p1: Char = '2'
@JsExport
var p2: Char = '3'
@JsExport
var p3: Char = '4'
get() = field + 1
set(value) {
+1 -2
View File
@@ -1,6 +1,5 @@
// EXPECTED_REACHABLE_NODES: 1293
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
open class A {
fun foo(): Char = 'X'
}
+1 -3
View File
@@ -1,8 +1,6 @@
// EXPECTED_REACHABLE_NODES: 1276
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
class A(val x: Char)
class A(@JsName("x") val x: Char)
fun typeOf(x: dynamic): String = js("typeof x")
+1 -2
View File
@@ -1,6 +1,5 @@
// EXPECTED_REACHABLE_NODES: 1288
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
@JsExport
interface I {
val a: Char
@@ -1,6 +1,4 @@
// EXPECTED_REACHABLE_NODES: 1292
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
abstract class A<out T> {
abstract fun foo(): T
}
@@ -1,6 +1,4 @@
// EXPECTED_REACHABLE_NODES: 1282
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
fun box(): String {
val a = 'Q'.foo()
if (a != "number") return "fail1: $a"
+4 -6
View File
@@ -1,10 +1,8 @@
// EXPECTED_REACHABLE_NODES: 1283
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// 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
// CHECK_NOT_CALLED_IN_SCOPE: function=toBoxedChar scope=box$lambda TARGET_BACKENDS=JS
// CHECK_CALLED_IN_SCOPE: function=unboxChar scope=box$lambda TARGET_BACKENDS=JS
// CHECK_CALLED_IN_SCOPE: function=toBoxedChar scope=box TARGET_BACKENDS=JS
// CHECK_NOT_CALLED_IN_SCOPE: function=unboxChar scope=box TARGET_BACKENDS=JS
fun <T> bar(x: T, y: (T) -> Boolean): Boolean = y(x) && jsTypeOf(x.asDynamic()) != "number"
@@ -1,7 +1,6 @@
// EXPECTED_REACHABLE_NODES: 1289
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
@JsExport
open class A {
val foo: Char
get() = 'X'
@@ -31,6 +30,7 @@ interface I {
val mutable: Any
}
@JsExport
class B : A(), I
fun typeOf(x: dynamic): String = js("typeof x")
@@ -1,6 +1,4 @@
// EXPECTED_REACHABLE_NODES: 1283
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
fun foo(x: Any): String {
return when (x) {
is Char -> "char: ${x.toInt()}"
@@ -1,6 +1,4 @@
// EXPECTED_REACHABLE_NODES: 1293
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
package foo
@@ -1,6 +1,5 @@
// EXPECTED_REACHABLE_NODES: 1281
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
fun box(): String {
val a = CharArray(1)
val aType = jsTypeOf(a.asDynamic()[0])
+1 -1
View File
@@ -1064,7 +1064,7 @@ public final class ByteArray {
public final operator fun set(index: kotlin.Int, value: kotlin.Byte): kotlin.Unit
}
public final class Char : kotlin.Comparable<kotlin.Char> {
/*∆*/ public final class Char : kotlin.Comparable<kotlin.Char> {
public open override operator fun compareTo(other: kotlin.Char): kotlin.Int
public final operator fun dec(): kotlin.Char
+1 -1
View File
@@ -1032,7 +1032,7 @@ public final class ByteArray {
public final operator fun set(index: kotlin.Int, value: kotlin.Byte): kotlin.Unit
}
public final class Char : kotlin.Comparable<kotlin.Char> {
/*∆*/ public final inline class Char : kotlin.Comparable<kotlin.Char> {
/*∆*/ @kotlin.SinceKotlin(version = "1.5")
/*∆*/ @kotlin.WasExperimental(markerClass = {kotlin.ExperimentalStdlibApi::class})
/*∆*/ public constructor Char(code: kotlin.UShort)
+7 -17
View File
@@ -9,13 +9,13 @@ package kotlin
* Represents a 16-bit Unicode character.
* On the JVM, non-nullable values of this type are represented as values of the primitive type `char`.
*/
// TODO: KT-35100
//public inline class Char internal constructor (val value: Int) : Comparable<Char> {
public class Char
@SinceKotlin("1.5")
@WasExperimental(ExperimentalStdlibApi::class)
constructor(code: UShort) : Comparable<Char> {
private val value: Int = code.toInt()
public value class Char
@kotlin.internal.LowPriorityInOverloadResolution
internal constructor(private val value: Int) : Comparable<Char> {
@SinceKotlin("1.5")
@WasExperimental(ExperimentalStdlibApi::class)
public constructor(code: UShort) : this(code.toInt())
/**
* Compares this value with the specified value for order.
@@ -76,16 +76,6 @@ constructor(code: UShort) : Comparable<Char> {
@DeprecatedSinceKotlin(warningSince = "1.5")
public fun toDouble(): Double = value.toDouble()
override fun equals(other: Any?): Boolean {
@Suppress("IMPLICIT_BOXING_IN_IDENTITY_EQUALS")
if (other === this) return true
if (other !is Char) return false
return this.value == other.value
}
override fun hashCode(): Int = value
// TODO implicit usages of toString and valueOf must be covered in DCE
@Suppress("JS_NAME_PROHIBITED_FOR_OVERRIDE")
@JsName("toString")
+1 -2
View File
@@ -34,8 +34,7 @@ internal fun booleanArray(size: Int): BooleanArray = withType("BooleanArray", fi
internal fun booleanArrayOf(arr: Array<Boolean>): BooleanArray = withType("BooleanArray", arr.asDynamic().slice()).unsafeCast<BooleanArray>()
//internal fun charArray(size: Int): CharArray = withType("CharArray", fillArrayVal(Array<Int>(size), 0)).unsafeCast<CharArray>()
internal fun charArray(size: Int): CharArray = withType("CharArray", fillArrayVal(Array<Char>(size), Char(0))).unsafeCast<CharArray>()
internal fun charArray(size: Int): CharArray = withType("CharArray", fillArrayVal(Array<Int>(size), 0)).unsafeCast<CharArray>()
internal fun charArrayOf(arr: Array<Char>): CharArray = withType("CharArray", arr.asDynamic().slice()).unsafeCast<CharArray>()