IR: Don't use IrStringConcatenation for ordinary toString calls
We can only use IrStrinConcatentation to represent calls to Any?.toString and toString calls on primitive types. Otherwise, x.toString() and "$x" are observably different when x is a non-null type with null value (e.g., an @NotNull value coming from Java).
This commit is contained in:
committed by
Dmitry Petrov
parent
c1b9fdd2f3
commit
58685be4e2
Generated
+5
@@ -26325,6 +26325,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/strings/interpolation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaToStringNPE.kt")
|
||||
public void testJavaToStringNPE() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/strings/javaToStringNPE.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt2592.kt")
|
||||
public void testKt2592() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/strings/kt2592.kt");
|
||||
|
||||
+9
-8
@@ -16,10 +16,7 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrStringConcatenationImpl
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.ir.types.isString
|
||||
import org.jetbrains.kotlin.ir.types.isStringClassType
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
@@ -126,9 +123,13 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
||||
return function.isToString || function.isNullableToString
|
||||
}
|
||||
|
||||
/** @return true if the given expression is a [IrStringConcatenation], or an [IrCall] to [toString] or [String.plus]. */
|
||||
/** @return true if the given expression is a call to [Any?.toString] or a call of [toString] on a primitive type. */
|
||||
private val IrCall.isSpecialToStringCall: Boolean
|
||||
get() = isToStringCall && dispatchReceiver?.type?.isPrimitiveType() != false
|
||||
|
||||
/** @return true if the given expression is a [IrStringConcatenation], or an [IrCall] to [String.plus]. */
|
||||
private fun isStringConcatenationExpression(expression: IrExpression): Boolean =
|
||||
(expression is IrStringConcatenation) || (expression is IrCall) && (expression.isStringPlusCall || expression.isToStringCall)
|
||||
(expression is IrStringConcatenation) || (expression is IrCall) && expression.isStringPlusCall
|
||||
|
||||
/** Recursively collects string concatenation arguments from the given expression. */
|
||||
private fun collectStringConcatenationArguments(expression: IrExpression): List<IrExpression> {
|
||||
@@ -141,7 +142,7 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
if (isStringConcatenationExpression(expression)) {
|
||||
if (isStringConcatenationExpression(expression) || expression.isToStringCall) {
|
||||
// Recursively collect from call arguments.
|
||||
expression.acceptChildrenVoid(this)
|
||||
} else {
|
||||
@@ -172,7 +173,7 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
||||
override fun visitExpression(expression: IrExpression): IrExpression {
|
||||
// Only modify/flatten string concatenation expressions.
|
||||
val transformedExpression =
|
||||
if (isStringConcatenationExpression(expression))
|
||||
if (isStringConcatenationExpression(expression) || expression is IrCall && expression.isSpecialToStringCall)
|
||||
expression.run {
|
||||
IrStringConcatenationImpl(
|
||||
startOffset,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
// FILE: J.java
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class J {
|
||||
@NotNull
|
||||
public static String notNullStringIsNull() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
fun box(): String {
|
||||
try {
|
||||
J.notNullStringIsNull().toString()
|
||||
} catch (e: java.lang.NullPointerException) {
|
||||
return "OK"
|
||||
}
|
||||
return "Fail"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
val chars = listOf('O', 'K')
|
||||
|
||||
fun box(): String {
|
||||
val b = StringBuilder()
|
||||
for (c in chars) {
|
||||
b.append(c)
|
||||
}
|
||||
return b.toString()
|
||||
}
|
||||
|
||||
// 0 INVOKESTATIC java/lang/String.valueOf
|
||||
// 1 INVOKEVIRTUAL java/lang/StringBuilder.toString
|
||||
+5
@@ -27846,6 +27846,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/strings/interpolation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaToStringNPE.kt")
|
||||
public void testJavaToStringNPE() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/strings/javaToStringNPE.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt2592.kt")
|
||||
public void testKt2592() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/strings/kt2592.kt");
|
||||
|
||||
@@ -4245,6 +4245,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/singleConcat.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("stringBuilderToString.kt")
|
||||
public void testStringBuilderToString() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/stringBuilderToString.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("stringPlus.kt")
|
||||
public void testStringPlus() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/stringPlus.kt");
|
||||
|
||||
+5
@@ -26663,6 +26663,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/strings/interpolation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaToStringNPE.kt")
|
||||
public void testJavaToStringNPE() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/strings/javaToStringNPE.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt2592.kt")
|
||||
public void testKt2592() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/strings/kt2592.kt");
|
||||
|
||||
+5
@@ -26325,6 +26325,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/strings/interpolation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaToStringNPE.kt")
|
||||
public void testJavaToStringNPE() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/strings/javaToStringNPE.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt2592.kt")
|
||||
public void testKt2592() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/strings/kt2592.kt");
|
||||
|
||||
+5
@@ -4163,6 +4163,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/singleConcat.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("stringBuilderToString.kt")
|
||||
public void testStringBuilderToString() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/stringBuilderToString.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("stringPlus.kt")
|
||||
public void testStringPlus() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/stringPlus.kt");
|
||||
|
||||
Reference in New Issue
Block a user