Implement correct interpretation of toList function

This commit is contained in:
Ivan Kylchik
2020-06-10 22:57:12 +03:00
parent ba8147cd47
commit 38822c3bf8
7 changed files with 56 additions and 21 deletions
@@ -54,7 +54,10 @@ class IrInterpreter(irModule: IrModuleFragment) {
is Float -> irBuiltIns.floatType
is Double -> irBuiltIns.doubleType
null -> irBuiltIns.nothingType
else -> defaultType
else -> when (defaultType.classifierOrNull?.owner) {
is IrTypeParameter -> stack.getVariableState(defaultType.classifierOrFail.descriptor).irClass.defaultType
else -> defaultType
}
}
}
@@ -173,7 +176,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
functionImplementation.valueParameters
.map { Variable(it.descriptor, stack.getVariableState(it.descriptor)) }
.forEach { valueArguments.add(it) }
return stack.newFrame(initPool = valueArguments) {
return stack.newFrame(asSubFrame = true, initPool = valueArguments) {
functionImplementation.interpret()
}
}
@@ -195,7 +198,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
.map { Variable(it.second.descriptor, stack.getVariableState(it.first.descriptor)) }
.forEach { valueArguments.add(it) }
return stack.newFrame(initPool = valueArguments) {
return stack.newFrame(asSubFrame = true, initPool = valueArguments) {
val overriddenOwner = overridden.owner
return@newFrame when {
overriddenOwner.body != null -> overriddenOwner.interpret()
@@ -316,10 +319,11 @@ class IrInterpreter(irModule: IrModuleFragment) {
interpretValueParameters(expression, irFunction, valueArguments).check { return it }
valueArguments.addAll(getTypeArguments(irFunction, expression) { stack.getVariableState(it) })
if (dispatchReceiver is Common) valueArguments.addAll(dispatchReceiver.typeArguments)
if (extensionReceiver is Common) valueArguments.addAll(extensionReceiver.typeArguments)
if (dispatchReceiver is Complex) valueArguments.addAll(dispatchReceiver.typeArguments)
if (extensionReceiver is Complex) valueArguments.addAll(extensionReceiver.typeArguments)
if (irFunction.isLocal) valueArguments.addAll(dispatchReceiver.extractNonLocalDeclarations())
val isLocal = (dispatchReceiver as? Complex)?.getOriginal()?.irClass?.isLocal ?: irFunction.isLocal
if (isLocal) valueArguments.addAll(dispatchReceiver.extractNonLocalDeclarations())
return stack.newFrame(asSubFrame = irFunction.isInline || irFunction.isLocal, initPool = valueArguments) {
val isWrapper = dispatchReceiver is Wrapper && rawExtensionReceiver == null
@@ -364,8 +368,10 @@ class IrInterpreter(irModule: IrModuleFragment) {
interpretValueParameters(constructorCall, owner, valueArguments).check { return it }
val parent = owner.parent as IrClass
val typeArguments = getTypeArguments(parent, constructorCall) { stack.getVariableState(it) } + stack.getAllTypeArguments()
if (parent.hasAnnotation(evaluateIntrinsicAnnotation)) {
return stack.newFrame(initPool = valueArguments) { Wrapper.getConstructorMethod(owner).invokeMethod(owner) }
.apply { (stack.peekReturnValue() as? Wrapper)?.typeArguments?.addAll(typeArguments) } // can be exception
}
if (parent.defaultType.isArray() || parent.defaultType.isPrimitiveArray()) {
@@ -373,8 +379,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
return stack.newFrame(initPool = valueArguments) { handleIntrinsicMethods(owner) }
}
val state = Common(parent)
state.typeArguments.addAll(getTypeArguments(parent, constructorCall) { stack.getVariableState(it) } + stack.getAllTypeArguments())
val state = Common(parent).apply { this.typeArguments.addAll(typeArguments) }
if (parent.isLocal) state.fields.addAll(stack.getAll()) // TODO save only necessary declarations
valueArguments.add(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
return stack.newFrame(initPool = valueArguments + state.typeArguments) {
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
// main purpose is to get receiver from constructor call
fun IrMemberAccessExpression.getThisAsReceiver(): DeclarationDescriptor {
@@ -238,6 +239,7 @@ fun State?.getFunctionReceiver(superIrClass: IrClass?): State? {
fun IrFunctionAccessExpression.getVarargType(index: Int): IrType? {
val varargType = this.symbol.owner.valueParameters[index].varargElementType ?: return null
varargType.classOrNull?.let { return this.symbol.owner.valueParameters[index].type }
val typeParameter = varargType.classifierOrFail.owner as IrTypeParameter
return this.getTypeArgument(typeParameter.index)
}
@@ -245,15 +247,25 @@ fun IrFunctionAccessExpression.getVarargType(index: Int): IrType? {
fun getTypeArguments(
container: IrTypeParametersContainer, expression: IrFunctionAccessExpression, mapper: (TypeParameterDescriptor) -> State
): List<Variable> {
return container.typeParameters.mapIndexed { index, typeParameter ->
val typeArgument = expression.getTypeArgument(index)!!
val argumentState = typeArgument.classOrNull?.owner?.let { Common(it) }
?: mapper(typeArgument.classifierOrFail.descriptor as TypeParameterDescriptor)
Variable(typeParameter.descriptor, argumentState)
fun IrType.getState(): State {
return this.classOrNull?.owner?.let { Common(it) } ?: mapper(this.classifierOrFail.descriptor as TypeParameterDescriptor)
}
val typeArguments = container.typeParameters.mapIndexed { index, typeParameter ->
val typeArgument = expression.getTypeArgument(index)!!
Variable(typeParameter.descriptor, typeArgument.getState())
}.toMutableList()
if (container is IrSimpleFunction) {
container.returnType.classifierOrFail.owner.safeAs<IrTypeParameter>()
?.let { typeArguments.add(Variable(it.descriptor, expression.type.getState())) }
}
return typeArguments
}
fun State?.extractNonLocalDeclarations(): List<Variable> {
this ?: return listOf()
return this.fields.filterNot { it.descriptor.containingDeclaration == this.irClass.descriptor }
val state = this.takeIf { it !is Complex } ?: (this as Complex).getOriginal()
return state.fields.filterNot { it.descriptor.containingDeclaration == state.irClass.descriptor }
}
@@ -65,7 +65,8 @@ class StackImpl : Stack {
val fileName = irFunction.file.name
val fileNameCapitalized = fileName.replace(".kt", "Kt").capitalize()
val lineNum = irFunction.fileEntry.getLineNumber(irFunction.startOffset) + 1
getCurrentFrame().frameEntryPoint = "at $fileNameCapitalized.${irFunction.fqNameWhenAvailable}($fileName:$lineNum)"
if (getCurrentFrame().frameEntryPoint == null)
getCurrentFrame().frameEntryPoint = "at $fileNameCapitalized.${irFunction.fqNameWhenAvailable}($fileName:$lineNum)"
}
override fun getStackTrace(): List<String> {
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.isInterface
class Common private constructor(
override val irClass: IrClass, override val fields: MutableList<Variable>, val typeArguments: MutableList<Variable>,
override val irClass: IrClass, override val fields: MutableList<Variable>, override val typeArguments: MutableList<Variable>,
superClass: Complex?, subClass: Complex?
) : Complex(irClass, fields, superClass, subClass) {
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
abstract class Complex(
override val irClass: IrClass, override val fields: MutableList<Variable>, var superClass: Complex?, var subClass: Complex?
) : State {
abstract val typeArguments: MutableList<Variable>
fun setSuperClassInstance(superClass: Complex) {
if (this.irClass == superClass.irClass) {
// if superClass is just secondary constructor instance, then copy properties that isn't already present in instance
@@ -18,6 +18,7 @@ import kotlin.math.min
class ExceptionState private constructor(
override val irClass: IrClass, override val fields: MutableList<Variable>, stackTrace: List<String>, subClass: Complex? = null
) : Complex(irClass, fields, null, subClass) {
override val typeArguments: MutableList<Variable> = mutableListOf()
private lateinit var exceptionFqName: String
private val exceptionHierarchy = mutableListOf<String>()
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.ir.util.isTypeParameter
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithDifferentJvmName
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.firstOverridden
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -35,13 +36,13 @@ import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
class Wrapper private constructor(
val value: Any, override val irClass: IrClass, subClass: Complex?
val value: Any, override val irClass: IrClass, subClass: Complex?, override val typeArguments: MutableList<Variable>
) : Complex(irClass, mutableListOf(), null, subClass) {
private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe()
private val receiverClass = irClass.defaultType.getClass(true)
constructor(value: Any, irClass: IrClass) : this(value, irClass, null)
constructor(value: Any, irClass: IrClass) : this(value, irClass, null, mutableListOf())
fun getMethod(irFunction: IrFunction): MethodHandle? {
if (irFunction.getEvaluateIntrinsicValue()?.isEmpty() == true) return null // this method will handle IntrinsicEvaluator
@@ -136,11 +137,24 @@ class Wrapper private constructor(
this.isArray() -> if (asObject) Array<Any?>::class.javaObjectType else Array<Any?>::class.java
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Class.forName(owner!!.getEvaluateIntrinsicValue())
//TODO primitive array
this.isTypeParameter() -> Any::class.java
else -> JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(fqName!!))?.let { Class.forName(it.asSingleFqName().toString()) }
this.isTypeParameter() -> Any::class.java // TODO use typeArguments
else -> JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(fqName!!))?.let { Class.forName(it.getAsString()) }
} ?: Class.forName(fqName)
}
private fun ClassId.getAsString(): String {
// TODO come up with something better
val fqName = this.asSingleFqName().toString()
val names = fqName.split(".")
val result = StringBuilder()
for (i in 0 until (names.size - 1)) {
result.append(names[i])
if (names[i][0].isUpperCase() && names[i + 1][0].isUpperCase()) result.append("$") else result.append(".")
}
result.append(names.last())
return result.toString()
}
private fun IrFunction.getOriginalOverriddenSymbols(): MutableList<IrFunctionSymbol> {
val overriddenSymbols = mutableListOf<IrFunctionSymbol>()
if (this is IrFunctionImpl) {
@@ -184,7 +198,7 @@ class Wrapper private constructor(
}
override fun copy(): State {
return Wrapper(value, irClass, subClass ?: this)
return Wrapper(value, irClass, subClass ?: this, typeArguments)
}
override fun toString(): String {