[IR] Inliner: supported tricky function references
This includes references to functions with varargs and default arguments
This commit is contained in:
+43
-13
@@ -24,8 +24,7 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
|||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.isNullable
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
@@ -201,34 +200,65 @@ class FunctionInlining(val context: CommonBackendContext) : IrElementTransformer
|
|||||||
val unboundArgsSet = unboundFunctionParameters.toSet()
|
val unboundArgsSet = unboundFunctionParameters.toSet()
|
||||||
val valueParameters = expression.getArgumentsWithIr().drop(1) // Skip dispatch receiver.
|
val valueParameters = expression.getArgumentsWithIr().drop(1) // Skip dispatch receiver.
|
||||||
|
|
||||||
|
val superType = functionArgument.type as IrSimpleType
|
||||||
|
val superTypeArgumentsMap = expression.symbol.owner.parentAsClass.typeParameters.associate { typeParam ->
|
||||||
|
typeParam.symbol to superType.arguments[typeParam.index].typeOrNull!!
|
||||||
|
}
|
||||||
|
|
||||||
val immediateCall = with(expression) {
|
val immediateCall = with(expression) {
|
||||||
if (function is IrConstructor) {
|
if (function is IrConstructor) {
|
||||||
val classTypeParametersCount = function.parentAsClass.typeParameters.size
|
val classTypeParametersCount = function.parentAsClass.typeParameters.size
|
||||||
IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, function.returnType, function.symbol, classTypeParametersCount)
|
IrConstructorCallImpl.fromSymbolOwner(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
function.returnType,
|
||||||
|
function.symbol,
|
||||||
|
classTypeParametersCount
|
||||||
|
)
|
||||||
} else
|
} else
|
||||||
IrCallImpl(startOffset, endOffset, function.returnType, functionArgument.symbol)
|
IrCallImpl(startOffset, endOffset, function.returnType, functionArgument.symbol)
|
||||||
}.apply {
|
}.apply {
|
||||||
functionParameters.forEach {
|
for (parameter in functionParameters) {
|
||||||
val argument =
|
val argument =
|
||||||
if (unboundArgsSet.contains(it)) {
|
if (parameter !in unboundArgsSet) {
|
||||||
assert(unboundIndex < valueParameters.size) {
|
val arg = boundFunctionParametersMap[parameter]!!
|
||||||
"Attempt to use unbound parameter outside of the callee's value parameters"
|
|
||||||
}
|
|
||||||
valueParameters[unboundIndex++].second
|
|
||||||
} else {
|
|
||||||
val arg = boundFunctionParametersMap[it]!!
|
|
||||||
if (arg is IrGetValueWithoutLocation)
|
if (arg is IrGetValueWithoutLocation)
|
||||||
arg.withLocation(expression.startOffset, expression.endOffset)
|
arg.withLocation(expression.startOffset, expression.endOffset)
|
||||||
else arg
|
else arg
|
||||||
|
} else {
|
||||||
|
if (unboundIndex == valueParameters.size && parameter.defaultValue != null)
|
||||||
|
copyIrElement.copy(parameter.defaultValue!!.expression) as IrExpression
|
||||||
|
else if (!parameter.isVararg) {
|
||||||
|
assert(unboundIndex < valueParameters.size) {
|
||||||
|
"Attempt to use unbound parameter outside of the callee's value parameters"
|
||||||
|
}
|
||||||
|
valueParameters[unboundIndex++].second
|
||||||
|
} else {
|
||||||
|
val elements = mutableListOf<IrVarargElement>()
|
||||||
|
while (unboundIndex < valueParameters.size) {
|
||||||
|
val (param, value) = valueParameters[unboundIndex++]
|
||||||
|
val substitutedParamType = param.type.substitute(superTypeArgumentsMap)
|
||||||
|
if (substitutedParamType == parameter.varargElementType!!)
|
||||||
|
elements += value
|
||||||
|
else
|
||||||
|
elements += IrSpreadElementImpl(expression.startOffset, expression.endOffset, value)
|
||||||
|
}
|
||||||
|
IrVarargImpl(
|
||||||
|
expression.startOffset, expression.endOffset,
|
||||||
|
parameter.type,
|
||||||
|
parameter.varargElementType!!,
|
||||||
|
elements
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
when (it) {
|
when (parameter) {
|
||||||
function.dispatchReceiverParameter ->
|
function.dispatchReceiverParameter ->
|
||||||
this.dispatchReceiver = argument.implicitCastIfNeededTo(function.dispatchReceiverParameter!!.type)
|
this.dispatchReceiver = argument.implicitCastIfNeededTo(function.dispatchReceiverParameter!!.type)
|
||||||
|
|
||||||
function.extensionReceiverParameter ->
|
function.extensionReceiverParameter ->
|
||||||
this.extensionReceiver = argument.implicitCastIfNeededTo(function.extensionReceiverParameter!!.type)
|
this.extensionReceiver = argument.implicitCastIfNeededTo(function.extensionReceiverParameter!!.type)
|
||||||
|
|
||||||
else -> putValueArgument(it.index, argument.implicitCastIfNeededTo(function.valueParameters[it.index].type))
|
else -> putValueArgument(parameter.index, argument.implicitCastIfNeededTo(function.valueParameters[parameter.index].type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(unboundIndex == valueParameters.size) { "Not all arguments of the callee are used" }
|
assert(unboundIndex == valueParameters.size) { "Not all arguments of the callee are used" }
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ val IrType.classifierOrNull: IrClassifierSymbol?
|
|||||||
val IrType.classOrNull: IrClassSymbol?
|
val IrType.classOrNull: IrClassSymbol?
|
||||||
get() = classifierOrNull as? IrClassSymbol
|
get() = classifierOrNull as? IrClassSymbol
|
||||||
|
|
||||||
|
val IrTypeArgument.typeOrNull: IrType? get() = (this as? IrTypeProjection)?.type
|
||||||
|
|
||||||
fun IrType.makeNotNull() =
|
fun IrType.makeNotNull() =
|
||||||
if (this is IrSimpleType && this.hasQuestionMark) {
|
if (this is IrSimpleType && this.hasQuestionMark) {
|
||||||
buildSimpleType {
|
buildSimpleType {
|
||||||
|
|||||||
Reference in New Issue
Block a user