diff --git a/compiler/ir/ir.interpreter/build.gradle.kts b/compiler/ir/ir.interpreter/build.gradle.kts index ee70e31cb64..21ebc6991d2 100644 --- a/compiler/ir/ir.interpreter/build.gradle.kts +++ b/compiler/ir/ir.interpreter/build.gradle.kts @@ -4,7 +4,8 @@ plugins { } dependencies { - compile(project(":compiler:ir.tree")) + compileOnly(project(":compiler:ir.tree")) + compileOnly(project(":kotlin-reflect-api")) } sourceSets { 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 e149be93cc2..e3f78fadf6f 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 @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.interpreter.exceptions.* import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy.Companion.asProxy import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy +import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.ReflectionProxy import org.jetbrains.kotlin.ir.interpreter.proxy.wrap import org.jetbrains.kotlin.ir.interpreter.stack.StackImpl import org.jetbrains.kotlin.ir.interpreter.stack.Variable @@ -140,6 +141,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map is IrStringConcatenation -> interpretStringConcatenation(this) is IrFunctionExpression -> interpretFunctionExpression(this) is IrFunctionReference -> interpretFunctionReference(this) + is IrPropertyReference -> interpretPropertyReference(this) is IrComposite -> interpretComposite(this) else -> TODO("${this.javaClass} not supported") @@ -317,6 +319,10 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map return@newFrame when { dispatchReceiver is Wrapper && !isInlineOnly -> dispatchReceiver.getMethod(irFunction).invokeMethod(irFunction) irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction) + dispatchReceiver is ReflectionState -> { + stack.pushReturnValue((dispatchReceiver.wrap(this) as ReflectionProxy).evaluate(expression, stack.getAll())) + Next + } dispatchReceiver is Primitive<*> -> calculateBuiltIns(irFunction) // 'is Primitive' check for js char and js long irFunction.body == null -> irFunction.trySubstituteFunctionBody() ?: irFunction.tryCalculateLazyConst() ?: calculateBuiltIns(irFunction) @@ -873,4 +879,12 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map else -> TODO("${expression.origin} not implemented") } } + + private fun interpretPropertyReference(propertyReference: IrPropertyReference): ExecutionResult { + val dispatchReceiver = propertyReference.dispatchReceiver?.interpret()?.check { return it }?.let { stack.popReturnValue() } + val extensionReceiver = propertyReference.extensionReceiver?.interpret()?.check { return it }?.let { stack.popReturnValue() } + val propertyState = KPropertyState(propertyReference, dispatchReceiver, extensionReceiver) + stack.pushReturnValue(propertyState) + return Next + } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/Proxy.kt index 8b7d8f6aa1b..dd660280c78 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/Proxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/Proxy.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.interpreter.proxy import org.jetbrains.kotlin.ir.interpreter.IrInterpreter import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy.Companion.asProxy import org.jetbrains.kotlin.ir.interpreter.proxy.LambdaProxy.Companion.asProxy +import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.ReflectionProxy.Companion.asProxy import org.jetbrains.kotlin.ir.interpreter.state.* internal interface Proxy { @@ -29,6 +30,7 @@ internal fun State.wrap(interpreter: IrInterpreter, extendFrom: Class<*>? = null is Primitive<*> -> this.value is Common -> this.asProxy(interpreter, extendFrom, calledFromBuiltIns) is Lambda -> this.asProxy(interpreter) + is ReflectionState -> this.asProxy(interpreter) else -> throw AssertionError("${this::class} is unsupported as argument for wrap function") } } 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 new file mode 100644 index 00000000000..8efdad67c0c --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/AbstractKPropertyProxy.kt @@ -0,0 +1,56 @@ +/* + * 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.declarations.IrProperty +import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.state.KPropertyState +import org.jetbrains.kotlin.ir.interpreter.state.State +import kotlin.reflect.KProperty +import kotlin.reflect.KType +import kotlin.reflect.KVisibility + +internal abstract class AbstractKPropertyProxy( + override val state: KPropertyState, override val interpreter: IrInterpreter +) : ReflectionProxy, KProperty { + private val propertyOwner: IrProperty + get() = state.propertyReference.symbol.owner + + override val isAbstract: Boolean + get() = propertyOwner.modality == Modality.ABSTRACT + override val isConst: Boolean + get() = propertyOwner.isConst + override val isFinal: Boolean + get() = propertyOwner.modality == Modality.FINAL + override val isLateinit: Boolean + get() = propertyOwner.isLateinit + override val isOpen: Boolean + get() = propertyOwner.modality == Modality.OPEN + override val isSuspend: Boolean + get() = TODO("Not yet implemented") + override val name: String + get() = propertyOwner.name.asString() + + override val annotations: List + get() = TODO("Not yet implemented") + override val returnType: KType + get() = TODO("Not yet implemented") + override val visibility: KVisibility? + get() = 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/KProperty0Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt new file mode 100644 index 00000000000..38823bc3c97 --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt @@ -0,0 +1,74 @@ +/* + * 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.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.stack.Variable +import org.jetbrains.kotlin.ir.interpreter.state.KPropertyState +import org.jetbrains.kotlin.ir.interpreter.state.State +import org.jetbrains.kotlin.ir.interpreter.toState +import kotlin.reflect.* + +internal open class KProperty0Proxy( + override val state: KPropertyState, override val interpreter: IrInterpreter +) : AbstractKPropertyProxy(state, interpreter), KProperty0 { + override fun evaluate(expression: IrCall, args: List): State { + val result: Any = when (expression.symbol.owner.name.asString()) { + "" -> name + "get" -> get() + "invoke" -> invoke() + else -> TODO("not supported expression for kProperty0") + } + + return result.toState(expression.type) + } + + override val getter: KProperty0.Getter + get() = TODO("Not yet implemented") + override val parameters: List + get() = TODO("Not yet implemented") + override val typeParameters: List + get() = TODO("Not yet implemented") + + override fun call(vararg args: Any?): State { + TODO("Not yet implemented") + } + + override fun callBy(args: Map): State { + TODO("Not yet implemented") + } + + override fun get(): State { + return state.dispatchReceiver!!.getState(state.propertyReference.symbol)!! + } + + override fun getDelegate(): Any? { + TODO("Not yet implemented") + } + + override fun invoke(): State = get() +} + +internal class KMutableProperty0Proxy( + override val state: KPropertyState, override val interpreter: IrInterpreter +) : KProperty0Proxy(state, interpreter), KMutableProperty0 { + override fun evaluate(expression: IrCall, args: List): State { + val result: Any = when (expression.symbol.owner.name.asString()) { + "set" -> set(args[1].state) + else -> return super.evaluate(expression, args) + } + + return result.toState(expression.type) + } + + override val setter: KMutableProperty0.Setter + get() = TODO("Not yet implemented") + + override fun set(value: State) { + state.dispatchReceiver!!.setField(Variable(state.propertyReference.symbol, value)) + } +} 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 new file mode 100644 index 00000000000..e41e09e7d95 --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty1Proxy.kt @@ -0,0 +1,74 @@ +/* + * 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.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.stack.Variable +import org.jetbrains.kotlin.ir.interpreter.state.KPropertyState +import org.jetbrains.kotlin.ir.interpreter.state.State +import org.jetbrains.kotlin.ir.interpreter.toState +import kotlin.reflect.* + +internal open class KProperty1Proxy( + override val state: KPropertyState, override val interpreter: IrInterpreter +) : AbstractKPropertyProxy(state, interpreter), KProperty1 { + override fun evaluate(expression: IrCall, args: List): State { + val result: Any = when (expression.symbol.owner.name.asString()) { + "" -> name + "get" -> get(args[1].state) + "invoke" -> invoke(args[1].state) + else -> TODO("not supported expression for kProperty0") + } + + return result.toState(expression.type) + } + + override val getter: KProperty1.Getter + get() = TODO("Not yet implemented") + override val parameters: List + get() = TODO("Not yet implemented") + override val typeParameters: List + get() = TODO("Not yet implemented") + + override fun call(vararg args: Any?): State { + TODO("Not yet implemented") + } + + override fun callBy(args: Map): State { + TODO("Not yet implemented") + } + + override fun get(receiver: State): State { + return receiver.getState(state.propertyReference.symbol)!! + } + + override fun getDelegate(receiver: State): Any? { + TODO("Not yet implemented") + } + + override fun invoke(p1: State): State = get(p1) +} + +internal class KMutableProperty1Proxy( + override val state: KPropertyState, override val interpreter: IrInterpreter +) : KProperty1Proxy(state, interpreter), KMutableProperty1 { + override fun evaluate(expression: IrCall, args: List): State { + val result: Any = when (expression.symbol.owner.name.asString()) { + "set" -> set(args[1].state, args[2].state) + else -> return super.evaluate(expression, args) + } + + return result.toState(expression.type) + } + + override val setter: KMutableProperty1.Setter + get() = TODO("Not yet implemented") + + override fun set(receiver: State, value: State) { + receiver.setField(Variable(state.propertyReference.symbol, value)) + } +} \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty2Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty2Proxy.kt new file mode 100644 index 00000000000..0daf375cbe1 --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty2Proxy.kt @@ -0,0 +1,74 @@ +/* + * 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.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.stack.Variable +import org.jetbrains.kotlin.ir.interpreter.state.KPropertyState +import org.jetbrains.kotlin.ir.interpreter.state.State +import org.jetbrains.kotlin.ir.interpreter.toState +import kotlin.reflect.* + +internal open class KProperty2Proxy( + override val state: KPropertyState, override val interpreter: IrInterpreter +) : AbstractKPropertyProxy(state, interpreter), KProperty2 { + override fun evaluate(expression: IrCall, args: List): State { + val result: Any = when (expression.symbol.owner.name.asString()) { + "" -> name + //"get" -> get() + //"invoke" -> invoke() + else -> TODO("not supported expression for kProperty0") + } + + return result.toState(expression.type) + } + + override val getter: KProperty2.Getter + get() = TODO("Not yet implemented") + override val parameters: List + get() = TODO("Not yet implemented") + override val typeParameters: List + get() = TODO("Not yet implemented") + + override fun call(vararg args: Any?): State { + TODO("Not yet implemented") + } + + override fun callBy(args: Map): State { + TODO("Not yet implemented") + } + + override fun get(receiver1: State, receiver2: State): State { + TODO("Not yet implemented") + } + + override fun getDelegate(receiver1: State, receiver2: State): Any? { + TODO("Not yet implemented") + } + + override fun invoke(p1: State, p2: State): State = get(p1, p2) +} + +internal class KMutableProperty2Proxy( + override val state: KPropertyState, override val interpreter: IrInterpreter +) : KProperty2Proxy(state, interpreter), KMutableProperty2 { + override fun evaluate(expression: IrCall, args: List): State { + val result: Any = when (expression.symbol.owner.name.asString()) { + //"set" -> set() + else -> return super.evaluate(expression, args) + } + + return result.toState(expression.type) + } + + override val setter: KMutableProperty2.Setter + get() = TODO("Not yet implemented") + + override fun set(receiver1: State, receiver2: State, value: State) { + 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/ReflectionProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/ReflectionProxy.kt new file mode 100644 index 00000000000..79818080be8 --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/ReflectionProxy.kt @@ -0,0 +1,35 @@ +/* + * 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.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy +import org.jetbrains.kotlin.ir.interpreter.stack.Variable +import org.jetbrains.kotlin.ir.interpreter.state.KPropertyState +import org.jetbrains.kotlin.ir.interpreter.state.ReflectionState +import org.jetbrains.kotlin.ir.interpreter.state.State + +internal interface ReflectionProxy : Proxy { + fun evaluate(expression: IrCall, args: List): State + + companion object { + 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.isKMutableProperty1() -> KMutableProperty1Proxy(this, interpreter) + this.isKProperty2() -> KProperty2Proxy(this, interpreter) + this.isKMutableProperty2() -> KMutableProperty2Proxy(this, interpreter) + else -> TODO() + } + 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 new file mode 100644 index 00000000000..aed9a1b8cd5 --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ReflectionState.kt @@ -0,0 +1,51 @@ +/* + * 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.state + +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrPropertyReference +import org.jetbrains.kotlin.ir.interpreter.stack.Variable +import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.util.parentAsClass + +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 +} + +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() + + fun isKProperty0(): Boolean { + return className == "KProperty0" + } + + fun isKProperty1(): Boolean { + return className == "KProperty1" + } + + fun isKProperty2(): Boolean { + return className == "KProperty2" + } + + fun isKMutableProperty0(): Boolean { + return className == "KMutableProperty0" + } + + fun isKMutableProperty1(): Boolean { + return className == "KMutableProperty1" + } + + fun isKMutableProperty2(): Boolean { + return className == "KMutableProperty2" + } +}