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 27090690238..547735a50c1 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 @@ -164,51 +164,6 @@ class IrInterpreter(irModule: IrModuleFragment) { return IntrinsicEvaluator().evaluate(irFunction, stack) { this.interpret() } } - private suspend fun calculateAbstract(irFunction: IrFunction): ExecutionResult { - if (irFunction.body == null) { - val receiver = stack.getVariableState(irFunction.getReceiver()!!) as Complex - val instance = receiver.getOriginal() - - val functionImplementation = instance.getIrFunction(irFunction.descriptor) - if (functionImplementation?.body == null) throw InterpreterMethodNotFoundException("Method \"${irFunction.name}\" wasn't implemented") - - val valueArguments = mutableListOf() - valueArguments.add(Variable(functionImplementation.getReceiver()!!, instance)) - functionImplementation.valueParameters - .map { Variable(it.descriptor, stack.getVariableState(it.descriptor)) } - .forEach { valueArguments.add(it) } - return stack.newFrame(asSubFrame = true, initPool = valueArguments) { - functionImplementation.interpret() - } - } - return irFunction.body!!.interpret() - } - - private suspend fun calculateOverridden(owner: IrSimpleFunction): ExecutionResult { - val variableDescriptor = owner.getReceiver()!! - val superQualifier = (stack.getVariableState(variableDescriptor) as? Complex)?.superClass - if (superQualifier == null) { - // superQualifier is null for exception state => find method in builtins - return calculateBuiltIns(owner.getLastOverridden() as IrSimpleFunction) - } - val overridden = owner.overriddenSymbols.single() - - val valueArguments = mutableListOf() - valueArguments.add(Variable(overridden.owner.getReceiver()!!, superQualifier)) - owner.valueParameters.zip(overridden.owner.valueParameters) - .map { Variable(it.second.descriptor, stack.getVariableState(it.first.descriptor)) } - .forEach { valueArguments.add(it) } - - return stack.newFrame(asSubFrame = true, initPool = valueArguments) { - val overriddenOwner = overridden.owner - return@newFrame when { - overriddenOwner.body != null -> overriddenOwner.interpret() - superQualifier.superClass == null -> calculateBuiltIns(overriddenOwner) - else -> calculateOverridden(overriddenOwner) - } - } - } - private suspend fun calculateBuiltIns(irFunction: IrFunction): ExecutionResult { val descriptor = irFunction.descriptor val methodName = when (val property = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol) { @@ -286,7 +241,7 @@ class IrInterpreter(irModule: IrModuleFragment) { return stack.newFrame(asSubFrame = true, initPool = pool) { for (i in valueArguments.indices) { (valueArguments[i] ?: defaultValues[i])?.interpret()?.check { return@newFrame it } - ?: stack.pushReturnValue(listOf().toPrimitiveStateArray(expression.getVarargType(i)!!)) + ?: stack.pushReturnValue(listOf().toPrimitiveStateArray(expression.getVarargType(i)!!)) // if vararg is empty with(Variable(valueParametersDescriptors[i], stack.popReturnValue())) { stack.addVar(this) //must add value argument in current stack because it can be used later as default argument @@ -309,9 +264,9 @@ class IrInterpreter(irModule: IrModuleFragment) { rawExtensionReceiver?.interpret()?.check { return it } val extensionReceiver = rawExtensionReceiver?.let { stack.popReturnValue() } - // find correct ir function - val functionReceiver = dispatchReceiver?.getFunctionReceiver(expression.superQualifierSymbol?.owner) - val irFunction = functionReceiver?.getIrFunction(expression.symbol.descriptor) ?: expression.symbol.owner + // get correct ir function + val irFunction = dispatchReceiver?.getIrFunctionByIrCall(expression) ?: expression.symbol.owner + val functionReceiver = dispatchReceiver.getCorrectReceiverByFunction(irFunction) // it is important firstly to add receiver, then arguments; this order is used in builtin method call irFunction.getDispatchReceiver()?.let { functionReceiver?.let { receiver -> valueArguments.add(Variable(it, receiver)) } } @@ -332,9 +287,7 @@ class IrInterpreter(irModule: IrModuleFragment) { return@newFrame when { dispatchReceiver is Wrapper && !isInlineOnly -> dispatchReceiver.getMethod(irFunction).invokeMethod(irFunction) irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction) - irFunction.isAbstract() -> calculateAbstract(irFunction) //abstract check must be before fake overridden check - irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrSimpleFunction) - irFunction.body == null || dispatchReceiver is Primitive<*> -> calculateBuiltIns(irFunction) // is Primitive because of js char and long + irFunction.body == null || dispatchReceiver is Primitive<*> -> calculateBuiltIns(irFunction) // 'is Primitive' because of js char and long else -> irFunction.interpret() } } @@ -730,7 +683,7 @@ class IrInterpreter(irModule: IrModuleFragment) { is Common -> { val toStringFun = returnValue.getToStringFunction() stack.newFrame(initPool = mutableListOf(Variable(toStringFun.getReceiver()!!, returnValue))) { - toStringFun.body?.let { toStringFun.interpret() } ?: calculateOverridden(toStringFun) + toStringFun.body?.let { toStringFun.interpret() } ?: calculateBuiltIns(toStringFun) }.check { executionResult -> return executionResult } stack.popReturnValue().asString() } 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 eef2d262048..081aea44204 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 @@ -12,20 +12,15 @@ import org.jetbrains.kotlin.builtins.UnsignedTypes import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.descriptors.WrappedReceiverParameterDescriptor import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.types.* -import org.jetbrains.kotlin.ir.util.defaultType -import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization -import org.jetbrains.kotlin.ir.util.isFakeOverride -import org.jetbrains.kotlin.ir.util.isInterface +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver -import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.utils.addToStdlib.safeAs // main purpose is to get receiver from constructor call @@ -50,7 +45,7 @@ fun IrFunctionAccessExpression.getBody(): IrBody? { } fun DeclarationDescriptor.equalTo(other: DeclarationDescriptor): Boolean { - return this.isSubtypeOf(other) || this.hasSameNameAs(other) || this == other + return this.isEqualByReceiverTo(other) || this.hasSameNameAs(other) || this == other } private fun WrappedReceiverParameterDescriptor.isEqualTo(other: DeclarationDescriptor): Boolean { @@ -60,14 +55,14 @@ private fun WrappedReceiverParameterDescriptor.isEqualTo(other: DeclarationDescr } } -private fun DeclarationDescriptor.isSubtypeOf(other: DeclarationDescriptor): Boolean { +private fun DeclarationDescriptor.isEqualByReceiverTo(other: DeclarationDescriptor): Boolean { if (this !is ReceiverParameterDescriptor || other !is ReceiverParameterDescriptor) return false return when { this is WrappedReceiverParameterDescriptor && other is WrappedReceiverParameterDescriptor -> this.isEqualTo(other) || other.isEqualTo(this) this is WrappedReceiverParameterDescriptor -> this.isEqualTo(other) other is WrappedReceiverParameterDescriptor -> other.isEqualTo(this) - this.value is ImplicitClassReceiver && other.value is ImplicitClassReceiver -> this.value.type.isSubtypeOf(other.value.type) + this.value is ImplicitClassReceiver && other.value is ImplicitClassReceiver -> this.value.type == other.value.type this.value is ExtensionReceiver && other.value is ExtensionReceiver -> this.value == other.value else -> false } @@ -81,14 +76,6 @@ private fun DeclarationDescriptor.hasSameNameAs(other: DeclarationDescriptor): B this.name == other.name) } -fun IrFunction.isAbstract(): Boolean { - return (this as? IrSimpleFunction)?.modality == Modality.ABSTRACT -} - -fun IrFunction.isFakeOverridden(): Boolean { - return this.isFakeOverride -} - fun State.toIrExpression(expression: IrExpression): IrExpression { val start = expression.startOffset val end = expression.endOffset @@ -177,7 +164,7 @@ fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? { } fun IrType.getFqName(): String? { - return this.classOrNull?.owner?.fqNameForIrSerialization?.asString() + return this.classOrNull?.owner?.fqNameWhenAvailable?.asString() } fun IrFunction.getArgsForMethodInvocation(args: List): List { @@ -202,13 +189,9 @@ fun IrFunction.getArgsForMethodInvocation(args: List): List { } fun IrFunction.getLastOverridden(): IrFunction { - if (this !is IrFunctionImpl) return this + if (this !is IrSimpleFunction) return this - var function = this as IrFunctionImpl - while (function.overriddenSymbols.isNotEmpty()) { - function = function.overriddenSymbols.first().owner as IrFunctionImpl - } - return function + return generateSequence(listOf(this)) { it.firstOrNull()?.overriddenSymbols?.map { it.owner } }.flatten().last() } fun List.toPrimitiveStateArray(type: IrType): Primitive<*> { @@ -225,18 +208,6 @@ fun List.toPrimitiveStateArray(type: IrType): Primitive<*> { } } -fun State?.getFunctionReceiver(superIrClass: IrClass?): State? { - return when { - superIrClass == null -> this - superIrClass.isInterface -> { - val interfaceState = Common(superIrClass) - (this!!.copy() as Complex).setSuperClassInstance(interfaceState) - interfaceState - } - else -> (this as Complex).superClass - } -} - fun IrFunctionAccessExpression.getVarargType(index: Int): IrType? { val varargType = this.symbol.owner.valueParameters[index].varargElementType ?: return null varargType.classOrNull?.let { return this.symbol.owner.valueParameters[index].type } @@ -268,4 +239,12 @@ fun State?.extractNonLocalDeclarations(): List { this ?: return listOf() val state = this.takeIf { it !is Complex } ?: (this as Complex).getOriginal() return state.fields.filterNot { it.descriptor.containingDeclaration == state.irClass.descriptor } +} + +fun State?.getCorrectReceiverByFunction(irFunction: IrFunction): State? { + if (this !is Complex) return this + + val original: Complex? = this.getOriginal() + val other = irFunction.dispatchReceiverParameter?.descriptor ?: return this + return generateSequence(original) { it.superClass }.firstOrNull { it.irClass.descriptor.thisAsReceiverParameter.equalTo(other) } ?: this } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsics/IntrinsicImplementations.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsics/IntrinsicImplementations.kt index c23cbfbd1db..49a044a09e9 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsics/IntrinsicImplementations.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsics/IntrinsicImplementations.kt @@ -137,7 +137,7 @@ object RegexReplace : IntrinsicBase() { object EnumHashCode : IntrinsicBase() { override fun equalTo(irFunction: IrFunction): Boolean { val fqName = irFunction.fqNameWhenAvailable.toString() - return fqName.endsWith(".hashCode") && irFunction.parentAsClass.isEnumClass + return fqName == "kotlin.Enum.hashCode" } override suspend fun evaluate( diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt index 8efb2b48cbb..dcd3e2a1f5f 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt @@ -5,12 +5,14 @@ package org.jetbrains.kotlin.backend.common.interpreter.state +import org.jetbrains.kotlin.backend.common.interpreter.getLastOverridden 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.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization +import org.jetbrains.kotlin.ir.util.isFakeOverride import org.jetbrains.kotlin.ir.util.isInterface class Common private constructor( @@ -42,10 +44,11 @@ class Common private constructor( return owner } - fun getToStringFunction(): IrFunctionImpl { + fun getToStringFunction(): IrFunction { return irClass.declarations.filterIsInstance() .filter { it.descriptor.name.asString() == "toString" } - .first { it.descriptor.valueParameters.isEmpty() } as IrFunctionImpl + .first { it.descriptor.valueParameters.isEmpty() } + .let { getOverridden(it as IrSimpleFunction, this) } } override fun copy(): State { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt index 821e944ba35..ede24906e49 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt @@ -6,12 +6,17 @@ package org.jetbrains.kotlin.backend.common.interpreter.state import org.jetbrains.kotlin.backend.common.interpreter.equalTo +import org.jetbrains.kotlin.backend.common.interpreter.getLastOverridden +import org.jetbrains.kotlin.backend.common.interpreter.getCorrectReceiverByFunction import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable 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.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization +import org.jetbrains.kotlin.ir.util.isInterface abstract class Complex( override val irClass: IrClass, override val fields: MutableList, var superClass: Complex?, var subClass: Complex? @@ -47,9 +52,45 @@ abstract class Complex( } } - override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { + private fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { val propertyGetters = irClass.declarations.filterIsInstance().mapNotNull { it.getter } val functions = irClass.declarations.filterIsInstance() return (propertyGetters + functions).singleOrNull { it.descriptor.equalTo(descriptor) } } + + private fun getThisOrSuperReceiver(superIrClass: IrClass?): Complex? { + return when { + superIrClass == null -> this.getOriginal() + superIrClass.isInterface -> { + val interfaceState = Common(superIrClass) + (this.copy() as Complex).setSuperClassInstance(interfaceState) + interfaceState + } + else -> this.superClass + } + } + + protected fun getOverridden(owner: IrSimpleFunction, qualifier: State?): IrSimpleFunction { + if (!owner.isFakeOverride) return owner + if (qualifier == null || qualifier is ExceptionState || (qualifier as? Complex)?.superClass == null) { + return owner.getLastOverridden() as IrSimpleFunction + } + + val overriddenOwner = owner.overriddenSymbols.single().owner + return when { + overriddenOwner.body != null -> overriddenOwner + else -> getOverridden(overriddenOwner, qualifier.superClass!!) + } + } + + override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { + val receiver = getThisOrSuperReceiver(expression.superQualifierSymbol?.owner) ?: return null + + val irFunction = receiver.getIrFunction(expression.symbol.descriptor) ?: return null + + return when (irFunction.body) { + null -> getOverridden(irFunction as IrSimpleFunction, this.getCorrectReceiverByFunction(irFunction)) + else -> irFunction + } + } } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt index 7e206623b1e..223c36a7120 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt @@ -7,9 +7,9 @@ package org.jetbrains.kotlin.backend.common.interpreter.state import org.jetbrains.kotlin.backend.common.interpreter.equalTo import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable -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.expressions.IrCall import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.nameForIrSerialization @@ -23,8 +23,8 @@ class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State throw UnsupportedOperationException("Method setState is not supported in Lambda class") } - override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { - return if (invokeDescriptor.equalTo(descriptor)) irFunction else null + override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { + return if (invokeDescriptor.equalTo(expression.symbol.descriptor)) irFunction else null } override fun copy(): State { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Primitive.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Primitive.kt index a92778d9ee9..66465e7e472 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Primitive.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Primitive.kt @@ -5,14 +5,16 @@ package org.jetbrains.kotlin.backend.common.interpreter.state +import org.jetbrains.kotlin.backend.common.interpreter.getLastOverridden import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable 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.expressions.IrCall import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.util.isFakeOverride class Primitive(var value: T, val type: IrType) : State { override val fields: MutableList = mutableListOf() @@ -31,12 +33,14 @@ class Primitive(var value: T, val type: IrType) : State { return Primitive(value, type) } - override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { + override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { + val descriptor = expression.symbol.descriptor // must add property's getter to declaration's list because they are not present in ir class for primitives val declarations = irClass.declarations.map { if (it is IrProperty) it.getter else it } return declarations.filterIsInstance() .filter { it.descriptor.name == descriptor.name } .firstOrNull { it.descriptor.valueParameters.map { it.type } == descriptor.valueParameters.map { it.type } } + ?.let { if (it.isFakeOverride) it.getLastOverridden() else it } } override fun equals(other: Any?): Boolean { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/State.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/State.kt index b930f519643..0e8b44f3e35 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/State.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/State.kt @@ -8,9 +8,9 @@ package org.jetbrains.kotlin.backend.common.interpreter.state import org.jetbrains.kotlin.backend.common.interpreter.equalTo import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable 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.expressions.IrCall interface State { val fields: MutableList @@ -31,7 +31,7 @@ interface State { */ fun copy(): State - fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? + fun getIrFunctionByIrCall(expression: IrCall): IrFunction? } fun State.asInt() = (this as Primitive<*>).value as Int