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 29a4f49ce71..3195b769fe4 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 @@ -28623,6 +28623,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusString.kt"); } + @Test + @TestMetadata("thisPlusStringWithObject.kt") + public void testThisPlusStringWithObject() throws Exception { + runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusStringWithObject.kt"); + } + @Test @TestMetadata("unsignedConst.kt") public void testUnsignedConst() 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 33eb7a05511..5b8c837b8d6 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 @@ -28623,6 +28623,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusString.kt"); } + @Test + @TestMetadata("thisPlusStringWithObject.kt") + public void testThisPlusStringWithObject() throws Exception { + runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusStringWithObject.kt"); + } + @Test @TestMetadata("unsignedConst.kt") public void testUnsignedConst() throws Exception { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index 96ea2df6ec1..08c4da7485e 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -305,11 +305,16 @@ internal fun IrClass.getSingleAbstractMethod(): IrFunction { } internal fun IrExpression?.isAccessToNotNullableObject(): Boolean { - if (this !is IrGetValue) return false - val owner = this.symbol.owner - val expectedClass = this.type.classOrNull?.owner - if (expectedClass == null || !expectedClass.isObject || this.type.isNullable()) return false - return owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER || owner.name.asString() == "" + return when (this) { + is IrGetObjectValue -> !this.type.isNullable() + is IrGetValue -> { + val owner = this.symbol.owner + val expectedClass = this.type.classOrNull?.owner + if (expectedClass == null || !expectedClass.isObject || this.type.isNullable()) return false + owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER || owner.name.asString() == "" + } + else -> false + } } internal fun IrFunction.isAccessorOfPropertyWithBackingField(): Boolean { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt index c4d93403202..01fb325760d 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt @@ -58,17 +58,18 @@ class IrInterpreterCommonChecker : IrInterpreterChecker { } override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean { + val owner = expression.symbol.owner + + if (expression.dispatchReceiver.isAccessToNotNullableObject() && expression.isGetterToConstVal()) { + return visitBodyIfNeeded(owner, data) + } + if (!data.mode.canEvaluateExpression(expression)) return false - val owner = expression.symbol.owner if (!data.mode.canEvaluateFunction(owner)) return false if (expression.isKCallableNameCall(data.irBuiltIns) || expression.isEnumName()) return true - if (expression.dispatchReceiver.isAccessToNotNullableObject()) { - return expression.isGetterToConstVal() - } - val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, data) ?: true val extensionReceiverComputable = expression.extensionReceiver?.accept(this, data) ?: true if (!visitValueArguments(expression, data)) return false @@ -146,8 +147,7 @@ class IrInterpreterCommonChecker : IrInterpreterChecker { } override fun visitGetObjectValue(expression: IrGetObjectValue, data: IrInterpreterCheckerData): Boolean { - // to get object value we need nothing, but it will contain only fields with compile time annotation - return true + return data.mode.canEvaluateExpression(expression) } override fun visitGetEnumValue(expression: IrGetEnumValue, data: IrInterpreterCheckerData): Boolean { @@ -185,7 +185,7 @@ class IrInterpreterCommonChecker : IrInterpreterChecker { expression.receiver == null -> property?.isConst == true && owner.initializer?.accept(this, data) == true owner.origin == IrDeclarationOrigin.PROPERTY_BACKING_FIELD && property?.isConst == true -> { val receiverComputable = (expression.receiver?.accept(this, data) ?: true) - || expression.isAccessToNotNullableObject() + || expression.receiver.isAccessToNotNullableObject() val initializerComputable = owner.initializer?.accept(this, data) ?: false receiverComputable && initializerComputable } diff --git a/compiler/testData/codegen/box/involvesIrInterpreter/stringOperations.kt b/compiler/testData/codegen/box/involvesIrInterpreter/stringOperations.kt index f8a5322c950..7693979d459 100644 --- a/compiler/testData/codegen/box/involvesIrInterpreter/stringOperations.kt +++ b/compiler/testData/codegen/box/involvesIrInterpreter/stringOperations.kt @@ -1,15 +1,18 @@ // TARGET_BACKEND: JVM_IR // TARGET_BACKEND: NATIVE // TARGET_BACKEND: JS_IR +// WITH_STDLIB fun T.id() = this const val someStr = "123" const val otherStr = "other" const val oneVal = 1 +const val oneUnsignedVal = 1u const val plus1 = someStr.plus(otherStr) const val plus2 = someStr.plus(oneVal) +const val plus3 = someStr.plus(oneUnsignedVal) const val length1 = someStr.length const val length2 = otherStr.length @@ -31,6 +34,7 @@ const val toString1 = someStr.toString() fun box(): String { if (plus1.id() != "123other") return "Fail 1.1" if (plus2.id() != "1231") return "Fail 1.2" + if (plus3.id() != "1231") return "Fail 1.3" if (length1.id() != 3) return "Fail 2.1" if (length2.id() != 5) return "Fail 2.2" diff --git a/compiler/testData/codegen/box/involvesIrInterpreter/thisPlusStringWithObject.kt b/compiler/testData/codegen/box/involvesIrInterpreter/thisPlusStringWithObject.kt new file mode 100644 index 00000000000..29a6d9e9590 --- /dev/null +++ b/compiler/testData/codegen/box/involvesIrInterpreter/thisPlusStringWithObject.kt @@ -0,0 +1,47 @@ +// TARGET_BACKEND: JVM_IR +// TODO enable for JS, Native when const lowering is applied in corresponding backends + +object Test + +fun test1(): String { + val a = "test 1: " + Test + + val test = Test + val b = "test 1: " + test + + if (a != b) return "Fail 1: \"$a\" != \"$b\"" + return "OK" +} + +fun test2(): String { + val a = "test 2: " + Test.toString() + + val test = Test + val b = "test 2: " + test.toString() + + if (a != b) return "Fail 2: \"$a\" != \"$b\"" + return "OK" +} + +fun test3(): String { + val a = "test 3: $Test" + + val test = Test + val b = "test 3: $test" + + if (a != b) return "Fail 3: \"$a\" != \"$b\"" + return "OK" +} + +fun box(): String { + val test1Result = test1() + if (test1Result != "OK") return test1Result + + val test2Result = test2() + if (test2Result != "OK") return test2Result + + val test3Result = test2() + if (test3Result != "OK") return test3Result + + return "OK" +} 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 93b5cebf283..c378bab0f07 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 @@ -28623,6 +28623,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusString.kt"); } + @Test + @TestMetadata("thisPlusStringWithObject.kt") + public void testThisPlusStringWithObject() throws Exception { + runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusStringWithObject.kt"); + } + @Test @TestMetadata("unsignedConst.kt") public void testUnsignedConst() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java index 4cb2745c5c8..3455dd8277a 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java @@ -28623,6 +28623,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusString.kt"); } + @Test + @TestMetadata("thisPlusStringWithObject.kt") + public void testThisPlusStringWithObject() throws Exception { + runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusStringWithObject.kt"); + } + @Test @TestMetadata("unsignedConst.kt") public void testUnsignedConst() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 783c4a1f867..aba59025057 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -24139,6 +24139,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusString.kt"); } + @TestMetadata("thisPlusStringWithObject.kt") + public void testThisPlusStringWithObject() throws Exception { + runTest("compiler/testData/codegen/box/involvesIrInterpreter/thisPlusStringWithObject.kt"); + } + @TestMetadata("unsignedConst.kt") public void testUnsignedConst() throws Exception { runTest("compiler/testData/codegen/box/involvesIrInterpreter/unsignedConst.kt");