From 40bf4fafc9ed01e37f96fb4f05e1e049c57e24fc Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sun, 20 Sep 2020 23:06:23 +0300 Subject: [PATCH] Implement basic interpretation of IrClassReference --- .../kotlin/ir/interpreter/IrInterpreter.kt | 8 +- .../ir/interpreter/checker/EvaluationMode.kt | 5 +- .../checker/IrCompileTimeChecker.kt | 4 + .../reflection/AbstractKPropertyProxy.kt | 27 ++-- .../proxy/reflection/KClassProxy.kt | 77 +++++++++++ .../proxy/reflection/KFunctionProxy.kt | 64 ++++----- .../proxy/reflection/KProperty0Proxy.kt | 4 +- .../proxy/reflection/KProperty1Proxy.kt | 4 +- .../proxy/reflection/ReflectionProxy.kt | 8 +- .../ir/interpreter/state/ReflectionState.kt | 130 +++++++++++++++--- 10 files changed, 255 insertions(+), 76 deletions(-) create mode 100644 compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KClassProxy.kt 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 a415bcce63e..d967f5baaa6 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 @@ -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 = emptyMap()) { +class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map = emptyMap()) { private val irExceptions = mutableListOf() 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 + } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/EvaluationMode.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/EvaluationMode.kt index 916862baa88..fe2aaa64044 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/EvaluationMode.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/EvaluationMode.kt @@ -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 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 3c04e160670..1b8e9005089 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 @@ -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() } + } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/AbstractKPropertyProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/AbstractKPropertyProxy.kt index 51504488817..f6722ed33f0 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/AbstractKPropertyProxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/AbstractKPropertyProxy.kt @@ -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 { 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 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() } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KClassProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KClassProxy.kt new file mode 100644 index 00000000000..817d8cfd135 --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KClassProxy.kt @@ -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 { + 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> + get() = state.getConstructors(interpreter) as Collection> + override val members: Collection> + get() = state.getMembers(interpreter) + override val nestedClasses: Collection> + get() = TODO("Not yet implemented") + override val objectInstance: Proxy? + get() = TODO("Not yet implemented") + override val typeParameters: List + get() = TODO("Not yet implemented") + override val supertypes: List + get() = TODO("Not yet implemented") + override val sealedSubclasses: List> + get() = TODO("Not yet implemented") + override val annotations: List + 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") + } +} \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt index 125020dd497..a33b3c2d228 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt @@ -20,50 +20,26 @@ internal class KFunctionProxy( ) : ReflectionProxy, KFunction, 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 - 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 + get() = TODO("Not yet implemented") override val parameters: List get() = TODO("Not yet implemented") override val returnType: KType get() = TODO("Not yet implemented") override val typeParameters: List 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): 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() + } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt index 5061d5c0d53..945812e854c 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt @@ -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))) } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty1Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty1Proxy.kt index f95ad6e5b15..0fc6f05f2f7 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty1Proxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty1Proxy.kt @@ -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))) } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/ReflectionProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/ReflectionProxy.kt index 30cbf294762..5c3c25ceae0 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/ReflectionProxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/ReflectionProxy.kt @@ -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") } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ReflectionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ReflectionState.kt index 11189723fe7..1079c4542a9 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ReflectionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ReflectionState.kt @@ -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 = mutableListOf() override val typeArguments: MutableList = 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>? = null + private var _constructors: Collection>? = null + + constructor(classReference: IrClassReference) : this(classReference.symbol.owner as IrClass) + + fun getMembers(interpreter: IrInterpreter): Collection> { + 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> { + if (_constructors != null) return _constructors!! + _constructors = irClass.declarations + .filterIsInstance() + .map { KFunctionProxy(KFunctionState(it, interpreter.irBuiltIns.functionFactory), interpreter) as KFunction } + 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 = mutableListOf() override val typeArguments: MutableList = 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("") || it == Name.special("") } + 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" + } } } \ No newline at end of file