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");
|
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")
|
@TestMetadata("kt2592.kt")
|
||||||
public void testKt2592() throws Exception {
|
public void testKt2592() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/strings/kt2592.kt");
|
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.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrStringConcatenationImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrStringConcatenationImpl
|
||||||
import org.jetbrains.kotlin.ir.types.isAny
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
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.util.fqNameWhenAvailable
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
@@ -126,9 +123,13 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
|||||||
return function.isToString || function.isNullableToString
|
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 =
|
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. */
|
/** Recursively collects string concatenation arguments from the given expression. */
|
||||||
private fun collectStringConcatenationArguments(expression: IrExpression): List<IrExpression> {
|
private fun collectStringConcatenationArguments(expression: IrExpression): List<IrExpression> {
|
||||||
@@ -141,7 +142,7 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall) {
|
override fun visitCall(expression: IrCall) {
|
||||||
if (isStringConcatenationExpression(expression)) {
|
if (isStringConcatenationExpression(expression) || expression.isToStringCall) {
|
||||||
// Recursively collect from call arguments.
|
// Recursively collect from call arguments.
|
||||||
expression.acceptChildrenVoid(this)
|
expression.acceptChildrenVoid(this)
|
||||||
} else {
|
} else {
|
||||||
@@ -172,7 +173,7 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
|||||||
override fun visitExpression(expression: IrExpression): IrExpression {
|
override fun visitExpression(expression: IrExpression): IrExpression {
|
||||||
// Only modify/flatten string concatenation expressions.
|
// Only modify/flatten string concatenation expressions.
|
||||||
val transformedExpression =
|
val transformedExpression =
|
||||||
if (isStringConcatenationExpression(expression))
|
if (isStringConcatenationExpression(expression) || expression is IrCall && expression.isSpecialToStringCall)
|
||||||
expression.run {
|
expression.run {
|
||||||
IrStringConcatenationImpl(
|
IrStringConcatenationImpl(
|
||||||
startOffset,
|
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");
|
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")
|
@TestMetadata("kt2592.kt")
|
||||||
public void testKt2592() throws Exception {
|
public void testKt2592() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/strings/kt2592.kt");
|
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");
|
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")
|
@TestMetadata("stringPlus.kt")
|
||||||
public void testStringPlus() throws Exception {
|
public void testStringPlus() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/stringPlus.kt");
|
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");
|
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")
|
@TestMetadata("kt2592.kt")
|
||||||
public void testKt2592() throws Exception {
|
public void testKt2592() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/strings/kt2592.kt");
|
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");
|
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")
|
@TestMetadata("kt2592.kt")
|
||||||
public void testKt2592() throws Exception {
|
public void testKt2592() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/strings/kt2592.kt");
|
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");
|
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")
|
@TestMetadata("stringPlus.kt")
|
||||||
public void testStringPlus() throws Exception {
|
public void testStringPlus() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/stringPlus.kt");
|
runTest("compiler/testData/codegen/bytecodeText/stringOperations/stringPlus.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user