Describe default behaviour for Any class methods

We are talking about such methods as equals, hashCode and toString.
This commit is contained in:
Ivan Kylchik
2020-01-23 13:16:05 +03:00
parent a6cc7cdc23
commit 0839e7afdc
@@ -18,10 +18,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isSubtypeOf import org.jetbrains.kotlin.ir.types.isSubtypeOf
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.isSubclassOf
import org.jetbrains.kotlin.ir.util.statements
import java.lang.invoke.MethodHandle import java.lang.invoke.MethodHandle
enum class Code(var info: String = "") { enum class Code(var info: String = "") {
@@ -167,14 +164,15 @@ class IrInterpreter(irModule: IrModuleFragment) {
val superQualifier = (data.getVariableState(variableDescriptor) as Complex).superType!! val superQualifier = (data.getVariableState(variableDescriptor) as Complex).superType!!
val overridden = owner.overriddenSymbols.first { it.getReceiver()?.equalTo(superQualifier.getReceiver()) == true } val overridden = owner.overriddenSymbols.first { it.getReceiver()?.equalTo(superQualifier.getReceiver()) == true }
val valueParameters = owner.valueParameters.zip(overridden.owner.valueParameters) val newStates = InterpreterFrame(mutableListOf(Variable(overridden.getReceiver()!!, superQualifier)))
owner.valueParameters.zip(overridden.owner.valueParameters)
.map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) } .map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) }
val newStates = InterpreterFrame(valueParameters.toMutableList()) .forEach { newStates.addVar(it) }
newStates.addVar(Variable(overridden.getReceiver()!!, superQualifier))
val overriddenOwner = overridden.owner as IrFunctionImpl val overriddenOwner = overridden.owner as IrFunctionImpl
return when { return when {
overriddenOwner.body != null -> overriddenOwner.interpret(newStates) overriddenOwner.body != null -> overriddenOwner.interpret(newStates)
superQualifier.superType == null -> calculateBuiltIns(overriddenOwner, newStates)
else -> calculateOverridden(overriddenOwner, newStates) else -> calculateOverridden(overriddenOwner, newStates)
}.apply { data.pushReturnValue(newStates) } }.apply { data.pushReturnValue(newStates) }
} }
@@ -182,34 +180,47 @@ class IrInterpreter(irModule: IrModuleFragment) {
private fun calculateBuiltIns(irFunction: IrFunction, data: Frame): Code { private fun calculateBuiltIns(irFunction: IrFunction, data: Frame): Code {
val descriptor = irFunction.descriptor val descriptor = irFunction.descriptor
val methodName = descriptor.name.asString() val methodName = descriptor.name.asString()
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type val args = data.getAll().map { it.state }
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { it.original.type }
val argsValues = data.getAll() val result: Any?
.map { it.state } if (irFunction.parent.fqNameForIrSerialization.toString() == "kotlin.Any" || args.any { it !is Primitive<*> }) {
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") } // if ir function is declaration in Any class OR it is ir builtin operator for non primitive types
.map { it.value } val receiver = (args[0] as Complex).instance
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() }) result = when (methodName) {
//todo try catch "equals", "EQEQ", "EQEQEQ" -> (args[1] as Complex).instance === receiver
val result = when (argsType.size) { "hashCode" -> System.identityHashCode(receiver)
1 -> { "toString" -> receiver?.irClass?.name?.asString() + "@" + System.identityHashCode(receiver).toString(16).padStart(8)
val function = unaryFunctions[signature] else -> throw IllegalStateException("Method $methodName can not be interpreted")
?: throw NoSuchMethodException("For given function $signature there is no entry in unary map")
function.invoke(argsValues.first())
} }
2 -> { } else {
val function = binaryFunctions[signature] val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
?: throw NoSuchMethodException("For given function $signature there is no entry in binary map") val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { it.original.type }
when (methodName) { val argsValues = args
"rangeTo" -> return calculateRangeTo(irFunction.returnType, data) .map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
else -> function.invoke(argsValues[0], argsValues[1]) .map { it.value }
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() })
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(irFunction.returnType, data)
else -> function.invoke(argsValues[0], argsValues[1])
}
}
3 -> {
val function = ternaryFunctions[signature]
?: throw NoSuchMethodException("For given function $signature there is no entry in ternary map")
function.invoke(argsValues[0], argsValues[1], argsValues[2])
}
else -> throw UnsupportedOperationException("Unsupported number of arguments")
} }
3 -> {
val function = ternaryFunctions[signature]
?: throw NoSuchMethodException("For given function $signature there is no entry in ternary map")
function.invoke(argsValues[0], argsValues[1], argsValues[2])
}
else -> throw UnsupportedOperationException("Unsupported number of arguments")
} }
data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
return Code.NEXT return Code.NEXT
@@ -295,9 +306,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
val state = Complex(parent, mutableListOf()) val state = Complex(parent, mutableListOf())
newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
val code = constructorCall.getBody()?.interpret(newFrame) ?: Code.NEXT val code = constructorCall.getBody()?.interpret(newFrame) ?: Code.NEXT
if (newFrame.hasReturnValue()) { state.superType = newFrame.popReturnValue() as Complex
state.superType = newFrame.popReturnValue() as Complex
}
data.pushReturnValue(state) data.pushReturnValue(state)
return code return code
} }
@@ -311,6 +320,8 @@ class IrInterpreter(irModule: IrModuleFragment) {
private fun interpretDelegatedConstructorCall(delegatingConstructorCall: IrDelegatingConstructorCall, data: Frame): Code { private fun interpretDelegatedConstructorCall(delegatingConstructorCall: IrDelegatingConstructorCall, data: Frame): Code {
if (delegatingConstructorCall.symbol.descriptor.containingDeclaration.defaultType == DefaultBuiltIns.Instance.anyType) { if (delegatingConstructorCall.symbol.descriptor.containingDeclaration.defaultType == DefaultBuiltIns.Instance.anyType) {
val anyComplex = Complex(irBuiltIns.anyClass.owner, mutableListOf())
data.pushReturnValue(anyComplex)
return Code.NEXT return Code.NEXT
} }
@@ -323,7 +334,6 @@ class IrInterpreter(irModule: IrModuleFragment) {
} }
private fun interpretStatements(statements: List<IrStatement>, data: Frame): Code { private fun interpretStatements(statements: List<IrStatement>, data: Frame): Code {
//create newFrame
val newFrame = data.copy() val newFrame = data.copy()
var code = Code.NEXT var code = Code.NEXT