Add possibility to interpret and fold IrStringConcatenation expression

This commit is contained in:
Ivan Kylchik
2023-02-09 12:29:27 +01:00
committed by Space Team
parent 7cf9dda8dc
commit 63b340651d
77 changed files with 305 additions and 184 deletions
@@ -398,7 +398,10 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
is Primitive<*> -> {
// This block is not really needed, but this way it is easier to handle `toString` with `treatFloatInSpecialWay` enabled.
callStack.popState()
val toStringCall = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, environment.irBuiltIns.memberToString)
val toStringCall = IrCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
if (state.isNull()) environment.irBuiltIns.extensionToString else environment.irBuiltIns.memberToString
)
callStack.pushSimpleInstruction(toStringCall)
callStack.pushState(state)
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrStringConcatenationImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
@@ -21,6 +22,8 @@ import org.jetbrains.kotlin.ir.interpreter.toIrConst
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import kotlin.math.max
import kotlin.math.min
class IrConstTransformer(
private val interpreter: IrInterpreter,
@@ -100,6 +103,56 @@ class IrConstTransformer(
return super.visitField(declaration)
}
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression {
fun IrExpression.wrapInStringConcat(): IrExpression = IrStringConcatenationImpl(
this.startOffset, this.endOffset, expression.type, listOf(this@wrapInStringConcat)
)
fun IrExpression.wrapInToStringConcatAndInterpret(): IrExpression = wrapInStringConcat().interpret(failAsError = false)
// here `StringBuilder`'s list is used to optimize memory, everything works without it
val folded = mutableListOf<IrExpression>()
val buildersList = mutableListOf<StringBuilder>()
for (next in expression.arguments) {
val last = folded.lastOrNull()
when {
!next.wrapInStringConcat().canBeInterpreted() -> {
folded += next
buildersList.add(StringBuilder())
}
last == null || !last.wrapInStringConcat().canBeInterpreted() -> {
val result = next.wrapInToStringConcatAndInterpret()
folded += result
buildersList.add(StringBuilder((result as? IrConst<*>)?.value?.toString() ?: ""))
}
else -> {
val nextAsConst = next.wrapInToStringConcatAndInterpret()
if (nextAsConst !is IrConst<*>) {
folded += next
buildersList.add(StringBuilder())
} else {
folded[folded.size - 1] = IrConstImpl.string(
// Inlined strings may have `last.startOffset > next.endOffset`
min(last.startOffset, next.startOffset), max(last.endOffset, next.endOffset), expression.type, ""
)
buildersList.last().append(nextAsConst.value.toString())
}
}
}
}
val foldedConst = folded.singleOrNull() as? IrConst<*>
if (foldedConst != null) {
return IrConstImpl.string(expression.startOffset, expression.endOffset, expression.type, buildersList.single().toString())
}
folded.zip(buildersList).forEach {
@Suppress("UNCHECKED_CAST")
(it.first as? IrConst<String>)?.value = it.second.toString()
}
return IrStringConcatenationImpl(expression.startOffset, expression.endOffset, expression.type, folded)
}
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
transformAnnotations(declaration)
return super.visitDeclaration(declaration)