[JS IR BE] hashCode, toString, number conversion support

This commit is contained in:
Svyatoslav Kuzmich
2018-06-13 15:54:34 +03:00
parent a7a695f203
commit 83f8cfaa66
73 changed files with 602 additions and 108 deletions
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.types.Variance
class JsIntrinsics(
private val module: ModuleDescriptor,
private val irBuiltIns: IrBuiltIns,
context: JsIrBackendContext
val context: JsIrBackendContext
) {
private val stubBuilder = DeclarationStubGenerator(module, context.symbolTable, JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB)
@@ -89,15 +89,35 @@ class JsIntrinsics(
val jsTypeOf = unOp("jsTypeOf", irBuiltIns.string)
// Number conversions:
val jsAsIs = getInternalFunction("asIs") // as-is conversion. Call can be replaced with first paramenter
val jsNumberToByte = getInternalFunction("numberToByte")
val jsNumberToDouble = getInternalFunction("numberToDouble")
val jsNumberToInt = getInternalFunction("numberToInt")
val jsNumberToShort = getInternalFunction("numberToShort")
val jsToByte = getInternalFunction("toByte")
val jsToShort = getInternalFunction("toShort")
// Other:
val jsObjectCreate = defineObjectCreateIntrinsic() // Object.create
val jsSetJSField = defineSetJSPropertyIntrinsic() // till we don't have dynamic type we use intrinsic which sets a field with any name
val jsToJsType = defineToJsType() // creates name reference to KotlinType
val jsCode = context.getInternalFunctions("js").singleOrNull()?.let { context.symbolTable.referenceFunction(it) } // js("<code>")
val jsCode = getInternalFunction("js") // js("<code>")
val jsHashCode = getInternalFunction("hashCode")
val jsToString = getInternalFunction("toString")
val jsCompareTo = getInternalFunction("compareTo")
val jsEquals = getInternalFunction("equals")
// Helpers:
private fun getInternalFunction(name: String) =
context.symbolTable.referenceSimpleFunction(context.getInternalFunctions(name).single())
private fun defineToJsType(): IrSimpleFunction {
val desc = SimpleFunctionDescriptorImpl.create(
module,
@@ -6,11 +6,14 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.utils.isNullable
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOfClass
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
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.backend.js.utils.isFakeOverriddenFromAny
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
@@ -19,19 +22,23 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.SimpleType
class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileLoweringPass {
private val intrinsics = context.intrinsics
private val irBuiltIns = context.irBuiltIns
// TODO: should/can we unify these maps?
private val memberToTransformer: Map<SimpleMemberKey, (IrCall) -> IrCall>
private val memberToIrFunction: Map<SimpleMemberKey, IrSimpleFunction>
private val memberToTransformer: Map<SimpleMemberKey, (IrCall) -> IrExpression>
private val memberToIrFunction: Map<SimpleMemberKey, IrSimpleFunctionSymbol>
private val symbolToIrFunction: Map<IrFunctionSymbol, IrSimpleFunction>
private val nameToIrTransformer: Map<Name, (IrCall) -> IrCall>
private val nameToIrTransformer: Map<Name, (IrCall) -> IrExpression>
init {
memberToIrFunction = mutableMapOf()
@@ -43,65 +50,100 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
memberToIrFunction.run {
for (type in primitiveNumbers) {
op(type, OperatorNames.UNARY_PLUS, context.intrinsics.jsUnaryPlus)
op(type, OperatorNames.UNARY_MINUS, context.intrinsics.jsUnaryMinus)
op(type, OperatorNames.UNARY_PLUS, intrinsics.jsUnaryPlus)
op(type, OperatorNames.UNARY_MINUS, intrinsics.jsUnaryMinus)
op(type, OperatorNames.ADD, context.intrinsics.jsPlus)
op(type, OperatorNames.SUB, context.intrinsics.jsMinus)
op(type, OperatorNames.MUL, context.intrinsics.jsMult)
op(type, OperatorNames.DIV, context.intrinsics.jsDiv)
op(type, OperatorNames.MOD, context.intrinsics.jsMod)
op(type, OperatorNames.REM, context.intrinsics.jsMod)
op(type, OperatorNames.ADD, intrinsics.jsPlus)
op(type, OperatorNames.SUB, intrinsics.jsMinus)
op(type, OperatorNames.MUL, intrinsics.jsMult)
op(type, OperatorNames.DIV, intrinsics.jsDiv)
op(type, OperatorNames.MOD, intrinsics.jsMod)
op(type, OperatorNames.REM, intrinsics.jsMod)
}
context.irBuiltIns.stringType.let {
op(it, OperatorNames.ADD, context.intrinsics.jsPlus)
irBuiltIns.stringType.let {
op(it, OperatorNames.ADD, intrinsics.jsPlus)
}
context.irBuiltIns.intType.let {
op(it, OperatorNames.SHL, context.intrinsics.jsBitShiftL)
op(it, OperatorNames.SHR, context.intrinsics.jsBitShiftR)
op(it, OperatorNames.SHRU, context.intrinsics.jsBitShiftRU)
op(it, OperatorNames.AND, context.intrinsics.jsBitAnd)
op(it, OperatorNames.OR, context.intrinsics.jsBitOr)
op(it, OperatorNames.XOR, context.intrinsics.jsBitXor)
op(it, OperatorNames.INV, context.intrinsics.jsBitNot)
irBuiltIns.intType.let {
op(it, OperatorNames.SHL, intrinsics.jsBitShiftL)
op(it, OperatorNames.SHR, intrinsics.jsBitShiftR)
op(it, OperatorNames.SHRU, intrinsics.jsBitShiftRU)
op(it, OperatorNames.AND, intrinsics.jsBitAnd)
op(it, OperatorNames.OR, intrinsics.jsBitOr)
op(it, OperatorNames.XOR, intrinsics.jsBitXor)
op(it, OperatorNames.INV, intrinsics.jsBitNot)
}
context.irBuiltIns.booleanType.let {
op(it, OperatorNames.AND, context.intrinsics.jsBitAnd)
op(it, OperatorNames.OR, context.intrinsics.jsBitOr)
op(it, OperatorNames.NOT, context.intrinsics.jsNot)
op(it, OperatorNames.XOR, context.intrinsics.jsBitXor)
irBuiltIns.booleanType.let {
op(it, OperatorNames.AND, intrinsics.jsBitAnd)
op(it, OperatorNames.OR, intrinsics.jsBitOr)
op(it, OperatorNames.NOT, intrinsics.jsNot)
op(it, OperatorNames.XOR, intrinsics.jsBitXor)
}
// Conversion rules are ported from NumberAndCharConversionFIF
// TODO: Add Char, Long and Number conversions
irBuiltIns.byteType.let {
op(it, ConversionNames.TO_BYTE, intrinsics.jsAsIs)
op(it, ConversionNames.TO_DOUBLE, intrinsics.jsAsIs)
op(it, ConversionNames.TO_FLOAT, intrinsics.jsAsIs)
op(it, ConversionNames.TO_INT, intrinsics.jsAsIs)
op(it, ConversionNames.TO_SHORT, intrinsics.jsAsIs)
}
for (type in listOf(irBuiltIns.floatType, irBuiltIns.doubleType)) {
op(type, ConversionNames.TO_BYTE, intrinsics.jsNumberToByte)
op(type, ConversionNames.TO_DOUBLE, intrinsics.jsAsIs)
op(type, ConversionNames.TO_FLOAT, intrinsics.jsAsIs)
op(type, ConversionNames.TO_INT, intrinsics.jsNumberToInt)
op(type, ConversionNames.TO_SHORT, intrinsics.jsNumberToShort)
}
irBuiltIns.intType.let {
op(it, ConversionNames.TO_BYTE, intrinsics.jsToByte)
op(it, ConversionNames.TO_DOUBLE, intrinsics.jsAsIs)
op(it, ConversionNames.TO_FLOAT, intrinsics.jsAsIs)
op(it, ConversionNames.TO_INT, intrinsics.jsAsIs)
op(it, ConversionNames.TO_SHORT, intrinsics.jsToShort)
}
irBuiltIns.shortType.let {
op(it, ConversionNames.TO_BYTE, intrinsics.jsToByte)
op(it, ConversionNames.TO_DOUBLE, intrinsics.jsAsIs)
op(it, ConversionNames.TO_FLOAT, intrinsics.jsAsIs)
op(it, ConversionNames.TO_INT, intrinsics.jsAsIs)
op(it, ConversionNames.TO_SHORT, intrinsics.jsAsIs)
}
}
symbolToIrFunction.run {
add(context.irBuiltIns.eqeqeqSymbol, context.intrinsics.jsEqeqeq)
add(irBuiltIns.eqeqeqSymbol, intrinsics.jsEqeqeq)
// TODO: implement it a right way
add(context.irBuiltIns.eqeqSymbol, context.intrinsics.jsEqeq)
add(irBuiltIns.eqeqSymbol, intrinsics.jsEqeq)
// TODO: implement it a right way
add(context.irBuiltIns.ieee754equalsFunByOperandType, context.intrinsics.jsEqeqeq)
add(irBuiltIns.ieee754equalsFunByOperandType, intrinsics.jsEqeqeq)
add(context.irBuiltIns.booleanNotSymbol, context.intrinsics.jsNot)
add(irBuiltIns.booleanNotSymbol, intrinsics.jsNot)
add(context.irBuiltIns.lessFunByOperandType, context.intrinsics.jsLt)
add(context.irBuiltIns.lessOrEqualFunByOperandType, context.intrinsics.jsLtEq)
add(context.irBuiltIns.greaterFunByOperandType, context.intrinsics.jsGt)
add(context.irBuiltIns.greaterOrEqualFunByOperandType, context.intrinsics.jsGtEq)
add(irBuiltIns.lessFunByOperandType, intrinsics.jsLt)
add(irBuiltIns.lessOrEqualFunByOperandType, intrinsics.jsLtEq)
add(irBuiltIns.greaterFunByOperandType, intrinsics.jsGt)
add(irBuiltIns.greaterOrEqualFunByOperandType, intrinsics.jsGtEq)
}
memberToTransformer.run {
for (type in primitiveNumbers) {
// TODO: use increment and decrement when it's possible
op(type, OperatorNames.INC) {
irCall(it, context.intrinsics.jsPlus.symbol, dispatchReceiverAsFirstArgument = true).apply {
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, 1))
irCall(it, intrinsics.jsPlus.symbol, dispatchReceiverAsFirstArgument = true).apply {
putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, 1))
}
}
op(type, OperatorNames.DEC) {
irCall(it, context.intrinsics.jsMinus.symbol, dispatchReceiverAsFirstArgument = true).apply {
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, 1))
irCall(it, intrinsics.jsMinus.symbol, dispatchReceiverAsFirstArgument = true).apply {
putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, 1))
}
}
}
@@ -124,6 +166,24 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kPropertyClass) } ?: false},
{ call -> irCall(call, context.intrinsics.jsPropertySet.symbol, dispatchReceiverAsFirstArgument = true)}
)
addWithPredicate(
Name.identifier("hashCode"),
{ call -> (call.superQualifier == null) && (call.symbol.owner.descriptor.isFakeOverriddenFromAny()) },
{ call -> irCall(call, intrinsics.jsHashCode, dispatchReceiverAsFirstArgument = true) }
)
addWithPredicate(
Name.identifier("toString"), ::shouldReplaceToStringWithRuntimeCall,
{ call -> irCall(call, intrinsics.jsToString, dispatchReceiverAsFirstArgument = true) }
)
addWithPredicate(
Name.identifier("compareTo"), ::shouldReplaceCompareToWithRuntimeCall,
{ call -> irCall(call, intrinsics.jsCompareTo, dispatchReceiverAsFirstArgument = true) }
)
put(Name.identifier("equals"), ::transformEquals)
}
}
@@ -146,8 +206,11 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
val key = SimpleMemberKey(it.type, symbol.owner.name)
memberToIrFunction[key]?.let {
if (it == intrinsics.jsAsIs) {
return call.dispatchReceiver!!
}
// TODO: don't apply intrinsics when type of receiver or argument is Long
return irCall(call, it.symbol, dispatchReceiverAsFirstArgument = true)
return irCall(call, it, dispatchReceiverAsFirstArgument = true)
}
memberToTransformer[key]?.let {
@@ -159,17 +222,156 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
return it(call)
}
}
}
return call
}
}, null)
}
private fun transformEquals(call: IrCall): IrExpression {
if (call.superQualifier != null) return call
val symbol = call.symbol
if (!symbol.isBound) return call
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.descriptor.isFakeOverriddenFromAny()) {
irCall(call, intrinsics.jsEquals, true)
} else {
call
}
}
}
}
fun shouldReplaceToStringWithRuntimeCall(call: IrCall): Boolean {
if (call.superQualifier != null) return false
// 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
val receiverParameterType = with(call.symbol.owner) {
dispatchReceiverParameter ?: extensionReceiverParameter
}?.type ?: return false
return receiverParameterType.run {
this.isArray() ||
this.isAny() || this.isNullable() || this is IrDynamicType || this.isString()
}
}
fun shouldReplaceCompareToWithRuntimeCall(call: IrCall): Boolean {
if (call.superQualifier != null) return false
// 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? | Other | Other? |
|----------------|------|------|------|-------|------|-------|-------|--------|
| JsN | === | === | == | == | === | === | K.eq | K.eq |
| JsN? | === | == | == | == | === | 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 |
| Bool | === | === | === | === | === | === | K.eq | K.eq |
| Bool? | === | K.eq | === | K.eq | === | == | K.eq | K.eq |
| Other with .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 |
| Other? | 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
class IdentityOperator : EqualityLoweringType()
class EqualityOperator : EqualityLoweringType()
class RuntimeFunctionCall : EqualityLoweringType()
class RuntimeOrMethodCall : EqualityLoweringType()
fun translateEquals(lhs: IrType, rhs: IrType): EqualityLoweringType = when {
lhs.isJsNumber() -> translateEqualsForJsNumber(rhs)
lhs.isNullableJsNumber() -> translateEqualsForNullableJsNumber(rhs)
lhs.isLong() -> translateEqualsForLong(rhs)
lhs.isNullableLong() -> translateEqualsForNullableLong(rhs)
lhs.isBoolean() -> translateEqualsForBoolean(rhs)
lhs.isNullableBoolean() -> translateEqualsForNullableBoolean(rhs)
else -> RuntimeOrMethodCall()
}
fun translateEqualsForJsNumber(rhs: IrType): EqualityLoweringType = when {
rhs.isJsNumber() || rhs.isNullableJsNumber() -> IdentityOperator()
rhs.isLong() || rhs.isNullableLong() -> EqualityOperator()
rhs.isBoolean() || rhs.isNullableBoolean() -> IdentityOperator()
else -> RuntimeFunctionCall()
}
fun translateEqualsForNullableJsNumber(rhs: IrType): EqualityLoweringType = when {
rhs.isJsNumber() -> IdentityOperator()
rhs.isNullableJsNumber() -> EqualityOperator()
rhs.isLong() || rhs.isNullableLong() -> EqualityOperator()
rhs.isBoolean() -> IdentityOperator()
else -> RuntimeFunctionCall()
}
fun translateEqualsForLong(rhs: IrType): EqualityLoweringType = when {
rhs.isJsNumber() || rhs.isNullableJsNumber() -> EqualityOperator()
rhs.isLong() || rhs.isNullableLong() -> RuntimeFunctionCall()
rhs.isBoolean() || rhs.isNullableBoolean() -> IdentityOperator()
else -> RuntimeFunctionCall()
}
fun translateEqualsForNullableLong(rhs: IrType): EqualityLoweringType = when {
rhs.isJsNumber() || rhs.isNullableJsNumber() -> EqualityOperator()
rhs.isLong() || rhs.isNullableLong() -> RuntimeFunctionCall()
rhs.isBoolean() -> IdentityOperator()
else -> RuntimeFunctionCall()
}
fun translateEqualsForBoolean(rhs: IrType): EqualityLoweringType = when {
rhs.isJsNumber() || rhs.isNullableJsNumber() -> IdentityOperator()
rhs.isLong() || rhs.isNullableLong() -> IdentityOperator()
rhs.isBoolean() || rhs.isNullableBoolean() -> 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()
else -> RuntimeFunctionCall()
}
private fun IrType.isNullableJsNumber(): Boolean = isNullablePrimitiveType() && !isNullableLong()
private fun IrType.isJsNumber(): Boolean = isPrimitiveType() && !isLong()
// TODO extract to common place?
private fun irCall(call: IrCall, newSymbol: IrFunctionSymbol, dispatchReceiverAsFirstArgument: Boolean = false): IrCall =
fun irCall(call: IrCall, newSymbol: IrFunctionSymbol, dispatchReceiverAsFirstArgument: Boolean = false): IrCall =
call.run {
IrCallImpl(
startOffset,
@@ -204,10 +406,20 @@ private fun IrCall.copyTypeAndValueArgumentsFrom(call: IrCall, dispatchReceiverA
}
}
private fun <V> MutableMap<SimpleMemberKey, V>.op(type: IrType, name: Name, v: V) {
private fun MutableMap<SimpleMemberKey, IrSimpleFunctionSymbol>.op(type: IrType, name: Name, v: IrSimpleFunctionSymbol) {
put(SimpleMemberKey(type, name), v)
}
private fun MutableMap<SimpleMemberKey, IrSimpleFunctionSymbol>.op(type: IrType, name: Name, v: IrSimpleFunction) {
put(SimpleMemberKey(type, name), v.symbol)
}
private fun MutableMap<SimpleMemberKey, (IrCall) -> IrExpression>.op(type: IrType, name: Name, v: (IrCall) -> IrExpression) {
put(SimpleMemberKey(type, name), v)
}
// TODO issue: marked as unused, but used; rename works wrongly.
private fun <V> MutableMap<SimpleMemberKey, V>.op(type: IrType, name: String, v: V) {
put(SimpleMemberKey(type, Name.identifier(name)), v)
}
@@ -222,7 +434,7 @@ private fun <V> MutableMap<IrFunctionSymbol, V>.add(from: IrFunctionSymbol, to:
put(from, to)
}
private fun <K> MutableMap<K, (IrCall) -> IrCall>.addWithPredicate(from: K, predicate: (IrCall) -> Boolean, action: (IrCall) -> IrCall) {
private fun <K> MutableMap<K, (IrCall) -> IrExpression>.addWithPredicate(from: K, predicate: (IrCall) -> Boolean, action: (IrCall) -> IrExpression) {
put(from) { call: IrCall -> select({ predicate(call) }, { action(call) }, { call }) }
}
@@ -0,0 +1,18 @@
/*
* 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 org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.name.Name
object ConversionNames {
val TO_BYTE = Name.identifier("toByte")
val TO_CHAR = Name.identifier("toChar")
val TO_DOUBLE = Name.identifier("toDouble")
val TO_FLOAT = Name.identifier("toFloat")
val TO_INT = Name.identifier("toInt")
val TO_LONG = Name.identifier("toLong")
val TO_SHORT = Name.identifier("toShort")
}
@@ -62,4 +62,12 @@ val CallableMemberDescriptor.propertyIfAccessor
else this
val IrTypeParameter.isReified
get() = descriptor.isReified
get() = descriptor.isReified
// Return is method has no real implementation except fake overrides from Any
fun CallableMemberDescriptor.isFakeOverriddenFromAny(): Boolean {
if (kind.isReal) {
return (containingDeclaration is ClassDescriptor) && KotlinBuiltIns.isAny(containingDeclaration as ClassDescriptor)
}
return overriddenDescriptors.all { it.isFakeOverriddenFromAny() }
}
@@ -35,6 +35,7 @@ fun IrType.isAny(): Boolean = isBuiltInClassType(KotlinBuiltIns::isAny, hasQuest
fun IrType.isNullableAny(): Boolean = isBuiltInClassType(KotlinBuiltIns::isAny, hasQuestionMark = true)
fun IrType.isString(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.string)
fun IrType.isNullableString(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES.string)
fun IrType.isArray(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.array)
fun IrType.isNothing(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.nothing)
fun IrType.isPrimitiveType(): Boolean =
@@ -57,4 +58,7 @@ fun IrType.isInt(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._int)
fun IrType.isLong(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._long)
fun IrType.isFloat(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._float)
fun IrType.isDouble(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._double)
fun IrType.isNumber(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.number)
fun IrType.isNumber(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.number)
fun IrType.isNullableBoolean(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._boolean)
fun IrType.isNullableLong(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._long)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: NATIVE
fun equals1(a: Double, b: Double) = a.equals(b)
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS, NATIVE
fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
package test
interface TextField {
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
class KeySpan(val left: String) {
public fun matches(value : String) : Boolean {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
class A<in I>(init_o: I, private val init_k: I) {
private val o: I = init_o
private fun k(): I = init_k
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
data class A(val a: Boolean)
fun box() : String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
data class A(val a: Byte)
fun box() : String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
data class A(val a: Double)
fun box() : String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
data class A(val a: Float)
fun box() : String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
data class A(val a: Int)
fun box() : String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
data class A(val a: Short)
fun box() : String {
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
import kotlin.reflect.KProperty
var log = ""
@@ -15,4 +14,4 @@ var String.calc: String by UserDataProperty("K")
fun box(): String {
return "O".calc
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun <T> T.toPrefixedString(prefix: String = "", suffix: String="") = prefix + this.toString() + suffix
fun box() : String {
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
return justPrint(9.compareTo(4))
}
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
val foo1 = fun Any.(): String {
return "239" + this
}
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
fun Any.foo1() : ()-> String {
return { "239" + this }
}
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun foo(): Int {
val a = "test"
val b = "test"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun less1(a: Double, b: Double) = a.compareTo(b) == -1
fun less2(a: Double?, b: Double?) = a!!.compareTo(b!!) == -1
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun equals1(a: Double, b: Double) = a.equals(b)
fun equals2(a: Double?, b: Double?) = a!!.equals(b!!)
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
val plusZero: Double? = 0.0
val minusZero: Double = -0.0
@@ -1,5 +1,4 @@
// !LANGUAGE: +ProperIeee754Comparisons
// IGNORE_BACKEND: JS_IR
fun ne(x: Any, y: Any) = x is Double && y is Float && x != y
fun lt(x: Any, y: Any) = x is Double && y is Float && x < y
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
public fun box() : String {
var i : Short?
i = 10
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
if (12.toString().equals("13")) {
return "Fail"
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
var aByte: Byte? = 0
var bByte: Byte = 0
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun test(i: Int): Int {
return i
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun checkLess(x: Boolean, y: Boolean) = when {
x >= y -> "Fail $x >= $y"
!(x < y) -> "Fail !($x < $y)"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun checkLess(x: Double, y: Int) = when {
x >= y -> "Fail $x >= $y"
!(x < y) -> "Fail !($x < $y)"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
class A(val x: Int)
operator fun A.compareTo(other: A) = x.compareTo(other.x)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun checkLess(x: Int, y: Double) = when {
x >= y -> "Fail $x >= $y"
!(x < y) -> "Fail !($x < $y)"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit!
val nx: Byte? = 0.toByte()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit!
val nx: Short? = 0.toShort()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit!
val nx: Byte? = 0.toByte()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit!
val nx: Short? = 0.toShort()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit!
val nx: Any? = 0.toByte()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit!
val nx: Any? = 0.toShort()
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
val f : (Any) -> String = { it.toString() }
fun box() : String {
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
fun box() : String {
230?.toByte()?.hashCode()
9.hashCode()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun <T> assertEquals(a: T, b: T) {
if (a != b) throw AssertionError("$a != $b")
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
if (1 >= 1.9) return "Fail #1"
if (1.compareTo(1.1) >= 0) return "Fail #2"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// KT-3517 Can't call .equals() on a boolean
fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
object TestObject {
val testFloat: Float = 0.9999.toFloat()
val otherFloat: Float = 1.01.toFloat()
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
val _0 : Double = 0.0
val _0dbl : Double = 0.toDouble()
+1 -2
View File
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS_IR
inline fun <reified T> Any?.check(): Boolean {
return this is T
}
@@ -35,4 +34,4 @@ fun box(): String {
}
return "OK"
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
if (!foo(1.toByte())) return "fail 1"
if (!foo((1.toByte()).inc())) return "fail 2"