Implement better support for default args in interpreter
Now supported default args: 1. from super class or interface; 2. with field access, declared in interface; 3. with field access, declared in outer class.
This commit is contained in:
committed by
TeamCityServer
parent
42ea17b151
commit
b150cc9537
+26
-4
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
+50
@@ -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 = <!EVALUATED: `6`!>sum()<!>
|
||||
const val sum2 = <!EVALUATED: `1`!>sum(b = -3)<!>
|
||||
const val sum3 = <!EVALUATED: `3`!>sum(c = 1, a = 1, b = 1)<!>
|
||||
|
||||
const val sumBasedOnPrevious1 = <!EVALUATED: `7`!>sumBasedOnPrevious()<!>
|
||||
const val sumBasedOnPrevious2 = <!EVALUATED: `3`!>sumBasedOnPrevious(b = 1, c = 1)<!>
|
||||
|
||||
const val sumInInterfaceDefault1 = B().<!EVALUATED: `42`!>foo(1)<!>
|
||||
const val sumInInterfaceDefault2 = B().<!EVALUATED: `4`!>foo(x = 1, y = 2)<!>
|
||||
const val sumInInterfaceDefault3 = B().<!EVALUATED: `-1`!>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().<!EVALUATED: `100`!>withInner(100)<!>
|
||||
const val inner2 = Outer().Inner().<!EVALUATED: `-1`!>withInner()<!>
|
||||
const val inner3 = Outer().Inner().<!EVALUATED: `100`!>withOuter(100)<!>
|
||||
const val inner4 = Outer().Inner().<!EVALUATED: `-2`!>withOuter()<!>
|
||||
const val inner5 = Outer().Inner().<!EVALUATED: `100`!>withGlobal(100)<!>
|
||||
const val inner6 = Outer().Inner().<!EVALUATED: `0`!>withGlobal()<!>
|
||||
|
||||
@CompileTimeCalculation
|
||||
interface I<T> {
|
||||
val prop: T
|
||||
|
||||
fun foo(x: T = prop): T
|
||||
}
|
||||
|
||||
open class C<T> {
|
||||
open fun foo(x: T) = x
|
||||
}
|
||||
|
||||
@CompileTimeCalculation
|
||||
class D(override val prop: Int): C<Int>(), I<Int> {}
|
||||
|
||||
const val fooB1 = D(10).<!EVALUATED: `10`!>foo()<!>
|
||||
const val fooB2 = D(10).<!EVALUATED: `-1`!>foo(-1)<!>
|
||||
|
||||
Reference in New Issue
Block a user