[JVM IR] Use reference equality when comparing enums.
This commit is contained in:
committed by
Alexander Udalov
parent
a732e8f5fe
commit
368b0d9b0b
@@ -240,8 +240,9 @@ class ObjectCompare(
|
||||
|
||||
companion object {
|
||||
fun getObjectCompareOpcode(opToken: IElementType): Int = when (opToken) {
|
||||
KtTokens.EQEQEQ -> IF_ACMPNE
|
||||
KtTokens.EXCLEQEQEQ -> IF_ACMPEQ
|
||||
// "==" and "!=" are here because enum values are compared using reference equality.
|
||||
KtTokens.EQEQEQ, KtTokens.EQEQ -> IF_ACMPNE
|
||||
KtTokens.EXCLEQEQEQ, KtTokens.EXCLEQ -> IF_ACMPEQ
|
||||
else -> throw UnsupportedOperationException("don't know how to generate this condjump")
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+5
@@ -9797,6 +9797,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18731_2.kt")
|
||||
public void testKt18731_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt20651.kt")
|
||||
public void testKt20651() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.isEnumClass
|
||||
import org.jetbrains.kotlin.ir.util.isEnumEntry
|
||||
import org.jetbrains.kotlin.ir.util.isNullConst
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
@@ -80,10 +82,14 @@ class Equals(val operator: IElementType) : IntrinsicMethod() {
|
||||
val leftType = with(codegen) { a.asmType }
|
||||
val rightType = with(codegen) { b.asmType }
|
||||
val opToken = expression.origin
|
||||
val aIsEnum = a.type.classOrNull?.owner?.run { isEnumClass || isEnumEntry } == true
|
||||
val bIsEnum = b.type.classOrNull?.owner?.run { isEnumClass || isEnumEntry } == true
|
||||
val useEquals = opToken !== IrStatementOrigin.EQEQEQ && opToken !== IrStatementOrigin.EXCLEQEQ &&
|
||||
// `==` is `equals` for objects and floating-point numbers. In the latter case, the difference
|
||||
// is that `equals` is a total order (-0 < +0 and NaN == NaN) and `===` is IEEE754-compliant.
|
||||
(!isPrimitive(leftType) || leftType != rightType || leftType == Type.FLOAT_TYPE || leftType == Type.DOUBLE_TYPE)
|
||||
// Reference equality can be used for enums.
|
||||
&& !aIsEnum && !bIsEnum
|
||||
return if (useEquals) {
|
||||
a.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType)
|
||||
b.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType)
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ enum class Bar {
|
||||
fun isOne(i: Bar) = i == Bar.ONE
|
||||
|
||||
fun box(): String {
|
||||
return when (isOne(Bar.ONE) && !isOne(Bar.TWO)) {
|
||||
return when (isOne(Bar.ONE) && !isOne(Bar.TWO) && Bar.ONE != Bar.TWO) {
|
||||
true -> "OK"
|
||||
else -> "Failure"
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
|
||||
enum class Bar {
|
||||
ONE {
|
||||
override fun toString(): String {
|
||||
if (this != TWO && this == ONE) return "OK" else return "FAIL"
|
||||
}
|
||||
},
|
||||
TWO;
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return Bar.ONE.toString()
|
||||
}
|
||||
+2
-4
@@ -1,6 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TODO KT-36772 Equality compaison between enums should use reference equality in JVM_IR
|
||||
|
||||
enum class Bar {
|
||||
ONE,
|
||||
TWO
|
||||
@@ -9,11 +6,12 @@ enum class Bar {
|
||||
fun isOne(i: Bar) = i == Bar.ONE
|
||||
|
||||
fun box(): String {
|
||||
return when (isOne(Bar.ONE) && !isOne(Bar.TWO)) {
|
||||
return when (isOne(Bar.ONE) && !isOne(Bar.TWO) && Bar.ONE != Bar.TWO) {
|
||||
true -> "OK"
|
||||
else -> "Failure"
|
||||
}
|
||||
}
|
||||
|
||||
// 1 IF_ACMPNE
|
||||
// 1 IF_ACMPEQ
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual \(Ljava/lang/Object;Ljava/lang/Object;\)Z
|
||||
@@ -0,0 +1,16 @@
|
||||
enum class Bar {
|
||||
ONE {
|
||||
override fun toString(): String {
|
||||
if (this != TWO && this == ONE) return "OK" else return "FAIL"
|
||||
}
|
||||
},
|
||||
TWO;
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return Bar.ONE.toString()
|
||||
}
|
||||
|
||||
// 1 IF_ACMPNE
|
||||
// 1 IF_ACMPEQ
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual \(Ljava/lang/Object;Ljava/lang/Object;\)Z
|
||||
+5
@@ -10942,6 +10942,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18731_2.kt")
|
||||
public void testKt18731_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt20651.kt")
|
||||
public void testKt20651() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
||||
|
||||
@@ -1801,6 +1801,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
public void testKt18731() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/enum/kt18731.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18731_2.kt")
|
||||
public void testKt18731_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/enum/kt18731_2.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/exclExcl")
|
||||
|
||||
+5
@@ -10942,6 +10942,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18731_2.kt")
|
||||
public void testKt18731_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt20651.kt")
|
||||
public void testKt20651() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
||||
|
||||
+5
@@ -9797,6 +9797,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18731_2.kt")
|
||||
public void testKt18731_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt20651.kt")
|
||||
public void testKt20651() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
||||
|
||||
+5
@@ -1756,6 +1756,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
public void testKt18731() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/enum/kt18731.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18731_2.kt")
|
||||
public void testKt18731_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/enum/kt18731_2.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/exclExcl")
|
||||
|
||||
Generated
+5
@@ -8417,6 +8417,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18731_2.kt")
|
||||
public void testKt18731_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt20651.kt")
|
||||
public void testKt20651() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
||||
|
||||
+5
@@ -8417,6 +8417,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18731_2.kt")
|
||||
public void testKt18731_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt18731_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt20651.kt")
|
||||
public void testKt20651() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
||||
|
||||
Reference in New Issue
Block a user