Allow inner class to has outer super class in interpreter
This commit is contained in:
committed by
TeamCityServer
parent
574c607f1c
commit
0716c557fe
+16
-26
@@ -107,7 +107,6 @@ class IrInterpreter private constructor(
|
|||||||
is IrEnumConstructorCall -> interpretEnumConstructorCall(element)
|
is IrEnumConstructorCall -> interpretEnumConstructorCall(element)
|
||||||
is IrDelegatingConstructorCall -> interpretDelegatingConstructorCall(element)
|
is IrDelegatingConstructorCall -> interpretDelegatingConstructorCall(element)
|
||||||
is IrValueParameter -> interpretValueParameter(element)
|
is IrValueParameter -> interpretValueParameter(element)
|
||||||
is IrInstanceInitializerCall -> interpretInstanceInitializerCall(element)
|
|
||||||
is IrField -> interpretField(element)
|
is IrField -> interpretField(element)
|
||||||
is IrBody -> interpretBody(element)
|
is IrBody -> interpretBody(element)
|
||||||
is IrBlock -> interpretBlock(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) {
|
private fun interpretField(field: IrField) {
|
||||||
val irClass = field.parentAsClass
|
val irClass = field.parentAsClass
|
||||||
val receiver = irClass.thisReceiver!!.symbol
|
val receiver = irClass.thisReceiver!!.symbol
|
||||||
@@ -262,9 +246,11 @@ class IrInterpreter private constructor(
|
|||||||
val constructor = constructorCall.symbol.owner
|
val constructor = constructorCall.symbol.owner
|
||||||
val valueArguments = constructor.valueParameters.map { callStack.getState(it.symbol) }
|
val valueArguments = constructor.valueParameters.map { callStack.getState(it.symbol) }
|
||||||
val irClass = constructor.parentAsClass
|
val irClass = constructor.parentAsClass
|
||||||
|
val receiverSymbol = constructor.dispatchReceiverParameter?.symbol
|
||||||
|
|
||||||
val objectState = callStack.getState(constructorCall.getThisReceiver())
|
val objectState = callStack.getState(constructorCall.getThisReceiver())
|
||||||
if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure)
|
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.dropSubFrame()
|
||||||
callStack.newFrame(constructor)
|
callStack.newFrame(constructor)
|
||||||
@@ -273,15 +259,6 @@ class IrInterpreter private constructor(
|
|||||||
constructor.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) }
|
constructor.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) }
|
||||||
if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure)
|
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)) {
|
val superReceiver = when (val irStatement = constructor.body?.statements?.get(0)) {
|
||||||
null -> null // for jvm
|
null -> null // for jvm
|
||||||
is IrTypeOperatorCall -> (irStatement.argument as IrFunctionAccessExpression).getThisReceiver() // for enums
|
is IrTypeOperatorCall -> (irStatement.argument as IrFunctionAccessExpression).getThisReceiver() // for enums
|
||||||
@@ -291,6 +268,19 @@ class IrInterpreter private constructor(
|
|||||||
}
|
}
|
||||||
superReceiver?.let { callStack.addVariable(Variable(it, objectState)) }
|
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) {
|
callInterceptor.interceptConstructor(constructorCall, valueArguments) {
|
||||||
callStack.addInstruction(CompoundInstruction(constructor))
|
callStack.addInstruction(CompoundInstruction(constructor))
|
||||||
}
|
}
|
||||||
|
|||||||
+21
@@ -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 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()<!>
|
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()<!>
|
||||||
|
|||||||
Reference in New Issue
Block a user