Change IrInterpreter to modify tree structure into the flat one
This modification is necessary to implement right control flow
This commit is contained in:
+322
-151
@@ -5,172 +5,343 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.interpreter
|
package org.jetbrains.kotlin.backend.common.interpreter
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunction
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.binaryFunctions
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.*
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.*
|
||||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
import org.jetbrains.kotlin.ir.util.statements
|
import org.jetbrains.kotlin.ir.util.statements
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
class IrInterpreter : IrElementVisitor<State, Frame> {
|
enum class Code(var info: String = "") {
|
||||||
private val builtIns = DefaultBuiltIns.Instance
|
NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
|
||||||
private val empty = EmptyState()
|
}
|
||||||
|
|
||||||
fun interpret(expression: IrExpression): IrExpression {
|
fun interpret(expression: IrExpression): IrExpression {
|
||||||
return visitExpression(expression, InterpreterFrame()).toIrExpression(expression)
|
return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitElement(element: IrElement, data: Frame): State {
|
fun IrElement.interpret(data: Frame): Code {
|
||||||
return when (element) {
|
try {
|
||||||
is IrCall -> visitCall(element, data)
|
val code = when (this) {
|
||||||
is IrConstructorCall -> visitConstructor(element, data)
|
is IrCall -> this.interpretCall(data)
|
||||||
is IrDelegatingConstructorCall -> visitDelegatingConstructorCall(element, data)
|
is IrConstructorCall -> this.interpretConstructorCall(data)
|
||||||
is IrBody -> visitStatements(element.statements, data)
|
is IrDelegatingConstructorCall -> this.interpretDelegatedConstructorCall(data)
|
||||||
is IrBlock -> visitStatements(element.statements, data)
|
is IrBody -> this.interpretBody(data)
|
||||||
is IrSetField -> visitSetField(element, data)
|
is IrBlock -> this.interpretBlock(data)
|
||||||
is IrGetField -> visitGetField(element, data)
|
is IrReturn -> this.interpretReturn(data)
|
||||||
is IrGetValue -> visitGetValue(element, data)
|
is IrSetField -> this.interpretSetField(data)
|
||||||
is IrGetObjectValue -> visitGetObjectValue(element, data)
|
is IrGetField -> this.interpretGetField(data)
|
||||||
is IrConst<*> -> visitConst(element, data)
|
is IrGetValue -> this.interpretGetValue(data)
|
||||||
is IrWhen -> visitWhen(element, data)
|
is IrGetObjectValue -> this.interpretGetObjectValue(data)
|
||||||
else -> TODO("${element.javaClass} not supported")
|
is IrConst<*> -> this.interpretConst(data)
|
||||||
|
is IrVariable -> this.interpretVariable(data)
|
||||||
|
is IrSetVariable -> this.interpretSetVariable(data)
|
||||||
|
is IrTypeOperatorCall -> this.interpretTypeOperatorCall(data)
|
||||||
|
is IrBranch -> this.interpretBranch(data)
|
||||||
|
is IrWhileLoop -> this.interpretWhile(data)
|
||||||
|
is IrWhen -> this.interpretWhen(data)
|
||||||
|
is IrBreak -> this.interpretBreak(data)
|
||||||
|
|
||||||
|
else -> TODO("${this.javaClass} not supported")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall, data: Frame): State {
|
return when (code) {
|
||||||
val newFrame = InterpreterFrame()
|
Code.RETURN -> when (this) {
|
||||||
val valueParameters = convertValueParameters(expression, data)
|
is IrCall -> Code.NEXT
|
||||||
|
else -> Code.RETURN
|
||||||
val dispatchReceiver = expression.dispatchReceiver?.accept(this, data) // can be either Primitive or Complex
|
|
||||||
val extensionReceiver = expression.extensionReceiver?.accept(this, data) // similarly
|
|
||||||
|
|
||||||
val irFunction = dispatchReceiver.getIrFunction(expression)
|
|
||||||
// it is important firstly to add receiver, then arguments
|
|
||||||
val receiverParameter = irFunction.symbol.getReceiverDescriptor()
|
|
||||||
val receiver = (dispatchReceiver ?: extensionReceiver)
|
|
||||||
receiver?.let { newFrame.addVar(Variable(receiverParameter!!, it)) }
|
|
||||||
newFrame.addAll(valueParameters)
|
|
||||||
|
|
||||||
return when {
|
|
||||||
expression.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be first
|
|
||||||
expression.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame)
|
|
||||||
expression.getBody() == null -> calculateBuiltIns(expression, newFrame).toState(expression)
|
|
||||||
else -> (irFunction.body ?: expression.getBody())!!.accept(this, newFrame)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T> visitConst(expression: IrConst<T>, data: Frame): State {
|
|
||||||
return expression.toPrimitive()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitConstructor(constructor: IrFunctionAccessExpression, data: Frame): State {
|
|
||||||
val newFrame = InterpreterFrame(convertValueParameters(constructor, data))
|
|
||||||
val obj = Complex(constructor.symbol.owner.parent as IrClass, mutableListOf())
|
|
||||||
constructor.getBody()?.statements?.forEach {
|
|
||||||
when (it) {
|
|
||||||
is IrDelegatingConstructorCall -> {
|
|
||||||
val delegatingConstructorCall = visitDelegatingConstructorCall(it, newFrame)
|
|
||||||
if (delegatingConstructorCall != empty) {
|
|
||||||
val superObj = Variable(it.getThisAsReceiver(), delegatingConstructorCall)
|
|
||||||
obj.addSuperQualifier(superObj)
|
|
||||||
}
|
|
||||||
newFrame.addVar(Variable(constructor.getThisAsReceiver(), obj))
|
|
||||||
}
|
|
||||||
else -> it.accept(this, newFrame)
|
|
||||||
}
|
}
|
||||||
}
|
Code.BREAK_WHEN -> when (this) {
|
||||||
return obj
|
is IrWhen -> Code.NEXT
|
||||||
}
|
else -> code
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Frame): State {
|
|
||||||
if (expression.symbol.descriptor.containingDeclaration.defaultType == builtIns.anyType) {
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
return visitConstructor(expression, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitStatements(statements: List<IrStatement>, data: Frame): State {
|
|
||||||
statements.forEachIndexed { index, statement ->
|
|
||||||
when {
|
|
||||||
statement is IrReturn || index == statements.lastIndex -> return statement.accept(this, data)
|
|
||||||
else -> statement.accept(this, data)
|
|
||||||
}
|
}
|
||||||
}
|
Code.BREAK_LOOP -> when (this) {
|
||||||
|
is IrWhileLoop -> if ((this.label ?: "") == code.info) Code.NEXT else code
|
||||||
// unreachable state; method must return inside forEach
|
else -> code
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn, data: Frame): State {
|
|
||||||
return expression.value.accept(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitSetField(expression: IrSetField, data: Frame): State {
|
|
||||||
val value = expression.value.accept(this, data)
|
|
||||||
val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor
|
|
||||||
data.getVariableState(receiver).setState(Variable(expression.symbol.owner.descriptor, value))
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField, data: Frame): State {
|
|
||||||
val receiver = (expression.receiver as? IrDeclarationReference)?.symbol?.descriptor // receiver is null, for example, for top level fields
|
|
||||||
return receiver?.let { data.getVariableState(receiver).getState(expression.symbol.descriptor)?.copy() }
|
|
||||||
?: expression.symbol.owner.initializer!!.expression.accept(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue, data: Frame): State {
|
|
||||||
return data.getVariableState(expression.symbol.descriptor).copy()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitVariable(declaration: IrVariable, data: Frame): State {
|
|
||||||
val variable = declaration.initializer?.accept(this, data)
|
|
||||||
variable?.let { data.addVar(Variable(declaration.descriptor, it)) }
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitSetVariable(expression: IrSetVariable, data: Frame): State {
|
|
||||||
if (data.contains(expression.symbol.descriptor)) {
|
|
||||||
val variable = data.getVariableState(expression.symbol.descriptor)
|
|
||||||
variable.setState(Variable(expression.symbol.descriptor, expression.value.accept(this, data)))
|
|
||||||
} else {
|
|
||||||
val variable = expression.value.accept(this, data)
|
|
||||||
data.addVar(Variable(expression.symbol.descriptor, variable))
|
|
||||||
}
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitWhen(expression: IrWhen, data: Frame): State {
|
|
||||||
expression.branches.forEach {
|
|
||||||
if ((it.condition.accept(this, data) as? Primitive<*>)?.getIrConst()?.value == true) {
|
|
||||||
return it.result.accept(this, data)
|
|
||||||
}
|
}
|
||||||
|
Code.CONTINUE -> TODO("Code.CONTINUE not implemented")
|
||||||
|
Code.EXCEPTION -> TODO("Code.EXCEPTION not implemented")
|
||||||
|
Code.NEXT -> Code.NEXT
|
||||||
}
|
}
|
||||||
return empty
|
} catch (e: Exception) {
|
||||||
}
|
e.printStackTrace()
|
||||||
|
assert(false)
|
||||||
override fun visitGetObjectValue(expression: IrGetObjectValue, data: Frame): State {
|
return Code.EXCEPTION
|
||||||
return Complex(expression.symbol.owner, mutableListOf())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: Frame): State {
|
|
||||||
when (expression.operator) {
|
|
||||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
|
|
||||||
expression.argument.accept(this, data)
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
else -> TODO("${expression.operator} not implemented")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitWhileLoop(loop: IrWhileLoop, data: Frame): State {
|
|
||||||
while ((loop.condition.accept(this, data) as? Primitive<*>)?.getIrConst()?.value == true) {
|
|
||||||
loop.body?.accept(this, InterpreterFrame(data.getAll().toMutableList()))
|
|
||||||
}
|
|
||||||
return empty
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun calculateAbstract(irFunction: IrFunction, data: Frame): Code {
|
||||||
|
return irFunction.body?.interpret(data)
|
||||||
|
?: throw NoSuchMethodException("Method \"${irFunction.name}\" wasn't implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateOverridden(owner: IrFunctionImpl, data: Frame): Code {
|
||||||
|
val variableDescriptor = owner.symbol.getThisAsReceiver()!!
|
||||||
|
val superQualifier = (data.getVariableState(variableDescriptor) as Complex).getSuperQualifier()!!
|
||||||
|
val overridden = owner.overriddenSymbols.first { it.getThisAsReceiver()?.equalTo(superQualifier.getThisReceiver()) == true }
|
||||||
|
|
||||||
|
val valueParameters = owner.valueParameters.zip(overridden.owner.valueParameters)
|
||||||
|
.map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) }
|
||||||
|
val newStates = InterpreterFrame((valueParameters + Variable(superQualifier.getThisReceiver(), superQualifier)).toMutableList())
|
||||||
|
|
||||||
|
val overriddenOwner = overridden.owner as IrFunctionImpl
|
||||||
|
val body = overriddenOwner.body
|
||||||
|
return when {
|
||||||
|
body != null -> body.interpret(newStates)
|
||||||
|
else -> calculateOverridden(overriddenOwner, newStates)
|
||||||
|
}.apply { data.pushReturnValue(newStates) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isBuiltIn(irFunction: IrFunction): Boolean {
|
||||||
|
val descriptor = irFunction.descriptor
|
||||||
|
val methodName = descriptor.name.asString()
|
||||||
|
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
||||||
|
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) }
|
||||||
|
val signature = CompileTimeFunction(
|
||||||
|
methodName,
|
||||||
|
argsType.map { it.toString() })
|
||||||
|
return (unaryFunctions[signature] ?: binaryFunctions[signature]) != null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateBuiltIns(expression: IrCall, data: Frame): Code {
|
||||||
|
val descriptor = expression.symbol.descriptor
|
||||||
|
val methodName = descriptor.name.asString()
|
||||||
|
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
||||||
|
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) }
|
||||||
|
val argsValues = data.getAll()
|
||||||
|
.map { it.state }
|
||||||
|
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
||||||
|
.map { it.getIrConst().value }
|
||||||
|
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() })
|
||||||
|
//todo try catch
|
||||||
|
val result = when (argsType.size) {
|
||||||
|
1 -> {
|
||||||
|
val function = unaryFunctions[signature]
|
||||||
|
?: throw NoSuchMethodException("For given function $signature there is no entry in unary map")
|
||||||
|
function.invoke(argsValues.first())
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
val function = binaryFunctions[signature]
|
||||||
|
?: throw NoSuchMethodException("For given function $signature there is no entry in binary map")
|
||||||
|
when (methodName) {
|
||||||
|
"rangeTo" -> return calculateRangeTo(expression, data)
|
||||||
|
else -> function.invoke(argsValues[0], argsValues[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw UnsupportedOperationException("Unsupported number of arguments")
|
||||||
|
}
|
||||||
|
data.pushReturnValue(result.toState(expression))
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateRangeTo(expression: IrExpression, data: Frame): Code {
|
||||||
|
val constructor = expression.type.classOrNull!!.owner.constructors.first()
|
||||||
|
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
||||||
|
|
||||||
|
val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> }
|
||||||
|
primitiveValueParameters.forEachIndexed { index, primitive -> constructorCall.putValueArgument(index, primitive.getIrConst()) }
|
||||||
|
|
||||||
|
val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters)
|
||||||
|
val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList())
|
||||||
|
|
||||||
|
val code = constructorCall.interpret(newFrame)
|
||||||
|
data.pushReturnValue(newFrame)
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrMemberAccessExpression.interpretValueParameters(data: Frame): Code {
|
||||||
|
for (i in (this.valueArgumentsCount - 1) downTo 0) {
|
||||||
|
val code = this.getValueArgument(i)?.interpret(data) ?: Code.NEXT
|
||||||
|
if (code != Code.NEXT) return code
|
||||||
|
}
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrCall.interpretCall(data: Frame): Code {
|
||||||
|
val newFrame = InterpreterFrame()
|
||||||
|
|
||||||
|
this.interpretValueParameters(data).also { if (it != Code.NEXT) return it }
|
||||||
|
val valueParameters = this.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }
|
||||||
|
|
||||||
|
val rawReceiver = this.dispatchReceiver ?: this.extensionReceiver
|
||||||
|
rawReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it }
|
||||||
|
|
||||||
|
val receiver = rawReceiver?.let { data.popReturnValue() }
|
||||||
|
val irFunction = receiver.getIrFunction(this)
|
||||||
|
val receiverParameter = irFunction.symbol.getThisAsReceiver()
|
||||||
|
// it is important firstly to add receiver, then arguments
|
||||||
|
receiver?.let { newFrame.addVar(Variable(receiverParameter!!, it)) }
|
||||||
|
newFrame.addAll(valueParameters)
|
||||||
|
|
||||||
|
val code = when {
|
||||||
|
//irFunction.annotations.any { it.descriptor.containingDeclaration.fqNameSafe == evaluateIntrinsicAnnotation } -> empty
|
||||||
|
isBuiltIn(irFunction) -> calculateBuiltIns(this, newFrame)
|
||||||
|
this.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check
|
||||||
|
this.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame)
|
||||||
|
else -> (irFunction.body ?: this.getBody())!!.interpret(newFrame)
|
||||||
|
}
|
||||||
|
data.pushReturnValue(newFrame)
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrFunctionAccessExpression.interpretConstructor(data: Frame): Code {
|
||||||
|
this.interpretValueParameters(data).also { if (it != Code.NEXT) return it }
|
||||||
|
val valueParameters = this.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList()
|
||||||
|
|
||||||
|
val newFrame = InterpreterFrame(valueParameters)
|
||||||
|
val state = Complex(this.symbol.owner.parent as IrClass, mutableListOf())
|
||||||
|
newFrame.addVar(Variable(this.getThisAsReceiver(), state)) //used to set up fields in body
|
||||||
|
val code = this.getBody()?.interpret(newFrame) ?: Code.NEXT
|
||||||
|
if (newFrame.hasReturnValue()) {
|
||||||
|
state.setSuperQualifier(newFrame.popReturnValue() as Complex)
|
||||||
|
}
|
||||||
|
data.pushReturnValue(state)
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrConstructorCall.interpretConstructorCall(data: Frame): Code {
|
||||||
|
return this.interpretConstructor(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrDelegatingConstructorCall.interpretDelegatedConstructorCall(data: Frame): Code {
|
||||||
|
if (this.symbol.descriptor.containingDeclaration.defaultType == DefaultBuiltIns.Instance.anyType) {
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.interpretConstructor(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrConst<*>.interpretConst(data: Frame): Code {
|
||||||
|
data.pushReturnValue(this.toPrimitive())
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<IrStatement>.interpretStatements(data: Frame): Code {
|
||||||
|
//create newFrame
|
||||||
|
val newFrame = data.copy()
|
||||||
|
|
||||||
|
var code = Code.NEXT
|
||||||
|
val iterator = this.asSequence().iterator()
|
||||||
|
while (code == Code.NEXT && iterator.hasNext()) {
|
||||||
|
code = iterator.next().interpret(newFrame)
|
||||||
|
}
|
||||||
|
data.pushReturnValue(newFrame)
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBlock.interpretBlock(data: Frame): Code {
|
||||||
|
return this.statements.interpretStatements(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBody.interpretBody(data: Frame): Code {
|
||||||
|
return this.statements.interpretStatements(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrReturn.interpretReturn(data: Frame): Code {
|
||||||
|
val code = this.value.interpret(data)
|
||||||
|
return if (code == Code.NEXT) Code.RETURN else code
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrWhileLoop.interpretWhile(data: Frame): Code {
|
||||||
|
var code = Code.NEXT
|
||||||
|
while (code == Code.NEXT) {
|
||||||
|
code = this.condition.interpret(data)
|
||||||
|
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getIrConst()?.value as? Boolean == true) {
|
||||||
|
code = this.body?.interpret(data) ?: Code.NEXT
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrWhen.interpretWhen(data: Frame): Code {
|
||||||
|
var code = Code.NEXT
|
||||||
|
val iterator = this.branches.asSequence().iterator()
|
||||||
|
while (code == Code.NEXT && iterator.hasNext()) {
|
||||||
|
code = iterator.next().interpret(data)
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBranch.interpretBranch(data: Frame): Code {
|
||||||
|
var code = this.condition.interpret(data)
|
||||||
|
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getIrConst()?.value as? Boolean == true) {
|
||||||
|
code = this.result.interpret(data)
|
||||||
|
if (code == Code.NEXT) return Code.BREAK_WHEN
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBreak.interpretBreak(data: Frame): Code {
|
||||||
|
return Code.BREAK_LOOP.apply { info = this@interpretBreak.label ?: "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrSetField.interpretSetField(data: Frame): Code {
|
||||||
|
val code = this.value.interpret(data)
|
||||||
|
if (code != Code.NEXT) return code
|
||||||
|
|
||||||
|
val receiver = (this.receiver as IrDeclarationReference).symbol.descriptor
|
||||||
|
data.getVariableState(receiver).setState(Variable(this.symbol.owner.descriptor, data.popReturnValue()))
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrGetField.interpretGetField(data: Frame): Code {
|
||||||
|
val receiver = (this.receiver as? IrDeclarationReference)?.symbol?.descriptor // receiver is null, for example, for top level fields
|
||||||
|
val result = receiver?.let { data.getVariableState(receiver).getState(this.symbol.descriptor)?.copy() }
|
||||||
|
if (result == null) {
|
||||||
|
return this.symbol.owner.initializer?.expression?.interpret(data) ?: Code.NEXT
|
||||||
|
}
|
||||||
|
data.pushReturnValue(result)
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrGetValue.interpretGetValue(data: Frame): Code {
|
||||||
|
data.pushReturnValue(data.getVariableState(this.symbol.descriptor).copy())
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrVariable.interpretVariable(data: Frame): Code {
|
||||||
|
val code = this.initializer?.interpret(data)
|
||||||
|
if (code != Code.NEXT) return code ?: Code.NEXT
|
||||||
|
data.addVar(Variable(this.descriptor, data.popReturnValue()))
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrSetVariable.interpretSetVariable(data: Frame): Code {
|
||||||
|
val code = this.value.interpret(data)
|
||||||
|
if (code != Code.NEXT) return code
|
||||||
|
|
||||||
|
if (data.contains(this.symbol.descriptor)) {
|
||||||
|
val variable = data.getVariableState(this.symbol.descriptor)
|
||||||
|
variable.setState(Variable(this.symbol.descriptor, data.popReturnValue()))
|
||||||
|
} else {
|
||||||
|
data.addVar(Variable(this.symbol.descriptor, data.popReturnValue()))
|
||||||
|
}
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrGetObjectValue.interpretGetObjectValue(data: Frame): Code {
|
||||||
|
data.pushReturnValue(Complex(this.symbol.owner, mutableListOf()))
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrTypeOperatorCall.interpretTypeOperatorCall(data: Frame): Code {
|
||||||
|
return when (this.operator) {
|
||||||
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
|
||||||
|
this.argument.interpret(data)
|
||||||
|
}
|
||||||
|
IrTypeOperator.CAST -> {
|
||||||
|
this.argument.interpret(data) //todo check cast correctness
|
||||||
|
}
|
||||||
|
else -> TODO("${this.operator} not implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-91
@@ -5,114 +5,35 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.interpreter
|
package org.jetbrains.kotlin.backend.common.interpreter
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunction
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Complex
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.binaryFunctions
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.State
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.*
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
|
||||||
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
|
|
||||||
fun IrInterpreter.calculateAbstract(irFunction: IrFunction?, data: Frame): State {
|
|
||||||
return irFunction?.body?.accept(this, data)
|
|
||||||
?: throw NoSuchMethodException("Method \"$irFunction\" wasn't implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrInterpreter.calculateOverridden(owner: IrFunctionImpl, data: Frame): State {
|
|
||||||
val overridden = owner.overriddenSymbols.first()
|
|
||||||
|
|
||||||
val variableDescriptor = owner.symbol.getReceiverDescriptor()!!
|
|
||||||
val overriddenReceiver = overridden.getReceiverDescriptor()!!
|
|
||||||
val overriddenReceiverState = data.getVariableState(variableDescriptor).getState(overriddenReceiver)
|
|
||||||
?: throw NoSuchElementException("Variable \"$variableDescriptor\" doesn't contains state \"$overriddenReceiver\"")
|
|
||||||
|
|
||||||
val valueParameters = owner.valueParameters.zip(overridden.owner.valueParameters)
|
|
||||||
.map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) }
|
|
||||||
val newStates = InterpreterFrame((valueParameters + Variable(overriddenReceiver, overriddenReceiverState)).toMutableList())
|
|
||||||
|
|
||||||
var overriddenOwner: IrSimpleFunction? = overridden.owner
|
|
||||||
do {
|
|
||||||
val body = overriddenOwner?.body
|
|
||||||
when {
|
|
||||||
body != null -> return body.accept(this, newStates)
|
|
||||||
else -> overriddenOwner = overriddenOwner?.overriddenSymbols?.firstOrNull()?.owner
|
|
||||||
}
|
|
||||||
} while (overriddenOwner != null)
|
|
||||||
|
|
||||||
throw NoSuchMethodException("$owner has no body")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrInterpreter.calculateBuiltIns(expression: IrCall, frame: Frame): Any {
|
|
||||||
val descriptor = expression.symbol.descriptor
|
|
||||||
val methodName = descriptor.name.asString()
|
|
||||||
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
|
||||||
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) }
|
|
||||||
val argsValues = frame.getAll()
|
|
||||||
.map { it.state }
|
|
||||||
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
|
||||||
.map { it.getIrConst().value }
|
|
||||||
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() })
|
|
||||||
return when (argsType.size) {
|
|
||||||
1 -> {
|
|
||||||
val function = unaryFunctions[signature]
|
|
||||||
?: throw NoSuchMethodException("For given function $signature there is no entry in unary map")
|
|
||||||
function.invoke(argsValues.first())
|
|
||||||
}
|
|
||||||
2 -> {
|
|
||||||
val function = binaryFunctions[signature]
|
|
||||||
?: throw NoSuchMethodException("For given function $signature there is no entry in binary map")
|
|
||||||
when (methodName) {
|
|
||||||
"rangeTo" -> calculateRangeTo(expression, frame)
|
|
||||||
else -> function.invoke(argsValues[0], argsValues[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> throw UnsupportedOperationException("Unsupported number of arguments")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrInterpreter.calculateRangeTo(expression: IrExpression, data: Frame): Any {
|
|
||||||
val constructor = expression.type.classOrNull!!.owner.constructors.first()
|
|
||||||
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
|
||||||
|
|
||||||
val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> }
|
|
||||||
primitiveValueParameters.forEachIndexed { index, primitive -> constructorCall.putValueArgument(index, primitive.getIrConst()) }
|
|
||||||
|
|
||||||
val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters)
|
|
||||||
val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList())
|
|
||||||
|
|
||||||
return constructorCall.accept(this, newFrame)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrInterpreter.convertValueParameters(memberAccess: IrMemberAccessExpression, data: Frame): MutableList<Variable> {
|
|
||||||
return mutableListOf<Variable>().apply {
|
|
||||||
for (i in 0 until memberAccess.valueArgumentsCount) {
|
|
||||||
val arg = memberAccess.getValueArgument(i)?.accept(this@convertValueParameters, data)
|
|
||||||
arg?.let { add(Variable((memberAccess.symbol.descriptor as FunctionDescriptor).valueParameters[i], it)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// main purpose is to get receiver from constructor call
|
// main purpose is to get receiver from constructor call
|
||||||
fun IrFunctionAccessExpression.getThisAsReceiver(): DeclarationDescriptor {
|
fun IrMemberAccessExpression.getThisAsReceiver(): DeclarationDescriptor {
|
||||||
return (this.symbol.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter
|
return (this.symbol.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrFunctionSymbol.getReceiverDescriptor(): DeclarationDescriptor? {
|
fun IrFunctionSymbol.getThisAsReceiver(): DeclarationDescriptor? {
|
||||||
return this.owner.dispatchReceiverParameter?.descriptor ?: this.owner.extensionReceiverParameter?.descriptor
|
return (this.descriptor.containingDeclaration as? ClassDescriptor)?.thisAsReceiverParameter
|
||||||
|
?: this.owner.extensionReceiverParameter?.descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*fun IrFunctionSymbol.getReceiverDescriptor(): DeclarationDescriptor? {
|
||||||
|
return this.owner.dispatchReceiverParameter?.descriptor ?: this.owner.extensionReceiverParameter?.descriptor
|
||||||
|
}*/
|
||||||
|
|
||||||
fun IrFunctionAccessExpression.getBody(): IrBody? {
|
fun IrFunctionAccessExpression.getBody(): IrBody? {
|
||||||
return this.symbol.owner.body
|
return this.symbol.owner.body
|
||||||
}
|
}
|
||||||
@@ -143,7 +64,7 @@ fun IrCall.isFakeOverridden(): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun State?.getIrFunction(expression: IrCall): IrFunction {
|
fun State?.getIrFunction(expression: IrCall): IrFunction {
|
||||||
return this.let { (it as? Complex)?.getIrFunctionByName(expression.symbol.descriptor.name) } ?: expression.symbol.owner
|
return this.let { it?.getIrFunctionByName(expression.symbol.descriptor.name) } ?: expression.symbol.owner
|
||||||
}
|
}
|
||||||
|
|
||||||
fun State.toIrExpression(expression: IrExpression): IrExpression {
|
fun State.toIrExpression(expression: IrExpression): IrExpression {
|
||||||
|
|||||||
+43
-1
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.backend.common.interpreter.stack
|
|||||||
import org.jetbrains.kotlin.backend.common.interpreter.equalTo
|
import org.jetbrains.kotlin.backend.common.interpreter.equalTo
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||||
import java.util.*
|
import kotlin.NoSuchElementException
|
||||||
|
|
||||||
data class Variable(val descriptor: DeclarationDescriptor, val state: State) {
|
data class Variable(val descriptor: DeclarationDescriptor, val state: State) {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
@@ -26,9 +26,19 @@ interface Frame {
|
|||||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
||||||
fun getAll(): List<Variable>
|
fun getAll(): List<Variable>
|
||||||
fun contains(descriptor: DeclarationDescriptor): Boolean
|
fun contains(descriptor: DeclarationDescriptor): Boolean
|
||||||
|
fun pushReturnValue(state: State)
|
||||||
|
fun pushReturnValue(frame: Frame)
|
||||||
|
fun peekReturnValue(): State
|
||||||
|
//fun peekReturnValueOrNull(): State?
|
||||||
|
fun popReturnValue(): State
|
||||||
|
//fun popReturnValueOrNull(): State?
|
||||||
|
fun hasReturnValue(): Boolean
|
||||||
|
fun copy(): Frame
|
||||||
}
|
}
|
||||||
|
|
||||||
class InterpreterFrame(val pool: MutableList<Variable> = mutableListOf()) : Frame {
|
class InterpreterFrame(val pool: MutableList<Variable> = mutableListOf()) : Frame {
|
||||||
|
private val returnStack: MutableList<State> = mutableListOf()
|
||||||
|
|
||||||
override fun addVar(variable: Variable) {
|
override fun addVar(variable: Variable) {
|
||||||
pool.add(variable)
|
pool.add(variable)
|
||||||
}
|
}
|
||||||
@@ -49,4 +59,36 @@ class InterpreterFrame(val pool: MutableList<Variable> = mutableListOf()) : Fram
|
|||||||
override fun contains(descriptor: DeclarationDescriptor): Boolean {
|
override fun contains(descriptor: DeclarationDescriptor): Boolean {
|
||||||
return pool.any { it.descriptor == descriptor }
|
return pool.any { it.descriptor == descriptor }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun pushReturnValue(state: State) {
|
||||||
|
returnStack += state
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pushReturnValue(frame: Frame) {
|
||||||
|
if (frame.hasReturnValue()) this.pushReturnValue(frame.popReturnValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasReturnValue(): Boolean {
|
||||||
|
return returnStack.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun peekReturnValue(): State {
|
||||||
|
if (returnStack.isNotEmpty()) {
|
||||||
|
return returnStack.last()
|
||||||
|
}
|
||||||
|
throw NoSuchElementException("Return values stack is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popReturnValue(): State {
|
||||||
|
if (returnStack.isNotEmpty()) {
|
||||||
|
val item = returnStack.last()
|
||||||
|
returnStack.removeAt(returnStack.size - 1)
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
throw NoSuchElementException("Return values stack is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copy(): Frame {
|
||||||
|
return InterpreterFrame(pool.toMutableList())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-29
@@ -9,8 +9,8 @@ import org.jetbrains.kotlin.backend.common.interpreter.equalTo
|
|||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -19,6 +19,7 @@ interface State {
|
|||||||
fun getState(descriptor: DeclarationDescriptor): State?
|
fun getState(descriptor: DeclarationDescriptor): State?
|
||||||
fun setState(newVar: Variable)
|
fun setState(newVar: Variable)
|
||||||
fun copy(): State
|
fun copy(): State
|
||||||
|
fun getIrFunctionByName(name: Name): IrFunction?
|
||||||
}
|
}
|
||||||
|
|
||||||
class Primitive<T>(private var value: IrConst<T>) : State {
|
class Primitive<T>(private var value: IrConst<T>) : State {
|
||||||
@@ -39,24 +40,38 @@ class Primitive<T>(private var value: IrConst<T>) : State {
|
|||||||
return Primitive(value)
|
return Primitive(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getIrFunctionByName(name: Name): IrFunction? {
|
||||||
|
//if (this.value.kind != IrConstKind.String) return null
|
||||||
|
val declarations = value.type.classOrNull!!.owner.declarations.flatMap {
|
||||||
|
when {
|
||||||
|
it is IrProperty -> listOf(it, it.getter)
|
||||||
|
else -> listOf(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return declarations.firstOrNull { it?.descriptor?.name == name } as? IrFunction
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Primitive(value=${value.value})"
|
return "Primitive(value=${value.value})"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Complex(private var classOfObject: IrClass, private val values: MutableList<Variable>) : State {
|
class Complex(private var classOfObject: IrClass, private val values: MutableList<Variable>) : State {
|
||||||
fun addSuperQualifier(superObj: Variable) {
|
var superType: Complex? = null
|
||||||
val superTypesList = getSuperTypes(classOfObject).map { it.descriptor.thisAsReceiverParameter }
|
|
||||||
(superObj.state as? Complex)?.values?.filter { superTypesList.contains(it.descriptor) }?.let { values += it }
|
fun setSuperQualifier(superType: Complex) {
|
||||||
values += superObj
|
this.superType = superType
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSuperTypes(descriptor: IrClass): List<IrClassSymbol> {
|
fun getSuperQualifier(): Complex? {
|
||||||
val superTypesList = descriptor.superTypes.mapNotNull { it.classOrNull }.toMutableList()
|
return superType
|
||||||
return superTypesList + superTypesList.flatMap { getSuperTypes(it.owner) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getIrFunctionByName(name: Name): IrFunction? {
|
fun getThisReceiver(): DeclarationDescriptor {
|
||||||
|
return classOfObject.thisReceiver!!.descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIrFunctionByName(name: Name): IrFunction? {
|
||||||
return classOfObject.declarations.filterIsInstance<IrFunction>().firstOrNull { it.descriptor.name == name }
|
return classOfObject.declarations.filterIsInstance<IrFunction>().firstOrNull { it.descriptor.name == name }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,28 +87,10 @@ class Complex(private var classOfObject: IrClass, private val values: MutableLis
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun copy(): State {
|
override fun copy(): State {
|
||||||
return Complex(classOfObject, values)
|
return Complex(classOfObject, values).apply { this@apply.superType = this@Complex.superType }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Complex(obj='${classOfObject.fqNameForIrSerialization}', values=$values)"
|
return "Complex(obj='${classOfObject.fqNameForIrSerialization}', super=$superType, values=$values)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmptyState : State {
|
|
||||||
override fun getState(descriptor: DeclarationDescriptor): State {
|
|
||||||
throw UnsupportedOperationException("Get state is not supported in empty state object")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setState(newVar: Variable) {
|
|
||||||
throw UnsupportedOperationException("Set state is not supported in empty state object")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun copy(): State {
|
|
||||||
throw UnsupportedOperationException("Copy method is not supported in empty state object")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "EmptyState"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user