From 7a5e8b43161fcd0899e66330228d193246229815 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Wed, 18 Dec 2019 17:24:55 +0300 Subject: [PATCH] [IR] Inliner: supported tricky function references This includes references to functions with varargs and default arguments --- .../common/lower/inline/FunctionInlining.kt | 56 ++++++++++++++----- .../org/jetbrains/kotlin/ir/types/irTypes.kt | 2 + 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt index 27965a00d44..43f1a362686 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt @@ -24,8 +24,7 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.isNullable +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitor @@ -201,34 +200,65 @@ class FunctionInlining(val context: CommonBackendContext) : IrElementTransformer val unboundArgsSet = unboundFunctionParameters.toSet() 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) { if (function is IrConstructor) { 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 IrCallImpl(startOffset, endOffset, function.returnType, functionArgument.symbol) }.apply { - functionParameters.forEach { + for (parameter in functionParameters) { val argument = - if (unboundArgsSet.contains(it)) { - assert(unboundIndex < valueParameters.size) { - "Attempt to use unbound parameter outside of the callee's value parameters" - } - valueParameters[unboundIndex++].second - } else { - val arg = boundFunctionParametersMap[it]!! + if (parameter !in unboundArgsSet) { + val arg = boundFunctionParametersMap[parameter]!! if (arg is IrGetValueWithoutLocation) arg.withLocation(expression.startOffset, expression.endOffset) 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() + 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 -> this.dispatchReceiver = argument.implicitCastIfNeededTo(function.dispatchReceiverParameter!!.type) function.extensionReceiverParameter -> 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" } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypes.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypes.kt index c9c7b80630f..aeafdde1f22 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypes.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypes.kt @@ -43,6 +43,8 @@ val IrType.classifierOrNull: IrClassifierSymbol? val IrType.classOrNull: IrClassSymbol? get() = classifierOrNull as? IrClassSymbol +val IrTypeArgument.typeOrNull: IrType? get() = (this as? IrTypeProjection)?.type + fun IrType.makeNotNull() = if (this is IrSimpleType && this.hasQuestionMark) { buildSimpleType {