Fix specialization of equality comparison calls for inline classes
Receiver of equals() call should be checked instead of argument
^KT-57261: Fixed
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java
index a030bf1..49055d8 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java
@@ -22614,6 +22614,12 @@
}
@Test
+ @TestMetadata("kt57261.kt")
+ public void testKt57261() throws Exception {
+ runTest("compiler/testData/codegen/box/inlineClasses/kt57261.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
+ }
+
+ @Test
@TestMetadata("lateinitInlineClasses.kt")
public void testLateinitInlineClasses() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/lateinitInlineClasses.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java
index 8118349..6139f40 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java
@@ -22614,6 +22614,12 @@
}
@Test
+ @TestMetadata("kt57261.kt")
+ public void testKt57261() throws Exception {
+ runTest("compiler/testData/codegen/box/inlineClasses/kt57261.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
+ }
+
+ @Test
@TestMetadata("lateinitInlineClasses.kt")
public void testLateinitInlineClasses() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/lateinitInlineClasses.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
index 2d5a80f..21f1bb8 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
@@ -22,7 +22,6 @@
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
-import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.transformStatement
import org.jetbrains.kotlin.ir.types.*
@@ -335,11 +334,11 @@
coerceInlineClasses(arg, expression.symbol.owner.dispatchReceiverParameter!!.type, expression.type)
}
// Specialize calls to equals when the left argument is a value of inline class type.
- expression.isSpecializedInlineClassEqEq || expression.isSpecializedInlineClassEquals -> {
+ expression.isEqEqCallOnInlineClass || expression.isEqualsMethodCallOnInlineClass -> {
expression.transformChildrenVoid()
val leftOp: IrExpression
val rightOp: IrExpression
- if (expression.isSpecializedInlineClassEqEq) {
+ if (expression.isEqEqCallOnInlineClass) {
leftOp = expression.getValueArgument(0)!!
rightOp = expression.getValueArgument(1)!!
} else {
@@ -354,29 +353,29 @@
super.visitCall(expression)
}
- private val IrCall.isSpecializedInlineClassEquals: Boolean
+ private val IrCall.isEqualsMethodCallOnInlineClass: Boolean
get() {
- return isSpecializedInlineClassEqualityCheck { symbol.owner.isEquals() }
+ if (!symbol.owner.isEquals()) return false
+ val receiverClass = dispatchReceiver?.type?.classOrNull?.owner
+ return receiverClass?.canUseSpecializedEqMethod ?: false
}
- private val IrCall.isSpecializedInlineClassEqEq: Boolean
+ private val IrCall.isEqEqCallOnInlineClass: Boolean
get() {
// Note that reference equality (x === y) is not allowed on values of inline class type,
// so it is enough to check for eqeq.
- return isSpecializedInlineClassEqualityCheck { symbol == context.irBuiltIns.eqeqSymbol }
+ if (symbol != context.irBuiltIns.eqeqSymbol) return false
+ val leftOperandClass = getValueArgument(0)?.type?.classOrNull?.owner
+ return leftOperandClass?.canUseSpecializedEqMethod ?: false
}
- private inline fun IrCall.isSpecializedInlineClassEqualityCheck(calleePredicate: (IrSimpleFunctionSymbol) -> Boolean): Boolean {
-
- if (!calleePredicate(symbol)) return false
-
- val leftClass = getValueArgument(0)?.type?.classOrNull?.owner?.takeIf { it.isSingleFieldValueClass }
- ?: return false
-
- // Before version 1.4, we cannot rely on the Result.equals-impl0 method
- return (leftClass.fqNameWhenAvailable != StandardNames.RESULT_FQ_NAME) ||
- context.state.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4
- }
+ private val IrClass.canUseSpecializedEqMethod: Boolean
+ get() {
+ if (!isSingleFieldValueClass) return false
+ // Before version 1.4, we cannot rely on the Result.equals-impl0 method
+ return fqNameWhenAvailable != StandardNames.RESULT_FQ_NAME ||
+ context.state.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4
+ }
override fun visitGetField(expression: IrGetField): IrExpression {
val field = expression.symbol.owner
diff --git a/compiler/testData/codegen/box/inlineClasses/kt57261.kt b/compiler/testData/codegen/box/inlineClasses/kt57261.kt
new file mode 100644
index 0000000..83a2d21
--- /dev/null
+++ b/compiler/testData/codegen/box/inlineClasses/kt57261.kt
@@ -0,0 +1,19 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_STDLIB
+// WORKS_WHEN_VALUE_CLASS
+// LANGUAGE: +ValueClasses
+
+OPTIONAL_JVM_INLINE_ANNOTATION
+value class Ic(val x: Int)
+
+fun box(): String {
+
+ val strAsAny : Any = "a"
+
+ if ("a".equals(Ic(1))) return "Fail 1"
+ if (strAsAny.equals(Ic(1))) return "Fail 2"
+ if (Ic(1).equals("a")) return "Fail 3"
+ if (Ic(1).equals(strAsAny)) return "Fail 4"
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
index 6da1be1..47a4bbe 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
@@ -22614,6 +22614,12 @@
}
@Test
+ @TestMetadata("kt57261.kt")
+ public void testKt57261() throws Exception {
+ runTest("compiler/testData/codegen/box/inlineClasses/kt57261.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
+ }
+
+ @Test
@TestMetadata("lateinitInlineClasses.kt")
public void testLateinitInlineClasses() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/lateinitInlineClasses.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());