Change conditions for saving type arguments into stack
For now all type arguments are saved. This is necessary for several reason: 1. ir type operator call need to get right type argument class 2. if class is local then information about type argument cannot be lost
This commit is contained in:
+14
-20
@@ -309,19 +309,11 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
|
||||
interpretValueParameters(expression, irFunction, valueArguments).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)
|
||||
valueArguments.add(Variable(typeParameter.descriptor, typeArgumentState))
|
||||
}
|
||||
}
|
||||
valueArguments.addAll(getTypeArguments(irFunction, expression) { stack.getVariableState(it) })
|
||||
if (dispatchReceiver is Common) valueArguments.addAll(dispatchReceiver.typeArguments)
|
||||
if (extensionReceiver is Common) valueArguments.addAll(extensionReceiver.typeArguments)
|
||||
|
||||
// load data from declaration if it is local
|
||||
if (dispatchReceiver != null && (irFunction.isLocal || dispatchReceiver.irClass.isLocal)) {
|
||||
with(dispatchReceiver) { this.fields.filterNot { it.descriptor.containingDeclaration == this.irClass.descriptor } }
|
||||
.apply { valueArguments.addAll(this) }
|
||||
}
|
||||
if (irFunction.isLocal) valueArguments.addAll(dispatchReceiver.extractNonLocalDeclarations())
|
||||
|
||||
return stack.newFrame(asSubFrame = irFunction.isInline || irFunction.isLocal, initPool = valueArguments) {
|
||||
val isWrapper = dispatchReceiver is Wrapper && rawExtensionReceiver == null
|
||||
@@ -376,9 +368,10 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
}
|
||||
|
||||
val state = Common(parent)
|
||||
state.typeArguments.addAll(getTypeArguments(parent, constructorCall) { stack.getVariableState(it) } + stack.getAllTypeArguments())
|
||||
if (parent.isLocal) state.fields.addAll(stack.getAll()) // TODO save only necessary declarations
|
||||
valueArguments.add(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
|
||||
return stack.newFrame(initPool = valueArguments) {
|
||||
return stack.newFrame(initPool = valueArguments + state.typeArguments) {
|
||||
val statements = constructorCall.getBody()!!.statements
|
||||
// enum entry use IrTypeOperatorCall with IMPLICIT_COERCION_TO_UNIT as delegation call, but we need the value
|
||||
((statements[0] as? IrTypeOperatorCall)?.argument ?: statements[0]).interpret().check { return@newFrame it }
|
||||
@@ -550,7 +543,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
|
||||
val objectState = when {
|
||||
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getCompanionObject(owner)
|
||||
else -> Common(owner).apply { setSuperClassRecursive() }
|
||||
else -> Common(owner).apply { setSuperClassRecursive() } // TODO test type arguments
|
||||
}
|
||||
mapOfObjects[objectSignature] = objectState
|
||||
stack.pushReturnValue(objectState)
|
||||
@@ -600,29 +593,30 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
|
||||
private suspend fun interpretTypeOperatorCall(expression: IrTypeOperatorCall): ExecutionResult {
|
||||
val executionResult = expression.argument.interpret().check { return it }
|
||||
val typeOperandDescriptor = expression.typeOperand.classifierOrFail.descriptor
|
||||
val typeOperandClass = expression.typeOperand.classOrNull?.owner ?: stack.getVariableState(typeOperandDescriptor).irClass
|
||||
|
||||
when (expression.operator) {
|
||||
// coercion to unit means that return value isn't used
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> stack.popReturnValue()
|
||||
IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> {
|
||||
if (!stack.peekReturnValue().irClass.defaultType.isSubtypeOf(expression.type, irBuiltIns)) {
|
||||
if (!stack.peekReturnValue().irClass.isSubclassOf(typeOperandClass)) {
|
||||
val convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable
|
||||
val castClassName = expression.type.classOrNull?.owner?.fqNameWhenAvailable
|
||||
throw ClassCastException("$convertibleClassName cannot be cast to $castClassName")
|
||||
throw ClassCastException("$convertibleClassName cannot be cast to ${typeOperandClass.fqNameWhenAvailable}")
|
||||
}
|
||||
}
|
||||
IrTypeOperator.SAFE_CAST -> {
|
||||
if (!stack.peekReturnValue().irClass.defaultType.isSubtypeOf(expression.type, irBuiltIns)) {
|
||||
if (!stack.peekReturnValue().irClass.isSubclassOf(typeOperandClass)) {
|
||||
stack.popReturnValue()
|
||||
stack.pushReturnValue(null.toState(irBuiltIns.nothingType))
|
||||
}
|
||||
}
|
||||
IrTypeOperator.INSTANCEOF -> {
|
||||
val isInstance = stack.popReturnValue().irClass.defaultType.isSubtypeOf(expression.typeOperand, irBuiltIns)
|
||||
val isInstance = stack.popReturnValue().irClass.isSubclassOf(typeOperandClass)
|
||||
stack.pushReturnValue(isInstance.toState(irBuiltIns.nothingType))
|
||||
}
|
||||
IrTypeOperator.NOT_INSTANCEOF -> {
|
||||
val isInstance = stack.popReturnValue().irClass.defaultType.isSubtypeOf(expression.typeOperand, irBuiltIns)
|
||||
val isInstance = stack.popReturnValue().irClass.isSubclassOf(typeOperandClass)
|
||||
stack.pushReturnValue((!isInstance).toState(irBuiltIns.nothingType))
|
||||
}
|
||||
else -> TODO("${expression.operator} not implemented")
|
||||
|
||||
+15
@@ -74,6 +74,7 @@ private fun DeclarationDescriptor.isSubtypeOf(other: DeclarationDescriptor): Boo
|
||||
|
||||
private fun DeclarationDescriptor.hasSameNameAs(other: DeclarationDescriptor): Boolean {
|
||||
return (this is VariableDescriptor && other is VariableDescriptor && this.name == other.name) ||
|
||||
(this is TypeParameterDescriptor && other is TypeParameterDescriptor && this.name == other.name) ||
|
||||
(this is FunctionDescriptor && other is FunctionDescriptor && //this == other
|
||||
this.valueParameters.map { it.type.toString() } == other.valueParameters.map { it.type.toString() } &&
|
||||
this.name == other.name)
|
||||
@@ -239,4 +240,18 @@ fun IrFunctionAccessExpression.getVarargType(index: Int): IrType? {
|
||||
val varargType = this.symbol.owner.valueParameters[index].varargElementType ?: return null
|
||||
val typeParameter = varargType.classifierOrFail.owner as IrTypeParameter
|
||||
return this.getTypeArgument(typeParameter.index)
|
||||
}
|
||||
|
||||
fun getTypeArguments(
|
||||
container: IrTypeParametersContainer, expression: IrFunctionAccessExpression, mapper: (TypeParameterDescriptor) -> State
|
||||
): List<Variable> {
|
||||
return container.typeParameters.mapIndexed { index, typeParameter ->
|
||||
val argumentState = expression.getTypeArgument(index)?.classOrNull?.owner?.let { Common(it) } ?: mapper(typeParameter.descriptor)
|
||||
Variable(typeParameter.descriptor, argumentState)
|
||||
}
|
||||
}
|
||||
|
||||
fun State?.extractNonLocalDeclarations(): List<Variable> {
|
||||
this ?: return listOf()
|
||||
return this.fields.filterNot { it.descriptor.containingDeclaration == this.irClass.descriptor }
|
||||
}
|
||||
+13
-3
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.common.interpreter.stack
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.equalTo
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.state.State
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import kotlin.NoSuchElementException
|
||||
|
||||
interface Frame {
|
||||
@@ -16,6 +17,7 @@ interface Frame {
|
||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
||||
fun tryGetVariableState(variableDescriptor: DeclarationDescriptor): State?
|
||||
fun getAll(): List<Variable>
|
||||
fun getAllTypeArguments(): List<Variable> // TODO try to get rid of this method; possibly by finding all type arguments in local class
|
||||
fun contains(descriptor: DeclarationDescriptor): Boolean
|
||||
fun pushReturnValue(state: State)
|
||||
fun pushReturnValue(frame: Frame) // TODO rename to getReturnValueFrom
|
||||
@@ -25,7 +27,10 @@ interface Frame {
|
||||
}
|
||||
|
||||
// TODO replace exceptions with InterpreterException
|
||||
class InterpreterFrame(val pool: MutableList<Variable> = mutableListOf()) : Frame {
|
||||
class InterpreterFrame(
|
||||
private val pool: MutableList<Variable> = mutableListOf(),
|
||||
private val typeArguments: List<Variable> = listOf()
|
||||
) : Frame {
|
||||
private val returnStack: MutableList<State> = mutableListOf()
|
||||
|
||||
override fun addVar(variable: Variable) {
|
||||
@@ -37,7 +42,8 @@ class InterpreterFrame(val pool: MutableList<Variable> = mutableListOf()) : Fram
|
||||
}
|
||||
|
||||
override fun tryGetVariableState(variableDescriptor: DeclarationDescriptor): State? {
|
||||
return pool.firstOrNull { it.descriptor.equalTo(variableDescriptor) }?.state
|
||||
return (if (variableDescriptor is TypeParameterDescriptor) typeArguments else pool)
|
||||
.firstOrNull { it.descriptor.equalTo(variableDescriptor) }?.state
|
||||
}
|
||||
|
||||
override fun getVariableState(variableDescriptor: DeclarationDescriptor): State {
|
||||
@@ -49,8 +55,12 @@ class InterpreterFrame(val pool: MutableList<Variable> = mutableListOf()) : Fram
|
||||
return pool
|
||||
}
|
||||
|
||||
override fun getAllTypeArguments(): List<Variable> {
|
||||
return typeArguments
|
||||
}
|
||||
|
||||
override fun contains(descriptor: DeclarationDescriptor): Boolean {
|
||||
return pool.any { it.descriptor == descriptor }
|
||||
return (typeArguments + pool).any { it.descriptor == descriptor }
|
||||
}
|
||||
|
||||
override fun pushReturnValue(state: State) {
|
||||
|
||||
+10
-1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.interpreter.ExecutionResult
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.exceptions.InterpreterException
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.state.State
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.name
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
@@ -29,6 +30,7 @@ interface Stack {
|
||||
fun addAll(variables: List<Variable>)
|
||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
||||
fun getAll(): List<Variable>
|
||||
fun getAllTypeArguments(): List<Variable>
|
||||
|
||||
fun contains(descriptor: DeclarationDescriptor): Boolean
|
||||
fun hasReturnValue(): Boolean
|
||||
@@ -42,7 +44,9 @@ class StackImpl : Stack {
|
||||
private fun getCurrentFrame() = frameList.last()
|
||||
|
||||
override suspend fun newFrame(asSubFrame: Boolean, initPool: List<Variable>, block: suspend () -> ExecutionResult): ExecutionResult {
|
||||
val newFrame = InterpreterFrame(initPool.toMutableList())
|
||||
val typeArgumentsPool = initPool.filter { it.descriptor is TypeParameterDescriptor }
|
||||
val valueArguments = initPool.filter { it.descriptor !is TypeParameterDescriptor }
|
||||
val newFrame = InterpreterFrame(valueArguments.toMutableList(), typeArgumentsPool)
|
||||
if (asSubFrame) getCurrentFrame().addSubFrame(newFrame) else frameList.add(FrameContainer(newFrame))
|
||||
|
||||
return try {
|
||||
@@ -90,6 +94,10 @@ class StackImpl : Stack {
|
||||
return getCurrentFrame().getAll()
|
||||
}
|
||||
|
||||
override fun getAllTypeArguments(): List<Variable> {
|
||||
return getCurrentFrame().getAllTypeArguments()
|
||||
}
|
||||
|
||||
override fun contains(descriptor: DeclarationDescriptor): Boolean {
|
||||
return getCurrentFrame().contains(descriptor)
|
||||
}
|
||||
@@ -128,6 +136,7 @@ private class FrameContainer(current: Frame = InterpreterFrame()) {
|
||||
fun addVar(variable: Variable) = getTopFrame().addVar(variable)
|
||||
fun addAll(variables: List<Variable>) = getTopFrame().addAll(variables)
|
||||
fun getAll() = innerStack.flatMap { it.getAll() }
|
||||
fun getAllTypeArguments() = innerStack.flatMap { it.getAllTypeArguments() }
|
||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State {
|
||||
return innerStack.firstNotNullResult { it.tryGetVariableState(variableDescriptor) }
|
||||
?: throw InterpreterException("$variableDescriptor not found") // TODO better message
|
||||
|
||||
+4
-3
@@ -14,10 +14,11 @@ import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
|
||||
class Common private constructor(
|
||||
override val irClass: IrClass, override val fields: MutableList<Variable>, superClass: Complex?, subClass: Complex?
|
||||
override val irClass: IrClass, override val fields: MutableList<Variable>, val typeArguments: MutableList<Variable>,
|
||||
superClass: Complex?, subClass: Complex?
|
||||
) : Complex(irClass, fields, superClass, subClass) {
|
||||
|
||||
constructor(irClass: IrClass) : this(irClass, mutableListOf(), null, null)
|
||||
constructor(irClass: IrClass) : this(irClass, mutableListOf(), mutableListOf(), null, null)
|
||||
|
||||
fun setSuperClassRecursive() {
|
||||
var thisClass: Common? = this
|
||||
@@ -48,7 +49,7 @@ class Common private constructor(
|
||||
}
|
||||
|
||||
override fun copy(): State {
|
||||
return Common(irClass, fields, superClass, subClass ?: this)
|
||||
return Common(irClass, fields, typeArguments, superClass, subClass ?: this)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
||||
Reference in New Issue
Block a user