JS IR: char (always boxed for now)
This commit is contained in:
committed by
Anton Bannykh
parent
d709b03160
commit
9233e6c176
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js
|
package org.jetbrains.kotlin.ir.backend.js
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
@@ -128,6 +129,8 @@ class JsIntrinsics(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val charConstructor = context.symbolTable.referenceConstructor(context.getClass(KotlinBuiltIns.FQ_NAMES._char.toSafe()).constructors.single())
|
||||||
|
|
||||||
// Helpers:
|
// Helpers:
|
||||||
|
|
||||||
private fun getInternalFunction(name: String) =
|
private fun getInternalFunction(name: String) =
|
||||||
|
|||||||
+33
-3
@@ -152,6 +152,27 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
|||||||
op(type, OperatorNames.MOD, withLongCoercion(intrinsics.jsMod))
|
op(type, OperatorNames.MOD, withLongCoercion(intrinsics.jsMod))
|
||||||
op(type, OperatorNames.REM, withLongCoercion(intrinsics.jsMod))
|
op(type, OperatorNames.REM, withLongCoercion(intrinsics.jsMod))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (type in arrayOf(irBuiltIns.byteType, irBuiltIns.intType)) {
|
||||||
|
op(type, ConversionNames.TO_CHAR) {
|
||||||
|
irCall(it, intrinsics.charConstructor, dispatchReceiverAsFirstArgument = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (type in arrayOf(irBuiltIns.floatType, irBuiltIns.doubleType)) {
|
||||||
|
op(type, ConversionNames.TO_CHAR) {
|
||||||
|
IrCallImpl(
|
||||||
|
it.startOffset,
|
||||||
|
it.endOffset,
|
||||||
|
irBuiltIns.charType,
|
||||||
|
intrinsics.charConstructor
|
||||||
|
).apply {
|
||||||
|
putValueArgument(0, irCall(it, intrinsics.jsNumberToInt, dispatchReceiverAsFirstArgument = true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
op(irBuiltIns.charType, ConversionNames.TO_CHAR) { it.dispatchReceiver!! }
|
||||||
}
|
}
|
||||||
|
|
||||||
nameToTransformer.run {
|
nameToTransformer.run {
|
||||||
@@ -210,12 +231,21 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
|||||||
return IrCallImpl(
|
return IrCallImpl(
|
||||||
expression.startOffset,
|
expression.startOffset,
|
||||||
expression.endOffset,
|
expression.endOffset,
|
||||||
context.intrinsics.longConstructor.owner.returnType,
|
irBuiltIns.longType,
|
||||||
context.intrinsics.longConstructor
|
context.intrinsics.longConstructor
|
||||||
).apply {
|
).apply {
|
||||||
putValueArgument(0, JsIrBuilder.buildInt(context.irBuiltIns.intType, low))
|
putValueArgument(0, JsIrBuilder.buildInt(context.irBuiltIns.intType, low))
|
||||||
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, high))
|
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, high))
|
||||||
}
|
}
|
||||||
|
} else if (expression.kind is IrConstKind.Char) {
|
||||||
|
return IrCallImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
irBuiltIns.charType,
|
||||||
|
context.intrinsics.charConstructor
|
||||||
|
).apply {
|
||||||
|
putValueArgument(0, JsIrBuilder.buildInt(context.irBuiltIns.intType, IrConstKind.Char.valueOf(expression).toInt()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return super.visitConst(expression)
|
return super.visitConst(expression)
|
||||||
}
|
}
|
||||||
@@ -490,9 +520,9 @@ fun translateEqualsForNullableBoolean(rhs: IrType): EqualityLoweringType = when
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun IrType.isNullableJsNumber(): Boolean = isNullablePrimitiveType() && !isNullableLong()
|
private fun IrType.isNullableJsNumber(): Boolean = isNullablePrimitiveType() && !isNullableLong() && !isNullableChar()
|
||||||
|
|
||||||
private fun IrType.isJsNumber(): Boolean = isPrimitiveType() && !isLong()
|
private fun IrType.isJsNumber(): Boolean = isPrimitiveType() && !isLong() && !isChar()
|
||||||
|
|
||||||
|
|
||||||
// TODO extract to common place?
|
// TODO extract to common place?
|
||||||
|
|||||||
+4
-4
@@ -45,7 +45,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
|||||||
|
|
||||||
private val isInterfaceSymbol = getInternalFunction("isInterface")
|
private val isInterfaceSymbol = getInternalFunction("isInterface")
|
||||||
private val isArraySymbol = getInternalFunction("isArray")
|
private val isArraySymbol = getInternalFunction("isArray")
|
||||||
private val isCharSymbol = getInternalFunction("isChar")
|
// private val isCharSymbol = getInternalFunction("isChar")
|
||||||
private val isObjectSymbol = getInternalFunction("isObject")
|
private val isObjectSymbol = getInternalFunction("isObject")
|
||||||
|
|
||||||
private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf.symbol
|
private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf.symbol
|
||||||
@@ -199,7 +199,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
|||||||
return when {
|
return when {
|
||||||
toType.isAny() -> generateIsObjectCheck(argument)
|
toType.isAny() -> generateIsObjectCheck(argument)
|
||||||
isTypeOfCheckingType(toType) -> generateTypeOfCheck(argument, toType)
|
isTypeOfCheckingType(toType) -> generateTypeOfCheck(argument, toType)
|
||||||
toType.isChar() -> generateCheckForChar(argument)
|
// toType.isChar() -> generateCheckForChar(argument)
|
||||||
toType.isArray() -> generateGenericArrayCheck(argument)
|
toType.isArray() -> generateGenericArrayCheck(argument)
|
||||||
toType.isPrimitiveArray() -> generatePrimitiveArrayTypeCheck(argument, toType)
|
toType.isPrimitiveArray() -> generatePrimitiveArrayTypeCheck(argument, toType)
|
||||||
toType.isTypeParameter() -> generateTypeCheckWithTypeParameter(argument, toType)
|
toType.isTypeParameter() -> generateTypeCheckWithTypeParameter(argument, toType)
|
||||||
@@ -224,8 +224,8 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateCheckForChar(argument: IrExpression) =
|
// private fun generateCheckForChar(argument: IrExpression) =
|
||||||
JsIrBuilder.buildCall(isCharSymbol).apply { dispatchReceiver = argument }
|
// JsIrBuilder.buildCall(isCharSymbol).apply { dispatchReceiver = argument }
|
||||||
|
|
||||||
private fun generateTypeOfCheck(argument: IrExpression, toType: IrType): IrExpression {
|
private fun generateTypeOfCheck(argument: IrExpression, toType: IrType): IrExpression {
|
||||||
val marker = when {
|
val marker = when {
|
||||||
|
|||||||
+1
-1
@@ -83,7 +83,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
is IrConstKind.Short -> JsIntLiteral(kind.valueOf(expression).toInt())
|
is IrConstKind.Short -> JsIntLiteral(kind.valueOf(expression).toInt())
|
||||||
is IrConstKind.Int -> JsIntLiteral(kind.valueOf(expression))
|
is IrConstKind.Int -> JsIntLiteral(kind.valueOf(expression))
|
||||||
is IrConstKind.Long -> throw IllegalStateException("Long const should have been lowered at this point")
|
is IrConstKind.Long -> throw IllegalStateException("Long const should have been lowered at this point")
|
||||||
is IrConstKind.Char -> TODO("Char const")
|
is IrConstKind.Char -> throw IllegalStateException("Char const should have been lowered at this point")
|
||||||
is IrConstKind.Float -> JsDoubleLiteral(kind.valueOf(expression).toDouble())
|
is IrConstKind.Float -> JsDoubleLiteral(kind.valueOf(expression).toDouble())
|
||||||
is IrConstKind.Double -> JsDoubleLiteral(kind.valueOf(expression))
|
is IrConstKind.Double -> JsDoubleLiteral(kind.valueOf(expression))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,3 +62,4 @@ fun IrType.isNumber(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.numb
|
|||||||
|
|
||||||
fun IrType.isNullableBoolean(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._boolean)
|
fun IrType.isNullableBoolean(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._boolean)
|
||||||
fun IrType.isNullableLong(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._long)
|
fun IrType.isNullableLong(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._long)
|
||||||
|
fun IrType.isNullableChar(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._char)
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ abstract class BasicIrBoxTest(
|
|||||||
"libraries/stdlib/js/irRuntime/numberConversion.kt",
|
"libraries/stdlib/js/irRuntime/numberConversion.kt",
|
||||||
"libraries/stdlib/js/irRuntime/compareTo.kt",
|
"libraries/stdlib/js/irRuntime/compareTo.kt",
|
||||||
"libraries/stdlib/js/irRuntime/annotations.kt",
|
"libraries/stdlib/js/irRuntime/annotations.kt",
|
||||||
|
"libraries/stdlib/js/irRuntime/char.kt",
|
||||||
"libraries/stdlib/js/irRuntime/DefaultConstructorMarker.kt",
|
"libraries/stdlib/js/irRuntime/DefaultConstructorMarker.kt",
|
||||||
"libraries/stdlib/js/irRuntime/exceptions.kt",
|
"libraries/stdlib/js/irRuntime/exceptions.kt",
|
||||||
"libraries/stdlib/js/irRuntime/internalAnnotations.kt",
|
"libraries/stdlib/js/irRuntime/internalAnnotations.kt",
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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`.
|
||||||
|
*/
|
||||||
|
public class Char(value: Int) : Comparable<Char> {
|
||||||
|
|
||||||
|
private val value = value and 0xFFFF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares this value with the specified value for order.
|
||||||
|
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
|
||||||
|
* or a positive number if it's greater than other.
|
||||||
|
*/
|
||||||
|
public override fun compareTo(other: Char): Int = value - other.value
|
||||||
|
|
||||||
|
/** Adds the other Int value to this value resulting a Char. */
|
||||||
|
public operator fun plus(other: Int): Char = Char(value + other)
|
||||||
|
|
||||||
|
/** Subtracts the other Char value from this value resulting an Int. */
|
||||||
|
public operator fun minus(other: Char): Int = value - other.value
|
||||||
|
/** Subtracts the other Int value from this value resulting a Char. */
|
||||||
|
public operator fun minus(other: Int): Char = Char(value - other)
|
||||||
|
|
||||||
|
/** Increments this value. */
|
||||||
|
public operator fun inc(): Char = Char(value + 1)
|
||||||
|
/** Decrements this value. */
|
||||||
|
public operator fun dec(): Char = Char(value - 1)
|
||||||
|
|
||||||
|
/** Creates a range from this value to the specified [other] value. */
|
||||||
|
public operator fun rangeTo(other: Char): CharRange = null!! // TODO
|
||||||
|
|
||||||
|
/** Returns the value of this character as a `Byte`. */
|
||||||
|
public fun toByte(): Byte = value.toByte()
|
||||||
|
/** Returns the value of this character as a `Char`. */
|
||||||
|
public fun toChar(): Char = this
|
||||||
|
/** Returns the value of this character as a `Short`. */
|
||||||
|
public fun toShort(): Short = value.toShort()
|
||||||
|
/** Returns the value of this character as a `Int`. */
|
||||||
|
public fun toInt(): Int = value
|
||||||
|
/** Returns the value of this character as a `Long`. */
|
||||||
|
public fun toLong(): Long = value.toLong()
|
||||||
|
/** Returns the value of this character as a `Float`. */
|
||||||
|
public fun toFloat(): Float = value.toFloat()
|
||||||
|
/** Returns the value of this character as a `Double`. */
|
||||||
|
public fun toDouble(): Double = value.toDouble()
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean = other is Char && value == other.value
|
||||||
|
|
||||||
|
override fun hashCode(): Int = value
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val value = value
|
||||||
|
return js("String.fromCharCode(value)").unsafeCast<String>()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* The minimum value of a Unicode high-surrogate code unit.
|
||||||
|
*/
|
||||||
|
public const val MIN_HIGH_SURROGATE: Char = '\uD800'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum value of a Unicode high-surrogate code unit.
|
||||||
|
*/
|
||||||
|
public const val MAX_HIGH_SURROGATE: Char = '\uDBFF'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum value of a Unicode low-surrogate code unit.
|
||||||
|
*/
|
||||||
|
public const val MIN_LOW_SURROGATE: Char = '\uDC00'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum value of a Unicode low-surrogate code unit.
|
||||||
|
*/
|
||||||
|
public const val MAX_LOW_SURROGATE: Char = '\uDFFF'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum value of a Unicode surrogate code unit.
|
||||||
|
*/
|
||||||
|
public const val MIN_SURROGATE: Char = MIN_HIGH_SURROGATE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum value of a Unicode surrogate code unit.
|
||||||
|
*/
|
||||||
|
public const val MAX_SURROGATE: Char = MAX_LOW_SURROGATE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -65,7 +65,7 @@ fun hashCode(obj: dynamic): Int {
|
|||||||
var POW_2_32 = 4294967296;
|
var POW_2_32 = 4294967296;
|
||||||
// TODO: consider switching to Symbol type once we are on ES6.
|
// TODO: consider switching to Symbol type once we are on ES6.
|
||||||
/** @const */
|
/** @const */
|
||||||
var OBJECT_HASH_CODE_PROPERTY_NAME = "kotlinHashCodeValue${'$'}";
|
var OBJECT_HASH_CODE_PROPERTY_NAME = "kotlinHashCodeValue${"$"}";
|
||||||
|
|
||||||
function getObjectHashCode(obj) {
|
function getObjectHashCode(obj) {
|
||||||
if (!(OBJECT_HASH_CODE_PROPERTY_NAME in obj)) {
|
if (!(OBJECT_HASH_CODE_PROPERTY_NAME in obj)) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ private fun isInterfaceImpl(ctor: dynamic, iface: dynamic): Boolean {
|
|||||||
val self = ::isInterfaceImpl
|
val self = ::isInterfaceImpl
|
||||||
return js(
|
return js(
|
||||||
"""
|
"""
|
||||||
var metadata = ctor.${'$'}metadata${'$'};
|
var metadata = ctor.${"$"}metadata${"$"};
|
||||||
if (metadata != null) {
|
if (metadata != null) {
|
||||||
var interfaces = metadata.interfaces;
|
var interfaces = metadata.interfaces;
|
||||||
for (var i = 0; i < interfaces.length; i++) {
|
for (var i = 0; i < interfaces.length; i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user