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 5fae48cc6d1..01c2c6391e8 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 @@ -12,6 +12,7 @@ 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.IrGetObjectValueImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException import org.jetbrains.kotlin.ir.interpreter.exceptions.verify @@ -21,6 +22,7 @@ import org.jetbrains.kotlin.ir.interpreter.state.* import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid internal fun IrExpression.handleAndDropResult(callStack: CallStack, dropOnlyUnit: Boolean = false) { val dropResult = fun() { @@ -131,11 +133,31 @@ private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callSt callStack.addInstruction(SimpleInstruction(expression)) fun getDefaultForParameterAt(index: Int): IrExpression? { + fun IrExpressionBody.replaceGetValueFromOtherClass(): IrExpressionBody { + return this.deepCopyWithSymbols(irFunction).transform( + object : IrElementTransformerVoid() { + override fun visitGetValue(expression: IrGetValue): IrExpression { + val parameter = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression) + if (parameter.parent == irFunction) return super.visitGetValue(expression) + val newParameter = when (val indexInParameters = parameter.index) { + -1 -> (irFunction.dispatchReceiverParameter ?: irFunction.extensionReceiverParameter)!! + else -> irFunction.valueParameters[indexInParameters] + } + return IrGetValueImpl(expression.startOffset, expression.endOffset, expression.type, newParameter.symbol) + } + }, null + ) + } + fun IrValueParameter.getDefault(): IrExpressionBody? { - return defaultValue - ?: (this.parent as? IrSimpleFunction)?.overriddenSymbols - ?.map { it.owner.valueParameters[this.index].getDefault() } - ?.firstNotNullOfOrNull { it } + if (defaultValue != null) return defaultValue + val overriddenDefault = (this.parent as? IrSimpleFunction)?.overriddenSymbols + ?.map { it.owner.valueParameters[this.index] } + ?.firstNotNullOfOrNull { it.getDefault() } + + if (overriddenDefault == null || overriddenDefault.expression is IrConst<*>) return overriddenDefault + + return overriddenDefault.replaceGetValueFromOtherClass() } return irFunction.valueParameters[index].getDefault()?.expression 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 a35bc6829dd..4565bf74e10 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 @@ -167,6 +167,9 @@ class IrInterpreter private constructor( //must add value argument in current stack because it can be used later as default argument callStack.addVariable(Variable(valueParameter.symbol, state)) + + // outer classes can be used in default args evaluation + if (isReceiver() && state is Complex) state.loadOuterClassesInto(callStack) } private fun interpretCall(call: IrCall) { @@ -204,9 +207,7 @@ class IrInterpreter private constructor( .forEach { callStack.addVariable(Variable(it.symbol, KTypeState(call.getTypeArgument(it.index)!!, irBuiltIns.anyClass.owner))) } // 5. load outer class object - if (dispatchReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) { - generateSequence(dispatchReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) } - } + if (dispatchReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) dispatchReceiver.loadOuterClassesInto(callStack) // 6. load up values onto stack if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame() @@ -277,7 +278,7 @@ class IrInterpreter private constructor( callStack.addVariable(Variable(receiverSymbol, outerClass)) } // used to get information from outer class - generateSequence(outerClassVar) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) } + objectState.loadOuterClassesInto(callStack) } if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt index 5fcd21d85b2..ed2791b2c6c 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt @@ -12,8 +12,8 @@ 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.interpreter.stack.CallStack import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol -import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.isAny import org.jetbrains.kotlin.ir.util.* @@ -51,4 +51,8 @@ internal interface Complex: State { val irFunction = getIrFunctionFromGivenClass(receiver, expression.symbol) ?: return null return getOverridden(irFunction as IrSimpleFunction) } + + fun loadOuterClassesInto(callStack: CallStack) { + generateSequence(outerClass) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) } + } } \ No newline at end of file diff --git a/compiler/testData/ir/interpreter/defaultArgs.kt b/compiler/testData/ir/interpreter/defaultArgs.kt index 1ec374036f6..a492c612ddb 100644 --- a/compiler/testData/ir/interpreter/defaultArgs.kt +++ b/compiler/testData/ir/interpreter/defaultArgs.kt @@ -4,9 +4,59 @@ 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 +@CompileTimeCalculation +interface A { + fun foo(x: Int, y: Int = x + 20, z: Int = y * 2) = z +} + +@CompileTimeCalculation +class B : A {} + 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 sumInInterfaceDefault1 = B().foo(1) +const val sumInInterfaceDefault2 = B().foo(x = 1, y = 2) +const val sumInInterfaceDefault3 = B().foo(x = 1, y = 2, z = -1) + +const val someConstProp = 0 +@CompileTimeCalculation +class Outer { + val prop = -1 + + inner class Inner { + val innerProp = -2 + + fun withInner(x: Int = prop) = x + fun withOuter(x: Int = innerProp) = x + fun withGlobal(x: Int = someConstProp) = x + } +} + +const val inner1 = Outer().Inner().withInner(100) +const val inner2 = Outer().Inner().withInner() +const val inner3 = Outer().Inner().withOuter(100) +const val inner4 = Outer().Inner().withOuter() +const val inner5 = Outer().Inner().withGlobal(100) +const val inner6 = Outer().Inner().withGlobal() + +@CompileTimeCalculation +interface I { + val prop: T + + fun foo(x: T = prop): T +} + +open class C { + open fun foo(x: T) = x +} + +@CompileTimeCalculation +class D(override val prop: Int): C(), I {} + +const val fooB1 = D(10).foo() +const val fooB2 = D(10).foo(-1)