From 35dfcb61bb892abdb1abe0ce5f03b630ed93c1b9 Mon Sep 17 00:00:00 2001 From: "vladislav.grechko" Date: Fri, 10 Mar 2023 18:15:09 +0100 Subject: [PATCH] Fix specialization of equality comparison calls for inline classes Receiver of equals() call should be checked instead of argument ^KT-57261: Fixed --- ...LightTreeBlackBoxCodegenTestGenerated.java | 6 ++++ .../FirPsiBlackBoxCodegenTestGenerated.java | 6 ++++ .../jvm/lower/JvmInlineClassLowering.kt | 35 +++++++++---------- .../codegen/box/inlineClasses/kt57261.kt | 19 ++++++++++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++++ 5 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 compiler/testData/codegen/box/inlineClasses/kt57261.kt 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 169197ab5f2..ba666377c35 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 @@ -22619,6 +22619,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr runTest("compiler/testData/codegen/box/inlineClasses/kt57242.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal()); } + @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 { 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 489c6ceda1e..cdc37c39737 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 @@ -22619,6 +22619,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo runTest("compiler/testData/codegen/box/inlineClasses/kt57242.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal()); } + @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 { 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 2d5a80f32ef..21f1bb8bbd1 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.builders.declarations.buildFun 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 @@ internal class JvmInlineClassLowering( 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 @@ internal class JvmInlineClassLowering( 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 00000000000..83a2d21ff1f --- /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 76150549d7e..a181cfecdec 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 @@ -22619,6 +22619,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inlineClasses/kt57242.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal()); } + @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 {