Implement interpretation for KType and KTypeParameter

This commit is contained in:
Ivan Kylchik
2020-09-21 13:11:26 +03:00
committed by TeamCityServer
parent 88b5b5f702
commit 5a95e5b45f
9 changed files with 292 additions and 33 deletions
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.lang.invoke.MethodType
import kotlin.math.min
internal fun IrFunction.getDispatchReceiver(): IrValueParameterSymbol? = this.dispatchReceiverParameter?.symbol
@@ -225,6 +226,24 @@ internal fun IrType.isInterface() = classOrNull?.owner?.kind == ClassKind.INTERF
internal fun IrType.isThrowable() = this.getClass()?.fqNameWhenAvailable?.asString() == "kotlin.Throwable"
internal fun IrType.renderType(): String {
var renderedType = this.render()
do {
val index = renderedType.indexOf(" of ")
if (index == -1) break
val replaceUntilComma = renderedType.indexOf(',', index)
val replaceUntilTriangle = renderedType.indexOf('>', index)
val replaceUntil = when {
replaceUntilComma == -1 && replaceUntilTriangle == -1 -> renderedType.length
replaceUntilComma == -1 -> replaceUntilTriangle
replaceUntilTriangle == -1 -> replaceUntilComma
else -> min(replaceUntilComma, replaceUntilTriangle)
}
renderedType = renderedType.replaceRange(index, replaceUntil, "")
} while (true)
return renderedType
}
fun IrClass.internalName(): String {
val internalName = StringBuilder(this.name.asString())
generateSequence(this as? IrDeclarationParent) { (it as? IrDeclaration)?.parent }
@@ -188,9 +188,14 @@ class IrCompileTimeChecker(
}
override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean {
return expression.asVisited {
mode.canEvaluateFunction(expression.symbol.owner) && expression.symbol.owner.body?.accept(this, data) == true
}
val owner = expression.symbol.owner
if (!mode.canEvaluateFunction(owner)) return false
val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, null) ?: true
val extensionReceiverComputable = expression.extensionReceiver?.accept(this, null) ?: true
val bodyComputable = owner.asVisited { if (mode.canEvaluateBody(owner)) owner.body?.accept(this, null) ?: true else true }
return dispatchReceiverComputable && extensionReceiverComputable && bodyComputable
}
override fun visitFunctionExpression(expression: IrFunctionExpression, data: Nothing?): Boolean {
@@ -261,6 +266,12 @@ class IrCompileTimeChecker(
}
override fun visitClassReference(expression: IrClassReference, data: Nothing?): Boolean {
return with(mode) { (expression.symbol.owner as IrClass).isMarkedAsCompileTime() }
return with(mode) {
when (this) {
EvaluationMode.FULL -> true
EvaluationMode.WITH_ANNOTATIONS -> (expression.symbol.owner as IrClass).isMarkedAsCompileTime()
EvaluationMode.ONLY_BUILTINS -> false
}
}
}
}
@@ -8,6 +8,7 @@ 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.state.KPropertyState
import org.jetbrains.kotlin.ir.interpreter.state.KTypeState
import org.jetbrains.kotlin.ir.types.IrType
import kotlin.reflect.KProperty
import kotlin.reflect.KType
@@ -38,7 +39,7 @@ internal abstract class AbstractKPropertyProxy(
override val annotations: List<Annotation>
get() = TODO("Not yet implemented")
override val returnType: KType
get() = TODO("Not yet implemented")
get() = KTypeProxy(KTypeState(propertyType), interpreter)
override val visibility: KVisibility?
get() = state.irClass.visibility.toKVisibility()
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.ir.interpreter.proxy.reflection
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.internalName
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
@@ -17,9 +16,9 @@ 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
get() = state.irClass.name.takeIf { !it.isSpecial }?.asString()
override val qualifiedName: String?
get() = state.irClass.internalName()
get() = if (!state.irClass.name.isSpecial) state.irClass.internalName() else null
@Suppress("UNCHECKED_CAST")
override val constructors: Collection<KFunction<Proxy>>
@@ -31,9 +30,9 @@ internal class KClassProxy(
override val objectInstance: Proxy?
get() = TODO("Not yet implemented")
override val typeParameters: List<KTypeParameter>
get() = TODO("Not yet implemented")
get() = state.getTypeParameters(interpreter)
override val supertypes: List<KType>
get() = TODO("Not yet implemented")
get() = state.getSupertypes(interpreter)
override val sealedSubclasses: List<KClass<out Proxy>>
get() = TODO("Not yet implemented")
override val annotations: List<Annotation>
@@ -65,14 +64,17 @@ internal class KClassProxy(
}
override fun equals(other: Any?): Boolean {
TODO("Not yet implemented")
if (this === other) return true
if (other !is KClassProxy) 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()
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.KFunctionState
import org.jetbrains.kotlin.ir.interpreter.state.KTypeState
import org.jetbrains.kotlin.ir.interpreter.toState
import org.jetbrains.kotlin.ir.util.isSuspend
import kotlin.reflect.*
@@ -37,9 +38,9 @@ internal class KFunctionProxy(
override val parameters: List<KParameter>
get() = TODO("Not yet implemented")
override val returnType: KType
get() = TODO("Not yet implemented")
get() = KTypeProxy(KTypeState(state.irFunction.returnType), interpreter)
override val typeParameters: List<KTypeParameter>
get() = TODO("Not yet implemented")
get() = state.getTypeParameters(interpreter)
override fun call(vararg args: Any?): Any? {
var index = 0
@@ -0,0 +1,39 @@
/*
* 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.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.state.KTypeParameterState
import org.jetbrains.kotlin.types.Variance
import kotlin.reflect.*
internal class KTypeParameterProxy(
override val state: KTypeParameterState, override val interpreter: IrInterpreter
) : ReflectionProxy, KTypeParameter {
override val name: String
get() = state.irTypeParameter.name.asString()
override val upperBounds: List<KType>
get() = state.getUpperBounds(interpreter)
override val variance: KVariance
get() = when (state.irTypeParameter.variance) {
Variance.INVARIANT -> KVariance.INVARIANT
Variance.IN_VARIANCE -> KVariance.IN
Variance.OUT_VARIANCE -> KVariance.OUT
}
override val isReified: Boolean
get() = state.irTypeParameter.isReified
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is KTypeParameterProxy) return false
return state == other.state
}
override fun hashCode(): Int = state.hashCode()
override fun toString(): String = state.toString()
}
@@ -0,0 +1,44 @@
/*
* 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.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.state.KClassState
import org.jetbrains.kotlin.ir.interpreter.state.KTypeParameterState
import org.jetbrains.kotlin.ir.interpreter.state.KTypeState
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isMarkedNullable
import kotlin.reflect.KClassifier
import kotlin.reflect.KType
import kotlin.reflect.KTypeProjection
internal class KTypeProxy(override val state: KTypeState, override val interpreter: IrInterpreter) : ReflectionProxy, KType {
override val classifier: KClassifier?
get() = when (val classifier = state.irType.classifierOrFail.owner) {
is IrClass -> KClassProxy(KClassState(classifier), interpreter)
is IrTypeParameter -> KTypeParameterProxy(KTypeParameterState(classifier), interpreter)
else -> TODO()
}
override val arguments: List<KTypeProjection>
get() = state.getArguments(interpreter)
override val isMarkedNullable: Boolean
get() = state.irType.isMarkedNullable()
override val annotations: List<Annotation>
get() = TODO("Not yet implemented")
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is KTypeProxy) return false
return state == other.state
}
override fun hashCode(): Int = state.hashCode()
override fun toString(): String = state.toString()
}
@@ -9,9 +9,11 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
import org.jetbrains.kotlin.ir.interpreter.state.*
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.KTypeState
import org.jetbrains.kotlin.ir.interpreter.state.ReflectionState
import kotlin.reflect.KVisibility
@@ -40,6 +42,8 @@ internal interface ReflectionProxy : Proxy {
}
is KFunctionState -> KFunctionProxy(this, interpreter)
is KClassState -> KClassProxy(this, interpreter)
is KTypeState -> KTypeProxy(this, interpreter)
is KTypeParameterState -> KTypeParameterProxy(this, interpreter)
else -> TODO("not supported reference state")
}
}
@@ -13,47 +13,67 @@ 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.internalName
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.proxy.reflection.KTypeParameterProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
import org.jetbrains.kotlin.ir.interpreter.renderType
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.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.types.*
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.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.cast
import kotlin.reflect.KCallable
import kotlin.reflect.KFunction
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import kotlin.reflect.*
internal abstract class ReflectionState(override val irClass: IrClass) : State {
internal abstract class ReflectionState(val irClassifierSymbol: IrClassifierSymbol) : State {
override val irClass: IrClass = irClassifierSymbol.extractClass()
override val fields: MutableList<Variable> = mutableListOf()
override val typeArguments: MutableList<Variable> = mutableListOf()
constructor(irTypeParameter: IrTypeParameter) : this(irTypeParameter.superTypes.firstNotNullResult { it.classifierOrNull }!!)
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? = null
protected fun renderReceivers(dispatchReceiver: IrType?, extensionReceiver: IrType?): String {
return buildString {
if (dispatchReceiver != null) {
append(dispatchReceiver.render())
append(dispatchReceiver.renderType())
append(".")
}
val addParentheses = dispatchReceiver != null && extensionReceiver != null
if (addParentheses) append("(")
if (extensionReceiver != null) {
append(extensionReceiver.render())
append(extensionReceiver.renderType())
append(".")
}
if (addParentheses) append(")")
}
}
companion object {
private fun IrClassifierSymbol.extractClass(): IrClass {
return (owner as? IrClass) ?: (owner as IrTypeParameter).extractAnyClass()
}
private fun IrTypeParameter.extractAnyClass(): IrClass {
return this.superTypes
.firstNotNullResult { it.classOrNull?.owner ?: (it.classifierOrNull?.owner as? IrTypeParameter)?.extractAnyClass() }!!
}
}
}
internal class KClassState(override val irClass: IrClass) : ReflectionState(irClass) {
internal class KClassState(override val irClass: IrClass) : ReflectionState(irClass.symbol) {
private var _members: Collection<KCallable<*>>? = null
private var _constructors: Collection<KFunction<Proxy>>? = null
private var _typeParameters: List<KTypeParameter>? = null
private var _supertypes: List<KType>? = null
constructor(classReference: IrClassReference) : this(classReference.symbol.owner as IrClass)
@@ -78,11 +98,43 @@ internal class KClassState(override val irClass: IrClass) : ReflectionState(irCl
.map { KFunctionProxy(KFunctionState(it, interpreter.irBuiltIns.functionFactory), interpreter) as KFunction<Proxy> }
return _constructors!!
}
fun getTypeParameters(interpreter: IrInterpreter): List<KTypeParameter> {
if (_typeParameters != null) return _typeParameters!!
_typeParameters = irClass.typeParameters.map { KTypeParameterProxy(KTypeParameterState(it), interpreter) }
return _typeParameters!!
}
fun getSupertypes(interpreter: IrInterpreter): List<KType> {
if (_supertypes != null) return _supertypes!!
_supertypes = (irClass.superTypes.map { it } + interpreter.irBuiltIns.anyType).toSet()
.map { KTypeProxy(KTypeState(it), interpreter) }
return _supertypes!!
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KClassState
if (irClass != other.irClass) return false
return true
}
override fun hashCode(): Int {
return irClass.hashCode()
}
override fun toString(): String {
return "class ${irClass.internalName()}"
}
}
internal class KPropertyState(
val property: IrProperty, val dispatchReceiver: State?, val extensionReceiver: State?
) : ReflectionState(property.parentAsClass) {
) : ReflectionState(property.parentAsClass.symbol) {
constructor(propertyReference: IrPropertyReference, dispatchReceiver: State?, extensionReceiver: State?)
: this(propertyReference.symbol.owner, dispatchReceiver, extensionReceiver)
@@ -133,18 +185,25 @@ internal class KPropertyState(
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()
val returnType = property.getter!!.returnType.renderType()
return "$prefix $receivers${property.name}: $returnType"
}
}
internal class KFunctionState(val irFunction: IrFunction, override val irClass: IrClass) : ReflectionState(irClass) {
internal class KFunctionState(val irFunction: IrFunction, override val irClass: IrClass) : ReflectionState(irClass.symbol) {
override val fields: MutableList<Variable> = mutableListOf()
override val typeArguments: MutableList<Variable> = mutableListOf()
private var _typeParameters: List<KTypeParameter>? = null
constructor(functionReference: IrFunctionReference) : this(functionReference.symbol.owner, functionReference.type.classOrNull!!.owner)
constructor(irFunction: IrFunction, functionFactory: IrAbstractFunctionFactory) :
this(irFunction, functionFactory.functionN(irFunction.valueParameters.size))
this(irFunction, functionFactory.kFunctionN(irFunction.valueParameters.size))
fun getTypeParameters(interpreter: IrInterpreter): List<KTypeParameter> {
if (_typeParameters != null) return _typeParameters!!
_typeParameters = irClass.typeParameters.map { KTypeParameterProxy(KTypeParameterState(it), interpreter) }
return _typeParameters!!
}
private val invokeSymbol = irClass.declarations
.single { it.nameForIrSerialization.asString() == "invoke" }
@@ -163,17 +222,96 @@ internal class KFunctionState(val irFunction: IrFunction, override val irClass:
override fun toString(): String {
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()
val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.renderType()
val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.renderType() }
val returnType = irFunction.returnType.renderType()
("$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()
val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.renderType() }
val returnType = irFunction.returnType.renderType()
"fun $receivers${irFunction.name}$arguments: $returnType"
}
}
}
internal class KTypeState(val irType: IrType) : ReflectionState(irType.classifierOrFail) {
private var _arguments: List<KTypeProjection>? = null
fun getArguments(interpreter: IrInterpreter): List<KTypeProjection> {
if (_arguments != null) return _arguments!!
_arguments = (irType as IrSimpleType).arguments
.map {
when (it.getVariance()) {
Variance.INVARIANT -> KTypeProjection.invariant(KTypeProxy(KTypeState(it.typeOrNull!!), interpreter))
Variance.IN_VARIANCE -> KTypeProjection.contravariant(KTypeProxy(KTypeState(it.typeOrNull!!), interpreter))
Variance.OUT_VARIANCE -> KTypeProjection.covariant(KTypeProxy(KTypeState(it.typeOrNull!!), interpreter))
null -> KTypeProjection.STAR
}
}
return _arguments!!
}
private fun IrTypeArgument.getVariance(): Variance? {
return when (this) {
is IrSimpleType -> Variance.INVARIANT
is IrTypeProjection -> this.variance
is IrStarProjection -> null
else -> TODO()
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KTypeState
if (irType != other.irType) return false
return true
}
override fun hashCode(): Int {
return irType.hashCode()
}
override fun toString(): String {
return irType.renderType()
}
}
internal class KTypeParameterState(val irTypeParameter: IrTypeParameter) : ReflectionState(irTypeParameter) {
private var _upperBounds: List<KType>? = null
fun getUpperBounds(interpreter: IrInterpreter): List<KType> {
if (_upperBounds != null) return _upperBounds!!
_upperBounds = irTypeParameter.superTypes.map { KTypeProxy(KTypeState(it), interpreter) }
return _upperBounds!!
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KTypeParameterState
if (irTypeParameter != other.irTypeParameter) return false
return true
}
override fun hashCode(): Int {
return irTypeParameter.hashCode()
}
override fun toString(): String {
return irTypeParameter.name.asString()
}
}
internal class KParameterState(val irType: IrType) : ReflectionState(irType.classifierOrFail) {
}