diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt index 9b668d03563..d6e99197725 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt @@ -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) { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt index 36ab9e60194..eef2d262048 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt @@ -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 { - 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() + ?.let { typeArguments.add(Variable(it.descriptor, expression.type.getState())) } + } + + return typeArguments } fun State?.extractNonLocalDeclarations(): List { 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 } } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Stack.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Stack.kt index 8b39ce5fe85..64de5c215ad 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Stack.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Stack.kt @@ -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 { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt index 39d1995598d..8efb2b48cbb 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt @@ -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, val typeArguments: MutableList, + override val irClass: IrClass, override val fields: MutableList, override val typeArguments: MutableList, superClass: Complex?, subClass: Complex? ) : Complex(irClass, fields, superClass, subClass) { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt index c7c30699da1..821e944ba35 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt @@ -16,6 +16,8 @@ import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization abstract class Complex( override val irClass: IrClass, override val fields: MutableList, var superClass: Complex?, var subClass: Complex? ) : State { + abstract val typeArguments: MutableList + 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 diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/ExceptionState.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/ExceptionState.kt index a254fb3c4a9..5a56f6bf84c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/ExceptionState.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/ExceptionState.kt @@ -18,6 +18,7 @@ import kotlin.math.min class ExceptionState private constructor( override val irClass: IrClass, override val fields: MutableList, stackTrace: List, subClass: Complex? = null ) : Complex(irClass, fields, null, subClass) { + override val typeArguments: MutableList = mutableListOf() private lateinit var exceptionFqName: String private val exceptionHierarchy = mutableListOf() diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt index 23287ce26d8..7f2ab4e2fa2 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt @@ -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 ) : 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::class.javaObjectType else Array::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 { val overriddenSymbols = mutableListOf() 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 {