[IR] Simplify calculateBuiltIns method in interpreter
This commit is contained in:
+26
-28
@@ -144,6 +144,9 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
|
||||
return true
|
||||
}
|
||||
|
||||
private data class Signature(var name: String, var args: List<Arg>)
|
||||
private data class Arg(var type: String, var value: Any?)
|
||||
|
||||
private fun calculateBuiltIns(irFunction: IrFunction, args: List<State>) {
|
||||
val methodName = when (val property = irFunction.property?.symbol) {
|
||||
null -> irFunction.name.asString()
|
||||
@@ -151,42 +154,37 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
|
||||
}
|
||||
|
||||
val receiverType = irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type
|
||||
val argsType = (listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type }).map {
|
||||
// TODO: for consistency with current K/JS implementation Float constant should be treated as a Double (KT-35422)
|
||||
if (environment.configuration.treatFloatInSpecialWay && it.makeNotNull().isFloat()) {
|
||||
if (it.isNullable()) irBuiltIns.doubleType.makeNullable() else irBuiltIns.doubleType
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
val argsType = (listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type }).map { it.getOnlyName() }
|
||||
val argsValues = args.wrap(this, irFunction)
|
||||
|
||||
// TODO replace unary, binary, ternary functions with vararg
|
||||
withExceptionHandler(environment) {
|
||||
val result = when (argsType.size) {
|
||||
1 -> when {
|
||||
methodName == "toString" && environment.configuration.treatFloatInSpecialWay && (argsValues[0] is Double || argsValues[0] is Float) -> {
|
||||
argsValues[0].specialToStringForJs()
|
||||
}
|
||||
else -> interpretUnaryFunction(methodName, argsType[0].getOnlyName(), argsValues[0])
|
||||
}
|
||||
2 -> when (methodName) {
|
||||
"rangeTo" -> return calculateRangeTo(irFunction.returnType, args)
|
||||
else -> interpretBinaryFunction(
|
||||
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsValues[0], argsValues[1]
|
||||
)
|
||||
}
|
||||
3 -> interpretTernaryFunction(
|
||||
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsType[2].getOnlyName(),
|
||||
argsValues[0], argsValues[1], argsValues[2]
|
||||
)
|
||||
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin function: $methodName")
|
||||
}
|
||||
if (methodName == "rangeTo") return calculateRangeTo(irFunction.returnType, args)
|
||||
val result = interpretBuiltinFunction(Signature(methodName, argsType.zip(argsValues).map { Arg(it.first, it.second) }))
|
||||
// TODO check "result is Unit"
|
||||
callStack.pushState(environment.convertToState(result, result.getType(irFunction.returnType)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun interpretBuiltinFunction(signature: Signature): Any? {
|
||||
if (environment.configuration.treatFloatInSpecialWay) {
|
||||
if (signature.name == "toString") return signature.args[0].value.specialToStringForJs()
|
||||
if (signature.name == "toFloat") signature.name = "toDouble"
|
||||
signature.args.filter { it.type == "Float" }.forEach {
|
||||
it.type = "Double"
|
||||
it.value = it.value.toString().toDouble()
|
||||
}
|
||||
}
|
||||
|
||||
val name = signature.name
|
||||
val args = signature.args
|
||||
return when (args.size) {
|
||||
1 -> interpretUnaryFunction(name, args[0].type, args[0].value)
|
||||
2 -> interpretBinaryFunction(name, args[0].type, args[1].type, args[0].value, args[1].value)
|
||||
3 -> interpretTernaryFunction(name, args[0].type, args[1].type, args[2].type, args[0].value, args[1].value, args[2].value)
|
||||
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin function: $name")
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateRangeTo(type: IrType, args: List<State>) {
|
||||
val constructor = type.classOrNull!!.owner.constructors.first()
|
||||
val constructorCall = constructor.createConstructorCall()
|
||||
|
||||
+1
-1
@@ -395,7 +395,7 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
|
||||
val explicitToStringCheck = fun() {
|
||||
when (val state = callStack.peekState()) {
|
||||
is Primitive<*> -> {
|
||||
// This block is not really needed, but this way it is easier to handle `toString` with `treatFloatInSpecialWay` enabled.
|
||||
// This block is not really needed, but this way it is easier to handle `toString` for JS.
|
||||
callStack.popState()
|
||||
val toStringCall = IrCallImpl.fromSymbolOwner(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
internal val TEMP_CLASS_FOR_INTERPRETER = object : IrDeclarationOriginImpl("TEMP_CLASS_FOR_INTERPRETER") {}
|
||||
internal val TEMP_FUNCTION_FOR_INTERPRETER = object : IrDeclarationOriginImpl("TEMP_FUNCTION_FOR_INTERPRETER") {}
|
||||
|
||||
fun Any?.toIrConstOrNull(irType: IrType, startOffset: Int = SYNTHETIC_OFFSET, endOffset: Int = SYNTHETIC_OFFSET): IrConst<*>? {
|
||||
private fun Any?.toIrConstOrNull(irType: IrType, startOffset: Int = SYNTHETIC_OFFSET, endOffset: Int = SYNTHETIC_OFFSET): IrConst<*>? {
|
||||
if (this == null) return IrConstImpl.constNull(startOffset, endOffset, irType)
|
||||
|
||||
val constType = irType.makeNotNull().removeAnnotations()
|
||||
|
||||
-7
@@ -61,13 +61,6 @@ class IrInterpreterCommonChecker : IrInterpreterChecker {
|
||||
val owner = expression.symbol.owner
|
||||
if (!data.mode.canEvaluateFunction(owner)) return false
|
||||
|
||||
// We disable `toFloat` folding on K/JS till `toFloat` is fixed (KT-35422)
|
||||
// This check must be placed here instead of CallInterceptor because we still
|
||||
// want to evaluate (1) `const val` expressions and (2) values in annotations.
|
||||
if (owner.name.asString() == "toFloat" && data.interpreterConfiguration.treatFloatInSpecialWay) {
|
||||
return super.visitCall(expression, data)
|
||||
}
|
||||
|
||||
if (expression.dispatchReceiver.isAccessToNotNullableObject()) {
|
||||
return expression.isGetterToConstVal()
|
||||
}
|
||||
|
||||
@@ -35,8 +35,6 @@ internal fun State.wrap(callInterceptor: CallInterceptor, remainArraysAsIs: Bool
|
||||
is Primitive<*> -> when {
|
||||
this.isNull() -> null
|
||||
this.type.isArray() || this.type.isPrimitiveArray() -> if (remainArraysAsIs) this else this.value
|
||||
// TODO: for consistency with current K/JS implementation Float constant should be treated as a Double (KT-35422)
|
||||
this.type.isFloat() && callInterceptor.environment.configuration.treatFloatInSpecialWay -> this.value.toString().toDouble()
|
||||
else -> this.value
|
||||
}
|
||||
is Common -> this.asProxy(callInterceptor, extendFrom)
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ internal abstract class IrConstAnnotationTransformer(
|
||||
}
|
||||
|
||||
private fun IrExpression.transformSingleArg(expectedType: IrType): IrExpression {
|
||||
if (this.canBeInterpreted(configuration = interpreter.environment.configuration.copy(treatFloatInSpecialWay = false))) {
|
||||
if (this.canBeInterpreted()) {
|
||||
return this.interpret(failAsError = true).convertToConstIfPossible(expectedType)
|
||||
} else if (this is IrConstructorCall) {
|
||||
transformAnnotation(this)
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ internal class IrConstExpressionTransformer(
|
||||
if (!isConst) return super.visitField(declaration, data)
|
||||
|
||||
val getField = declaration.createGetField()
|
||||
if (getField.canBeInterpreted(interpreter.environment.configuration.copy(treatFloatInSpecialWay = false))) {
|
||||
if (getField.canBeInterpreted()) {
|
||||
initializer.expression = expression.interpret(failAsError = true)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user