Allow compile time calculations inside object declaration
This commit is contained in:
+15
-9
@@ -14,20 +14,22 @@ import org.jetbrains.kotlin.ir.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
import org.jetbrains.kotlin.ir.util.isLocal
|
import org.jetbrains.kotlin.ir.util.isLocal
|
||||||
|
import org.jetbrains.kotlin.ir.util.isObject
|
||||||
import org.jetbrains.kotlin.ir.util.statements
|
import org.jetbrains.kotlin.ir.util.statements
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
enum class CompileTimeMode {
|
enum class EvaluationMode {
|
||||||
FULL, ONLY_BUILTINS
|
FULL, ONLY_BUILTINS
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrCompileTimeChecker(
|
class IrCompileTimeChecker(
|
||||||
containingDeclaration: String = "", private val mode: CompileTimeMode = CompileTimeMode.FULL
|
containingDeclaration: IrSymbol? = null, private val mode: EvaluationMode = EvaluationMode.FULL
|
||||||
) : IrElementVisitor<Boolean, Nothing?> {
|
) : IrElementVisitor<Boolean, Nothing?> {
|
||||||
private val callStack = mutableListOf<String>().apply { if (containingDeclaration.isNotEmpty()) add(containingDeclaration) }
|
private val callStack = mutableListOf<IrSymbol>().apply { if (containingDeclaration != null) add(containingDeclaration) }
|
||||||
|
|
||||||
private val compileTimeTypeAliases = setOf(
|
private val compileTimeTypeAliases = setOf(
|
||||||
"java.lang.StringBuilder", "java.lang.IllegalArgumentException", "java.util.NoSuchElementException"
|
"java.lang.StringBuilder", "java.lang.IllegalArgumentException", "java.util.NoSuchElementException"
|
||||||
@@ -57,7 +59,7 @@ class IrCompileTimeChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun IrSymbol.withCallStack(block: () -> Boolean): Boolean {
|
private fun IrSymbol.withCallStack(block: () -> Boolean): Boolean {
|
||||||
callStack += this.descriptor.toString()
|
callStack += this
|
||||||
val result = block()
|
val result = block()
|
||||||
callStack.removeAt(callStack.lastIndex)
|
callStack.removeAt(callStack.lastIndex)
|
||||||
return result
|
return result
|
||||||
@@ -66,7 +68,7 @@ class IrCompileTimeChecker(
|
|||||||
override fun visitElement(element: IrElement, data: Nothing?) = false
|
override fun visitElement(element: IrElement, data: Nothing?) = false
|
||||||
|
|
||||||
private fun visitStatements(statements: List<IrStatement>, data: Nothing?): Boolean {
|
private fun visitStatements(statements: List<IrStatement>, data: Nothing?): Boolean {
|
||||||
if (mode == CompileTimeMode.ONLY_BUILTINS) return false
|
if (mode == EvaluationMode.ONLY_BUILTINS) return false
|
||||||
return statements.all { it.accept(this, data) }
|
return statements.all { it.accept(this, data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +149,9 @@ class IrCompileTimeChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue, data: Nothing?): Boolean {
|
override fun visitGetValue(expression: IrGetValue, data: Nothing?): Boolean {
|
||||||
return callStack.contains(expression.symbol.descriptor.containingDeclaration.toString())
|
val parent = expression.symbol.owner.parent as IrSymbolOwner
|
||||||
|
val isObject = (parent as? IrClass)?.isObject == true //used to evaluate constants inside object
|
||||||
|
return callStack.contains(parent.symbol) || isObject
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSetVariable(expression: IrSetVariable, data: Nothing?): Boolean {
|
override fun visitSetVariable(expression: IrSetVariable, data: Nothing?): Boolean {
|
||||||
@@ -155,12 +159,14 @@ class IrCompileTimeChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField, data: Nothing?): Boolean {
|
override fun visitGetField(expression: IrGetField, data: Nothing?): Boolean {
|
||||||
return callStack.contains(expression.symbol.descriptor.containingDeclaration.toString())
|
val parent = expression.symbol.owner.parent as IrSymbolOwner
|
||||||
|
return callStack.contains(parent.symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSetField(expression: IrSetField, data: Nothing?): Boolean {
|
override fun visitSetField(expression: IrSetField, data: Nothing?): Boolean {
|
||||||
//todo check receiver?
|
//todo check receiver?
|
||||||
return callStack.contains(expression.symbol.descriptor.containingDeclaration.toString()) && expression.value.accept(this, data)
|
val parent = expression.symbol.owner.parent as IrSymbolOwner
|
||||||
|
return callStack.contains(parent.symbol) && expression.value.accept(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitConstructorCall(expression: IrConstructorCall, data: Nothing?): Boolean {
|
override fun visitConstructorCall(expression: IrConstructorCall, data: Nothing?): Boolean {
|
||||||
@@ -223,7 +229,7 @@ class IrCompileTimeChecker(
|
|||||||
override fun visitContinue(jump: IrContinue, data: Nothing?): Boolean = true
|
override fun visitContinue(jump: IrContinue, data: Nothing?): Boolean = true
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean {
|
override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean {
|
||||||
if (!callStack.contains(expression.returnTargetSymbol.descriptor.toString())) return false
|
if (!callStack.contains(expression.returnTargetSymbol)) return false
|
||||||
return expression.value.accept(this, data)
|
return expression.value.accept(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-4
@@ -515,6 +515,9 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretGetValue(expression: IrGetValue): ExecutionResult {
|
private fun interpretGetValue(expression: IrGetValue): ExecutionResult {
|
||||||
|
val owner = expression.type.classOrNull?.owner
|
||||||
|
// used to evaluate constants inside object
|
||||||
|
if (owner != null && owner.isObject) return getOrCreateObjectValue(owner) // TODO is this correct behaviour?
|
||||||
stack.pushReturnValue(stack.getVariableState(expression.symbol.descriptor).copy())
|
stack.pushReturnValue(stack.getVariableState(expression.symbol.descriptor).copy())
|
||||||
return Next
|
return Next
|
||||||
}
|
}
|
||||||
@@ -538,13 +541,16 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretGetObjectValue(expression: IrGetObjectValue): ExecutionResult {
|
private fun interpretGetObjectValue(expression: IrGetObjectValue): ExecutionResult {
|
||||||
val owner = expression.symbol.owner
|
return getOrCreateObjectValue(expression.symbol.owner)
|
||||||
val objectSignature = owner.fqNameWhenAvailable.toString()
|
}
|
||||||
|
|
||||||
|
private fun getOrCreateObjectValue(objectClass: IrClass): ExecutionResult {
|
||||||
|
val objectSignature = objectClass.fqNameWhenAvailable.toString()
|
||||||
mapOfObjects[objectSignature]?.let { return Next.apply { stack.pushReturnValue(it) } }
|
mapOfObjects[objectSignature]?.let { return Next.apply { stack.pushReturnValue(it) } }
|
||||||
|
|
||||||
val objectState = when {
|
val objectState = when {
|
||||||
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getCompanionObject(owner)
|
objectClass.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getCompanionObject(objectClass)
|
||||||
else -> Common(owner).apply { setSuperClassRecursive() } // TODO test type arguments
|
else -> Common(objectClass).apply { setSuperClassRecursive() } // TODO test type arguments
|
||||||
}
|
}
|
||||||
mapOfObjects[objectSignature] = objectState
|
mapOfObjects[objectSignature] = objectState
|
||||||
stack.pushReturnValue(objectState)
|
stack.pushReturnValue(objectState)
|
||||||
|
|||||||
Reference in New Issue
Block a user