Compare commits

...

1 Commits

Author SHA1 Message Date
Steven Schäfer
ef34e4176f 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).
2020-03-27 14:58:04 +03:00
9 changed files with 73 additions and 8 deletions

View File

@@ -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");

View File

@@ -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,

View File

@@ -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"
}

View File

@@ -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

View File

@@ -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");

View File

@@ -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");

View File

@@ -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");

View File

@@ -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");

View File

@@ -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");