[JVM IR] Use reference equality when comparing enums.

This commit is contained in:
Mark Punzalan
2020-03-06 01:35:05 -08:00
committed by Alexander Udalov
parent a732e8f5fe
commit 368b0d9b0b
14 changed files with 82 additions and 7 deletions
@@ -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")
}
}
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
@@ -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")
@@ -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");
@@ -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");
@@ -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")
@@ -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");
@@ -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");