diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/BranchedValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/BranchedValue.kt index dd0125d3f03..9554c4639e0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/BranchedValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/BranchedValue.kt @@ -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") } } diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 87fec79f94f..94cb31e495c 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Equals.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Equals.kt index 6f67a784d10..6200c88d464 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Equals.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Equals.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) diff --git a/compiler/testData/codegen/box/enum/kt18731.kt b/compiler/testData/codegen/box/enum/kt18731.kt index bc98fc4c1b8..465457e31bc 100644 --- a/compiler/testData/codegen/box/enum/kt18731.kt +++ b/compiler/testData/codegen/box/enum/kt18731.kt @@ -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" } diff --git a/compiler/testData/codegen/box/enum/kt18731_2.kt b/compiler/testData/codegen/box/enum/kt18731_2.kt new file mode 100644 index 00000000000..efaf9415cea --- /dev/null +++ b/compiler/testData/codegen/box/enum/kt18731_2.kt @@ -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() +} diff --git a/compiler/testData/codegen/bytecodeText/enum/kt18731.kt b/compiler/testData/codegen/bytecodeText/enum/kt18731.kt index 5175ee2b5c0..fc2419b3e50 100644 --- a/compiler/testData/codegen/bytecodeText/enum/kt18731.kt +++ b/compiler/testData/codegen/bytecodeText/enum/kt18731.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/enum/kt18731_2.kt b/compiler/testData/codegen/bytecodeText/enum/kt18731_2.kt new file mode 100644 index 00000000000..11ff86eb780 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/enum/kt18731_2.kt @@ -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 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index d8c6c3752aa..98c4c22ff10 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 7f845ec31e6..e2aed9709bf 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -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") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 6313b271d00..8e288b5105c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 8528e335302..ae4920a8136 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index 2e6646faf5f..17ea2e3d5a3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -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") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 5d663b8c9da..bbec77763fa 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 9a2c698963b..d719c0c1446 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -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");