[JS IR BE] Support Number.to(Byte|Short|Int|Float|Double|Long)

This commit is contained in:
Svyatoslav Kuzmich
2018-10-10 20:50:01 +03:00
parent bad9534abd
commit 783f27c554
5 changed files with 33 additions and 21 deletions
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.getPropertyGetter import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -101,6 +102,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
val jsNumberToInt = getInternalFunction("numberToInt") val jsNumberToInt = getInternalFunction("numberToInt")
val jsNumberToShort = getInternalFunction("numberToShort") val jsNumberToShort = getInternalFunction("numberToShort")
val jsNumberToLong = getInternalFunction("numberToLong") val jsNumberToLong = getInternalFunction("numberToLong")
val jsNumberToChar = getInternalFunction("numberToChar")
val jsToByte = getInternalFunction("toByte") val jsToByte = getInternalFunction("toByte")
val jsToShort = getInternalFunction("toShort") val jsToShort = getInternalFunction("toShort")
val jsToLong = getInternalFunction("toLong") val jsToLong = getInternalFunction("toLong")
@@ -174,6 +176,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
) )
val charClassSymbol = getInternalClassWithoutPackage("kotlin.Char") val charClassSymbol = getInternalClassWithoutPackage("kotlin.Char")
val charConstructor = charClassSymbol.constructors.single().owner
val uByteClassSymbol = getInternalClassWithoutPackage("kotlin.UByte") val uByteClassSymbol = getInternalClassWithoutPackage("kotlin.UByte")
val uShortClassSymbol = getInternalClassWithoutPackage("kotlin.UShort") val uShortClassSymbol = getInternalClassWithoutPackage("kotlin.UShort")
@@ -6,11 +6,10 @@
package org.jetbrains.kotlin.ir.backend.js.lower.calls package org.jetbrains.kotlin.ir.backend.js.lower.calls
import org.jetbrains.kotlin.ir.backend.js.ir.irCall import org.jetbrains.kotlin.ir.backend.js.ir.irCall
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -18,13 +17,13 @@ import org.jetbrains.kotlin.types.SimpleType
typealias SymbolToTransformer = MutableMap<IrFunctionSymbol, (IrCall) -> IrExpression> typealias SymbolToTransformer = MutableMap<IrFunctionSymbol, (IrCall) -> IrExpression>
internal fun SymbolToTransformer.add(from: Map<SimpleType, IrSimpleFunction>, to: IrSimpleFunction) { internal fun SymbolToTransformer.add(from: Map<SimpleType, IrFunction>, to: IrFunction) {
from.forEach { _, func -> from.forEach { _, func ->
add(func.symbol, to) add(func.symbol, to)
} }
} }
internal fun SymbolToTransformer.add(from: Map<SimpleType, IrSimpleFunction>, to: (IrCall) -> IrExpression) { internal fun SymbolToTransformer.add(from: Map<SimpleType, IrFunction>, to: (IrCall) -> IrExpression) {
from.forEach { _, func -> from.forEach { _, func ->
add(func.symbol, to) add(func.symbol, to)
} }
@@ -34,7 +33,7 @@ internal fun SymbolToTransformer.add(from: IrFunctionSymbol, to: (IrCall) -> IrE
put(from, to) put(from, to)
} }
internal fun SymbolToTransformer.add(from: IrFunctionSymbol, to: IrSimpleFunction, dispatchReceiverAsFirstArgument: Boolean = false) { internal fun SymbolToTransformer.add(from: IrFunctionSymbol, to: IrFunction, dispatchReceiverAsFirstArgument: Boolean = false) {
put(from) { call -> irCall(call, to.symbol, dispatchReceiverAsFirstArgument) } put(from) { call -> irCall(call, to.symbol, dispatchReceiverAsFirstArgument) }
} }
@@ -48,11 +47,11 @@ internal fun <K> MutableMap<K, (IrCall) -> IrExpression>.addWithPredicate(
internal typealias MemberToTransformer = HashMap<SimpleMemberKey, (IrCall) -> IrExpression> internal typealias MemberToTransformer = HashMap<SimpleMemberKey, (IrCall) -> IrExpression>
internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrSimpleFunctionSymbol) { internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunctionSymbol) {
add(type, name) { irCall(it, v, dispatchReceiverAsFirstArgument = true) } add(type, name) { irCall(it, v, dispatchReceiverAsFirstArgument = true) }
} }
internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrSimpleFunction) { internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunction) {
add(type, name, v.symbol) add(type, name, v.symbol)
} }
@@ -64,21 +64,25 @@ class NumberConversionCallsTransformer(context: JsIrBackendContext) : CallsTrans
add(it, ConversionNames.TO_LONG, intrinsics.jsToLong) add(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
} }
for (type in arrayOf(irBuiltIns.byteType, irBuiltIns.intType)) {
add(type, ConversionNames.TO_CHAR) { irBuiltIns.numberType.let {
irCall(it, intrinsics.charClassSymbol.constructors.single(), dispatchReceiverAsFirstArgument = true) add(it, ConversionNames.TO_BYTE, intrinsics.jsNumberToByte)
} add(it, ConversionNames.TO_DOUBLE, intrinsics.jsNumberToDouble)
add(it, ConversionNames.TO_FLOAT, intrinsics.jsNumberToDouble)
add(it, ConversionNames.TO_INT, intrinsics.jsNumberToInt)
add(it, ConversionNames.TO_SHORT, intrinsics.jsNumberToShort)
add(it, ConversionNames.TO_LONG, intrinsics.jsNumberToLong)
} }
for (type in arrayOf(irBuiltIns.floatType, irBuiltIns.doubleType)) { for (type in arrayOf(irBuiltIns.byteType, irBuiltIns.shortType, irBuiltIns.intType)) {
add(type, ConversionNames.TO_CHAR) { add(type, ConversionNames.TO_CHAR, intrinsics.charConstructor)
JsIrBuilder.buildCall(intrinsics.charClassSymbol.constructors.single()).apply {
putValueArgument(0, irCall(it, intrinsics.jsNumberToInt, dispatchReceiverAsFirstArgument = true))
}
}
} }
add(irBuiltIns.charType, ConversionNames.TO_CHAR) { it.dispatchReceiver!! } for (type in arrayOf(irBuiltIns.floatType, irBuiltIns.doubleType, irBuiltIns.numberType)) {
add(type, ConversionNames.TO_CHAR, intrinsics.jsNumberToChar)
}
add(irBuiltIns.charType, ConversionNames.TO_CHAR, ::useDispatchReceiver)
} }
override fun transformCall(call: IrCall): IrExpression { override fun transformCall(call: IrCall): IrExpression {
@@ -86,6 +86,10 @@ class IrBuiltIns(
val charType = char.toIrType() val charType = char.toIrType()
val charClass = builtIns.char.toIrSymbol() val charClass = builtIns.char.toIrSymbol()
val number = builtIns.number.defaultType
val numberType = number.toIrType()
val numberClass = builtIns.number.toIrSymbol()
val byte = builtIns.byteType val byte = builtIns.byteType
val byteType = byte.toIrType() val byteType = byte.toIrType()
val byteClass = builtIns.byte.toIrSymbol() val byteClass = builtIns.byte.toIrSymbol()
@@ -9,7 +9,7 @@ fun numberToByte(a: dynamic): Byte = toByte(numberToInt(a))
fun numberToDouble(a: dynamic): Double = js("+a").unsafeCast<Double>() fun numberToDouble(a: dynamic): Double = js("+a").unsafeCast<Double>()
fun numberToInt(a: dynamic): Int = doubleToInt(a) fun numberToInt(a: dynamic): Int = if (a is Long) a.toInt() else doubleToInt(a)
fun numberToShort(a: dynamic): Short = toShort(numberToInt(a)) fun numberToShort(a: dynamic): Short = toShort(numberToInt(a))
@@ -17,7 +17,7 @@ fun numberToShort(a: dynamic): Short = toShort(numberToInt(a))
fun toByte(a: dynamic): Byte = js("a << 24 >> 24").unsafeCast<Byte>() fun toByte(a: dynamic): Byte = js("a << 24 >> 24").unsafeCast<Byte>()
fun toShort(a: dynamic): Short = js("a << 16 >> 16").unsafeCast<Short>() fun toShort(a: dynamic): Short = js("a << 16 >> 16").unsafeCast<Short>()
fun numberToLong(a: dynamic): Long = fromNumber(a) fun numberToLong(a: dynamic): Long = if (a is Long) a else fromNumber(a)
fun toLong(a: dynamic): Long = fromInt(a) fun toLong(a: dynamic): Long = fromInt(a)
@@ -25,4 +25,6 @@ fun doubleToInt(a: dynamic) = js("""
if (a > 2147483647) return 2147483647; if (a > 2147483647) return 2147483647;
if (a < -2147483648) return -2147483648; if (a < -2147483648) return -2147483648;
return a | 0; return a | 0;
""").unsafeCast<Int>() """).unsafeCast<Int>()
fun numberToChar(a: dynamic) = Char(numberToInt(a))