[FIR2IR] Fix applying of equals intrinsics

This commit is contained in:
Ivan Kochurkin
2021-10-13 17:35:30 +03:00
committed by TeamCityServer
parent 31507e7e7e
commit 15d23f2a72
11 changed files with 60 additions and 249 deletions
@@ -11,15 +11,14 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.isNullable
import org.jetbrains.kotlin.ir.builders.primitiveOp1
import org.jetbrains.kotlin.ir.builders.primitiveOp2
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isDoubleOrFloatWithoutNullability
import org.jetbrains.kotlin.ir.util.getSimpleFunction
internal class OperatorExpressionGenerator(
@@ -69,9 +68,13 @@ internal class OperatorExpressionGenerator(
val (symbol, origin) = getSymbolAndOriginForComparison(operation, comparisonIrType.classifierOrFail)
return primitiveOp2(
startOffset, endOffset, symbol!!, irBuiltIns.booleanType, origin,
visitor.convertToIrExpression(comparisonExpression.left).asComparisonOperand(comparisonInfo.leftType, comparisonType),
visitor.convertToIrExpression(comparisonExpression.right).asComparisonOperand(comparisonInfo.rightType, comparisonType),
startOffset,
endOffset,
symbol!!,
irBuiltIns.booleanType,
origin,
comparisonExpression.left.convertToIrExpression(comparisonInfo, isLeftType = true),
comparisonExpression.right.convertToIrExpression(comparisonInfo, isLeftType = false)
)
}
@@ -108,10 +111,15 @@ internal class OperatorExpressionGenerator(
val comparisonType = comparisonInfo?.comparisonType
val eqeqSymbol = comparisonType?.let { typeConverter.classIdToSymbolMap[it.lookupTag.classId] }
?.let { irBuiltIns.ieee754equalsFunByOperandType[it] } ?: irBuiltIns.eqeqSymbol
val equalsCall = primitiveOp2(
startOffset, endOffset, eqeqSymbol, irBuiltIns.booleanType, origin,
visitor.convertToIrExpression(arguments[0]).asComparisonOperand(comparisonInfo?.leftType, comparisonType),
visitor.convertToIrExpression(arguments[1]).asComparisonOperand(comparisonInfo?.rightType, comparisonType)
startOffset,
endOffset,
eqeqSymbol,
irBuiltIns.booleanType,
origin,
arguments[0].convertToIrExpression(comparisonInfo, isLeftType = true),
arguments[1].convertToIrExpression(comparisonInfo, isLeftType = false)
)
return if (operation == FirOperation.EQ) {
equalsCall
@@ -129,7 +137,10 @@ internal class OperatorExpressionGenerator(
else -> error("Not an identity operation: $operation")
}
val identityCall = primitiveOp2(
startOffset, endOffset, irBuiltIns.eqeqeqSymbol, irBuiltIns.booleanType, origin,
startOffset, endOffset,
irBuiltIns.eqeqeqSymbol,
irBuiltIns.booleanType,
origin,
visitor.convertToIrExpression(arguments[0]),
visitor.convertToIrExpression(arguments[1])
)
@@ -143,16 +154,43 @@ internal class OperatorExpressionGenerator(
private fun IrExpression.negate(origin: IrStatementOrigin) =
primitiveOp1(startOffset, endOffset, irBuiltIns.booleanNotSymbol, irBuiltIns.booleanType, origin, this)
private fun FirExpression.convertToIrExpression(
comparisonInfo: PrimitiveConeNumericComparisonInfo?,
isLeftType: Boolean
): IrExpression {
return visitor.convertToIrExpression(this).asComparisonOperand(
if (isLeftType) comparisonInfo?.leftType else comparisonInfo?.rightType,
comparisonInfo?.comparisonType,
noImplicitCast = comparisonInfo?.leftType == comparisonInfo?.rightType
)
}
private fun IrExpression.asComparisonOperand(
operandType: ConeClassLikeType?,
targetType: ConeClassLikeType?
targetType: ConeClassLikeType?,
noImplicitCast: Boolean
): IrExpression {
if (targetType == null) return this
fun eraseImplicitCast(): IrExpression {
return if (noImplicitCast &&
this is IrTypeOperatorCall &&
this.operator == IrTypeOperator.IMPLICIT_CAST &&
!this.type.isDoubleOrFloatWithoutNullability()
) {
this.argument
} else {
this
}
}
if (targetType == null) {
return eraseImplicitCast()
}
if (operandType == null) error("operandType should be non-null if targetType is non-null")
val operandClassId = operandType.lookupTag.classId
val targetClassId = targetType.lookupTag.classId
if (operandClassId == targetClassId) return this
if (operandClassId == targetClassId) return eraseImplicitCast()
val conversionFunction =
typeConverter.classIdToSymbolMap[operandClassId]?.getSimpleFunction("to${targetType.lookupTag.classId.shortClassName.asString()}")
?: error("No conversion function for $operandType ~> $targetType")
@@ -132,6 +132,10 @@ fun IrType.isULong(): Boolean = isNotNullClassType(IdSignatureValues.uLong)
fun IrType.isFloat(): Boolean = isNotNullClassType(IdSignatureValues._float)
fun IrType.isDouble(): Boolean = isNotNullClassType(IdSignatureValues._double)
fun IrType.isNumber(): Boolean = isNotNullClassType(IdSignatureValues.number)
fun IrType.isDoubleOrFloatWithoutNullability(): Boolean {
return isClassType(IdSignatureValues._double, hasQuestionMark = null) ||
isClassType(IdSignatureValues._float, hasQuestionMark = null)
}
fun IrType.isComparable(): Boolean = isNotNullClassType(IdSignatureValues.comparable)
fun IrType.isCharSequence(): Boolean = isNotNullClassType(IdSignatureValues.charSequence)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun equals3(a: Char?, b: Char?) = a != null && b != null && a == b
fun equals4(a: Char?, b: Char?) = if (a is Char && b is Char) a == b else null!!
@@ -1,5 +1,4 @@
// !LANGUAGE: +ProperIeee754Comparisons
// IGNORE_BACKEND_FIR: JVM_IR
fun equals3(a: Int?, b: Int?) = a != null && b != null && a == b
fun equals4(a: Int?, b: Int?) = if (a is Int && b is Int) a == b else null!!
@@ -1,5 +1,4 @@
// !LANGUAGE: -ProperIeee754Comparisons
// IGNORE_BACKEND_FIR: JVM_IR
fun equals3(a: Int?, b: Int?) = a != null && b != null && a == b
fun equals4(a: Int?, b: Int?) = if (a is Int && b is Int) a == b else null!!
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun equals3(a: Long?, b: Long?) = a != null && b != null && a == b
fun equals4(a: Long?, b: Long?) = if (a is Long && b is Long) a == b else null!!
@@ -1,163 +0,0 @@
FILE fqName:<root> fileName:/typeParameterWithPrimitiveNumericSupertype.kt
FUN name:test0 visibility:public modality:FINAL <T> (x:kotlin.Any, y:T of <root>.test0) returnType:kotlin.Boolean
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?]
VALUE_PARAMETER name:x index:0 type:kotlin.Any
VALUE_PARAMETER name:y index:1 type:T of <root>.test0
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test0 <T> (x: kotlin.Any, y: T of <root>.test0): kotlin.Boolean declared in <root>'
WHEN type=kotlin.Boolean origin=ANDAND
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test0' type=kotlin.Any origin=null
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test0' type=kotlin.Any origin=null
arg1: GET_VAR 'y: T of <root>.test0 declared in <root>.test0' type=T of <root>.test0 origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
FUN name:test1 visibility:public modality:FINAL <T> (x:kotlin.Any, y:T of <root>.test1) returnType:kotlin.Boolean
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Float]
VALUE_PARAMETER name:x index:0 type:kotlin.Any
VALUE_PARAMETER name:y index:1 type:T of <root>.test1
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test1 <T> (x: kotlin.Any, y: T of <root>.test1): kotlin.Boolean declared in <root>'
WHEN type=kotlin.Boolean origin=ANDAND
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Float
GET_VAR 'x: kotlin.Any declared in <root>.test1' type=kotlin.Any origin=null
then: CALL 'public final fun ieee754equals (arg0: kotlin.Float?, arg1: kotlin.Float?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
GET_VAR 'x: kotlin.Any declared in <root>.test1' type=kotlin.Any origin=null
arg1: GET_VAR 'y: T of <root>.test1 declared in <root>.test1' type=T of <root>.test1 origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
FUN name:test2 visibility:public modality:FINAL <T> (x:kotlin.Any, y:T of <root>.test2) returnType:kotlin.Boolean
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Double]
VALUE_PARAMETER name:x index:0 type:kotlin.Any
VALUE_PARAMETER name:y index:1 type:T of <root>.test2
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test2 <T> (x: kotlin.Any, y: T of <root>.test2): kotlin.Boolean declared in <root>'
WHEN type=kotlin.Boolean origin=ANDAND
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Float
GET_VAR 'x: kotlin.Any declared in <root>.test2' type=kotlin.Any origin=null
then: CALL 'public final fun ieee754equals (arg0: kotlin.Double?, arg1: kotlin.Double?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
GET_VAR 'x: kotlin.Any declared in <root>.test2' type=kotlin.Any origin=null
arg1: GET_VAR 'y: T of <root>.test2 declared in <root>.test2' type=T of <root>.test2 origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
FUN name:test3 visibility:public modality:FINAL <T> (x:kotlin.Any, y:T of <root>.test3) returnType:kotlin.Boolean
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Float]
VALUE_PARAMETER name:x index:0 type:kotlin.Any
VALUE_PARAMETER name:y index:1 type:T of <root>.test3
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test3 <T> (x: kotlin.Any, y: T of <root>.test3): kotlin.Boolean declared in <root>'
WHEN type=kotlin.Boolean origin=ANDAND
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test3' type=kotlin.Any origin=null
then: CALL 'public final fun ieee754equals (arg0: kotlin.Float?, arg1: kotlin.Float?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: CALL 'public open fun toFloat (): kotlin.Float declared in kotlin.Int' type=kotlin.Float origin=null
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test3' type=kotlin.Any origin=null
arg1: GET_VAR 'y: T of <root>.test3 declared in <root>.test3' type=T of <root>.test3 origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
FUN name:test4 visibility:public modality:FINAL <T> (x:kotlin.Any, y:T of <root>.test4) returnType:kotlin.Boolean
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Float?]
VALUE_PARAMETER name:x index:0 type:kotlin.Any
VALUE_PARAMETER name:y index:1 type:T of <root>.test4
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test4 <T> (x: kotlin.Any, y: T of <root>.test4): kotlin.Boolean declared in <root>'
WHEN type=kotlin.Boolean origin=ANDAND
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test4' type=kotlin.Any origin=null
then: CALL 'public final fun ieee754equals (arg0: kotlin.Float?, arg1: kotlin.Float?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: CALL 'public open fun toFloat (): kotlin.Float declared in kotlin.Int' type=kotlin.Float origin=null
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test4' type=kotlin.Any origin=null
arg1: GET_VAR 'y: T of <root>.test4 declared in <root>.test4' type=T of <root>.test4 origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
FUN name:test5 visibility:public modality:FINAL <T, R> (x:kotlin.Any, y:R of <root>.test5) returnType:kotlin.Boolean
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Float?]
TYPE_PARAMETER name:R index:1 variance: superTypes:[T of <root>.test5]
VALUE_PARAMETER name:x index:0 type:kotlin.Any
VALUE_PARAMETER name:y index:1 type:R of <root>.test5
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test5 <T, R> (x: kotlin.Any, y: R of <root>.test5): kotlin.Boolean declared in <root>'
WHEN type=kotlin.Boolean origin=ANDAND
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test5' type=kotlin.Any origin=null
then: CALL 'public final fun ieee754equals (arg0: kotlin.Float?, arg1: kotlin.Float?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: CALL 'public open fun toFloat (): kotlin.Float declared in kotlin.Int' type=kotlin.Float origin=null
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test5' type=kotlin.Any origin=null
arg1: GET_VAR 'y: R of <root>.test5 declared in <root>.test5' type=R of <root>.test5 origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
FUN name:test6 visibility:public modality:FINAL <T> (x:kotlin.Any, y:T of <root>.test6) returnType:kotlin.Boolean
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Number]
VALUE_PARAMETER name:x index:0 type:kotlin.Any
VALUE_PARAMETER name:y index:1 type:T of <root>.test6
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test6 <T> (x: kotlin.Any, y: T of <root>.test6): kotlin.Boolean declared in <root>'
WHEN type=kotlin.Boolean origin=ANDAND
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test6' type=kotlin.Any origin=null
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.test6' type=kotlin.Any origin=null
arg1: GET_VAR 'y: T of <root>.test6 declared in <root>.test6' type=T of <root>.test6 origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
CLASS CLASS name:F modality:FINAL visibility:public superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.F<T of <root>.F>
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Float]
CONSTRUCTOR visibility:public <> () returnType:<root>.F<T of <root>.F> [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:F modality:FINAL visibility:public superTypes:[kotlin.Any]'
FUN name:testCapturedType visibility:public modality:FINAL <> ($this:<root>.F<T of <root>.F>, x:T of <root>.F, y:kotlin.Any) returnType:kotlin.Boolean
$this: VALUE_PARAMETER name:<this> type:<root>.F<T of <root>.F>
VALUE_PARAMETER name:x index:0 type:T of <root>.F
VALUE_PARAMETER name:y index:1 type:kotlin.Any
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun testCapturedType (x: T of <root>.F, y: kotlin.Any): kotlin.Boolean declared in <root>.F'
WHEN type=kotlin.Boolean origin=ANDAND
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Double
GET_VAR 'y: kotlin.Any declared in <root>.F.testCapturedType' type=kotlin.Any origin=null
then: CALL 'public final fun ieee754equals (arg0: kotlin.Double?, arg1: kotlin.Double?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
$this: GET_VAR 'x: T of <root>.F declared in <root>.F.testCapturedType' type=T of <root>.F origin=null
arg1: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
GET_VAR 'y: kotlin.Any declared in <root>.F.testCapturedType' type=kotlin.Any origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
@@ -1,64 +0,0 @@
fun <T : Any?> test0(x: Any, y: T): Boolean {
return when {
x is Int -> EQEQ(arg0 = x /*as Int */, arg1 = y)
else -> false
}
}
fun <T : Float> test1(x: Any, y: T): Boolean {
return when {
x is Float -> ieee754equals(arg0 = x /*as Float */, arg1 = y)
else -> false
}
}
fun <T : Double> test2(x: Any, y: T): Boolean {
return when {
x is Float -> ieee754equals(arg0 = x /*as Float */.toDouble(), arg1 = y)
else -> false
}
}
fun <T : Float> test3(x: Any, y: T): Boolean {
return when {
x is Int -> ieee754equals(arg0 = x /*as Int */.toFloat(), arg1 = y)
else -> false
}
}
fun <T : Float?> test4(x: Any, y: T): Boolean {
return when {
x is Int -> ieee754equals(arg0 = x /*as Int */.toFloat(), arg1 = y)
else -> false
}
}
fun <T : Float?, R : T> test5(x: Any, y: R): Boolean {
return when {
x is Int -> ieee754equals(arg0 = x /*as Int */.toFloat(), arg1 = y)
else -> false
}
}
fun <T : Number> test6(x: Any, y: T): Boolean {
return when {
x is Int -> EQEQ(arg0 = x /*as Int */, arg1 = y)
else -> false
}
}
class F<T : Float> {
constructor() /* primary */ {
super/*Any*/()
/* <init>() */
}
fun testCapturedType(x: T, y: Any): Boolean {
return when {
y is Double -> ieee754equals(arg0 = x.toDouble(), arg1 = y /*as Double */)
else -> false
}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun <T> test0(x: Any, y: T) = x is Int && x == y
fun <T : Float> test1(x: Any, y: T) = x is Float && x == y
fun <T : Double> test2(x: Any, y: T) = x is Float && x == y
+2 -4
View File
@@ -58,10 +58,8 @@ FILE fqName:<root> fileName:/kt23030.kt
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'x: kotlin.Any declared in <root>.testEqualsWithSmartCast' type=kotlin.Any origin=null
arg1: TYPE_OP type=kotlin.Char origin=IMPLICIT_CAST typeOperand=kotlin.Char
GET_VAR 'y: kotlin.Any declared in <root>.testEqualsWithSmartCast' type=kotlin.Any origin=null
arg0: GET_VAR 'x: kotlin.Any declared in <root>.testEqualsWithSmartCast' type=kotlin.Any origin=null
arg1: GET_VAR 'y: kotlin.Any declared in <root>.testEqualsWithSmartCast' type=kotlin.Any origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: CONST Boolean type=kotlin.Boolean value=false
+2 -1
View File
@@ -21,7 +21,7 @@ fun testEqualsWithSmartCast(x: Any, y: Any): Boolean {
when {
x is Int -> y is Char
else -> false
} -> EQEQ(arg0 = x /*as Int */, arg1 = y /*as Char */)
} -> EQEQ(arg0 = x, arg1 = y)
else -> false
}
}
@@ -52,3 +52,4 @@ class C {
}
}