From 25989b36c519cbcef75e52b2432f76adeb35af41 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Mon, 24 May 2021 16:21:37 +0300 Subject: [PATCH] Allow to create object in interpreter only if it is compile time --- .../org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt | 6 ++++-- .../kotlin/ir/interpreter/checker/IrCompileTimeChecker.kt | 7 ++++--- compiler/testData/ir/interpreter/object.kt | 5 +++++ 3 files changed, 13 insertions(+), 5 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 1320a248cad..a72ebb6e98a 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 @@ -370,11 +370,10 @@ class IrInterpreter private constructor( callStack.addInstruction(CompoundInstruction(field.initializer?.expression)) } expression.accessesTopLevelOrObjectField() -> { - // receiver is null, for example, for top level fields val propertyOwner = field.correspondingPropertySymbol?.owner val isConst = propertyOwner?.isConst == true || propertyOwner?.backingField?.initializer?.expression is IrConst<*> assert(isConst) { "Cannot interpret get method on top level non const properties" } - callStack.addInstruction(CompoundInstruction(expression.symbol.owner.initializer?.expression)) + callStack.addInstruction(CompoundInstruction(field.initializer?.expression)) } else -> { val result = callStack.getState(receiver!!).getField(field.correspondingPropertySymbol!!) @@ -390,6 +389,9 @@ class IrInterpreter private constructor( environment.mapOfObjects[objectClass.symbol] = state // must set object's state here to avoid cyclic evaluation callStack.addVariable(Variable(objectClass.thisReceiver!!.symbol, state)) + // non compile time objects can be used in interpreter, for example, to evaluate const properties + if (!objectClass.hasAnnotation(compileTimeAnnotation)) return@interceptGetObjectValue callStack.pushState(state) + val constructor = objectClass.constructors.firstOrNull() ?: return@interceptGetObjectValue callStack.pushState(state) val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) callStack.newSubFrame(constructorCall) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrCompileTimeChecker.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrCompileTimeChecker.kt index 9699f04a784..9edd45e4389 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrCompileTimeChecker.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrCompileTimeChecker.kt @@ -119,9 +119,10 @@ class IrCompileTimeChecker( } override fun visitGetValue(expression: IrGetValue, data: Nothing?): Boolean { - val parent = expression.symbol.owner.parent as IrSymbolOwner - val isObject = (parent as? IrClass)?.isObject == true //used to evaluate constants inside object - return visitedStack.contains(parent) || isObject + val owner = expression.symbol.owner + val parent = owner.parent as IrSymbolOwner + val isObjectReceiver = (parent as? IrClass)?.isObject == true && owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER + return visitedStack.contains(parent) || isObjectReceiver } override fun visitSetValue(expression: IrSetValue, data: Nothing?): Boolean { diff --git a/compiler/testData/ir/interpreter/object.kt b/compiler/testData/ir/interpreter/object.kt index c8de07d80d7..d4787c912ae 100644 --- a/compiler/testData/ir/interpreter/object.kt +++ b/compiler/testData/ir/interpreter/object.kt @@ -1,3 +1,4 @@ +@CompileTimeCalculation class A { const val a = { 10 }() @@ -10,10 +11,13 @@ class A { } } +@CompileTimeCalculation object ObjectWithConst { const val a = 100 const val b = concat("Value in a: ", a) + val nonConst = "Not const field in compile time object" + fun concat(first: String, second: Any) = "$first$second" } @@ -21,3 +25,4 @@ const val num = A().a const val numStatic = A.static const val numStaticFromFun = A.getStaticNumber() const val valFromObject = ObjectWithConst.b +const val valFnonConstFromObject = ObjectWithConst.nonConst