[JS IR BE] Refactor equals and compareTo lowering
This commit is contained in:
@@ -134,6 +134,8 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val jsToString = getInternalFunction("toString")
|
||||
val jsAnyToString = getInternalFunction("anyToString")
|
||||
val jsCompareTo = getInternalFunction("compareTo")
|
||||
// TODO: Use annotations
|
||||
val compareToDoNotIntrinsicify = getInternalFunction("compareToDoNotIntrinsicify")
|
||||
val jsEquals = getInternalFunction("equals")
|
||||
|
||||
// Coroutines
|
||||
|
||||
+151
-221
@@ -6,9 +6,9 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf
|
||||
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOfClass
|
||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
@@ -16,10 +16,6 @@ import org.jetbrains.kotlin.ir.backend.js.ir.irCall
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.ConversionNames
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
@@ -131,9 +127,8 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
symbolToTransformer.run {
|
||||
add(irBuiltIns.eqeqeqSymbol, intrinsics.jsEqeqeq)
|
||||
add(irBuiltIns.eqeqSymbol, ::transformEqeqOperator)
|
||||
|
||||
// ieee754equals can only be applied in between statically known Floats or Doubles
|
||||
add(irBuiltIns.ieee754equalsFunByOperandType, intrinsics.jsEqeqeq)
|
||||
// ieee754equals can only be applied in between statically known Floats, Doubles, null or undefined
|
||||
add(irBuiltIns.ieee754equalsFunByOperandType, ::chooseEqualityOperatorForPrimitiveTypes)
|
||||
|
||||
add(irBuiltIns.booleanNotSymbol, intrinsics.jsNot)
|
||||
|
||||
@@ -237,11 +232,6 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
)
|
||||
|
||||
|
||||
addWithPredicate(
|
||||
Name.identifier("compareTo"), ::shouldReplaceCompareToWithRuntimeCall,
|
||||
{ call -> irCall(call, intrinsics.jsCompareTo, dispatchReceiverAsFirstArgument = true) }
|
||||
)
|
||||
|
||||
put(Name.identifier("toString")) { call ->
|
||||
if (shouldReplaceToStringWithRuntimeCall(call)) {
|
||||
if (call.isSuperToAny()) {
|
||||
@@ -266,7 +256,7 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
put(Name.identifier("compareTo"), ::transformCompareToMethodCall)
|
||||
put(Name.identifier("equals"), ::transformEqualsMethodCall)
|
||||
}
|
||||
|
||||
@@ -352,6 +342,12 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
if (declaration.symbol == intrinsics.compareToDoNotIntrinsicify)
|
||||
return declaration
|
||||
return super.visitFunction(declaration)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val call = super.visitCall(expression)
|
||||
|
||||
@@ -430,50 +426,6 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformEqeqOperator(call: IrCall): IrExpression {
|
||||
val lhs = call.getValueArgument(0)!!
|
||||
val rhs = call.getValueArgument(1)!!
|
||||
|
||||
// Special optimization for "<expression> == null"
|
||||
if (lhs.isNullConst() || rhs.isNullConst())
|
||||
return irCall(call, intrinsics.jsEqeq.symbol)
|
||||
|
||||
return when (translateEquals(lhs.type, rhs.type)) {
|
||||
is IdentityOperator -> irCall(call, intrinsics.jsEqeqeq.symbol)
|
||||
is EqualityOperator -> irCall(call, intrinsics.jsEqeq.symbol)
|
||||
is RuntimeFunctionCall -> irCall(call, intrinsics.jsEquals)
|
||||
is RuntimeOrMethodCall -> {
|
||||
assert(!lhs.type.isNullable())
|
||||
val equalsMethod = lhs.type.findEqualsMethod(rhs.type)
|
||||
if (equalsMethod != null) {
|
||||
irCall(call, equalsMethod.symbol, firstArgumentAsDispatchReceiver = true)
|
||||
} else {
|
||||
irCall(call, intrinsics.jsEquals)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrType.findEqualsMethod(rhs: IrType): IrSimpleFunction? {
|
||||
val classifier = classifierOrNull ?: return null
|
||||
return ((classifier.owner as? IrClass) ?: return null).declarations
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.filter {
|
||||
it.name == Name.identifier("equals")
|
||||
&& it.valueParameters.size == 1
|
||||
&& rhs.isSubtypeOf(it.valueParameters[0].type)
|
||||
&& !it.isFakeOverriddenFromAny()
|
||||
}
|
||||
.maxWith( // Find the most specific function
|
||||
Comparator { f1, f2 ->
|
||||
val t1 = f1.valueParameters[0].type
|
||||
val t2 = f2.valueParameters[0].type
|
||||
if (t1.isSubtypeOf(t2)) {
|
||||
if (t2.isSubtypeOf(t1)) 0 else 1
|
||||
} else -1
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun withLongCoercion(intrinsic: IrSimpleFunction): (IrCall) -> IrExpression = { call ->
|
||||
assert(call.valueArgumentsCount == 1)
|
||||
@@ -528,177 +480,149 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformEqualsMethodCall(call: IrCall): IrExpression {
|
||||
val symbol = call.symbol
|
||||
val function = (symbol.owner as? IrFunction) ?: return call
|
||||
val lhs = function.dispatchReceiverParameter ?: function.extensionReceiverParameter ?: return call
|
||||
val rhs = call.getValueArgument(0) ?: return call
|
||||
return when (translateEquals(lhs.type, rhs.type)) {
|
||||
is IdentityOperator -> irCall(call, intrinsics.jsEqeqeq.symbol)
|
||||
is EqualityOperator -> irCall(call, intrinsics.jsEqeq.symbol)
|
||||
is RuntimeFunctionCall -> irCall(call, intrinsics.jsEquals, true)
|
||||
is RuntimeOrMethodCall -> if (symbol.owner.isFakeOverriddenFromAny()) {
|
||||
if (call.isSuperToAny()) {
|
||||
irCall(call, intrinsics.jsEqeqeq.symbol, dispatchReceiverAsFirstArgument = true)
|
||||
} else {
|
||||
irCall(call, intrinsics.jsEquals, dispatchReceiverAsFirstArgument = true)
|
||||
}
|
||||
} else {
|
||||
private fun transformEqeqOperator(call: IrCall): IrExpression {
|
||||
val lhs = call.getValueArgument(0)!!
|
||||
val rhs = call.getValueArgument(1)!!
|
||||
|
||||
|
||||
val lhsJsType = lhs.type.getPrimitiveType()
|
||||
val rhsJsType = rhs.type.getPrimitiveType()
|
||||
|
||||
val equalsMethod = lhs.type.findEqualsMethod()
|
||||
val isLhsPrimitive = lhsJsType != PrimitiveType.OTHER
|
||||
|
||||
return when {
|
||||
lhs.type is IrDynamicType ->
|
||||
irCall(call, intrinsics.jsEqeq.symbol)
|
||||
|
||||
// Special optimization for "<expression> == null"
|
||||
lhs.isNullConst() || rhs.isNullConst() ->
|
||||
irCall(call, intrinsics.jsEqeq.symbol)
|
||||
|
||||
// For non-float primitives of the same type use JS `==`
|
||||
isLhsPrimitive && lhsJsType == rhsJsType && lhsJsType != PrimitiveType.FLOATING_POINT_NUMBER ->
|
||||
chooseEqualityOperatorForPrimitiveTypes(call)
|
||||
|
||||
!isLhsPrimitive && !lhs.type.toKotlinType().isNullable() && equalsMethod != null ->
|
||||
irCall(call, equalsMethod.symbol, firstArgumentAsDispatchReceiver = true)
|
||||
|
||||
else ->
|
||||
irCall(call, intrinsics.jsEquals)
|
||||
}
|
||||
}
|
||||
|
||||
private fun chooseEqualityOperatorForPrimitiveTypes(call: IrCall): IrExpression = when {
|
||||
call.allValueArgumentsAreNullable() ->
|
||||
irCall(call, intrinsics.jsEqeq.symbol)
|
||||
else ->
|
||||
irCall(call, intrinsics.jsEqeqeq.symbol)
|
||||
}
|
||||
|
||||
private fun IrCall.allValueArgumentsAreNullable() =
|
||||
(0 until valueArgumentsCount).all { getValueArgument(it)!!.type.isNullable() }
|
||||
|
||||
private fun transformCompareToMethodCall(call: IrCall): IrExpression {
|
||||
val function = call.symbol.owner as IrSimpleFunction
|
||||
if (function.parent !is IrClass) return call
|
||||
|
||||
fun IrSimpleFunction.isFakeOverriddenFromComparable(): Boolean = when {
|
||||
origin != IrDeclarationOrigin.FAKE_OVERRIDE ->
|
||||
parentAsClass.thisReceiver!!.type.isComparable()
|
||||
|
||||
else -> overriddenSymbols.all { it.owner.isFakeOverriddenFromComparable() }
|
||||
}
|
||||
|
||||
return when {
|
||||
// Use runtime function call in case when receiverType is a primitive JS type that doesn't have `compareTo` method,
|
||||
// or has a potential to be primitive type (being fake overridden from `Comparable`)
|
||||
function.isMethodOfPrimitiveJSType() || function.isFakeOverriddenFromComparable() ->
|
||||
irCall(call, intrinsics.jsCompareTo, dispatchReceiverAsFirstArgument = true)
|
||||
|
||||
// Valid `compareTo` method must be present at this point
|
||||
else ->
|
||||
call
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun transformEqualsMethodCall(call: IrCall): IrExpression {
|
||||
val function = call.symbol.owner
|
||||
return when {
|
||||
// Nothing special
|
||||
!function.isEqualsInheritedFromAny() -> call
|
||||
|
||||
// `Any.equals` works as identity operator
|
||||
call.isSuperToAny() ->
|
||||
irCall(call, intrinsics.jsEqeqeq.symbol, dispatchReceiverAsFirstArgument = true)
|
||||
|
||||
// Use runtime function call in case when receiverType is a primitive JS type that doesn't have `equals` method,
|
||||
// or has a potential to be primitive type (being fake overridden from `Any`)
|
||||
function.isMethodOfPotentiallyPrimitiveJSType() ->
|
||||
irCall(call, intrinsics.jsEquals, dispatchReceiverAsFirstArgument = true)
|
||||
|
||||
// Valid `equals` method must be present at this point
|
||||
else -> call
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrType.findEqualsMethod(): IrSimpleFunction? {
|
||||
val klass = getClass() ?: return null
|
||||
return klass.declarations
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.filter { it.isEqualsInheritedFromAny() && !it.isFakeOverriddenFromAny() }
|
||||
.also { assert(it.size <= 1) }
|
||||
.singleOrNull()
|
||||
}
|
||||
|
||||
private fun IrFunction.isMethodOfPrimitiveJSType() =
|
||||
dispatchReceiverParameter?.type?.getPrimitiveType() != PrimitiveType.OTHER
|
||||
|
||||
private fun IrFunction.isMethodOfPotentiallyPrimitiveJSType() =
|
||||
isMethodOfPrimitiveJSType() || isFakeOverriddenFromAny()
|
||||
|
||||
private fun IrFunction.isEqualsInheritedFromAny() =
|
||||
name == Name.identifier("equals") &&
|
||||
dispatchReceiverParameter != null &&
|
||||
valueParameters.size == 1 &&
|
||||
valueParameters[0].type.isNullableAny()
|
||||
|
||||
private fun shouldReplaceToStringWithRuntimeCall(call: IrCall): Boolean {
|
||||
// TODO: (KOTLIN-CR-2079)
|
||||
// - User defined extension functions Any?.toString() call can be lost during lowering.
|
||||
// - Use direct method call for dynamic types???
|
||||
// - Define Any?.toString() in runtime library and stop intrincifying extensions
|
||||
|
||||
if (call.valueArgumentsCount > 0)
|
||||
return false
|
||||
|
||||
val receiverParameterType = with(call.symbol.owner) {
|
||||
dispatchReceiverParameter ?: extensionReceiverParameter
|
||||
}?.type ?: return false
|
||||
|
||||
return receiverParameterType.run {
|
||||
isArray() || isAny() || isNullable() || this is IrDynamicType || isString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldReplaceToStringWithRuntimeCall(call: IrCall): Boolean {
|
||||
// TODO: (KOTLIN-CR-2079)
|
||||
// - User defined extension functions Any?.toString() call can be lost during lowering.
|
||||
// - Use direct method call for dynamic types???
|
||||
// - Define Any?.toString() in runtime library and stop intrincifying extensions
|
||||
enum class PrimitiveType {
|
||||
FLOATING_POINT_NUMBER,
|
||||
INTEGER_NUMBER,
|
||||
STRING,
|
||||
BOOLEAN,
|
||||
OTHER
|
||||
}
|
||||
|
||||
if (call.valueArgumentsCount > 0)
|
||||
return false
|
||||
|
||||
val receiverParameterType = with(call.symbol.owner) {
|
||||
dispatchReceiverParameter ?: extensionReceiverParameter
|
||||
}?.type ?: return false
|
||||
|
||||
return receiverParameterType.run {
|
||||
isArray() || isAny() || isNullable() || this is IrDynamicType || isString()
|
||||
fun IrType.getPrimitiveType() = makeNotNull().run {
|
||||
when {
|
||||
isBoolean() -> PrimitiveType.BOOLEAN
|
||||
isByte() || isShort() || isInt() -> PrimitiveType.INTEGER_NUMBER
|
||||
isFloat() || isDouble() -> PrimitiveType.FLOATING_POINT_NUMBER
|
||||
isString() -> PrimitiveType.STRING
|
||||
else -> PrimitiveType.OTHER
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldReplaceCompareToWithRuntimeCall(call: IrCall): Boolean {
|
||||
// TODO: Replace all compareTo to with runtime call when Comparable<*>.compareTo() bridge is implemented
|
||||
return call.symbol.owner.dispatchReceiverParameter?.run {
|
||||
type is IrDynamicType
|
||||
|| type.isJsNumber()
|
||||
|| type.isNullableJsNumber()
|
||||
|| type.isBoolean() || type.isNullableBoolean()
|
||||
|| type.isString() || type.isNullableString()
|
||||
} ?: false
|
||||
}
|
||||
|
||||
/*
|
||||
Equality translation table:
|
||||
|
||||
| | JsN | JsN? | Long | Long? | Bool | Bool? | String | String? | Other | Other? |
|
||||
|----------------|------|------|------|-------|------|-------|--------|---------|-------|--------|
|
||||
| JsN | === | === | == | == | === | === | === | === | K.eq | K.eq |
|
||||
| JsN? | === | == | == | == | === | K.eq | === | K.eq | K.eq | K.eq |
|
||||
| Long | == | == | K.eq | K.eq | === | === | === | === | K.eq | K.eq |
|
||||
| Long? | == | == | K.eq | K.eq | === | K.eq | === | K.eq | K.eq | K.eq |
|
||||
| Bool | === | === | === | === | === | === | === | === | K.eq | K.eq |
|
||||
| Bool? | === | K.eq | === | K.eq | === | == | === | K.eq | K.eq | K.eq |
|
||||
| String | === | === | === | === | === | === | === | === | K.eq | K.eq |
|
||||
| String? | === | K.eq | === | K.eq | === | K.eq | === | == | K.eq | K.eq |
|
||||
| Other with .eq | .eq | .eq | .eq | .eq | .eq | .eq | .eq | .eq | .eq | .eq |
|
||||
| Other w/o .eq | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq |
|
||||
| Other? | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq | K.eq |
|
||||
|
||||
|
||||
JsNumber -- type lowered to JS Number
|
||||
K.eq -- runtime library call
|
||||
.eq -- .equals(x) method call
|
||||
|
||||
*/
|
||||
|
||||
sealed class EqualityLoweringType
|
||||
object IdentityOperator : EqualityLoweringType()
|
||||
object EqualityOperator : EqualityLoweringType()
|
||||
object RuntimeFunctionCall : EqualityLoweringType()
|
||||
object RuntimeOrMethodCall : EqualityLoweringType()
|
||||
|
||||
fun translateEquals(lhs: IrType, rhs: IrType): EqualityLoweringType = when {
|
||||
lhs is IrDynamicType -> EqualityOperator
|
||||
lhs.isJsNumber() -> translateEqualsForJsNumber(rhs)
|
||||
lhs.isNullableJsNumber() -> translateEqualsForNullableJsNumber(rhs)
|
||||
lhs.isLong() -> translateEqualsForLong(rhs)
|
||||
lhs.isNullableLong() -> translateEqualsForNullableLong(rhs)
|
||||
lhs.isBoolean() -> translateEqualsForBoolean(rhs)
|
||||
lhs.isNullableBoolean() -> translateEqualsForNullableBoolean(rhs)
|
||||
lhs.isString() -> translateEqualsForString(rhs)
|
||||
lhs.isNullableString() -> translateEqualsForNullableString(rhs)
|
||||
// TODO: Fix unbound symbols (in inline)
|
||||
lhs.toKotlinType().isNullable() -> RuntimeFunctionCall
|
||||
else -> RuntimeOrMethodCall
|
||||
}
|
||||
|
||||
fun translateEqualsForJsNumber(rhs: IrType): EqualityLoweringType = when {
|
||||
rhs.isJsNumber() || rhs.isNullableJsNumber() -> IdentityOperator
|
||||
rhs.isLong() || rhs.isNullableLong() -> EqualityOperator
|
||||
rhs.isBoolean() || rhs.isNullableBoolean() -> IdentityOperator
|
||||
rhs.isString() || rhs.isNullableString() -> IdentityOperator
|
||||
else -> RuntimeFunctionCall
|
||||
}
|
||||
|
||||
fun translateEqualsForNullableJsNumber(rhs: IrType): EqualityLoweringType = when {
|
||||
rhs.isJsNumber() -> IdentityOperator
|
||||
rhs.isNullableJsNumber() -> EqualityOperator
|
||||
rhs.isLong() || rhs.isNullableLong() -> EqualityOperator
|
||||
rhs.isBoolean() || rhs.isString() -> IdentityOperator
|
||||
else -> RuntimeFunctionCall
|
||||
}
|
||||
|
||||
fun translateEqualsForLong(rhs: IrType): EqualityLoweringType = when {
|
||||
rhs.isJsNumber() || rhs.isNullableJsNumber() -> EqualityOperator
|
||||
rhs.isLong() || rhs.isNullableLong() -> RuntimeFunctionCall
|
||||
rhs.isBoolean() || rhs.isNullableBoolean() -> IdentityOperator
|
||||
rhs.isString() || rhs.isNullableString() -> IdentityOperator
|
||||
else -> RuntimeFunctionCall
|
||||
}
|
||||
|
||||
fun translateEqualsForNullableLong(rhs: IrType): EqualityLoweringType = when {
|
||||
rhs.isJsNumber() || rhs.isNullableJsNumber() -> EqualityOperator
|
||||
rhs.isLong() || rhs.isNullableLong() -> RuntimeFunctionCall
|
||||
rhs.isBoolean() -> IdentityOperator
|
||||
rhs.isString() -> IdentityOperator
|
||||
else -> RuntimeFunctionCall
|
||||
}
|
||||
|
||||
fun translateEqualsForBoolean(rhs: IrType): EqualityLoweringType = when {
|
||||
rhs.isJsNumber() || rhs.isNullableJsNumber() -> IdentityOperator
|
||||
rhs.isLong() || rhs.isNullableLong() -> IdentityOperator
|
||||
rhs.isBoolean() || rhs.isNullableBoolean() -> IdentityOperator
|
||||
rhs.isString() || rhs.isNullableString() -> IdentityOperator
|
||||
else -> RuntimeFunctionCall
|
||||
}
|
||||
|
||||
fun translateEqualsForNullableBoolean(rhs: IrType): EqualityLoweringType = when {
|
||||
rhs.isJsNumber() -> IdentityOperator
|
||||
rhs.isNullableJsNumber() -> RuntimeFunctionCall
|
||||
rhs.isLong() -> IdentityOperator
|
||||
rhs.isNullableLong() -> RuntimeFunctionCall
|
||||
rhs.isBoolean() -> IdentityOperator
|
||||
rhs.isNullableBoolean() -> EqualityOperator
|
||||
rhs.isString() -> IdentityOperator
|
||||
else -> RuntimeFunctionCall
|
||||
}
|
||||
|
||||
fun translateEqualsForString(rhs: IrType): EqualityLoweringType = when {
|
||||
rhs.isJsNumber() || rhs.isNullableJsNumber() -> IdentityOperator
|
||||
rhs.isLong() || rhs.isNullableLong() -> IdentityOperator
|
||||
rhs.isBoolean() || rhs.isNullableBoolean() -> IdentityOperator
|
||||
rhs.isString() || rhs.isNullableString() -> IdentityOperator
|
||||
else -> RuntimeFunctionCall
|
||||
}
|
||||
|
||||
fun translateEqualsForNullableString(rhs: IrType): EqualityLoweringType = when {
|
||||
rhs.isJsNumber() -> IdentityOperator
|
||||
rhs.isNullableJsNumber() -> RuntimeFunctionCall
|
||||
rhs.isLong() -> IdentityOperator
|
||||
rhs.isNullableLong() -> RuntimeFunctionCall
|
||||
rhs.isBoolean() -> IdentityOperator
|
||||
rhs.isNullableBoolean() -> RuntimeFunctionCall
|
||||
rhs.isString() -> IdentityOperator
|
||||
rhs.isNullableString() -> EqualityOperator
|
||||
else -> RuntimeFunctionCall
|
||||
}
|
||||
|
||||
private fun IrType.isNullableJsNumber(): Boolean = isNullablePrimitiveType() && !isNullableLong() && !isNullableChar()
|
||||
|
||||
private fun IrType.isJsNumber(): Boolean = isPrimitiveType() && !isLong() && !isChar()
|
||||
|
||||
private fun MemberToTransformer.op(type: IrType, name: Name, v: IrSimpleFunctionSymbol) {
|
||||
op(type, name, v = { irCall(it, v, dispatchReceiverAsFirstArgument = true) })
|
||||
}
|
||||
@@ -723,6 +647,12 @@ private fun SymbolToTransformer.add(from: Map<SimpleType, IrSimpleFunction>, to:
|
||||
}
|
||||
}
|
||||
|
||||
private fun SymbolToTransformer.add(from: Map<SimpleType, IrSimpleFunction>, to: (IrCall) -> IrExpression) {
|
||||
from.forEach { _, func ->
|
||||
add(func.symbol, to)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SymbolToTransformer.add(from: IrFunctionSymbol, to: (IrCall) -> IrExpression) {
|
||||
put(from, to)
|
||||
}
|
||||
@@ -780,4 +710,4 @@ private val IrClassSymbol.sizeConstructor
|
||||
get() = owner.declarations.filterIsInstance<IrConstructor>().first { it.valueParameters.size == 1 }.symbol
|
||||
|
||||
private val IrClassSymbol.lengthProperty
|
||||
get() = owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "length" }.getter!!.symbol
|
||||
get() = owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "length" }.getter!!.symbol
|
||||
|
||||
@@ -60,6 +60,8 @@ fun IrType.isFloat(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._floa
|
||||
fun IrType.isDouble(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._double)
|
||||
fun IrType.isNumber(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.number)
|
||||
|
||||
fun IrType.isComparable(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.comparable.toUnsafe())
|
||||
|
||||
fun IrType.isNullableBoolean(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._boolean)
|
||||
fun IrType.isNullableLong(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._long)
|
||||
fun IrType.isNullableChar(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._char)
|
||||
|
||||
Reference in New Issue
Block a user