Fix for KT-26164 (#1954)

This commit is contained in:
Sergey Bogolepov
2018-08-28 15:01:58 +03:00
committed by GitHub
parent aee041fc7a
commit 31e64442d7
2 changed files with 26 additions and 22 deletions
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.getDefault import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
@@ -34,11 +34,9 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructor
@@ -313,12 +311,12 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private class ParameterToArgument(val parameterDescriptor: ParameterDescriptor, private class ParameterToArgument(val parameter: IrValueParameter,
val argumentExpression : IrExpression) { val argumentExpression : IrExpression) {
val isInlinableLambdaArgument : Boolean val isInlinableLambdaArgument : Boolean
get() { get() {
if (!InlineUtil.isInlineParameter(parameterDescriptor)) return false if (!InlineUtil.isInlineParameter(parameter.descriptor)) return false
if (argumentExpression is IrFunctionReference if (argumentExpression is IrFunctionReference
&& !argumentExpression.descriptor.isSuspend) return true // Skip suspend functions for now since it's not supported by FE anyway. && !argumentExpression.descriptor.isSuspend) return true // Skip suspend functions for now since it's not supported by FE anyway.
@@ -347,21 +345,20 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
): List<ParameterToArgument> { ): List<ParameterToArgument> {
val parameterToArgument = mutableListOf<ParameterToArgument>() // Result list. val parameterToArgument = mutableListOf<ParameterToArgument>() // Result list.
val functionDescriptor = irFunction.descriptor.original // Descriptor of function to be called.
if (irCall.dispatchReceiver != null && // Only if there are non null dispatch receivers both if (irCall.dispatchReceiver != null && // Only if there are non null dispatch receivers both
functionDescriptor.dispatchReceiverParameter != null) // on call site and in function declaration. irFunction.dispatchReceiverParameter != null) // on call site and in function declaration.
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameterDescriptor = functionDescriptor.dispatchReceiverParameter!!, parameter = irFunction.dispatchReceiverParameter!!,
argumentExpression = irCall.dispatchReceiver!! argumentExpression = irCall.dispatchReceiver!!
) )
val valueArguments = val valueArguments =
irCall.descriptor.valueParameters.map { irCall.getValueArgument(it) }.toMutableList() irCall.descriptor.valueParameters.map { irCall.getValueArgument(it) }.toMutableList()
if (functionDescriptor.extensionReceiverParameter != null) { if (irFunction.extensionReceiverParameter != null) {
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameterDescriptor = functionDescriptor.extensionReceiverParameter!!, parameter = irFunction.extensionReceiverParameter!!,
argumentExpression = if (irCall.extensionReceiver != null) { argumentExpression = if (irCall.extensionReceiver != null) {
irCall.extensionReceiver!! irCall.extensionReceiver!!
} else { } else {
@@ -376,25 +373,25 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>() val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
irFunction.valueParameters.forEach { parameter -> // Iterate value parameters. irFunction.valueParameters.forEach { parameter -> // Iterate value parameters.
val parameterDescriptor = parameter.descriptor as ValueParameterDescriptor val argument = valueArguments[parameter.index] // Get appropriate argument from call site.
val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site.
when { when {
argument != null -> { // Argument is good enough. argument != null -> { // Argument is good enough.
parameterToArgument += ParameterToArgument( // Associate current parameter with the argument. parameterToArgument += ParameterToArgument( // Associate current parameter with the argument.
parameterDescriptor = parameterDescriptor, parameter = parameter,
argumentExpression = argument argumentExpression = argument
) )
} }
parameterDescriptor.hasDefaultValue() -> { // There is no argument - try default value. // After ExpectDeclarationsRemoving pass default values from expect declarations
val defaultArgument = irFunction.getDefault(parameterDescriptor)!! // are represented correctly in IR.
parameter.defaultValue != null -> { // There is no argument - try default value.
parametersWithDefaultToArgument += ParameterToArgument( parametersWithDefaultToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor, parameter = parameter,
argumentExpression = defaultArgument.expression argumentExpression = parameter.defaultValue!!.expression
) )
} }
parameterDescriptor.varargElementType != null -> { parameter.varargElementType != null -> {
val emptyArray = IrVarargImpl( val emptyArray = IrVarargImpl(
startOffset = irCall.startOffset, startOffset = irCall.startOffset,
endOffset = irCall.endOffset, endOffset = irCall.endOffset,
@@ -402,14 +399,14 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
varargElementType = parameter.varargElementType!! varargElementType = parameter.varargElementType!!
) )
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor, parameter = parameter,
argumentExpression = emptyArray argumentExpression = emptyArray
) )
} }
else -> { else -> {
val message = "Incomplete expression: call to $functionDescriptor " + val message = "Incomplete expression: call to ${irFunction.descriptor} " +
"has no argument at index ${parameterDescriptor.index}" "has no argument at index ${parameter.index}"
throw Error(message) throw Error(message)
} }
} }
@@ -428,7 +425,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val evaluationStatements = mutableListOf<IrStatement>() // List of evaluation statements. val evaluationStatements = mutableListOf<IrStatement>() // List of evaluation statements.
val substitutor = ParameterSubstitutor() val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach { parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameterDescriptor val parameterDescriptor = it.parameter.descriptor
/* /*
* We need to create temporary variable for each argument except inlinable lambda arguments. * We need to create temporary variable for each argument except inlinable lambda arguments.
@@ -20,6 +20,7 @@ fun box() {
Test5().Inner().test() Test5().Inner().test()
42.test6() 42.test6()
assertEquals(inlineFunction("OK"), "OK,0,null")
} }
expect fun test1(x: Int = 42): Int expect fun test1(x: Int = 42): Int
@@ -66,3 +67,9 @@ expect fun Int.test6(arg: Int = this)
actual fun Int.test6(arg: Int) { actual fun Int.test6(arg: Int) {
assertEquals(arg, this) assertEquals(arg, this)
} }
// Default parameter in inline function.
expect inline fun inlineFunction(a: String, b: Int = 0, c: () -> Double? = { null }): String
actual inline fun inlineFunction(a: String, b: Int, c: () -> Double?): String = a + "," + b + "," + c()