Support interpretation of String's plus method and its extension version
This commit is contained in:
+27
-17
@@ -172,13 +172,18 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
}
|
||||
val args = stack.getAll().map { it.state }
|
||||
|
||||
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
||||
val receiverType = descriptor.dispatchReceiverParameter?.type
|
||||
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { it.original.type }
|
||||
val argsValues = args.map {
|
||||
when (it) {
|
||||
is Complex -> it.getOriginal()
|
||||
is Complex -> when (irFunction.fqNameWhenAvailable?.asString()) {
|
||||
// must explicitly convert Common to String in String plus method or else will be taken default toString from Common
|
||||
"kotlin.String.plus" -> stack.apply { interpretToString(it) }.popReturnValue().asString()
|
||||
else -> it.getOriginal()
|
||||
}
|
||||
is Primitive<*> -> it.value
|
||||
else -> it // lambda can be used in built in calculation, for example, in null check
|
||||
is Lambda -> it // lambda can be used in built in calculation, for example, in null check or toString
|
||||
else -> TODO("unsupported type of argument for builtins calculations: ${it::class.java}")
|
||||
}
|
||||
}
|
||||
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() })
|
||||
@@ -684,26 +689,31 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
val result = StringBuilder()
|
||||
expression.arguments.forEach {
|
||||
it.interpret().check { executionResult -> return executionResult }
|
||||
result.append(
|
||||
when (val returnValue = stack.popReturnValue()) {
|
||||
is Primitive<*> -> returnValue.value.toString()
|
||||
is Wrapper -> returnValue.value.toString()
|
||||
is Common -> {
|
||||
val toStringFun = returnValue.getToStringFunction()
|
||||
stack.newFrame(initPool = mutableListOf(Variable(toStringFun.getReceiver()!!, returnValue))) {
|
||||
toStringFun.body?.let { toStringFun.interpret() } ?: calculateBuiltIns(toStringFun)
|
||||
}.check { executionResult -> return executionResult }
|
||||
stack.popReturnValue().asString()
|
||||
}
|
||||
else -> throw InterpreterException("$returnValue cannot be used in StringConcatenation expression")
|
||||
}
|
||||
)
|
||||
interpretToString(stack.popReturnValue()).check { executionResult -> return executionResult }
|
||||
result.append(stack.popReturnValue().asString())
|
||||
}
|
||||
|
||||
stack.pushReturnValue(result.toString().toState(expression.type))
|
||||
return Next
|
||||
}
|
||||
|
||||
private suspend fun interpretToString(state: State): ExecutionResult {
|
||||
val result = when (state) {
|
||||
is Primitive<*> -> state.value.toString()
|
||||
is Wrapper -> state.value.toString()
|
||||
is Common -> {
|
||||
val toStringFun = state.getToStringFunction()
|
||||
return stack.newFrame(initPool = mutableListOf(Variable(toStringFun.getReceiver()!!, state))) {
|
||||
toStringFun.body?.let { toStringFun.interpret() } ?: calculateBuiltIns(toStringFun)
|
||||
}
|
||||
}
|
||||
is Lambda -> state.toString()
|
||||
else -> throw InterpreterException("${state::class.java} cannot be used in StringConcatenation expression")
|
||||
}
|
||||
stack.pushReturnValue(result.toState(irBuiltIns.stringType))
|
||||
return Next
|
||||
}
|
||||
|
||||
private fun interpretFunctionExpression(expression: IrFunctionExpression): ExecutionResult {
|
||||
val lambda = Lambda(expression.function, expression.type.classOrNull!!.owner)
|
||||
if (expression.function.isLocal) lambda.fields.addAll(stack.getAll()) // TODO save only necessary declarations
|
||||
|
||||
+2
-2
@@ -163,8 +163,8 @@ fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? {
|
||||
}
|
||||
}
|
||||
|
||||
fun IrType.getFqName(): String? {
|
||||
return this.classOrNull?.owner?.fqNameWhenAvailable?.asString()
|
||||
fun IrType.getFqName(withNullableSymbol: Boolean = false): String? {
|
||||
return this.classOrNull?.owner?.fqNameWhenAvailable?.asString()?.let { if (this.isNullable() && withNullableSymbol) "$it?" else it }
|
||||
}
|
||||
|
||||
fun IrFunction.getArgsForMethodInvocation(args: List<Variable>): List<Any?> {
|
||||
|
||||
+1
@@ -470,6 +470,7 @@ val ternaryFunctions = mapOf<CompileTimeFunction, Function3<Any?, Any?, Any?, An
|
||||
|
||||
private fun Any.defaultToString(): String {
|
||||
return when (this) {
|
||||
is Lambda -> this.toString()
|
||||
is State -> "${this.irClass.name}@" + System.identityHashCode(this).toString(16).padStart(8, '0')
|
||||
else -> this.toString().replaceAfter("@", System.identityHashCode(this).toString(16).padStart(8, '0'))
|
||||
}
|
||||
|
||||
+5
-2
@@ -6,11 +6,11 @@
|
||||
package org.jetbrains.kotlin.backend.common.interpreter.state
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.equalTo
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.getFqName
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
|
||||
|
||||
class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State {
|
||||
@@ -32,6 +32,9 @@ class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Lambda(${irClass.fqNameForIrSerialization})"
|
||||
val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.getFqName(true)
|
||||
val arguments = irFunction.valueParameters.map { it.type.getFqName(true) }.joinToString(prefix = "(", postfix = ")")
|
||||
val returnType = irFunction.returnType.getFqName(true)
|
||||
return ("$arguments -> $returnType").let { if (receiver != null) "$receiver.$it" else it }
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,7 @@ fun generateMap(): String {
|
||||
"""
|
||||
private fun Any.defaultToString(): String {
|
||||
return when (this) {
|
||||
is Lambda -> this.toString()
|
||||
is State -> "${'$'}{this.irClass.name}@" + System.identityHashCode(this).toString(16).padStart(8, '0')
|
||||
else -> this.toString().replaceAfter("@", System.identityHashCode(this).toString(16).padStart(8, '0'))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user