JVM IR: Unify the handling of IrStringConcatenation and toString

This commit is contained in:
Steven Schäfer
2019-10-04 13:39:47 +02:00
committed by Alexander Udalov
parent c2de89cb8c
commit 78b4024ccb
3 changed files with 41 additions and 59 deletions
@@ -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
}
}
}
@@ -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)
}
}
}