Implement basic interpretation of IrClassReference

This commit is contained in:
Ivan Kylchik
2020-09-20 23:06:23 +03:00
committed by TeamCityServer
parent 002804941f
commit 40bf4fafc9
10 changed files with 255 additions and 76 deletions
@@ -34,7 +34,7 @@ import java.lang.invoke.MethodHandle
private const val MAX_COMMANDS = 500_000
private const val MAX_STACK = 500
class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSignature, IrBody> = emptyMap()) {
class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSignature, IrBody> = emptyMap()) {
private val irExceptions = mutableListOf<IrClass>()
private val stack = StackImpl()
@@ -142,6 +142,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map
is IrFunctionExpression -> interpretFunctionExpression(this)
is IrFunctionReference -> interpretFunctionReference(this)
is IrPropertyReference -> interpretPropertyReference(this)
is IrClassReference -> interpretClassReference(this)
is IrComposite -> interpretComposite(this)
else -> TODO("${this.javaClass} not supported")
@@ -889,4 +890,9 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map
stack.pushReturnValue(propertyState)
return Next
}
private fun interpretClassReference(classReference: IrClassReference): ExecutionResult {
stack.pushReturnValue(KClassState(classReference))
return Next
}
}
@@ -29,7 +29,7 @@ enum class EvaluationMode(protected val mustCheckBody: Boolean) {
WITH_ANNOTATIONS(mustCheckBody = false) {
override fun canEvaluateFunction(function: IrFunction, expression: IrCall?): Boolean {
if (function.isCompileTimeProperty()) return true
return function.isMarkedWith(compileTimeAnnotation) || function.origin == IrBuiltIns.BUILTIN_OPERATOR ||
return function.isMarkedAsCompileTime() || function.origin == IrBuiltIns.BUILTIN_OPERATOR ||
(function is IrSimpleFunction && function.isOperator && function.name.asString() == "invoke") ||
(function is IrSimpleFunction && function.isFakeOverride && function.overriddenSymbols.any { canEvaluateFunction(it.owner) }) ||
function.isCompileTimeTypeAlias()
@@ -38,7 +38,7 @@ enum class EvaluationMode(protected val mustCheckBody: Boolean) {
private fun IrDeclaration?.isCompileTimeProperty(): Boolean {
val property = (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: return false
if (property.isConst) return true
if (property.isMarkedWith(compileTimeAnnotation) || property.isCompileTimeTypeAlias()) return true
if (property.isMarkedAsCompileTime() || property.isCompileTimeTypeAlias()) return true
val backingField = property.backingField
val backingFieldExpression = backingField?.initializer?.expression as? IrGetValue
@@ -73,6 +73,7 @@ enum class EvaluationMode(protected val mustCheckBody: Boolean) {
"java.lang.StringBuilder", "java.lang.IllegalArgumentException", "java.util.NoSuchElementException"
)
fun IrDeclaration.isMarkedAsCompileTime() = isMarkedWith(compileTimeAnnotation)
private fun IrDeclaration.isContract() = isMarkedWith(contractsDslAnnotation)
private fun IrDeclaration.isMarkedAsEvaluateIntrinsic() = isMarkedWith(evaluateIntrinsicAnnotation)
protected fun IrDeclaration.isCompileTimeTypeAlias() = this.parentClassOrNull?.fqNameWhenAvailable?.asString() in compileTimeTypeAliases
@@ -259,4 +259,8 @@ class IrCompileTimeChecker(
override fun visitPropertyReference(expression: IrPropertyReference, data: Nothing?): Boolean {
return mode.canEvaluateFunction(expression.getter!!.owner)
}
override fun visitClassReference(expression: IrClassReference, data: Nothing?): Boolean {
return with(mode) { (expression.symbol.owner as IrClass).isMarkedAsCompileTime() }
}
}
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.ir.interpreter.proxy.reflection
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.state.KPropertyState
import org.jetbrains.kotlin.ir.types.IrType
@@ -19,25 +18,22 @@ internal abstract class AbstractKPropertyProxy(
) : ReflectionProxy, KProperty<Any?> {
protected val propertyType: IrType
get() = state.propertyReference.getter!!.owner.returnType
private val propertyOwner: IrProperty
get() = state.propertyReference.symbol.owner
get() = state.property.getter!!.returnType
override val isAbstract: Boolean
get() = propertyOwner.modality == Modality.ABSTRACT
get() = state.property.modality == Modality.ABSTRACT
override val isConst: Boolean
get() = propertyOwner.isConst
get() = state.property.isConst
override val isFinal: Boolean
get() = propertyOwner.modality == Modality.FINAL
get() = state.property.modality == Modality.FINAL
override val isLateinit: Boolean
get() = propertyOwner.isLateinit
get() = state.property.isLateinit
override val isOpen: Boolean
get() = propertyOwner.modality == Modality.OPEN
get() = state.property.modality == Modality.OPEN
override val isSuspend: Boolean
get() = TODO("Not yet implemented")
get() = false
override val name: String
get() = propertyOwner.name.asString()
get() = state.property.name.asString()
override val annotations: List<Annotation>
get() = TODO("Not yet implemented")
@@ -47,14 +43,15 @@ internal abstract class AbstractKPropertyProxy(
get() = TODO("Not yet implemented")
override fun equals(other: Any?): Boolean {
TODO("Not yet implemented")
if (other !is AbstractKPropertyProxy) return false
return state == other.state
}
override fun hashCode(): Int {
TODO("Not yet implemented")
return state.hashCode()
}
override fun toString(): String {
TODO("Not yet implemented")
return state.toString()
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.interpreter.proxy.reflection
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.internalName
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
import org.jetbrains.kotlin.ir.interpreter.state.KClassState
import kotlin.reflect.*
internal class KClassProxy(
override val state: KClassState, override val interpreter: IrInterpreter
) : ReflectionProxy, KClass<Proxy> {
override val simpleName: String?
get() = state.irClass.name.asString() // TODO return null if class has no name
override val qualifiedName: String?
get() = state.irClass.internalName()
@Suppress("UNCHECKED_CAST")
override val constructors: Collection<KFunction<Proxy>>
get() = state.getConstructors(interpreter) as Collection<KFunction<Proxy>>
override val members: Collection<KCallable<*>>
get() = state.getMembers(interpreter)
override val nestedClasses: Collection<KClass<*>>
get() = TODO("Not yet implemented")
override val objectInstance: Proxy?
get() = TODO("Not yet implemented")
override val typeParameters: List<KTypeParameter>
get() = TODO("Not yet implemented")
override val supertypes: List<KType>
get() = TODO("Not yet implemented")
override val sealedSubclasses: List<KClass<out Proxy>>
get() = TODO("Not yet implemented")
override val annotations: List<Annotation>
get() = TODO("Not yet implemented")
override val visibility: KVisibility?
get() = TODO("Not yet implemented")
override val isFinal: Boolean
get() = state.irClass.modality == Modality.FINAL
override val isOpen: Boolean
get() = state.irClass.modality == Modality.OPEN
override val isAbstract: Boolean
get() = state.irClass.modality == Modality.ABSTRACT
override val isSealed: Boolean
get() = state.irClass.modality == Modality.SEALED
override val isData: Boolean
get() = state.irClass.isData
override val isInner: Boolean
get() = state.irClass.isInner
override val isCompanion: Boolean
get() = state.irClass.isCompanion
override val isFun: Boolean
get() = state.irClass.isFun
override val isValue: Boolean
get() = state.irClass.isInline
override fun isInstance(value: Any?): Boolean {
TODO("Not yet implemented")
}
override fun equals(other: Any?): Boolean {
TODO("Not yet implemented")
}
override fun hashCode(): Int {
TODO("Not yet implemented")
}
override fun toString(): String {
TODO("Not yet implemented")
}
}
@@ -20,50 +20,26 @@ internal class KFunctionProxy(
) : ReflectionProxy, KFunction<Any?>, FunctionWithAllInvokes {
override val arity: Int = state.getArity() ?: BuiltInFunctionArity.BIG_ARITY
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is ReflectionProxy) return false
return state == other.state
}
override fun hashCode(): Int {
return state.hashCode()
}
override fun toString(): String {
return state.toString()
}
override val annotations: List<Annotation>
get() = TODO("Not yet implemented")
override val isAbstract: Boolean
get() = state.irFunction is IrSimpleFunction && state.irFunction.modality == Modality.ABSTRACT
override val isExternal: Boolean
get() = state.irFunction.isExternal
override val isFinal: Boolean
get() = state.irFunction is IrSimpleFunction && state.irFunction.modality == Modality.FINAL
override val isInfix: Boolean
get() = state.irFunction is IrSimpleFunction && state.irFunction.isInfix
override val isInline: Boolean
get() = state.irFunction.isInline
override val isOpen: Boolean
get() = state.irFunction is IrSimpleFunction && state.irFunction.modality == Modality.OPEN
override val isExternal: Boolean
get() = state.irFunction.isExternal
override val isOperator: Boolean
get() = state.irFunction is IrSimpleFunction && state.irFunction.isOperator
override val isSuspend: Boolean
get() = state.irFunction.isSuspend
override val isInfix: Boolean
get() = state.irFunction is IrSimpleFunction && state.irFunction.isInfix
override val name: String
get() = state.irFunction.name.asString()
override val annotations: List<Annotation>
get() = TODO("Not yet implemented")
override val parameters: List<KParameter>
get() = TODO("Not yet implemented")
override val returnType: KType
get() = TODO("Not yet implemented")
override val typeParameters: List<KTypeParameter>
get() = TODO("Not yet implemented")
override val visibility: KVisibility?
get() = TODO("Not yet implemented")
override fun call(vararg args: Any?): Any? {
var index = 0
@@ -77,5 +53,31 @@ internal class KFunctionProxy(
override fun callBy(args: Map<KParameter, Any?>): Any? {
TODO("Not yet implemented")
}
override val visibility: KVisibility?
get() = TODO("Not yet implemented")
override val isFinal: Boolean
get() = state.irFunction is IrSimpleFunction && state.irFunction.modality == Modality.FINAL
override val isOpen: Boolean
get() = state.irFunction is IrSimpleFunction && state.irFunction.modality == Modality.OPEN
override val isAbstract: Boolean
get() = state.irFunction is IrSimpleFunction && state.irFunction.modality == Modality.ABSTRACT
override val isSuspend: Boolean
get() = state.irFunction.isSuspend
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is ReflectionProxy) return false
return state == other.state
}
override fun hashCode(): Int {
return state.hashCode()
}
override fun toString(): String {
return state.toString()
}
}
@@ -35,7 +35,7 @@ internal open class KProperty0Proxy(
}
override fun get(): Any? {
return state.dispatchReceiver!!.getState(state.propertyReference.symbol)!!
return state.dispatchReceiver!!.getState(state.property.symbol)!!
}
override fun getDelegate(): Any? {
@@ -53,6 +53,6 @@ internal class KMutableProperty0Proxy(
get() = TODO("Not yet implemented")
override fun set(value: Any?) {
state.dispatchReceiver!!.setField(Variable(state.propertyReference.symbol, value.toState(propertyType)))
state.dispatchReceiver!!.setField(Variable(state.property.symbol, value.toState(propertyType)))
}
}
@@ -36,7 +36,7 @@ internal open class KProperty1Proxy(
}
override fun get(receiver: Proxy): Any? {
return receiver.state.getState(state.propertyReference.symbol)!!.wrap(interpreter)
return receiver.state.getState(state.property.symbol)!!.wrap(interpreter)
}
override fun getDelegate(receiver: Proxy): Any? {
@@ -54,6 +54,6 @@ internal class KMutableProperty1Proxy(
get() = TODO("Not yet implemented")
override fun set(receiver: Proxy, value: Any?) {
receiver.state.setField(Variable(state.propertyReference.symbol, value.toState(propertyType)))
receiver.state.setField(Variable(state.property.symbol, value.toState(propertyType)))
}
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.interpreter.proxy.reflection
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
import org.jetbrains.kotlin.ir.interpreter.state.KClassState
import org.jetbrains.kotlin.ir.interpreter.state.KFunctionState
import org.jetbrains.kotlin.ir.interpreter.state.KPropertyState
import org.jetbrains.kotlin.ir.interpreter.state.ReflectionState
@@ -16,15 +17,16 @@ internal interface ReflectionProxy : Proxy {
internal fun ReflectionState.asProxy(interpreter: IrInterpreter): ReflectionProxy {
return when (this) {
is KPropertyState -> when {
this.isKProperty0() -> KProperty0Proxy(this, interpreter)
this.isKMutableProperty0() -> KMutableProperty0Proxy(this, interpreter)
this.isKProperty1() -> KProperty1Proxy(this, interpreter)
this.isKProperty0() -> KProperty0Proxy(this, interpreter)
this.isKMutableProperty1() -> KMutableProperty1Proxy(this, interpreter)
this.isKProperty2() -> KProperty2Proxy(this, interpreter)
this.isKProperty1() -> KProperty1Proxy(this, interpreter)
this.isKMutableProperty2() -> KMutableProperty2Proxy(this, interpreter)
this.isKProperty2() -> KProperty2Proxy(this, interpreter)
else -> TODO()
}
is KFunctionState -> KFunctionProxy(this, interpreter)
is KClassState -> KClassProxy(this, interpreter)
else -> TODO("not supported reference state")
}
}
@@ -5,67 +5,146 @@
package org.jetbrains.kotlin.ir.interpreter.state
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrAbstractFunctionFactory
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrClassReference
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.getLastOverridden
import org.jetbrains.kotlin.ir.interpreter.isFunction
import org.jetbrains.kotlin.ir.interpreter.isKFunction
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KFunctionProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KProperty1Proxy
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.cast
import kotlin.reflect.KCallable
import kotlin.reflect.KFunction
internal abstract class ReflectionState(override val irClass: IrClass) : State {
override val fields: MutableList<Variable> = mutableListOf()
override val typeArguments: MutableList<Variable> = mutableListOf()
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? = null
protected fun renderReceivers(dispatchReceiver: IrType?, extensionReceiver: IrType?): String {
return buildString {
if (dispatchReceiver != null) {
append(dispatchReceiver.render())
append(".")
}
val addParentheses = dispatchReceiver != null && extensionReceiver != null
if (addParentheses) append("(")
if (extensionReceiver != null) {
append(extensionReceiver.render())
append(".")
}
if (addParentheses) append(")")
}
}
}
internal class KClassState(override val irClass: IrClass) : ReflectionState(irClass) {
private var _members: Collection<KCallable<*>>? = null
private var _constructors: Collection<KFunction<Proxy>>? = null
constructor(classReference: IrClassReference) : this(classReference.symbol.owner as IrClass)
fun getMembers(interpreter: IrInterpreter): Collection<KCallable<*>> {
if (_members != null) return _members!!
_members = irClass.declarations
.filter { it !is IrClass && it !is IrConstructor }
.map {
when (it) {
is IrProperty -> KProperty1Proxy(KPropertyState(it, null, null), interpreter) // TODO KProperty2
is IrFunction -> KFunctionProxy(KFunctionState(it, interpreter.irBuiltIns.functionFactory), interpreter)
else -> TODO()
}
}
return _members!!
}
fun getConstructors(interpreter: IrInterpreter): Collection<KFunction<Proxy>> {
if (_constructors != null) return _constructors!!
_constructors = irClass.declarations
.filterIsInstance<IrConstructor>()
.map { KFunctionProxy(KFunctionState(it, interpreter.irBuiltIns.functionFactory), interpreter) as KFunction<Proxy> }
return _constructors!!
}
}
internal class KPropertyState(
val propertyReference: IrPropertyReference, val dispatchReceiver: State?, val extensionReceiver: State?
) : ReflectionState(propertyReference.symbol.owner.parentAsClass) {
val className = propertyReference.type.classOrNull?.owner?.name?.asString()
val property: IrProperty, val dispatchReceiver: State?, val extensionReceiver: State?
) : ReflectionState(property.parentAsClass) {
constructor(propertyReference: IrPropertyReference, dispatchReceiver: State?, extensionReceiver: State?)
: this(propertyReference.symbol.owner, dispatchReceiver, extensionReceiver)
fun isKProperty0(): Boolean {
return className == "KProperty0"
return dispatchReceiver != null && extensionReceiver == null
}
fun isKProperty1(): Boolean {
return className == "KProperty1"
return dispatchReceiver == null && extensionReceiver == null
}
fun isKProperty2(): Boolean {
return className == "KProperty2"
return dispatchReceiver != null && extensionReceiver != null
}
fun isKMutableProperty0(): Boolean {
return className == "KMutableProperty0"
return isKProperty0() && property.isVar
}
fun isKMutableProperty1(): Boolean {
return className == "KMutableProperty1"
return isKProperty1() && property.isVar
}
fun isKMutableProperty2(): Boolean {
return className == "KMutableProperty2"
return isKProperty1() && property.isVar
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KPropertyState
if (property != other.property) return false
if (dispatchReceiver != other.dispatchReceiver) return false
if (extensionReceiver != other.extensionReceiver) return false
return true
}
override fun hashCode(): Int {
var result = property.hashCode()
result = 31 * result + (dispatchReceiver?.hashCode() ?: 0)
result = 31 * result + (extensionReceiver?.hashCode() ?: 0)
return result
}
override fun toString(): String {
val prefix = if (property.isVar) "var" else "val"
val receivers = renderReceivers(property.getter?.dispatchReceiverParameter?.type, property.getter?.extensionReceiverParameter?.type)
val returnType = property.getter!!.returnType.render()
return "$prefix $receivers${property.name}: $returnType"
}
}
internal class KFunctionState(val irFunction: IrFunction, override val irClass: IrClass) : ReflectionState(irClass) {
override val fields: MutableList<Variable> = mutableListOf()
override val typeArguments: MutableList<Variable> = mutableListOf()
val isKFunction = irClass.defaultType.isKFunction()
val isFunction = irClass.defaultType.isFunction()
constructor(functionReference: IrFunctionReference) : this(functionReference.symbol.owner, functionReference.type.classOrNull!!.owner)
constructor(irFunction: IrFunction, functionFactory: IrAbstractFunctionFactory) :
this(irFunction, functionFactory.functionN(irFunction.valueParameters.size))
private val invokeSymbol = irClass.declarations
.single { it.nameForIrSerialization.asString() == "invoke" }
@@ -80,10 +159,21 @@ internal class KFunctionState(val irFunction: IrFunction, override val irClass:
return if (invokeSymbol == expression.symbol) irFunction else null
}
private fun isLambda(): Boolean = irFunction.name.let { it == Name.special("<anonymous>") || it == Name.special("<no name provided>") }
override fun toString(): String {
val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.render()
val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.render() }
val returnType = irFunction.returnType.render()
return ("$arguments -> $returnType").let { if (receiver != null) "$receiver.$it" else it }
return if (isLambda()) {
val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.render()
val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.render() }
val returnType = irFunction.returnType.render()
("$arguments -> $returnType").let { if (receiver != null) "$receiver.$it" else it }
} else {
val dispatchReceiver = irFunction.parentAsClass.defaultType // = instanceReceiverParameter
val extensionReceiver = irFunction.extensionReceiverParameter?.type
val receivers = if (irFunction is IrConstructor) "" else renderReceivers(dispatchReceiver, extensionReceiver)
val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.render() }
val returnType = irFunction.returnType.render()
"fun $receivers${irFunction.name}$arguments: $returnType"
}
}
}