[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 {
|
companion object {
|
||||||
fun getObjectCompareOpcode(opToken: IElementType): Int = when (opToken) {
|
fun getObjectCompareOpcode(opToken: IElementType): Int = when (opToken) {
|
||||||
KtTokens.EQEQEQ -> IF_ACMPNE
|
// "==" and "!=" are here because enum values are compared using reference equality.
|
||||||
KtTokens.EXCLEQEQEQ -> IF_ACMPEQ
|
KtTokens.EQEQEQ, KtTokens.EQEQ -> IF_ACMPNE
|
||||||
|
KtTokens.EXCLEQEQEQ, KtTokens.EXCLEQ -> IF_ACMPEQ
|
||||||
else -> throw UnsupportedOperationException("don't know how to generate this condjump")
|
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");
|
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")
|
@TestMetadata("kt20651.kt")
|
||||||
public void testKt20651() throws Exception {
|
public void testKt20651() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
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.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.types.isNullable
|
import org.jetbrains.kotlin.ir.types.isNullable
|
||||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
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.ir.util.isNullConst
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
@@ -80,10 +82,14 @@ class Equals(val operator: IElementType) : IntrinsicMethod() {
|
|||||||
val leftType = with(codegen) { a.asmType }
|
val leftType = with(codegen) { a.asmType }
|
||||||
val rightType = with(codegen) { b.asmType }
|
val rightType = with(codegen) { b.asmType }
|
||||||
val opToken = expression.origin
|
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 &&
|
val useEquals = opToken !== IrStatementOrigin.EQEQEQ && opToken !== IrStatementOrigin.EXCLEQEQ &&
|
||||||
// `==` is `equals` for objects and floating-point numbers. In the latter case, the difference
|
// `==` 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.
|
// 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)
|
(!isPrimitive(leftType) || leftType != rightType || leftType == Type.FLOAT_TYPE || leftType == Type.DOUBLE_TYPE)
|
||||||
|
// Reference equality can be used for enums.
|
||||||
|
&& !aIsEnum && !bIsEnum
|
||||||
return if (useEquals) {
|
return if (useEquals) {
|
||||||
a.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType)
|
a.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType)
|
||||||
b.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 isOne(i: Bar) = i == Bar.ONE
|
||||||
|
|
||||||
fun box(): String {
|
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"
|
true -> "OK"
|
||||||
else -> "Failure"
|
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 {
|
enum class Bar {
|
||||||
ONE,
|
ONE,
|
||||||
TWO
|
TWO
|
||||||
@@ -9,11 +6,12 @@ enum class Bar {
|
|||||||
fun isOne(i: Bar) = i == Bar.ONE
|
fun isOne(i: Bar) = i == Bar.ONE
|
||||||
|
|
||||||
fun box(): String {
|
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"
|
true -> "OK"
|
||||||
else -> "Failure"
|
else -> "Failure"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1 IF_ACMPNE
|
// 1 IF_ACMPNE
|
||||||
|
// 1 IF_ACMPEQ
|
||||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual \(Ljava/lang/Object;Ljava/lang/Object;\)Z
|
// 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");
|
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")
|
@TestMetadata("kt20651.kt")
|
||||||
public void testKt20651() throws Exception {
|
public void testKt20651() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
||||||
|
|||||||
@@ -1801,6 +1801,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
public void testKt18731() throws Exception {
|
public void testKt18731() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/enum/kt18731.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/bytecodeText/exclExcl")
|
||||||
|
|||||||
+5
@@ -10942,6 +10942,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/enum/kt18731.kt");
|
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")
|
@TestMetadata("kt20651.kt")
|
||||||
public void testKt20651() throws Exception {
|
public void testKt20651() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
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");
|
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")
|
@TestMetadata("kt20651.kt")
|
||||||
public void testKt20651() throws Exception {
|
public void testKt20651() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
||||||
|
|||||||
+5
@@ -1756,6 +1756,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
|||||||
public void testKt18731() throws Exception {
|
public void testKt18731() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/enum/kt18731.kt");
|
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")
|
@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");
|
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")
|
@TestMetadata("kt20651.kt")
|
||||||
public void testKt20651() throws Exception {
|
public void testKt20651() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
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");
|
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")
|
@TestMetadata("kt20651.kt")
|
||||||
public void testKt20651() throws Exception {
|
public void testKt20651() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
runTest("compiler/testData/codegen/box/enum/kt20651.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user