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.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
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.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrStringConcatenationImpl
|
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.isStringClassType
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameSafe
|
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
|
|
||||||
val flattenStringConcatenationPhase = makeIrFilePhase(
|
val flattenStringConcatenationPhase = makeIrFilePhase(
|
||||||
::FlattenStringConcatenationLowering,
|
::FlattenStringConcatenationLowering,
|
||||||
@@ -76,26 +78,45 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
|||||||
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
|
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
|
||||||
KotlinBuiltIns.FQ_NAMES.string.toSafe()
|
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]. */
|
/** @return true if the given expression is a call to [String.plus] */
|
||||||
private fun isStringConcatenationExpression(expression: IrExpression): Boolean {
|
private fun isStringPlusCall(expression: IrCall): Boolean {
|
||||||
return when (expression) {
|
val function = expression.symbol.owner
|
||||||
is IrStringConcatenation -> true
|
val receiver = expression.dispatchReceiver ?: expression.extensionReceiver
|
||||||
is IrCall -> {
|
|
||||||
val function = expression.symbol.owner
|
return receiver != null
|
||||||
val receiver = expression.dispatchReceiver ?: expression.extensionReceiver
|
&& receiver.type.isStringClassType()
|
||||||
receiver != null &&
|
&& function.returnType.isStringClassType()
|
||||||
receiver.type.isStringClassType() &&
|
&& function.valueParameters.size == 1
|
||||||
expression.type.isStringClassType() &&
|
&& function.name.asString() == "plus"
|
||||||
expression.valueArgumentsCount == 1 &&
|
&& function.fqNameWhenAvailable?.parent() in PARENT_NAMES
|
||||||
function.name == PLUS_NAME &&
|
|
||||||
function.fqNameWhenAvailable?.parent() in PARENT_NAMES
|
|
||||||
}
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @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. */
|
/** Recursively collects string concatenation arguments from the given expression. */
|
||||||
private fun collectStringConcatenationArguments(expression: IrExpression): List<IrExpression> {
|
private fun collectStringConcatenationArguments(expression: IrExpression): List<IrExpression> {
|
||||||
val arguments = mutableListOf<IrExpression>()
|
val arguments = mutableListOf<IrExpression>()
|
||||||
@@ -152,4 +173,4 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi
|
|||||||
transformedExpression.transformChildrenVoid(this)
|
transformedExpression.transformChildrenVoid(this)
|
||||||
return transformedExpression
|
return transformedExpression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-7
@@ -67,12 +67,6 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
|||||||
"isArrayOf",
|
"isArrayOf",
|
||||||
emptyList()
|
emptyList()
|
||||||
) to IsArrayOf,
|
) to IsArrayOf,
|
||||||
Key(
|
|
||||||
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
|
|
||||||
KotlinBuiltIns.FQ_NAMES.any.toSafe(),
|
|
||||||
"toString",
|
|
||||||
emptyList()
|
|
||||||
) to ToString,
|
|
||||||
Key(
|
Key(
|
||||||
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
|
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
|
||||||
null,
|
null,
|
||||||
@@ -108,7 +102,6 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
|||||||
unaryFunForPrimitives("inc", INC) +
|
unaryFunForPrimitives("inc", INC) +
|
||||||
unaryFunForPrimitives("dec", DEC) +
|
unaryFunForPrimitives("dec", DEC) +
|
||||||
unaryFunForPrimitives("hashCode", HashCode) +
|
unaryFunForPrimitives("hashCode", HashCode) +
|
||||||
unaryFunForPrimitives("toString", ToString) +
|
|
||||||
binaryFunForPrimitives("equals", EQUALS, irBuiltIns.anyClass) +
|
binaryFunForPrimitives("equals", EQUALS, irBuiltIns.anyClass) +
|
||||||
binaryFunForPrimitivesAcrossPrimitives("rangeTo", RangeTo) +
|
binaryFunForPrimitivesAcrossPrimitives("rangeTo", RangeTo) +
|
||||||
binaryOp("plus", IADD) +
|
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