Allow inner class to has outer super class in interpreter

This commit is contained in:
Ivan Kylchik
2021-06-04 22:56:11 +03:00
committed by TeamCityServer
parent 574c607f1c
commit 0716c557fe
2 changed files with 37 additions and 26 deletions
@@ -107,7 +107,6 @@ class IrInterpreter private constructor(
is IrEnumConstructorCall -> interpretEnumConstructorCall(element)
is IrDelegatingConstructorCall -> interpretDelegatingConstructorCall(element)
is IrValueParameter -> interpretValueParameter(element)
is IrInstanceInitializerCall -> interpretInstanceInitializerCall(element)
is IrField -> interpretField(element)
is IrBody -> interpretBody(element)
is IrBlock -> interpretBlock(element)
@@ -219,21 +218,6 @@ class IrInterpreter private constructor(
}
}
private fun interpretInstanceInitializerCall(call: IrInstanceInitializerCall) {
val irClass = call.classSymbol.owner
val classProperties = irClass.declarations.filterIsInstance<IrProperty>()
classProperties.forEach { property ->
property.backingField?.initializer?.expression ?: return@forEach
val receiver = irClass.thisReceiver!!.symbol
if (property.backingField?.initializer != null) {
val receiverState = callStack.getState(receiver)
val propertyVar = Variable(property.symbol, callStack.popState())
receiverState.setField(propertyVar)
}
}
}
private fun interpretField(field: IrField) {
val irClass = field.parentAsClass
val receiver = irClass.thisReceiver!!.symbol
@@ -262,9 +246,11 @@ class IrInterpreter private constructor(
val constructor = constructorCall.symbol.owner
val valueArguments = constructor.valueParameters.map { callStack.getState(it.symbol) }
val irClass = constructor.parentAsClass
val receiverSymbol = constructor.dispatchReceiverParameter?.symbol
val objectState = callStack.getState(constructorCall.getThisReceiver())
if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure)
val outerClass = if (irClass.isInner) callStack.getState(constructor.dispatchReceiverParameter!!.symbol) else null
val outerClass = receiverSymbol?.let { callStack.getState(it) }
callStack.dropSubFrame()
callStack.newFrame(constructor)
@@ -273,15 +259,6 @@ class IrInterpreter private constructor(
constructor.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) }
if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure)
if (outerClass != null) {
val outerClassVar = Variable(irClass.parentAsClass.thisReceiver!!.symbol, outerClass)
(objectState as Complex).outerClass = outerClassVar
// used in case when inner class has inner super class
callStack.addVariable(Variable(constructor.dispatchReceiverParameter!!.symbol, outerClass))
// used to get information from outer class
callStack.addVariable(outerClassVar)
}
val superReceiver = when (val irStatement = constructor.body?.statements?.get(0)) {
null -> null // for jvm
is IrTypeOperatorCall -> (irStatement.argument as IrFunctionAccessExpression).getThisReceiver() // for enums
@@ -291,6 +268,19 @@ class IrInterpreter private constructor(
}
superReceiver?.let { callStack.addVariable(Variable(it, objectState)) }
if (outerClass != null) {
val outerClassVar = Variable(irClass.parentAsClass.thisReceiver!!.symbol, outerClass)
(objectState as Complex).outerClass = outerClassVar
if (superReceiver != receiverSymbol) {
// This check is needed to test that this inner class is not subclass of its outer.
// If it is true and if we add the next symbol, it will interfere with super symbol in memory.
// In other case, we need this variable when inner class has inner super class.
callStack.addVariable(Variable(receiverSymbol, outerClass))
}
// used to get information from outer class
generateSequence(outerClassVar) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) }
}
callInterceptor.interceptConstructor(constructorCall, valueArguments) {
callStack.addInstruction(CompoundInstruction(constructor))
}
+21
View File
@@ -25,3 +25,24 @@ const val a2 = Outer().Middle().<!EVALUATED: `middle foo`!>foo()<!>
const val a3 = Outer().Middle().Inner().<!EVALUATED: `inner foo with outer bar = "bar"`!>foo()<!>
const val b = Outer().Middle().Inner().<!EVALUATED: `From inner: 3; from middle: 2; from outer: 1`!>getAllNums()<!>
open class A(val s: String) {
val z = s
fun test() = s
inner class B(s: String): A(s) {
fun testB(): String {
return when {
s != "OK" -> "Fail 1"
z != "OK" -> "Fail 2"
test() != "OK" -> "Fail 3"
this@A.s != "Fail" -> "Fail 4"
super.s != "OK" -> "Fail 5"
else -> "OK"
}
}
}
}
const val c = A("Fail").B("OK").<!EVALUATED: `OK`!>testB()<!>