[IR] [Refactoring] Add toString and String::plus to IrBuiltins

Also use `OperatorNameConventions` constants instead of magic strings
This commit is contained in:
Sergej Jaskiewicz
2021-10-28 08:35:11 +00:00
committed by Space
parent f8dd1b3512
commit a367b91aa1
10 changed files with 80 additions and 36 deletions
@@ -454,15 +454,31 @@ class IrBuiltInsOverFir(
}
override val extensionToString: IrSimpleFunctionSymbol by lazy {
findFunctions(kotlinPackage, Name.identifier("toString")).first { function ->
findFunctions(kotlinPackage, OperatorNameConventions.TO_STRING).single { function ->
function.owner.extensionReceiverParameter?.let { receiver -> receiver.type == anyNType } ?: false
}
}
override val stringPlus: IrSimpleFunctionSymbol
get() = intClass.functions.single {
it.owner.name == OperatorNameConventions.PLUS && it.owner.valueParameters[0].type == stringType
override val memberToString: IrSimpleFunctionSymbol by lazy {
findBuiltInClassMemberFunctions(anyClass, OperatorNameConventions.TO_STRING).single { function ->
function.owner.valueParameters.isEmpty()
}
}
override val extensionStringPlus: IrSimpleFunctionSymbol by lazy {
findFunctions(kotlinPackage, OperatorNameConventions.PLUS).single { function ->
val isStringExtension =
function.owner.extensionReceiverParameter?.let { receiver -> receiver.type == stringType.withHasQuestionMark(true) }
?: false
isStringExtension && function.owner.valueParameters.size == 1 && function.owner.valueParameters[0].type == anyNType
}
}
override val memberStringPlus: IrSimpleFunctionSymbol by lazy {
findBuiltInClassMemberFunctions(stringClass, OperatorNameConventions.PLUS).single { function ->
function.owner.valueParameters.size == 1 && function.owner.valueParameters[0].type == anyNType
}
}
private class KotlinPackageFuns(
val arrayOf: IrSimpleFunctionSymbol,
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
class Fir2IrLazyClass(
components: Fir2IrComponents,
@@ -214,9 +215,9 @@ class Fir2IrLazyClass(
private fun FirNamedFunctionSymbol.isAbstractMethodOfAny(): Boolean {
val fir = fir
if (fir.modality != Modality.ABSTRACT) return false
return when (fir.name.asString()) {
"equals" -> fir.valueParameters.singleOrNull()?.returnTypeRef?.isNullableAny == true
"hashCode", "toString" -> fir.valueParameters.isEmpty()
return when (fir.name) {
OperatorNameConventions.EQUALS -> fir.valueParameters.singleOrNull()?.returnTypeRef?.isNullableAny == true
OperatorNameConventions.HASH_CODE, OperatorNameConventions.TO_STRING -> fir.valueParameters.isEmpty()
else -> false
}
}
@@ -16,8 +16,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
object FunctionsFromAny {
val EQUALS_METHOD_NAME = OperatorNameConventions.EQUALS
val HASH_CODE_METHOD_NAME = Name.identifier("hashCode")
val TO_STRING_METHOD_NAME = Name.identifier("toString")
val HASH_CODE_METHOD_NAME = OperatorNameConventions.HASH_CODE
val TO_STRING_METHOD_NAME = OperatorNameConventions.TO_STRING
fun addFunctionFromAnyIfNeeded(
thisDescriptor: ClassDescriptor,
@@ -18,9 +18,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
@@ -187,7 +185,20 @@ open class BuiltinSymbolsBase(val irBuiltIns: IrBuiltIns, private val symbolTabl
fun kmutableproperty2(): IrClassSymbol = irBuiltIns.kMutableProperty2Class
val extensionToString: IrSimpleFunctionSymbol get() = irBuiltIns.extensionToString
val stringPlus: IrSimpleFunctionSymbol get() = irBuiltIns.stringPlus
val memberToString: IrSimpleFunctionSymbol get() = irBuiltIns.memberToString
val extensionStringPlus: IrSimpleFunctionSymbol get() = irBuiltIns.extensionStringPlus
val memberStringPlus: IrSimpleFunctionSymbol get() = irBuiltIns.memberStringPlus
fun isStringPlus(functionSymbol: IrFunctionSymbol): Boolean {
val plusSymbol = if (functionSymbol.owner.dispatchReceiverParameter?.type?.isString() == true)
memberStringPlus
else if (functionSymbol.owner.extensionReceiverParameter?.type?.isNullableString() == true)
extensionStringPlus
else
return false
return functionSymbol == plusSymbol
}
}
// Some symbols below are used in kotlin-native, so they can't be private
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.io.StringWriter
fun ir2string(ir: IrElement?): String = ir?.render() ?: ""
@@ -399,9 +400,9 @@ fun isElseBranch(branch: IrBranch) = branch is IrElseBranch || ((branch.conditio
fun IrFunction.isMethodOfAny(): Boolean =
extensionReceiverParameter == null && dispatchReceiverParameter != null &&
when (name.asString()) {
"hashCode", "toString" -> valueParameters.isEmpty()
"equals" -> valueParameters.singleOrNull()?.type?.isNullableAny() == true
when (name) {
OperatorNameConventions.HASH_CODE, OperatorNameConventions.TO_STRING -> valueParameters.isEmpty()
OperatorNameConventions.EQUALS -> valueParameters.singleOrNull()?.type?.isNullableAny() == true
else -> false
}
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.util.OperatorNameConventions
val flattenStringConcatenationPhase = makeIrFilePhase(
::FlattenStringConcatenationLowering,
@@ -86,14 +87,14 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
&& receiver.type.isStringClassType()
&& function.returnType.isStringClassType()
&& function.valueParameters.size == 1
&& function.name.asString() == "plus"
&& function.name == OperatorNameConventions.PLUS
&& function.fqNameWhenAvailable?.parent() in PARENT_NAMES
}
/** @return true if the function is Any.toString or an override of Any.toString */
val IrSimpleFunction.isToString: Boolean
get() {
if (name.asString() != "toString" || valueParameters.size != 0 || !returnType.isString())
if (name != OperatorNameConventions.TO_STRING || valueParameters.isNotEmpty() || !returnType.isString())
return false
return (dispatchReceiverParameter != null && extensionReceiverParameter == null
@@ -103,7 +104,7 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
/** @return true if the function is Any?.toString */
private val IrSimpleFunction.isNullableToString: Boolean
get() {
if (name.asString() != "toString" || valueParameters.size != 0 || !returnType.isString())
if (name != OperatorNameConventions.TO_STRING || valueParameters.isNotEmpty() || !returnType.isString())
return false
return dispatchReceiverParameter == null
@@ -55,10 +55,6 @@ class StringConcatenationLowering(context: CommonBackendContext) : FileLoweringP
it.valueParameters.isEmpty()
}
private val toStringFunction = stringBuilder.functions.single {
it.valueParameters.isEmpty() && it.name == OperatorNameConventions.TO_STRING
}
private val defaultAppendFunction = stringBuilder.functions.single {
it.name == nameAppend &&
it.valueParameters.size == 1 &&
@@ -90,22 +86,19 @@ class StringConcatenationLowering(context: CommonBackendContext) : FileLoweringP
builder.irCall(symbols.extensionToString).apply {
extensionReceiver = argument
}
else builder.irCall(
irBuiltIns.anyClass.functions
.single { it.owner.name == OperatorNameConventions.TO_STRING }).apply {
else builder.irCall(symbols.memberToString).apply {
dispatchReceiver = argument
}
}
arguments.size == 2 && arguments[0].type.isStringClassType() ->
if (arguments[0].type.isNullable())
builder.irCall(symbols.stringPlus).apply {
builder.irCall(symbols.extensionStringPlus).apply {
extensionReceiver = arguments[0]
putValueArgument(0, arguments[1])
}
else
builder.irCall(symbols.string.functions
.single { it.owner.name == OperatorNameConventions.PLUS }).apply {
builder.irCall(symbols.memberStringPlus).apply {
dispatchReceiver = arguments[0]
putValueArgument(0, arguments[1])
}
@@ -119,7 +112,7 @@ class StringConcatenationLowering(context: CommonBackendContext) : FileLoweringP
putValueArgument(0, arg)
}
}
+irCall(toStringFunction).apply {
+irCall(symbols.memberToString).apply {
dispatchReceiver = irGet(stringBuilderImpl)
}
}
@@ -16,8 +16,6 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -142,7 +140,10 @@ abstract class IrBuiltIns {
abstract val intXorSymbol: IrSimpleFunctionSymbol
abstract val extensionToString: IrSimpleFunctionSymbol
abstract val stringPlus: IrSimpleFunctionSymbol
abstract val memberToString: IrSimpleFunctionSymbol
abstract val extensionStringPlus: IrSimpleFunctionSymbol
abstract val memberStringPlus: IrSimpleFunctionSymbol
abstract val arrayOf: IrSimpleFunctionSymbol
abstract val arrayOfNulls: IrSimpleFunctionSymbol
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.util.OperatorNameConventions
@ObsoleteDescriptorBasedAPI
class IrBuiltInsOverDescriptors(
@@ -502,14 +503,22 @@ class IrBuiltInsOverDescriptors(
} else null
}
override val extensionToString: IrSimpleFunctionSymbol = findFunctions(Name.identifier("toString"), "kotlin").first {
override val extensionToString: IrSimpleFunctionSymbol = findFunctions(OperatorNameConventions.TO_STRING, "kotlin").first {
val descriptor = it.descriptor
descriptor is SimpleFunctionDescriptor && descriptor.dispatchReceiverParameter == null &&
descriptor.extensionReceiverParameter != null &&
KotlinBuiltIns.isNullableAny(descriptor.extensionReceiverParameter!!.type) && descriptor.valueParameters.size == 0
KotlinBuiltIns.isNullableAny(descriptor.extensionReceiverParameter!!.type) && descriptor.valueParameters.isEmpty()
}
override val stringPlus: IrSimpleFunctionSymbol = findFunctions(Name.identifier("plus"), "kotlin").first {
override val memberToString: IrSimpleFunctionSymbol = findBuiltInClassMemberFunctions(
anyClass,
OperatorNameConventions.TO_STRING
).single {
val descriptor = it.descriptor
descriptor is SimpleFunctionDescriptor && descriptor.valueParameters.isEmpty()
}
override val extensionStringPlus: IrSimpleFunctionSymbol = findFunctions(OperatorNameConventions.PLUS, "kotlin").first {
val descriptor = it.descriptor
descriptor is SimpleFunctionDescriptor && descriptor.dispatchReceiverParameter == null &&
descriptor.extensionReceiverParameter != null &&
@@ -518,6 +527,16 @@ class IrBuiltInsOverDescriptors(
KotlinBuiltIns.isNullableAny(descriptor.valueParameters.first().type)
}
override val memberStringPlus: IrSimpleFunctionSymbol = findBuiltInClassMemberFunctions(
stringClass,
OperatorNameConventions.PLUS
).single {
val descriptor = it.descriptor
descriptor is SimpleFunctionDescriptor &&
descriptor.valueParameters.size == 1 &&
KotlinBuiltIns.isNullableAny(descriptor.valueParameters.first().type)
}
override fun functionN(arity: Int): IrClass = functionFactory.functionN(arity)
override fun kFunctionN(arity: Int): IrClass = functionFactory.kFunctionN(arity)
override fun suspendFunctionN(arity: Int): IrClass = functionFactory.suspendFunctionN(arity)
@@ -24,6 +24,7 @@ object OperatorNameConventions {
@JvmField val PROVIDE_DELEGATE = Name.identifier("provideDelegate")
@JvmField val EQUALS = Name.identifier("equals")
@JvmField val HASH_CODE = Name.identifier("hashCode")
@JvmField val COMPARE_TO = Name.identifier("compareTo")
@JvmField val CONTAINS = Name.identifier("contains")
@JvmField val INVOKE = Name.identifier("invoke")