JVM IR: Unify the handling of IrStringConcatenation and toString
This commit is contained in:
committed by
Alexander Udalov
parent
c2de89cb8c
commit
78b4024ccb
+41
-20
@@ -11,18 +11,20 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
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.util.fqNameSafe
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
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.name.Name
|
||||
|
||||
val flattenStringConcatenationPhase = makeIrFilePhase(
|
||||
::FlattenStringConcatenationLowering,
|
||||
@@ -76,26 +78,45 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
||||
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
|
||||
KotlinBuiltIns.FQ_NAMES.string.toSafe()
|
||||
)
|
||||
private val PLUS_NAME = Name.identifier("plus")
|
||||
|
||||
/** @return true if the given expression is a [IrStringConcatenation] or [String.plus] [IrCall]. */
|
||||
private fun isStringConcatenationExpression(expression: IrExpression): Boolean {
|
||||
return when (expression) {
|
||||
is IrStringConcatenation -> true
|
||||
is IrCall -> {
|
||||
val function = expression.symbol.owner
|
||||
val receiver = expression.dispatchReceiver ?: expression.extensionReceiver
|
||||
receiver != null &&
|
||||
receiver.type.isStringClassType() &&
|
||||
expression.type.isStringClassType() &&
|
||||
expression.valueArgumentsCount == 1 &&
|
||||
function.name == PLUS_NAME &&
|
||||
function.fqNameWhenAvailable?.parent() in PARENT_NAMES
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
/** @return true if the given expression is a call to [String.plus] */
|
||||
private fun isStringPlusCall(expression: IrCall): Boolean {
|
||||
val function = expression.symbol.owner
|
||||
val receiver = expression.dispatchReceiver ?: expression.extensionReceiver
|
||||
|
||||
return receiver != null
|
||||
&& receiver.type.isStringClassType()
|
||||
&& function.returnType.isStringClassType()
|
||||
&& function.valueParameters.size == 1
|
||||
&& function.name.asString() == "plus"
|
||||
&& function.fqNameWhenAvailable?.parent() in PARENT_NAMES
|
||||
}
|
||||
|
||||
/** @return true if the given expression is a call to [toString] */
|
||||
private fun isToStringCall(expression: IrCall): Boolean {
|
||||
if (expression.superQualifierSymbol != null)
|
||||
return false
|
||||
|
||||
val function = expression.symbol.owner
|
||||
if (function.name.asString() != "toString" || function.valueParameters.size != 0 || !function.returnType.isString())
|
||||
return false
|
||||
|
||||
// Check for Any?.toString, which is an extension method defined in the kotlin package.
|
||||
if (function.dispatchReceiverParameter == null
|
||||
&& function.extensionReceiverParameter?.type?.isNullableAny() == true
|
||||
&& function.fqNameWhenAvailable?.parent() == KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
|
||||
return true
|
||||
|
||||
// Check for Any.toString or an override.
|
||||
return (function.dispatchReceiverParameter != null && function.extensionReceiverParameter == null
|
||||
&& (function.dispatchReceiverParameter?.type?.isAny() == true
|
||||
|| (function as? IrSimpleFunction)?.overriddenSymbols?.isNotEmpty() == true))
|
||||
}
|
||||
|
||||
/** @return true if the given expression is a [IrStringConcatenation], or an [IrCall] to [toString] or [String.plus]. */
|
||||
private fun isStringConcatenationExpression(expression: IrExpression): Boolean =
|
||||
(expression is IrStringConcatenation) || (expression is IrCall) && (isStringPlusCall(expression) || isToStringCall(expression))
|
||||
|
||||
/** Recursively collects string concatenation arguments from the given expression. */
|
||||
private fun collectStringConcatenationArguments(expression: IrExpression): List<IrExpression> {
|
||||
val arguments = mutableListOf<IrExpression>()
|
||||
@@ -152,4 +173,4 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
||||
transformedExpression.transformChildrenVoid(this)
|
||||
return transformedExpression
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-7
@@ -67,12 +67,6 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
||||
"isArrayOf",
|
||||
emptyList()
|
||||
) to IsArrayOf,
|
||||
Key(
|
||||
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
|
||||
KotlinBuiltIns.FQ_NAMES.any.toSafe(),
|
||||
"toString",
|
||||
emptyList()
|
||||
) to ToString,
|
||||
Key(
|
||||
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
|
||||
null,
|
||||
@@ -108,7 +102,6 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
||||
unaryFunForPrimitives("inc", INC) +
|
||||
unaryFunForPrimitives("dec", DEC) +
|
||||
unaryFunForPrimitives("hashCode", HashCode) +
|
||||
unaryFunForPrimitives("toString", ToString) +
|
||||
binaryFunForPrimitives("equals", EQUALS, irBuiltIns.anyClass) +
|
||||
binaryFunForPrimitivesAcrossPrimitives("rangeTo", RangeTo) +
|
||||
binaryOp("plus", IADD) +
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
|
||||
object ToString : IntrinsicMethod() {
|
||||
override fun toCallable(expression: IrFunctionAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction {
|
||||
val type = AsmUtil.stringValueOfType(calcReceiverType(expression, context))
|
||||
return IrIntrinsicFunction.create(expression, signature, context, type) {
|
||||
it.invokestatic("java/lang/String", "valueOf", "(${type.descriptor})Ljava/lang/String;", false)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user