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 }
|
interpretValueParameters(expression, irFunction, valueArguments).check { return it }
|
||||||
|
|
||||||
// TODO fun saveReifiedParameters
|
valueArguments.addAll(getTypeArguments(irFunction, expression) { stack.getVariableState(it) })
|
||||||
irFunction.takeIf { it.isInline }?.typeParameters?.forEachIndexed { index, typeParameter ->
|
if (dispatchReceiver is Common) valueArguments.addAll(dispatchReceiver.typeArguments)
|
||||||
if (typeParameter.isReified) {
|
if (extensionReceiver is Common) valueArguments.addAll(extensionReceiver.typeArguments)
|
||||||
val typeArgumentState = Common(expression.getTypeArgument(index)?.classOrNull!!.owner)
|
|
||||||
valueArguments.add(Variable(typeParameter.descriptor, typeArgumentState))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// load data from declaration if it is local
|
if (irFunction.isLocal) valueArguments.addAll(dispatchReceiver.extractNonLocalDeclarations())
|
||||||
if (dispatchReceiver != null && (irFunction.isLocal || dispatchReceiver.irClass.isLocal)) {
|
|
||||||
with(dispatchReceiver) { this.fields.filterNot { it.descriptor.containingDeclaration == this.irClass.descriptor } }
|
|
||||||
.apply { valueArguments.addAll(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return stack.newFrame(asSubFrame = irFunction.isInline || irFunction.isLocal, initPool = valueArguments) {
|
return stack.newFrame(asSubFrame = irFunction.isInline || irFunction.isLocal, initPool = valueArguments) {
|
||||||
val isWrapper = dispatchReceiver is Wrapper && rawExtensionReceiver == null
|
val isWrapper = dispatchReceiver is Wrapper && rawExtensionReceiver == null
|
||||||
@@ -376,9 +368,10 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val state = Common(parent)
|
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
|
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
|
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
|
val statements = constructorCall.getBody()!!.statements
|
||||||
// enum entry use IrTypeOperatorCall with IMPLICIT_COERCION_TO_UNIT as delegation call, but we need the value
|
// 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 }
|
((statements[0] as? IrTypeOperatorCall)?.argument ?: statements[0]).interpret().check { return@newFrame it }
|
||||||
@@ -550,7 +543,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
|
|
||||||
val objectState = when {
|
val objectState = when {
|
||||||
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getCompanionObject(owner)
|
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getCompanionObject(owner)
|
||||||
else -> Common(owner).apply { setSuperClassRecursive() }
|
else -> Common(owner).apply { setSuperClassRecursive() } // TODO test type arguments
|
||||||
}
|
}
|
||||||
mapOfObjects[objectSignature] = objectState
|
mapOfObjects[objectSignature] = objectState
|
||||||
stack.pushReturnValue(objectState)
|
stack.pushReturnValue(objectState)
|
||||||
@@ -600,29 +593,30 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
|
|
||||||
private suspend fun interpretTypeOperatorCall(expression: IrTypeOperatorCall): ExecutionResult {
|
private suspend fun interpretTypeOperatorCall(expression: IrTypeOperatorCall): ExecutionResult {
|
||||||
val executionResult = expression.argument.interpret().check { return it }
|
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) {
|
when (expression.operator) {
|
||||||
// coercion to unit means that return value isn't used
|
// coercion to unit means that return value isn't used
|
||||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> stack.popReturnValue()
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> stack.popReturnValue()
|
||||||
IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> {
|
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 convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable
|
||||||
val castClassName = expression.type.classOrNull?.owner?.fqNameWhenAvailable
|
throw ClassCastException("$convertibleClassName cannot be cast to ${typeOperandClass.fqNameWhenAvailable}")
|
||||||
throw ClassCastException("$convertibleClassName cannot be cast to $castClassName")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrTypeOperator.SAFE_CAST -> {
|
IrTypeOperator.SAFE_CAST -> {
|
||||||
if (!stack.peekReturnValue().irClass.defaultType.isSubtypeOf(expression.type, irBuiltIns)) {
|
if (!stack.peekReturnValue().irClass.isSubclassOf(typeOperandClass)) {
|
||||||
stack.popReturnValue()
|
stack.popReturnValue()
|
||||||
stack.pushReturnValue(null.toState(irBuiltIns.nothingType))
|
stack.pushReturnValue(null.toState(irBuiltIns.nothingType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrTypeOperator.INSTANCEOF -> {
|
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))
|
stack.pushReturnValue(isInstance.toState(irBuiltIns.nothingType))
|
||||||
}
|
}
|
||||||
IrTypeOperator.NOT_INSTANCEOF -> {
|
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))
|
stack.pushReturnValue((!isInstance).toState(irBuiltIns.nothingType))
|
||||||
}
|
}
|
||||||
else -> TODO("${expression.operator} not implemented")
|
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 {
|
private fun DeclarationDescriptor.hasSameNameAs(other: DeclarationDescriptor): Boolean {
|
||||||
return (this is VariableDescriptor && other is VariableDescriptor && this.name == other.name) ||
|
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 is FunctionDescriptor && other is FunctionDescriptor && //this == other
|
||||||
this.valueParameters.map { it.type.toString() } == other.valueParameters.map { it.type.toString() } &&
|
this.valueParameters.map { it.type.toString() } == other.valueParameters.map { it.type.toString() } &&
|
||||||
this.name == other.name)
|
this.name == other.name)
|
||||||
@@ -240,3 +241,17 @@ fun IrFunctionAccessExpression.getVarargType(index: Int): IrType? {
|
|||||||
val typeParameter = varargType.classifierOrFail.owner as IrTypeParameter
|
val typeParameter = varargType.classifierOrFail.owner as IrTypeParameter
|
||||||
return this.getTypeArgument(typeParameter.index)
|
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.equalTo
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.state.State
|
import org.jetbrains.kotlin.backend.common.interpreter.state.State
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
import kotlin.NoSuchElementException
|
import kotlin.NoSuchElementException
|
||||||
|
|
||||||
interface Frame {
|
interface Frame {
|
||||||
@@ -16,6 +17,7 @@ interface Frame {
|
|||||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
||||||
fun tryGetVariableState(variableDescriptor: DeclarationDescriptor): State?
|
fun tryGetVariableState(variableDescriptor: DeclarationDescriptor): State?
|
||||||
fun getAll(): List<Variable>
|
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 contains(descriptor: DeclarationDescriptor): Boolean
|
||||||
fun pushReturnValue(state: State)
|
fun pushReturnValue(state: State)
|
||||||
fun pushReturnValue(frame: Frame) // TODO rename to getReturnValueFrom
|
fun pushReturnValue(frame: Frame) // TODO rename to getReturnValueFrom
|
||||||
@@ -25,7 +27,10 @@ interface Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO replace exceptions with InterpreterException
|
// 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()
|
private val returnStack: MutableList<State> = mutableListOf()
|
||||||
|
|
||||||
override fun addVar(variable: Variable) {
|
override fun addVar(variable: Variable) {
|
||||||
@@ -37,7 +42,8 @@ class InterpreterFrame(val pool: MutableList<Variable> = mutableListOf()) : Fram
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun tryGetVariableState(variableDescriptor: DeclarationDescriptor): State? {
|
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 {
|
override fun getVariableState(variableDescriptor: DeclarationDescriptor): State {
|
||||||
@@ -49,8 +55,12 @@ class InterpreterFrame(val pool: MutableList<Variable> = mutableListOf()) : Fram
|
|||||||
return pool
|
return pool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAllTypeArguments(): List<Variable> {
|
||||||
|
return typeArguments
|
||||||
|
}
|
||||||
|
|
||||||
override fun contains(descriptor: DeclarationDescriptor): Boolean {
|
override fun contains(descriptor: DeclarationDescriptor): Boolean {
|
||||||
return pool.any { it.descriptor == descriptor }
|
return (typeArguments + pool).any { it.descriptor == descriptor }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pushReturnValue(state: State) {
|
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.exceptions.InterpreterException
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.state.State
|
import org.jetbrains.kotlin.backend.common.interpreter.state.State
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
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.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.name
|
import org.jetbrains.kotlin.ir.declarations.name
|
||||||
import org.jetbrains.kotlin.ir.util.file
|
import org.jetbrains.kotlin.ir.util.file
|
||||||
@@ -29,6 +30,7 @@ interface Stack {
|
|||||||
fun addAll(variables: List<Variable>)
|
fun addAll(variables: List<Variable>)
|
||||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
||||||
fun getAll(): List<Variable>
|
fun getAll(): List<Variable>
|
||||||
|
fun getAllTypeArguments(): List<Variable>
|
||||||
|
|
||||||
fun contains(descriptor: DeclarationDescriptor): Boolean
|
fun contains(descriptor: DeclarationDescriptor): Boolean
|
||||||
fun hasReturnValue(): Boolean
|
fun hasReturnValue(): Boolean
|
||||||
@@ -42,7 +44,9 @@ class StackImpl : Stack {
|
|||||||
private fun getCurrentFrame() = frameList.last()
|
private fun getCurrentFrame() = frameList.last()
|
||||||
|
|
||||||
override suspend fun newFrame(asSubFrame: Boolean, initPool: List<Variable>, block: suspend () -> ExecutionResult): ExecutionResult {
|
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))
|
if (asSubFrame) getCurrentFrame().addSubFrame(newFrame) else frameList.add(FrameContainer(newFrame))
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
@@ -90,6 +94,10 @@ class StackImpl : Stack {
|
|||||||
return getCurrentFrame().getAll()
|
return getCurrentFrame().getAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAllTypeArguments(): List<Variable> {
|
||||||
|
return getCurrentFrame().getAllTypeArguments()
|
||||||
|
}
|
||||||
|
|
||||||
override fun contains(descriptor: DeclarationDescriptor): Boolean {
|
override fun contains(descriptor: DeclarationDescriptor): Boolean {
|
||||||
return getCurrentFrame().contains(descriptor)
|
return getCurrentFrame().contains(descriptor)
|
||||||
}
|
}
|
||||||
@@ -128,6 +136,7 @@ private class FrameContainer(current: Frame = InterpreterFrame()) {
|
|||||||
fun addVar(variable: Variable) = getTopFrame().addVar(variable)
|
fun addVar(variable: Variable) = getTopFrame().addVar(variable)
|
||||||
fun addAll(variables: List<Variable>) = getTopFrame().addAll(variables)
|
fun addAll(variables: List<Variable>) = getTopFrame().addAll(variables)
|
||||||
fun getAll() = innerStack.flatMap { it.getAll() }
|
fun getAll() = innerStack.flatMap { it.getAll() }
|
||||||
|
fun getAllTypeArguments() = innerStack.flatMap { it.getAllTypeArguments() }
|
||||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State {
|
fun getVariableState(variableDescriptor: DeclarationDescriptor): State {
|
||||||
return innerStack.firstNotNullResult { it.tryGetVariableState(variableDescriptor) }
|
return innerStack.firstNotNullResult { it.tryGetVariableState(variableDescriptor) }
|
||||||
?: throw InterpreterException("$variableDescriptor not found") // TODO better message
|
?: 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
|
import org.jetbrains.kotlin.ir.util.isInterface
|
||||||
|
|
||||||
class Common private constructor(
|
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) {
|
) : Complex(irClass, fields, superClass, subClass) {
|
||||||
|
|
||||||
constructor(irClass: IrClass) : this(irClass, mutableListOf(), null, null)
|
constructor(irClass: IrClass) : this(irClass, mutableListOf(), mutableListOf(), null, null)
|
||||||
|
|
||||||
fun setSuperClassRecursive() {
|
fun setSuperClassRecursive() {
|
||||||
var thisClass: Common? = this
|
var thisClass: Common? = this
|
||||||
@@ -48,7 +49,7 @@ class Common private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun copy(): State {
|
override fun copy(): State {
|
||||||
return Common(irClass, fields, superClass, subClass ?: this)
|
return Common(irClass, fields, typeArguments, superClass, subClass ?: this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
|||||||
Reference in New Issue
Block a user