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.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
/**
|
||||
* This pass replaces calls to:
|
||||
@@ -134,9 +135,15 @@ internal class StringConcatenationTypeNarrowing(val context: Context) : FileLowe
|
||||
private fun buildNonNullableArgToString(argument: IrExpression): IrExpression {
|
||||
return if (argument.type.isString() || argument.type.isNullableString())
|
||||
argument
|
||||
else builder
|
||||
.irCall(context.ir.symbols.memberToString, context.irBuiltIns.stringType, valueArgumentsCount = 1, typeArgumentsCount = 0)
|
||||
.apply { dispatchReceiver = argument }
|
||||
else {
|
||||
val calleeOrNull = argument.type.classOrNull?.owner?.functions?.singleOrNull {
|
||||
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)
|
||||
|
||||
// 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
|
||||
fun runTest() {
|
||||
val foo = Foo(42)
|
||||
@@ -68,4 +102,8 @@ fun runTest() {
|
||||
println(maybeAnyMaybeString(null, null))
|
||||
println(maybeAnyString(foo, "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
|
||||
Foo(bar=42),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)
|
||||
|
||||
// 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
|
||||
fun runTest() {
|
||||
val foo = Foo(42)
|
||||
@@ -76,4 +91,5 @@ fun runTest() {
|
||||
println(appendMaybeString("foo"))
|
||||
println(appendMaybeString(null))
|
||||
println(appendString("foo"))
|
||||
println(appendFoo(foo))
|
||||
}
|
||||
|
||||
+1
@@ -4,3 +4,4 @@ Foo(bar=42)
|
||||
foo
|
||||
null
|
||||
foo
|
||||
Foo(bar=42)
|
||||
|
||||
+40
@@ -77,6 +77,43 @@ fun generatedPlusExtensionString(maybeStr: String?, str: String): String {
|
||||
|
||||
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
|
||||
fun runTest() {
|
||||
val foo = Foo(42)
|
||||
@@ -88,4 +125,7 @@ fun runTest() {
|
||||
println(generatedPlusExtensionAny(null, null))
|
||||
println(generatedPlusExtensionString("foo", "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
|
||||
foobar
|
||||
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)
|
||||
|
||||
// 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
|
||||
fun runTest() {
|
||||
val foo = Foo(42)
|
||||
@@ -77,4 +104,7 @@ fun runTest() {
|
||||
println(generatedPlusMemberAny("foo", null))
|
||||
println(generatedPlusMemberAny("foo", foo))
|
||||
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
|
||||
fooFoo(bar=42)
|
||||
foobar
|
||||
fooFoo(bar=42)
|
||||
fooFoo(bar=42)
|
||||
foonull
|
||||
|
||||
Reference in New Issue
Block a user