Unify value arguments interpretation

This commit is contained in:
Ivan Kylchik
2020-04-06 21:52:47 +03:00
parent 520f2455b3
commit c9e5b6a234
@@ -317,10 +317,25 @@ class IrInterpreter(irModule: IrModuleFragment) {
return constructorCall.interpret(newFrame).apply { data.pushReturnValue(newFrame) }
}
private suspend fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): ExecutionResult {
val defaultValues = (parametersContainer.symbol.owner as IrFunction).valueParameters.map { it.defaultValue }
for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) {
(parametersContainer.getValueArgument(i)?.interpret(data) ?: defaultValues[i]!!.expression.interpret(data)).check { return it }
private suspend fun interpretValueParameters(
expression: IrFunctionAccessExpression, irFunction: IrFunction, data: Frame, newFrame: Frame
): ExecutionResult {
// if irFunction is lambda and it has receiver, then first descriptor must be taken from extension receiver
val receiverAsFirstArgument = when (expression.dispatchReceiver?.type?.isFunction()) {
true -> listOfNotNull(irFunction.symbol.getExtensionReceiver())
else -> listOf()
}
val valueParametersDescriptors = receiverAsFirstArgument + irFunction.descriptor.valueParameters
val valueArguments = (0 until expression.valueArgumentsCount).map { expression.getValueArgument(it) }
val defaultValues = expression.symbol.owner.valueParameters.map { it.defaultValue?.expression }
val frameWithReceiverAndData = data.copy().apply { addAll(newFrame.getAll()) } // primary use case: copy method in data class
for ((i, valueArgument) in valueArguments.withIndex()) {
(valueArgument ?: defaultValues[i])!!.interpret(frameWithReceiverAndData).checkForReturn(frameWithReceiverAndData, data) { return it }
with(Variable(valueParametersDescriptors[i], frameWithReceiverAndData.popReturnValue())) {
frameWithReceiverAndData.addVar(this)
newFrame.addVar(this)
}
}
return Next
}
@@ -332,9 +347,12 @@ class IrInterpreter(irModule: IrModuleFragment) {
val rawDispatchReceiver = expression.dispatchReceiver
rawDispatchReceiver?.interpret(data)?.check { return it }
val dispatchReceiver = rawDispatchReceiver?.let { data.popReturnValue() }
val irFunctionReceiver = when (expression.superQualifierSymbol) {
null -> dispatchReceiver
else -> (dispatchReceiver as Complex).superClass?.takeIf { it.irClass.isSubclassOf(expression.superQualifierSymbol!!.owner) }
val superQualifier = expression.superQualifierSymbol
val irFunctionReceiver = when {
superQualifier == null -> dispatchReceiver
superQualifier.owner.isInterface -> null
else -> (dispatchReceiver as Complex).superClass
}
// 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
@@ -349,13 +367,9 @@ class IrInterpreter(irModule: IrModuleFragment) {
val extensionReceiver = rawExtensionReceiver?.let { data.popReturnValue() }
extensionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getExtensionReceiver()!!, it)) }
// if irFunction is lambda and it has receiver, then first descriptor must be taken from extension receiver
val receiverAsFirstArgument = if (dispatchReceiver is Lambda) listOfNotNull(irFunction.symbol.getExtensionReceiver()) else listOf()
val valueParametersDescriptors = receiverAsFirstArgument + irFunction.descriptor.valueParameters
val frameWithReceiverAndData = data.copy().apply { addAll(newFrame.getAll()) } // primary use case: copy method in data class
interpretValueParameters(expression, frameWithReceiverAndData).checkForReturn(frameWithReceiverAndData, data) { return it }
newFrame.addAll(valueParametersDescriptors.map { Variable(it, frameWithReceiverAndData.popReturnValue()) })
interpretValueParameters(expression, irFunction, data, newFrame).check { return it }
// TODO fun saveReifiedParameters
irFunction.takeIf { it.isInline }?.typeParameters?.forEachIndexed { index, typeParameter ->
if (typeParameter.isReified) {
val typeArgumentState = Common(expression.getTypeArgument(index)?.classOrNull!!.owner)
@@ -397,23 +411,23 @@ class IrInterpreter(irModule: IrModuleFragment) {
}
private suspend fun interpretConstructor(constructorCall: IrFunctionAccessExpression, data: Frame): ExecutionResult {
val isPrimary = (constructorCall.symbol.owner as IrConstructor).isPrimary
interpretValueParameters(constructorCall, data).check { return it }
val valueParameters = constructorCall.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList()
val newFrame = InterpreterFrame(valueParameters)
val owner = constructorCall.symbol.owner
val isPrimary = (owner as IrConstructor).isPrimary
val newFrame = InterpreterFrame()
interpretValueParameters(constructorCall, owner, data, newFrame)
val parent = owner.parent as IrClass
if (parent.hasAnnotation(evaluateIntrinsicAnnotation)) {
return when (constructorCall.symbol.owner.parentAsClass.getEvaluateIntrinsicValue()) {
return when (owner.parentAsClass.getEvaluateIntrinsicValue()) {
"kotlin.Long" -> {
val low = (valueParameters[0].state as Primitive<*>).value as Int
val high = (valueParameters[1].state as Primitive<*>).value as Int
val low = (newFrame.getVariableState(owner.valueParameters[0].descriptor) as Primitive<*>).value as Int
val high = (newFrame.getVariableState(owner.valueParameters[1].descriptor) as Primitive<*>).value as Int
data.pushReturnValue((high.toLong().shl(32) + low).toState(irBuiltIns.longType))
Next
}
"kotlin.Char" -> {
val value = (valueParameters.single().state as Primitive<*>).value as Int
val value = (newFrame.getVariableState(owner.valueParameters[0].descriptor) as Primitive<*>).value as Int
data.pushReturnValue(value.toChar().toState(irBuiltIns.longType))
Next
}
@@ -428,7 +442,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
val size = (newFrame.getVariableState(sizeDescriptor) as Primitive<*>).value as Int
val arrayValue = Array<Any?>(size) { 0 }
if (valueParameters.size == 2) {
if (owner.valueParameters.size == 2) {
val initDescriptor = arrayConstructor.owner.valueParameters.single { it.name.asString() == "init" }.descriptor
val initLambda = newFrame.getVariableState(initDescriptor) as Lambda
val indexDescriptor = initLambda.irFunction.valueParameters.single().descriptor
@@ -575,6 +589,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
val executionResult = expression.value.interpret(data)
if (executionResult.returnLabel != ReturnLabel.NEXT) return executionResult
// receiver is null only for top level var, but it cannot be used in constexpr; corresponding check is on frontend
val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor
data.getVariableState(receiver).setState(Variable(expression.symbol.owner.descriptor, data.popReturnValue()))
return Next
@@ -596,7 +611,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
}
private suspend fun interpretVariable(expression: IrVariable, data: Frame): ExecutionResult {
val executionResult = expression.initializer?.interpret(data)
val executionResult = expression.initializer?.interpret(data)// TODO replace with check
if (executionResult?.returnLabel != ReturnLabel.NEXT) return executionResult ?: Next
data.addVar(Variable(expression.descriptor, data.popReturnValue()))
return Next