From 4010eb11bd12483e91e04be18d8cf6f930d8119f Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Tue, 18 Aug 2020 22:54:00 +0300 Subject: [PATCH] Implement method to calculate EQEQ ir builtin function --- .../kotlin/ir/interpreter/IrInterpreter.kt | 30 +++++++++++++++---- .../kotlin/ir/interpreter/state/Common.kt | 12 ++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index 050e7099d55..f45538d48c3 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -173,13 +173,14 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map val argsType = listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type } val argsValues = args.map { when (it) { + is Wrapper -> it.value // wrapper can be used in built in calculation, for example, in null or equality checks is Complex -> when (irFunction.fqNameWhenAvailable?.asString()) { // must explicitly convert Common to String in String plus method or else will be taken default toString from Common "kotlin.String.plus" -> stack.apply { interpretToString(it) }.popReturnValue().asString() else -> it.getOriginal() } is Primitive<*> -> it.value - is Lambda -> it // lambda can be used in built in calculation, for example, in null check or toString + is Lambda -> it // lambda also can be used, for example, in null check or toString else -> TODO("unsupported type of argument for builtins calculations: ${it::class.java}") } } @@ -207,6 +208,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map ?: throw InterpreterMethodNotFoundError("For given function $signature there is no entry in binary map") when (methodName) { "rangeTo" -> return calculateRangeTo(irFunction.returnType) + "EQEQ" -> return calculateEquals(argsValues[0], argsValues[1]) else -> function.invoke(argsValues[0], argsValues[1]) } } @@ -238,6 +240,24 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map } } + private fun calculateEquals(first: Any?, second: Any?): ExecutionResult { + if (first == null || second == null || first !is Common || second !is Common) { + return Next.apply { stack.pushReturnValue((first == second).toState(irBuiltIns.booleanType)) } + } + + val valueArguments = mutableListOf() + val equalsFun = first.getEqualsFunction() + if (equalsFun.isFakeOverriddenFromAny()) { + return Next.apply { stack.pushReturnValue((first == second).toState(irBuiltIns.booleanType)) } + } + + equalsFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, first)) } + valueArguments.add(Variable(equalsFun.valueParameters.single().symbol, second)) + return stack.newFrame(initPool = valueArguments) { + equalsFun.interpret() + }.check { return it } + } + private fun interpretValueParameters( expression: IrFunctionAccessExpression, irFunction: IrFunction, pool: MutableList ): ExecutionResult { @@ -663,12 +683,12 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map } } IrTypeOperator.INSTANCEOF -> { - val isInstance = isErased || stack.peekReturnValue().isSubtypeOf(typeOperand) - stack.pushReturnValue(isInstance.toState(irBuiltIns.nothingType)) + val isInstance = stack.popReturnValue().isSubtypeOf(typeOperand) || isErased + stack.pushReturnValue(isInstance.toState(irBuiltIns.booleanType)) } IrTypeOperator.NOT_INSTANCEOF -> { - val isInstance = isErased || stack.peekReturnValue().isSubtypeOf(typeOperand) - stack.pushReturnValue((!isInstance).toState(irBuiltIns.nothingType)) + val isInstance = stack.popReturnValue().isSubtypeOf(typeOperand) || isErased + stack.pushReturnValue((!isInstance).toState(irBuiltIns.booleanType)) } IrTypeOperator.IMPLICIT_NOTNULL -> { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt index 422c19e9dff..8239a2129e6 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt @@ -11,7 +11,9 @@ import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.types.isNullableAny import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization +import org.jetbrains.kotlin.name.Name internal class Common private constructor( override val irClass: IrClass, override val fields: MutableList @@ -48,6 +50,16 @@ internal class Common private constructor( .let { getOverridden(it as IrSimpleFunction, this) } } + fun getEqualsFunction(): IrFunction { + val equalsFun = irClass.declarations + .filterIsInstance() + .single { + it.name == Name.identifier("equals") && it.dispatchReceiverParameter != null + && it.valueParameters.size == 1 && it.valueParameters[0].type.isNullableAny() + } + return getOverridden(equalsFun, this) + } + override fun toString(): String { return "Common(obj='${irClass.fqNameForIrSerialization}', super=$superClass, values=$fields)" }