From 0716c557fe0e3f243528066e7746f1e8066d6b79 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Fri, 4 Jun 2021 22:56:11 +0300 Subject: [PATCH] Allow inner class to has outer super class in interpreter --- .../kotlin/ir/interpreter/IrInterpreter.kt | 42 +++++++------------ .../testData/ir/interpreter/innerClass.kt | 21 ++++++++++ 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index 1f30e8b0014..576db190e55 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -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() - 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)) } diff --git a/compiler/testData/ir/interpreter/innerClass.kt b/compiler/testData/ir/interpreter/innerClass.kt index 778330a7434..12a6eb5699c 100644 --- a/compiler/testData/ir/interpreter/innerClass.kt +++ b/compiler/testData/ir/interpreter/innerClass.kt @@ -25,3 +25,24 @@ const val a2 = Outer().Middle().foo() const val a3 = Outer().Middle().Inner().foo() const val b = Outer().Middle().Inner().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").testB()