Call toString() within known class, during string concatenation type narrowing
^KT-53119 Improved Merge-request: KT-MR-6755 Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
+10
-3
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.ir.util.functions
|
|||||||
import org.jetbrains.kotlin.ir.util.shallowCopy
|
import org.jetbrains.kotlin.ir.util.shallowCopy
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This pass replaces calls to:
|
* This pass replaces calls to:
|
||||||
@@ -134,9 +135,15 @@ internal class StringConcatenationTypeNarrowing(val context: Context) : FileLowe
|
|||||||
private fun buildNonNullableArgToString(argument: IrExpression): IrExpression {
|
private fun buildNonNullableArgToString(argument: IrExpression): IrExpression {
|
||||||
return if (argument.type.isString() || argument.type.isNullableString())
|
return if (argument.type.isString() || argument.type.isNullableString())
|
||||||
argument
|
argument
|
||||||
else builder
|
else {
|
||||||
.irCall(context.ir.symbols.memberToString, context.irBuiltIns.stringType, valueArgumentsCount = 1, typeArgumentsCount = 0)
|
val calleeOrNull = argument.type.classOrNull?.owner?.functions?.singleOrNull {
|
||||||
.apply { dispatchReceiver = argument }
|
it.name == OperatorNameConventions.TO_STRING && it.valueParameters.isEmpty()
|
||||||
|
}?.symbol
|
||||||
|
val callee = calleeOrNull ?: context.ir.symbols.memberToString // defaults to `Any.toString()`
|
||||||
|
builder
|
||||||
|
.irCall(callee, callee.owner.returnType, valueArgumentsCount = 0, typeArgumentsCount = 0)
|
||||||
|
.apply { dispatchReceiver = argument }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+38
@@ -59,6 +59,40 @@ fun maybeAnyString(maybeAny1: Any?, string: String): String {
|
|||||||
|
|
||||||
data class Foo(val bar: Int)
|
data class Foo(val bar: Int)
|
||||||
|
|
||||||
|
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated#maybeAnyFoo
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
|
||||||
|
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT: Foo#toString(){}kotlin.String
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
|
||||||
|
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
|
||||||
|
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
||||||
|
|
||||||
|
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
|
||||||
|
// CHECK: ret %struct.ObjHeader*
|
||||||
|
|
||||||
|
fun maybeAnyFoo(maybeAny: Any?, foo: Foo): String {
|
||||||
|
return "$maybeAny,$foo"
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated#maybeAnyMaybeFoo
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
|
||||||
|
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
|
||||||
|
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
||||||
|
|
||||||
|
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
|
||||||
|
// CHECK: ret %struct.ObjHeader*
|
||||||
|
|
||||||
|
fun maybeAnyMaybeFoo(maybeAny: Any?, foo: Foo?): String {
|
||||||
|
return "$maybeAny,$foo"
|
||||||
|
}
|
||||||
@Test
|
@Test
|
||||||
fun runTest() {
|
fun runTest() {
|
||||||
val foo = Foo(42)
|
val foo = Foo(42)
|
||||||
@@ -68,4 +102,8 @@ fun runTest() {
|
|||||||
println(maybeAnyMaybeString(null, null))
|
println(maybeAnyMaybeString(null, null))
|
||||||
println(maybeAnyString(foo, "bar"))
|
println(maybeAnyString(foo, "bar"))
|
||||||
println(maybeAnyString(null, "bar"))
|
println(maybeAnyString(null, "bar"))
|
||||||
|
println(maybeAnyFoo(foo, foo))
|
||||||
|
println(maybeAnyFoo(null, foo))
|
||||||
|
println(maybeAnyMaybeFoo(foo, foo))
|
||||||
|
println(maybeAnyMaybeFoo(foo, null))
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -4,3 +4,7 @@ Foo(bar=42),bar
|
|||||||
null,null
|
null,null
|
||||||
Foo(bar=42),bar
|
Foo(bar=42),bar
|
||||||
null,bar
|
null,bar
|
||||||
|
Foo(bar=42),Foo(bar=42)
|
||||||
|
null,Foo(bar=42)
|
||||||
|
Foo(bar=42),Foo(bar=42)
|
||||||
|
Foo(bar=42),null
|
||||||
|
|||||||
+16
@@ -67,6 +67,21 @@ fun appendString(str: String): String {
|
|||||||
|
|
||||||
data class Foo(val bar: Int)
|
data class Foo(val bar: Int)
|
||||||
|
|
||||||
|
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_manual#appendFoo(codegen.stringConcatenationTypeNarrowing.kt53119_append_manual.Foo)
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_manual.Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
|
||||||
|
|
||||||
|
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
|
||||||
|
// CHECK: ret %struct.ObjHeader*
|
||||||
|
|
||||||
|
fun appendFoo(foo: Foo): String {
|
||||||
|
val sb = kotlin.text.StringBuilder()
|
||||||
|
sb.append(foo)
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun runTest() {
|
fun runTest() {
|
||||||
val foo = Foo(42)
|
val foo = Foo(42)
|
||||||
@@ -76,4 +91,5 @@ fun runTest() {
|
|||||||
println(appendMaybeString("foo"))
|
println(appendMaybeString("foo"))
|
||||||
println(appendMaybeString(null))
|
println(appendMaybeString(null))
|
||||||
println(appendString("foo"))
|
println(appendString("foo"))
|
||||||
|
println(appendFoo(foo))
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -4,3 +4,4 @@ Foo(bar=42)
|
|||||||
foo
|
foo
|
||||||
null
|
null
|
||||||
foo
|
foo
|
||||||
|
Foo(bar=42)
|
||||||
|
|||||||
+40
@@ -77,6 +77,43 @@ fun generatedPlusExtensionString(maybeStr: String?, str: String): String {
|
|||||||
|
|
||||||
data class Foo(val bar: Int)
|
data class Foo(val bar: Int)
|
||||||
|
|
||||||
|
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension#generatedPlusExtensionFoo
|
||||||
|
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
|
||||||
|
|
||||||
|
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension.Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT: Foo#toString(){}kotlin.String
|
||||||
|
|
||||||
|
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
|
||||||
|
// CHECK-NOT: call %struct.ObjHeader* @Kotlin_String_plusImpl
|
||||||
|
|
||||||
|
// CHECK-NOT: call %struct.ObjHeader* @"kfun:kotlin.String#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
|
||||||
|
|
||||||
|
// CHECK: ret %struct.ObjHeader*
|
||||||
|
|
||||||
|
fun generatedPlusExtensionFoo(maybeStr: String?, foo: Foo): String {
|
||||||
|
return "$maybeStr$foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension#generatedPlusExtensionMaybeFoo
|
||||||
|
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
|
||||||
|
|
||||||
|
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
|
||||||
|
// CHECK-NOT: call %struct.ObjHeader* @Kotlin_String_plusImpl
|
||||||
|
// CHECK-NOT: call %struct.ObjHeader* @"kfun:kotlin.String#toString(){}kotlin.String"
|
||||||
|
|
||||||
|
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension.Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT: Foo#toString(){}kotlin.String
|
||||||
|
|
||||||
|
// CHECK-NOT: call %struct.ObjHeader* @"kfun:kotlin.String#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
|
||||||
|
|
||||||
|
// CHECK: ret %struct.ObjHeader*
|
||||||
|
|
||||||
|
fun generatedPlusExtensionMaybeFoo(maybeStr: String?, foo: Foo?): String {
|
||||||
|
return "$maybeStr$foo"
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun runTest() {
|
fun runTest() {
|
||||||
val foo = Foo(42)
|
val foo = Foo(42)
|
||||||
@@ -88,4 +125,7 @@ fun runTest() {
|
|||||||
println(generatedPlusExtensionAny(null, null))
|
println(generatedPlusExtensionAny(null, null))
|
||||||
println(generatedPlusExtensionString("foo", "bar"))
|
println(generatedPlusExtensionString("foo", "bar"))
|
||||||
println(generatedPlusExtensionString(null, "bar"))
|
println(generatedPlusExtensionString(null, "bar"))
|
||||||
|
println(generatedPlusExtensionFoo(null, Foo(42)))
|
||||||
|
println(generatedPlusExtensionMaybeFoo("foo", Foo(42)))
|
||||||
|
println(generatedPlusExtensionMaybeFoo("foo", null))
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -6,3 +6,6 @@ fooFoo(bar=42)
|
|||||||
nullnull
|
nullnull
|
||||||
foobar
|
foobar
|
||||||
nullbar
|
nullbar
|
||||||
|
nullFoo(bar=42)
|
||||||
|
fooFoo(bar=42)
|
||||||
|
foonull
|
||||||
|
|||||||
+30
@@ -68,6 +68,33 @@ fun generatedPlusMemberString(str1: String, str2: String): String {
|
|||||||
|
|
||||||
data class Foo(val bar: Int)
|
data class Foo(val bar: Int)
|
||||||
|
|
||||||
|
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member#manualPlusMemberFoo
|
||||||
|
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
|
||||||
|
// CHECK call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member.Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT Foo#toString(){}kotlin.String
|
||||||
|
|
||||||
|
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
|
||||||
|
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
|
||||||
|
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
||||||
|
|
||||||
|
// CHECK: ret %struct.ObjHeader*
|
||||||
|
fun manualPlusMemberFoo(str1: String, foo: Foo): kotlin.String =
|
||||||
|
str1 + foo
|
||||||
|
|
||||||
|
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member#manualPlusMemberMaybeFoo
|
||||||
|
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
|
||||||
|
// CHECK call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member.Foo#toString(){}kotlin.String"
|
||||||
|
// CHECK-NOT Foo#toString(){}kotlin.String
|
||||||
|
|
||||||
|
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
|
||||||
|
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member.Foo#toString
|
||||||
|
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
|
||||||
|
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
||||||
|
|
||||||
|
// CHECK: ret %struct.ObjHeader*
|
||||||
|
fun manualPlusMemberMaybeFoo(str1: String, foo: Foo?): kotlin.String =
|
||||||
|
str1 + foo
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun runTest() {
|
fun runTest() {
|
||||||
val foo = Foo(42)
|
val foo = Foo(42)
|
||||||
@@ -77,4 +104,7 @@ fun runTest() {
|
|||||||
println(generatedPlusMemberAny("foo", null))
|
println(generatedPlusMemberAny("foo", null))
|
||||||
println(generatedPlusMemberAny("foo", foo))
|
println(generatedPlusMemberAny("foo", foo))
|
||||||
println(generatedPlusMemberString("foo", "bar"))
|
println(generatedPlusMemberString("foo", "bar"))
|
||||||
|
println(manualPlusMemberFoo("foo", Foo(42)))
|
||||||
|
println(manualPlusMemberMaybeFoo("foo", Foo(42)))
|
||||||
|
println(manualPlusMemberMaybeFoo("foo", null))
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -4,3 +4,6 @@ foobar
|
|||||||
foonull
|
foonull
|
||||||
fooFoo(bar=42)
|
fooFoo(bar=42)
|
||||||
foobar
|
foobar
|
||||||
|
fooFoo(bar=42)
|
||||||
|
fooFoo(bar=42)
|
||||||
|
foonull
|
||||||
|
|||||||
Reference in New Issue
Block a user