From 4dc1e587b45a5d7af614c6094abe14eb83e5fe67 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sat, 21 Dec 2019 22:59:15 +0300 Subject: [PATCH] Implement vararg interpretation --- compiler/ir/backend.common/build.gradle.kts | 1 + .../common/interpreter/IrInterpreter.kt | 77 +++++++++--- .../backend/common/interpreter/Utils.kt | 61 ++++----- .../backend/common/interpreter/stack/State.kt | 116 +++++++++++++++--- 4 files changed, 190 insertions(+), 65 deletions(-) diff --git a/compiler/ir/backend.common/build.gradle.kts b/compiler/ir/backend.common/build.gradle.kts index acb573d5779..df03cd11f8f 100644 --- a/compiler/ir/backend.common/build.gradle.kts +++ b/compiler/ir/backend.common/build.gradle.kts @@ -4,6 +4,7 @@ plugins { } dependencies { + compile(project(":core:descriptors.jvm")) //used to get java classes fq names by kotlin names compile(project(":compiler:util")) compile(project(":compiler:frontend")) compile(project(":compiler:backend-common")) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt index b8419ef476e..ef98b275ae9 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt @@ -12,18 +12,16 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl -import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.util.constructors -import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.statements import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.types.TypeUtils import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType @@ -31,10 +29,27 @@ enum class Code(var info: String = "") { NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION } -class IrInterpreter(private val irBuiltIns: IrBuiltIns) { +class IrInterpreter(irModule: IrModuleFragment) { + private val irBuiltIns = irModule.irBuiltins + + private fun Any?.getType(defaultType: IrType): IrType { + return when (this) { + is Boolean -> irBuiltIns.booleanType + is Char -> irBuiltIns.charType + is Byte -> irBuiltIns.byteType + is Short -> irBuiltIns.shortType + is Int -> irBuiltIns.intType + is Long -> irBuiltIns.longType + is String -> irBuiltIns.stringType + is Float -> irBuiltIns.floatType + is Double -> irBuiltIns.doubleType + null -> irBuiltIns.nothingType + else -> defaultType + } + } fun interpret(expression: IrExpression): IrExpression { - return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(irBuiltIns, expression) + return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(expression) } private fun IrElement.interpret(data: Frame): Code { @@ -60,6 +75,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { is IrWhen -> interpretWhen(this, data) is IrBreak -> interpretBreak(this, data) is IrContinue -> interpretContinue(this, data) + is IrVararg -> interpretVararg(this, data) else -> TODO("${this.javaClass} not supported") } @@ -133,11 +149,11 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { 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 argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { it.original.type } val argsValues = data.getAll() .map { it.state } .map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") } - .map { it.getValue() } + .map { it.value } val signature = CompileTimeFunction(methodName, argsType.map { it.toString() }) //todo try catch val result = when (argsType.size) { @@ -161,7 +177,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { } else -> throw UnsupportedOperationException("Unsupported number of arguments") } - data.pushReturnValue(result.toState(irBuiltIns)) + data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) return Code.NEXT } @@ -170,7 +186,9 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { 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.getValue().toIrConst(irBuiltIns)) } + primitiveValueParameters.forEachIndexed { index, primitive -> + constructorCall.putValueArgument(index, primitive.value.toIrConst(primitive.type)) + } val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters) val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList()) @@ -180,12 +198,13 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { return code } + // TODO extract in Wrapper private fun calculateIntrinsic(irFunction: IrFunction, data: Frame): Code { val annotation = irFunction.getAnnotation(evaluateIntrinsicAnnotation) val argsValues = data.getAll() .map { it.state } .map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") } - .map { it.getValue() } + .map { it.value } val textClass = Class.forName((annotation.getValueArgument(0) as IrConst<*>).value.toString()) val returnClass = irFunction.returnType.getFqName()!!.let { getPrimitiveClass(it) ?: Class.forName(it) } @@ -197,7 +216,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { val methodSignature = MethodType.methodType(returnClass, listOfNotNull(extensionClass) + argsClasses) val method = MethodHandles.lookup().findStatic(textClass, irFunction.name.asString(), methodSignature) val result = method.invokeWithArguments(argsValues) - data.pushReturnValue(result.toState(irBuiltIns)) + data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) return Code.NEXT } @@ -218,8 +237,8 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { // dispatch receiver processing val rawDispatchReceiver = expression.dispatchReceiver rawDispatchReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it } - val irCallReceiver = rawDispatchReceiver?.let { data.popReturnValue() } - val irFunctionReceiver = if (expression.superQualifierSymbol == null) irCallReceiver else (irCallReceiver as Complex).superType + val dispatchReceiver = rawDispatchReceiver?.let { data.popReturnValue() } + val irFunctionReceiver = if (expression.superQualifierSymbol == null) dispatchReceiver else (dispatchReceiver as Complex).superType // it is important firstly to add receiver, then arguments; this order is used in builtin method call val irFunction = irFunctionReceiver?.getIrFunction(expression.symbol.descriptor) ?: expression.symbol.owner irFunctionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getDispatchReceiver()!!, it)) } @@ -227,11 +246,15 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { // extension receiver processing val rawExtensionReceiver = expression.extensionReceiver rawExtensionReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it } - rawExtensionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getExtensionReceiver()!!, data.popReturnValue())) } + val extensionReceiver = rawExtensionReceiver?.let { data.popReturnValue() } + extensionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getExtensionReceiver()!!, it)) } newFrame.addAll(valueParameters) + val isWrapper = (dispatchReceiver is Wrapper && rawExtensionReceiver == null) || + (extensionReceiver is Wrapper && rawDispatchReceiver == null) val code = when { + isWrapper -> ((dispatchReceiver ?: extensionReceiver) as Wrapper).invoke(irFunction as IrFunctionImpl, newFrame) irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> calculateIntrinsic(irFunction, newFrame) irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame) @@ -307,7 +330,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { var code = Code.NEXT while (code == Code.NEXT) { code = expression.condition.interpret(data) - if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getValue() as? Boolean == true) { + if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.value as? Boolean == true) { code = expression.body?.interpret(data) ?: Code.NEXT } else { break @@ -327,7 +350,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { private fun interpretBranch(expression: IrBranch, data: Frame): Code { var code = expression.condition.interpret(data) - if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getValue() as? Boolean == true) { + if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.value as? Boolean == true) { code = expression.result.interpret(data) if (code == Code.NEXT) return Code.BREAK_WHEN } @@ -403,4 +426,26 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) { } } + @Suppress("UNCHECKED_CAST") + private fun interpretVararg(expression: IrVararg, data: Frame): Code { + val args = expression.elements.map { + it.interpret(data).apply { if (this != Code.NEXT) return this } + data.popReturnValue() + } + val type = expression.type + val array = when (type.getFqName()) { + "kotlin.ByteArray" -> Primitive(args.map { (it as Primitive).value }.toByteArray(), type) + "kotlin.CharArray" -> Primitive(args.map { (it as Primitive).value }.toCharArray(), type) + "kotlin.ShortArray" -> Primitive(args.map { (it as Primitive).value }.toShortArray(), type) + "kotlin.IntArray" -> Primitive(args.map { (it as Primitive).value }.toIntArray(), type) + "kotlin.LongArray" -> Primitive(args.map { (it as Primitive).value }.toLongArray(), type) + "kotlin.FloatArray" -> Primitive(args.map { (it as Primitive).value }.toFloatArray(), type) + "kotlin.DoubleArray" -> Primitive(args.map { (it as Primitive).value }.toDoubleArray(), type) + "kotlin.BooleanArray" -> Primitive(args.map { (it as Primitive).value }.toBooleanArray(), type) + else -> Primitive>(args.toTypedArray(), type) + } + data.pushReturnValue(array) + + return Code.NEXT + } } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt index c10f5306879..d8e4542c82c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt @@ -5,15 +5,14 @@ package org.jetbrains.kotlin.backend.common.interpreter -import org.jetbrains.kotlin.backend.common.interpreter.stack.Complex import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive import org.jetbrains.kotlin.backend.common.interpreter.stack.State +import org.jetbrains.kotlin.backend.common.interpreter.stack.Wrapper import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol @@ -81,35 +80,37 @@ fun IrFunction.isFakeOverridden(): Boolean { return this.symbol.owner.isFakeOverride } -fun State.toIrExpression(irBuiltIns: IrBuiltIns, expression: IrExpression): IrExpression { +fun State.toIrExpression(expression: IrExpression): IrExpression { return when (this) { - is Primitive<*> -> this.getValue().toIrConst( // this is necessary to replace ir offsets - irBuiltIns, expression.startOffset, expression.endOffset + is Primitive<*> -> this.value.toIrConst( // this is necessary to replace ir offsets + this.type, expression.startOffset, expression.endOffset ) else -> TODO("not supported") } } -fun Any?.toState(irBuiltIns: IrBuiltIns): State { +fun Any?.toState(irType: IrType): State { return when (this) { - is Complex -> this - else -> this.toIrConst(irBuiltIns).toPrimitive() + is State -> this + is Boolean, is Char, is Byte, is Short, is Int, is Long, is String, is Float, is Double -> Primitive(this, irType) + null -> Primitive(this, irType) + else -> Wrapper(irType.classOrNull!!.owner, this) } } -fun Any?.toIrConst(irBuiltIns: IrBuiltIns, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> { +fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> { return when (this) { - is Boolean -> IrConstImpl(startOffset, endOffset, irBuiltIns.booleanType, IrConstKind.Boolean, this) - is Char -> IrConstImpl(startOffset, endOffset, irBuiltIns.charType, IrConstKind.Char, this) - is Byte -> IrConstImpl(startOffset, endOffset, irBuiltIns.byteType, IrConstKind.Byte, this) - is Short -> IrConstImpl(startOffset, endOffset, irBuiltIns.shortType, IrConstKind.Short, this) - is Int -> IrConstImpl(startOffset, endOffset, irBuiltIns.intType, IrConstKind.Int, this) - is Long -> IrConstImpl(startOffset, endOffset, irBuiltIns.longType, IrConstKind.Long, this) - is String -> IrConstImpl(startOffset, endOffset, irBuiltIns.stringType, IrConstKind.String, this) - is Float -> IrConstImpl(startOffset, endOffset, irBuiltIns.floatType, IrConstKind.Float, this) - is Double -> IrConstImpl(startOffset, endOffset, irBuiltIns.doubleType, IrConstKind.Double, this) - null -> IrConstImpl(startOffset, endOffset, irBuiltIns.nothingType, IrConstKind.Null, this) - else -> throw UnsupportedOperationException("Unsupported const element type $this") + is Boolean -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Boolean, this) + is Char -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Char, this) + is Byte -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Byte, this) + is Short -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Short, this) + is Int -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Int, this) + is Long -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Long, this) + is String -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.String, this) + is Float -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Float, this) + is Double -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Double, this) + null -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Null, this) + else -> throw UnsupportedOperationException("Unsupported const element type ${this::class}") } } @@ -128,17 +129,17 @@ fun IrAnnotationContainer.getAnnotation(annotation: FqName): IrConstructorCall { return this.annotations.first { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation } } -fun getPrimitiveClass(fqName: String): Class<*>? { +fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? { return when (fqName) { - "kotlin.Boolean" -> Boolean::class.java - "kotlin.Char" -> Char::class.java - "kotlin.Byte" -> Byte::class.java - "kotlin.Short" -> Short::class.java - "kotlin.Int" -> Int::class.java - "kotlin.Long" -> Long::class.java - "kotlin.String" -> String::class.java - "kotlin.Float" -> Float::class.java - "kotlin.Double" -> Double::class.java + "kotlin.Boolean" -> if (asObject) Boolean::class.javaObjectType else Boolean::class.java + "kotlin.Char" -> if (asObject) Char::class.javaObjectType else Char::class.java + "kotlin.Byte" -> if (asObject) Byte::class.javaObjectType else Byte::class.java + "kotlin.Short" -> if (asObject) Short::class.javaObjectType else Short::class.java + "kotlin.Int" -> if (asObject) Int::class.javaObjectType else Int::class.java + "kotlin.Long" -> if (asObject) Long::class.javaObjectType else Long::class.java + "kotlin.String" -> if (asObject) String::class.javaObjectType else String::class.java + "kotlin.Float" -> if (asObject) Float::class.javaObjectType else Float::class.java + "kotlin.Double" -> if (asObject) Double::class.javaObjectType else Double::class.java else -> null } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt index d5164986764..7fef2eefe30 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt @@ -5,17 +5,27 @@ package org.jetbrains.kotlin.backend.common.interpreter.stack +import org.jetbrains.kotlin.backend.common.interpreter.* import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunction import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions -import org.jetbrains.kotlin.backend.common.interpreter.equalTo +import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.types.isNullable +import org.jetbrains.kotlin.ir.types.isPrimitiveType import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization +import org.jetbrains.kotlin.ir.util.isTypeParameter +import org.jetbrains.kotlin.name.FqNameUnsafe +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import java.lang.invoke.MethodHandles +import java.lang.invoke.MethodType interface State { val fields: MutableList @@ -29,26 +39,20 @@ interface State { fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? } -class Primitive(private var value: T, private val type: IrType?) : State { - override val fields: MutableList = mutableListOf() +open class Primitive(var value: T, val type: IrType) : State { + final override val fields: MutableList = mutableListOf() init { - if (type != null) { - val properties = type.classOrNull!!.owner.declarations.filterIsInstance() - for (property in properties) { - val propertySignature = CompileTimeFunction(property.name.asString(), listOf(type.getName())) - val propertyValue = unaryFunctions[propertySignature]?.invoke(value) - ?: throw NoSuchMethodException("For given property $propertySignature there is no entry in unary map") - fields.add(Variable(property.descriptor, Primitive(propertyValue, null))) - } + val properties = type.classOrNull!!.owner.declarations.filterIsInstance() + for (property in properties) { + val propertySignature = CompileTimeFunction(property.name.asString(), listOf(type.getName())) + val propertyValue = unaryFunctions[propertySignature]?.invoke(value) + ?: throw NoSuchMethodException("For given property $propertySignature there is no entry in unary map") + fields.add(Variable(property.descriptor, Primitive(propertyValue, property.backingField!!.type))) } } - private fun IrType?.getName() = this?.classOrNull!!.owner.name.asString() - - fun getValue(): T { - return value - } + private fun IrType.getName() = this.classOrNull!!.descriptor.defaultType.toString() override fun setState(newVar: Variable) { newVar.state as? Primitive ?: throw IllegalArgumentException("Cannot set $newVar in current $this") @@ -60,7 +64,6 @@ class Primitive(private var value: T, private val type: IrType?) : State { } override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { - if (type == null) return null // must add property's getter to declaration's list because they are not present in ir class for primitives val declarations = type.classOrNull!!.owner.declarations.map { if (it is IrProperty) it.getter else it } return declarations.filterIsInstance() @@ -69,11 +72,11 @@ class Primitive(private var value: T, private val type: IrType?) : State { } override fun toString(): String { - return "Primitive(value=$value, type=${type?.getName()})" + return "Primitive(value=$value, type=${type.getName()})" } } -class Complex(private var type: IrClass, override val fields: MutableList) : State { +open class Complex(private var type: IrClass, override val fields: MutableList) : State { var superType: Complex? = null var instance: Complex? = null @@ -110,3 +113,78 @@ class Complex(private var type: IrClass, override val fields: MutableList)?.value } + + val methodType = MethodType.methodType(returnClass, argsClasses) + val method = MethodHandles.lookup().findVirtual(receiverClass, methodName, methodType) + + val result = method.invokeWithArguments(argsValues) + data.pushReturnValue(result.toState(irFunction.returnType)) + + return Code.NEXT + } + + private fun IrType.getCorrespondingClass(asObject: Boolean): Class { + val fqName = this.getFqName() + return when { + this.isPrimitiveType() -> getPrimitiveClass(fqName!!, asObject) + this.isTypeParameter() -> Any::class.java + else -> JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(fqName!!))?.let { Class.forName(it.asSingleFqName().toString()) } + } ?: Class.forName(fqName) + } + + private fun IrFunctionImpl.getOriginalOverriddenSymbols(): MutableList { + val overriddenSymbols = mutableListOf() + val pool = this.overriddenSymbols.toMutableList() + val iterator = pool.listIterator() + for (symbol in iterator) { + if (symbol.owner.overriddenSymbols.isEmpty()) { + overriddenSymbols += symbol + iterator.remove() + } else { + symbol.owner.overriddenSymbols.forEach { iterator.add(it) } + } + } + + if (overriddenSymbols.isEmpty()) overriddenSymbols.add(this.symbol) + return overriddenSymbols + } + + private fun IrFunctionImpl.isReturnTypePrimitiveAsObject(): Boolean { + for (symbol in getOriginalOverriddenSymbols()) { + if (!symbol.owner.returnType.isTypeParameter() && !symbol.owner.returnType.isNullable()) { + return false + } + } + return true + } + + private fun IrFunctionImpl.isValueParameterPrimitiveAsObject(index: Int): Boolean { + for (symbol in getOriginalOverriddenSymbols()) { + if (!symbol.owner.valueParameters[index].type.isTypeParameter() && !symbol.owner.valueParameters[index].type.isNullable()) { + return false + } + } + return true + } + + override fun copy(): State { + return Wrapper(type, wrapperValue) + } + + override fun toString(): String { + return "Wrapper(obj='$typeFqName', value=$wrapperValue)" + } +}