diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt index 33406d5fd2d..c1e8734dfa0 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt @@ -7,11 +7,8 @@ package org.jetbrains.kotlin.ir.interpreter import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.interpreter.builtins.interpretBinaryFunction import org.jetbrains.kotlin.ir.interpreter.builtins.interpretTernaryFunction import org.jetbrains.kotlin.ir.interpreter.builtins.interpretUnaryFunction @@ -24,7 +21,6 @@ import org.jetbrains.kotlin.ir.interpreter.stack.CallStack import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.state.* import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState -import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.isArray @@ -55,9 +51,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : private val bodyMap: Map = interpreter.bodyMap override fun interceptProxy(irFunction: IrFunction, valueArguments: List, expectedResultClass: Class<*>): Any? { - val irCall = IrCallImpl.fromSymbolOwner( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.returnType, irFunction.symbol as IrSimpleFunctionSymbol - ) + val irCall = irFunction.createCall() return interpreter.withNewCallStack(irCall) { this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(irCall)) valueArguments.forEach { this@withNewCallStack.environment.callStack.pushState(it.state) } @@ -186,7 +180,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : private fun calculateRangeTo(type: IrType, args: List) { val constructor = type.classOrNull!!.owner.constructors.first() - val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) + val constructorCall = constructor.createConstructorCall() val constructorValueParameters = constructor.valueParameters.map { it.symbol } val primitiveValueParameters = args.map { it as Primitive<*> } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt index 0e539ac449a..864ba331430 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt @@ -6,30 +6,19 @@ package org.jetbrains.kotlin.ir.interpreter import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl -import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException import org.jetbrains.kotlin.ir.interpreter.exceptions.verify import org.jetbrains.kotlin.ir.interpreter.stack.CallStack import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.state.* -import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol -import org.jetbrains.kotlin.ir.symbols.IrValueSymbol -import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl import org.jetbrains.kotlin.ir.types.classOrNull -import org.jetbrains.kotlin.ir.types.isSubtypeOf import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.name.Name internal fun IrExpression.handleAndDropResult(callStack: CallStack, dropOnlyUnit: Boolean = false) { @@ -118,132 +107,54 @@ private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack) } private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) { - val irFunction = expression.symbol.owner - val hasDefaults = (0 until expression.valueArgumentsCount).any { expression.getValueArgument(it) == null } if (hasDefaults) { - val visibility = if (expression is IrEnumConstructorCall || expression is IrDelegatingConstructorCall) DescriptorVisibilities.LOCAL else irFunction.visibility - val defaultFun = IrFunctionImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER, - IrSimpleFunctionSymbolImpl(), Name.identifier(irFunction.name.asString() + "\$default"), - visibility, Modality.FINAL, irFunction.returnType, - isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isOperator = true, isInfix = false, isExpect = false - ) - defaultFun.parent = irFunction.parent - expression.dispatchReceiver?.let { - defaultFun.dispatchReceiverParameter = irFunction.dispatchReceiverParameter!!//.deepCopyWithSymbols(defaultFun) - } - expression.extensionReceiver?.let { - defaultFun.extensionReceiverParameter = irFunction.extensionReceiverParameter!!//.deepCopyWithSymbols(defaultFun) - } - val parameters = mutableListOf() - (0 until expression.valueArgumentsCount).forEach { - if (expression.getValueArgument(it) != null) { - val param = irFunction.valueParameters[it]//.deepCopyWithSymbols(defaultFun) - defaultFun.valueParameters += param - parameters += param - } + // if some arguments are not defined, then it is necessary to create temp function where defaults will be evaluated + val actualParameters = MutableList(expression.valueArgumentsCount) { null } + val ownerWithDefaults = expression.getFunctionThatContainsDefaults() + + val visibility = when (expression) { + is IrEnumConstructorCall, is IrDelegatingConstructorCall -> DescriptorVisibilities.LOCAL + else -> ownerWithDefaults.visibility } - val callToDefault = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, defaultFun.returnType, defaultFun.symbol) - expression.dispatchReceiver?.let { - callToDefault.dispatchReceiver = it - } - expression.extensionReceiver?.let { - callToDefault.extensionReceiver = it - } - var index = 0 - (0 until expression.valueArgumentsCount).forEach { - if (expression.getValueArgument(it) != null) { - callToDefault.putValueArgument(index++, expression.getValueArgument(it)) - } - } - - fun getDefaultForParameterAt(index: Int): IrExpression? { - fun IrExpressionBody.replaceGetValueFromOtherClass(owner: IrFunction): IrExpressionBody { - if (this.expression is IrConst<*>) return this - return this.deepCopyWithSymbols(owner).transform( - object : IrElementTransformerVoid() { - override fun visitGetValue(expression: IrGetValue): IrExpression { - val parameter = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression) - if (parameter.parent != owner) return super.visitGetValue(expression) - val newParameter = when (val indexInParameters = parameter.index) { - -1 -> (irFunction.dispatchReceiverParameter ?: irFunction.extensionReceiverParameter)!! - else -> parameters[indexInParameters]//parameters[indexInParameters] - } - return IrGetValueImpl(expression.startOffset, expression.endOffset, expression.type, newParameter.symbol) - } - }, null - )//.deepCopyWithSymbols(defaultFun) TODO ??? - } - - fun IrValueParameter.getDefault(): IrExpressionBody? { - if (defaultValue != null) return defaultValue?.replaceGetValueFromOtherClass(this.parent as IrFunction) - return (this.parent as? IrSimpleFunction)?.overriddenSymbols - ?.map { it.owner.valueParameters[this.index] } - ?.firstOrNull { it.getDefault() != null }?.let { it.getDefault()?.replaceGetValueFromOtherClass(it.parent as IrFunction) } - } - - return irFunction.valueParameters[index].getDefault()?.expression - } - - val newExpression = when (expression) { - is IrCall -> IrCallImpl.fromSymbolOwner(expression.startOffset, expression.endOffset, expression.type, expression.symbol) - is IrConstructorCall -> IrConstructorCallImpl.fromSymbolOwner(expression.type, expression.symbol) - is IrDelegatingConstructorCall -> IrDelegatingConstructorCallImpl(0, 0, expression.type, expression.symbol, expression.typeArgumentsCount, expression.valueArgumentsCount) - is IrEnumConstructorCall -> IrEnumConstructorCallImpl(0, 0, expression.type, expression.symbol, expression.typeArgumentsCount, expression.valueArgumentsCount) - else -> TODO() - } - - expression.dispatchReceiver?.let { - newExpression.dispatchReceiver = IrGetValueImpl(0, 0, defaultFun.dispatchReceiverParameter!!.type, defaultFun.dispatchReceiverParameter!!.symbol) - } - expression.extensionReceiver?.let { - newExpression.extensionReceiver = IrGetValueImpl(0, 0, defaultFun.extensionReceiverParameter!!.type, defaultFun.extensionReceiverParameter!!.symbol) - } - val variablesForDefault = mutableListOf() - index = 0 - (0 until expression.valueArgumentsCount).forEach { - val arg = if (expression.getValueArgument(it) != null) { - IrGetValueImpl(0, 0, defaultFun.valueParameters[index].type, defaultFun.valueParameters[index++].symbol) - } else { - val init = getDefaultForParameterAt(it) - ?: expression.getVarargType(it)?.let { // case when value parameter is vararg and it is missing - IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it) + val defaultFun = createTempFunction( + Name.identifier(ownerWithDefaults.name.asString() + "\$default"), ownerWithDefaults.returnType, + origin = IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER, visibility + ).apply { + this.parent = ownerWithDefaults.parent + this.dispatchReceiverParameter = ownerWithDefaults.dispatchReceiverParameter?.deepCopyWithSymbols(this) + this.extensionReceiverParameter = ownerWithDefaults.extensionReceiverParameter?.deepCopyWithSymbols(this) + (0 until expression.valueArgumentsCount).forEach { index -> + val parameter = ownerWithDefaults.valueParameters[index] + actualParameters[index] = if (expression.getValueArgument(index) != null) { + parameter.deepCopyWithSymbols(this).also { this.valueParameters += it } + } else { + parameter.createTempVariable().apply variable@{ + this@variable.initializer = parameter.getDefaultWithActualParameters(this@apply, actualParameters) + ?: expression.getVarargType(index)?.let { null.toIrConst(it) } // if parameter is vararg and it is missing } - val variable = IrVariableImpl( - 0, 0, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, IrVariableSymbolImpl(), - irFunction.valueParameters[it].name, irFunction.valueParameters[it].type, isVar = false, isConst = false, isLateinit = false - ) - variablesForDefault += variable - parameters += variable - variable.initializer = init - IrGetValueImpl(0, 0, variable.type, variable.symbol) - + } } - newExpression.putValueArgument(it, arg) - } - (0 until expression.typeArgumentsCount).forEach { - newExpression.putTypeArgument(it, expression.getTypeArgument(it)) } + val callWithAllArgs = expression.shallowCopy() // just a copy of given call, but with all arguments in place + expression.dispatchReceiver?.let { callWithAllArgs.dispatchReceiver = defaultFun.dispatchReceiverParameter!!.createGetValue() } + expression.extensionReceiver?.let { callWithAllArgs.extensionReceiver = defaultFun.extensionReceiverParameter!!.createGetValue() } + (0 until expression.valueArgumentsCount).forEach { callWithAllArgs.putValueArgument(it, actualParameters[it]?.createGetValue()) } + defaultFun.body = (actualParameters.filterIsInstance() + defaultFun.createReturn(callWithAllArgs)).wrapWithBlockBody() - defaultFun.body = IrBlockBodyImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - variablesForDefault + IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, defaultFun.returnType, defaultFun.symbol, newExpression) - ) - + val callToDefault = defaultFun.createCall().apply { expression.copyArgsInto(this) } callStack.addInstruction(CompoundInstruction(callToDefault)) } else { + val irFunction = expression.symbol.owner callStack.addInstruction(SimpleInstruction(expression)) fun IrValueParameter.schedule(arg: IrExpression?) { callStack.addInstruction(SimpleInstruction(this)) callStack.addInstruction(CompoundInstruction(arg)) } - (expression.valueArgumentsCount - 1 downTo 0).forEach { - irFunction.valueParameters[it].schedule(expression.getValueArgument(it)) - } + (expression.valueArgumentsCount - 1 downTo 0).forEach { irFunction.valueParameters[it].schedule(expression.getValueArgument(it)) } expression.extensionReceiver?.let { irFunction.extensionReceiverParameter!!.schedule(it) } expression.dispatchReceiver?.let { irFunction.dispatchReceiverParameter!!.schedule(it) } } @@ -311,7 +222,7 @@ private fun unfoldGetValue(expression: IrGetValue, environment: IrInterpreterEnv // used to evaluate constants inside object if (expectedClass != null && expectedClass.isObject && expression.symbol.owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER) { // TODO is this correct behaviour? - val irGetObject = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, expectedClass.defaultType, expectedClass.symbol) + val irGetObject = expectedClass.createGetObject() return unfoldGetObjectValue(irGetObject, environment) } environment.callStack.pushState(environment.callStack.getState(expression.symbol)) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt new file mode 100644 index 00000000000..a5909f676fd --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt @@ -0,0 +1,174 @@ +/* + * Copyright 2010-2021 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 + +import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.builtins.UnsignedType +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.DescriptorVisibility +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.interpreter.state.Complex +import org.jetbrains.kotlin.ir.interpreter.state.ExceptionState +import org.jetbrains.kotlin.ir.interpreter.state.Primitive +import org.jetbrains.kotlin.ir.interpreter.state.State +import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.name.Name + +internal val TEMP_CLASS_FOR_INTERPRETER = object : IrDeclarationOriginImpl("TEMP_CLASS_FOR_INTERPRETER") {} +internal val TEMP_FUNCTION_FOR_INTERPRETER = object : IrDeclarationOriginImpl("TEMP_FUNCTION_FOR_INTERPRETER") {} + +fun Any?.toIrConstOrNull(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*>? { + if (this == null) return IrConstImpl.constNull(startOffset, endOffset, irType) + + val constType = irType.makeNotNull() + return when (irType.getPrimitiveType()) { + PrimitiveType.BOOLEAN -> IrConstImpl.boolean(startOffset, endOffset, constType, this as Boolean) + PrimitiveType.CHAR -> IrConstImpl.char(startOffset, endOffset, constType, this as Char) + PrimitiveType.BYTE -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte()) + PrimitiveType.SHORT -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort()) + PrimitiveType.INT -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt()) + PrimitiveType.FLOAT -> IrConstImpl.float(startOffset, endOffset, constType, (this as Number).toFloat()) + PrimitiveType.LONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong()) + PrimitiveType.DOUBLE -> IrConstImpl.double(startOffset, endOffset, constType, (this as Number).toDouble()) + null -> when (constType.getUnsignedType()) { + UnsignedType.UBYTE -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte()) + UnsignedType.USHORT -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort()) + UnsignedType.UINT -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt()) + UnsignedType.ULONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong()) + null -> when { + constType.isString() -> IrConstImpl.string(startOffset, endOffset, constType, this as String) + else -> null + } + } + } +} + +fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> = + toIrConstOrNull(irType, startOffset, endOffset) + ?: throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}") + +fun Any?.toIrConst( + irType: IrType, irBuiltIns: IrBuiltIns, + startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET +): IrConst<*> = + toIrConstOrNull(irType, startOffset, endOffset) ?: run { + if (irType == irBuiltIns.stringType) IrConstImpl.string(startOffset, endOffset, irType.makeNotNull(), this as String) + else throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}") + } + +internal fun State.toIrExpression(expression: IrExpression): IrExpression { + val start = expression.startOffset + val end = expression.endOffset + val type = expression.type.makeNotNull() + return when (this) { + is Primitive<*> -> + when { + this.value == null -> this.value.toIrConst(type, start, end) + type.isPrimitiveType() || type.isString() -> this.value.toIrConst(type, start, end) + else -> expression // TODO support for arrays + } + is ExceptionState -> { + IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + this.getFullDescription()) + } + is Complex -> { + val stateType = this.irClass.defaultType + when { + stateType.isUnsignedType() -> (this.fields.single().state as Primitive<*>).value.toIrConst(type, start, end) + else -> expression + } + } + else -> expression // TODO support + } +} + +internal fun IrFunction.createCall(): IrCall { + this as IrSimpleFunction + return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, returnType, symbol, typeParameters.size, valueParameters.size) +} + +internal fun IrConstructor.createConstructorCall(): IrConstructorCall { + return IrConstructorCallImpl.fromSymbolOwner(returnType, symbol) +} + +internal fun IrValueDeclaration.createGetValue(): IrGetValue { + return IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this.type, this.symbol) +} + +internal fun IrValueDeclaration.createTempVariable(): IrVariable { + return IrVariableImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, IrVariableSymbolImpl(), + this.name, this.type, isVar = false, isConst = false, isLateinit = false + ) +} + +internal fun IrClass.createGetObject(): IrGetObjectValue { + return IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this.defaultType, this.symbol) +} + +internal fun IrFunction.createReturn(value: IrExpression): IrReturn { + return IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this.returnType, this.symbol, value) +} + +internal fun createTempFunction( + name: Name, + type: IrType, + origin: IrDeclarationOrigin = TEMP_FUNCTION_FOR_INTERPRETER, + visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC +): IrSimpleFunction { + return IrFunctionImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, IrSimpleFunctionSymbolImpl(), name, visibility, Modality.FINAL, type, + isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isOperator = true, isInfix = false, isExpect = false + ) +} + +internal fun createTempClass(name: Name, origin: IrDeclarationOrigin = TEMP_CLASS_FOR_INTERPRETER): IrClass { + return IrFactoryImpl.createClass( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, IrClassSymbolImpl(), name, + ClassKind.CLASS, DescriptorVisibilities.PRIVATE, Modality.FINAL + ) +} + +internal fun List.wrapWithBlockBody(): IrBlockBody { + return IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this) +} + +internal fun IrFunctionAccessExpression.shallowCopy(copyTypeArguments: Boolean = true): IrFunctionAccessExpression { + return when (this) { + is IrCall -> IrCallImpl.fromSymbolOwner(startOffset, endOffset, type, symbol) + is IrConstructorCall -> IrConstructorCallImpl.fromSymbolOwner(type, symbol) + is IrDelegatingConstructorCall -> IrDelegatingConstructorCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol) + is IrEnumConstructorCall -> + IrEnumConstructorCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, typeArgumentsCount, valueArgumentsCount) + else -> TODO("Expression $this cannot be copied") + }.apply { + if (copyTypeArguments) { + (0 until this@shallowCopy.typeArgumentsCount).forEach { this.putTypeArgument(it, this@shallowCopy.getTypeArgument(it)) } + } + } +} + +internal fun IrFunctionAccessExpression.copyArgsInto(newCall: IrFunctionAccessExpression) { + newCall.dispatchReceiver = this.dispatchReceiver + newCall.extensionReceiver = this.extensionReceiver + (0 until this.valueArgumentsCount) + .mapNotNull { this.getValueArgument(it) } + .forEachIndexed { i, arg -> newCall.putValueArgument(i, arg) } +} \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index bb479ff463f..93ecc43abea 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -7,23 +7,23 @@ package org.jetbrains.kotlin.ir.interpreter import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.StandardNames -import org.jetbrains.kotlin.builtins.UnsignedType -import org.jetbrains.kotlin.ir.IrBuiltIns -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy import org.jetbrains.kotlin.ir.interpreter.proxy.wrap -import org.jetbrains.kotlin.ir.interpreter.state.* +import org.jetbrains.kotlin.ir.interpreter.state.Primitive +import org.jetbrains.kotlin.ir.interpreter.state.State +import org.jetbrains.kotlin.ir.interpreter.state.Wrapper +import org.jetbrains.kotlin.ir.interpreter.state.isSubtypeOf import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.buildSimpleType import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance @@ -42,31 +42,6 @@ internal fun IrFunction.getReceiver(): IrSymbol? = this.getDispatchReceiver() ?: internal fun IrFunctionAccessExpression.getThisReceiver(): IrValueSymbol = this.symbol.owner.parentAsClass.thisReceiver!!.symbol -internal fun State.toIrExpression(expression: IrExpression): IrExpression { - val start = expression.startOffset - val end = expression.endOffset - val type = expression.type.makeNotNull() - return when (this) { - is Primitive<*> -> - when { - this.value == null -> this.value.toIrConst(type, start, end) - type.isPrimitiveType() || type.isString() -> this.value.toIrConst(type, start, end) - else -> expression // TODO support for arrays - } - is ExceptionState -> { - IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + this.getFullDescription()) - } - is Complex -> { - val stateType = this.irClass.defaultType - when { - stateType.isUnsignedType() -> (this.fields.single().state as Primitive<*>).value.toIrConst(type, start, end) - else -> expression - } - } - else -> expression // TODO support - } -} - /** * Convert object from outer world to state */ @@ -81,45 +56,6 @@ internal fun Any?.toState(irType: IrType): State { } } -fun Any?.toIrConstOrNull(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*>? { - if (this == null) return IrConstImpl.constNull(startOffset, endOffset, irType) - - val constType = irType.makeNotNull() - return when (irType.getPrimitiveType()) { - PrimitiveType.BOOLEAN -> IrConstImpl.boolean(startOffset, endOffset, constType, this as Boolean) - PrimitiveType.CHAR -> IrConstImpl.char(startOffset, endOffset, constType, this as Char) - PrimitiveType.BYTE -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte()) - PrimitiveType.SHORT -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort()) - PrimitiveType.INT -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt()) - PrimitiveType.FLOAT -> IrConstImpl.float(startOffset, endOffset, constType, (this as Number).toFloat()) - PrimitiveType.LONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong()) - PrimitiveType.DOUBLE -> IrConstImpl.double(startOffset, endOffset, constType, (this as Number).toDouble()) - null -> when (constType.getUnsignedType()) { - UnsignedType.UBYTE -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte()) - UnsignedType.USHORT -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort()) - UnsignedType.UINT -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt()) - UnsignedType.ULONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong()) - null -> when { - constType.isString() -> IrConstImpl.string(startOffset, endOffset, constType, this as String) - else -> null - } - } - } -} - -fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> = - toIrConstOrNull(irType, startOffset, endOffset) - ?: throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}") - -fun Any?.toIrConst( - irType: IrType, irBuiltIns: IrBuiltIns, - startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET -): IrConst<*> = - toIrConstOrNull(irType, startOffset, endOffset) ?: run { - if (irType == irBuiltIns.stringType) IrConstImpl.string(startOffset, endOffset, irType.makeNotNull(), this as String) - else throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}") - } - @Suppress("UNCHECKED_CAST") internal fun IrConst.toPrimitive(): Primitive = when { type.isByte() -> Primitive((value as Number).toByte() as T, type) @@ -276,3 +212,38 @@ internal fun IrType.getOnlyName(): String { internal fun IrFieldAccessExpression.accessesTopLevelOrObjectField(): Boolean { return this.receiver == null || (this.receiver?.type?.classifierOrNull?.owner as? IrClass)?.isObject == true } + +internal fun IrFunctionAccessExpression.getFunctionThatContainsDefaults(): IrFunction { + val irFunction = this.symbol.owner + fun IrValueParameter.lookup(): IrFunction? { + return defaultValue?.let { this.parent as IrFunction } + ?: (this.parent as? IrSimpleFunction)?.overriddenSymbols + ?.map { it.owner.valueParameters[this.index] } + ?.firstNotNullOfOrNull { it.lookup() } + } + + return (0 until this.valueArgumentsCount) + .first { this.getValueArgument(it) == null } + .let { irFunction.valueParameters[it].lookup() ?: irFunction } +} + +internal fun IrValueParameter.getDefaultWithActualParameters( + newParent: IrFunction, actualParameters: List +): IrExpression? { + val expression = this.defaultValue?.expression + if (expression is IrConst<*>) return expression + + val parameterOwner = this.parent as IrFunction + val transformer = object : IrElementTransformerVoid() { + override fun visitGetValue(expression: IrGetValue): IrExpression { + val parameter = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression) + if (parameter.parent != parameterOwner) return super.visitGetValue(expression) + val newParameter = when (parameter.index) { + -1 -> newParent.dispatchReceiverParameter ?: newParent.extensionReceiverParameter + else -> actualParameters[parameter.index] + } + return IrGetValueImpl(expression.startOffset, expression.endOffset, expression.type, newParameter!!.symbol) + } + } + return expression?.deepCopyWithSymbols(newParent)?.transform(transformer, null) +} diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt index 61e50ae216d..73010806a49 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt @@ -5,12 +5,11 @@ package org.jetbrains.kotlin.ir.interpreter.intrinsics -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.interpreter.* +import org.jetbrains.kotlin.ir.interpreter.createCall +import org.jetbrains.kotlin.ir.interpreter.createGetValue +import org.jetbrains.kotlin.ir.interpreter.toIrConst import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException import org.jetbrains.kotlin.ir.interpreter.exceptions.stop import org.jetbrains.kotlin.ir.interpreter.state.* @@ -235,10 +234,9 @@ internal object ArrayConstructor : IntrinsicBase() { callStack.setState(initSymbol, state) for (i in size - 1 downTo 0) { - val invoke = state.invokeSymbol.owner as IrSimpleFunction - val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, invoke.returnType, invoke.symbol) - call.dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, initSymbol) - call.putValueArgument(0, IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, environment.irBuiltIns.intType, i)) + val call = (state.invokeSymbol.owner as IrSimpleFunction).createCall() + call.dispatchReceiver = initSymbol.owner.createGetValue() + call.putValueArgument(0, i.toIrConst(environment.irBuiltIns.intType)) instructions += CompoundInstruction(call) } @@ -292,10 +290,10 @@ internal object AssertIntrinsic : IntrinsicBase() { override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List { if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment)) - val messageLambda = environment.callStack.getState(irFunction.valueParameters.last().symbol) as KFunctionState - val function = messageLambda.irFunction as IrSimpleFunction - environment.callStack.loadUpValues(messageLambda) - val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.returnType, function.symbol) + val lambdaParameter = irFunction.valueParameters.last() + val lambdaState = environment.callStack.getState(lambdaParameter.symbol) as KFunctionState + val call = (lambdaState.invokeSymbol.owner as IrSimpleFunction).createCall() + call.dispatchReceiver = lambdaParameter.createGetValue() return listOf(customEvaluateInstruction(irFunction, environment), CompoundInstruction(call)) } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt index 6ed81f4603f..919757e76b2 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt @@ -5,13 +5,12 @@ package org.jetbrains.kotlin.ir.interpreter.state -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.interpreter.createCall import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.types.isNullableAny import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization @@ -69,8 +68,7 @@ internal class Common private constructor(override val irClass: IrClass, overrid } fun createToStringIrCall(): IrCall { - val toStringFun = getToStringFunction() - return IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, toStringFun.returnType, toStringFun.symbol) + return getToStringFunction().createCall() } override fun toString(): String { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt index 4148c48d0ab..fef3cce38f9 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt @@ -5,29 +5,25 @@ package org.jetbrains.kotlin.ir.interpreter.state.reflection -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrBuiltIns -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.putArgument +import org.jetbrains.kotlin.ir.interpreter.* import org.jetbrains.kotlin.ir.interpreter.CallInterceptor +import org.jetbrains.kotlin.ir.interpreter.TEMP_FUNCTION_FOR_INTERPRETER +import org.jetbrains.kotlin.ir.interpreter.createTempClass +import org.jetbrains.kotlin.ir.interpreter.createTempFunction import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KParameterProxy import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeParameterProxy import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.state.StateWithClosure -import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol -import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol -import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.defaultType @@ -51,20 +47,11 @@ internal class KFunctionState( init { val invokeFunction = irClass.declarations.filterIsInstance().single { it.name == OperatorNameConventions.INVOKE } // TODO do we need new class here? if yes, do we need different names for temp classes? - functionClass = IrFactoryImpl.createClass( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - object : IrDeclarationOriginImpl("TEMP_CLASS_FOR_INTERPRETER") {}, IrClassSymbolImpl(), - Name.identifier("Function\$0"), ClassKind.CLASS, DescriptorVisibilities.PRIVATE, Modality.FINAL - ).apply { - parent = irFunction.parent - } + functionClass = createTempClass(Name.identifier("Function\$0")).apply { parent = irFunction.parent } functionClass.superTypes += irClass.defaultType - functionClass.declarations += IrFunctionImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - object : IrDeclarationOriginImpl("TEMP_FUNCTION_FOR_INTERPRETER") {}, IrSimpleFunctionSymbolImpl(), - OperatorNameConventions.INVOKE, DescriptorVisibilities.PUBLIC, Modality.FINAL, irFunction.returnType, - isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isOperator = true, isInfix = false, isExpect = false + functionClass.declarations += createTempFunction( + OperatorNameConventions.INVOKE, irFunction.returnType, TEMP_FUNCTION_FOR_INTERPRETER ).apply impl@{ parent = functionClass overriddenSymbols = listOf(invokeFunction.symbol) @@ -72,36 +59,29 @@ internal class KFunctionState( dispatchReceiverParameter = invokeFunction.dispatchReceiverParameter?.deepCopyWithSymbols(initialParent = this) valueParameters = mutableListOf() - val call = when (val symbol = irFunction.symbol) { - is IrSimpleFunctionSymbol -> IrCallImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - irFunction.returnType, symbol, irFunction.typeParameters.size, irFunction.valueParameters.size - ) - is IrConstructorSymbol -> IrConstructorCallImpl.fromSymbolOwner(irFunction.returnType, symbol) + val call = when (irFunction) { + is IrSimpleFunction -> irFunction.createCall() + is IrConstructor -> irFunction.createConstructorCall() else -> TODO("Unsupported symbol $symbol for invoke") }.apply { val dispatchParameter = irFunction.dispatchReceiverParameter val extensionParameter = irFunction.extensionReceiverParameter if (dispatchParameter != null) { - dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchParameter.type, dispatchParameter.symbol) - if (getField(dispatchParameter.symbol) == null) (this@impl.valueParameters as MutableList).add(dispatchParameter) + dispatchReceiver = dispatchParameter.createGetValue() + if (getField(dispatchParameter.symbol) == null) (this@impl.valueParameters as MutableList) += dispatchParameter } if (extensionParameter != null) { - extensionReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionParameter.type, extensionParameter.symbol) - if (getField(extensionParameter.symbol) == null) (this@impl.valueParameters as MutableList).add(extensionParameter) + extensionReceiver = extensionParameter.createGetValue() + if (getField(extensionParameter.symbol) == null) (this@impl.valueParameters as MutableList) += extensionParameter } irFunction.valueParameters.forEach { - putArgument(it, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, it.symbol)) - (this@impl.valueParameters as MutableList).add(it) + putArgument(it, it.createGetValue()) + (this@impl.valueParameters as MutableList) += it } } - body = IrBlockBodyImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - listOf(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this.returnType, this.symbol, call)) - ) - + body = listOf(this.createReturn(call)).wrapWithBlockBody() invokeSymbol = this.symbol } } diff --git a/compiler/testData/ir/interpreter/defaultArgs.kt b/compiler/testData/ir/interpreter/defaultArgs.kt index a492c612ddb..94b2091b8a7 100644 --- a/compiler/testData/ir/interpreter/defaultArgs.kt +++ b/compiler/testData/ir/interpreter/defaultArgs.kt @@ -2,7 +2,7 @@ fun sum(a: Int = 1, b: Int = 2, c: Int = 3) = a + b + c @CompileTimeCalculation -fun sumBasedOnPrevious(a: Int = 1, b: Int = a * 2, c: Int = b * 2) = a + b + c +fun sumBasedOnPrevious(a: Int = 1, b: Int = a * 2, c: Int = b * 2, d: Int = b * 2) = a + b + c + d @CompileTimeCalculation interface A { @@ -16,8 +16,9 @@ const val sum1 = sum() const val sum2 = sum(b = -3) const val sum3 = sum(c = 1, a = 1, b = 1) -const val sumBasedOnPrevious1 = sumBasedOnPrevious() -const val sumBasedOnPrevious2 = sumBasedOnPrevious(b = 1, c = 1) +const val sumBasedOnPrevious1 = sumBasedOnPrevious() +const val sumBasedOnPrevious2 = sumBasedOnPrevious(b = 1, c = 1) +const val sumBasedOnPrevious3 = sumBasedOnPrevious(a = 1, c = 1) const val sumInInterfaceDefault1 = B().foo(1) const val sumInInterfaceDefault2 = B().foo(x = 1, y = 2)