[JS IR] Use one concat elements for non vararg and vararg arguments

^KT-42357 fixed
This commit is contained in:
Ilya Goncharov
2020-11-23 15:21:06 +03:00
parent 67e4b0948e
commit 995d96e5a3
2 changed files with 25 additions and 19 deletions
@@ -160,7 +160,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
if (varargParameterIndex == -1) { if (varargParameterIndex == -1) {
JsNew(refForExternalClass, arguments) JsNew(refForExternalClass, arguments)
} else { } else {
val argumentsAsSingleArray = argumentsAsSingleArray( val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
JsNullLiteral(), JsNullLiteral(),
arguments, arguments,
varargParameterIndex varargParameterIndex
@@ -137,7 +137,7 @@ fun translateCall(
return if (isExternalVararg) { return if (isExternalVararg) {
// TODO: Don't use `Function.prototype.apply` when number of arguments is known at compile time (e.g. there are no spread operators) // TODO: Don't use `Function.prototype.apply` when number of arguments is known at compile time (e.g. there are no spread operators)
val argumentsAsSingleArray = argumentsAsSingleArray( val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
jsExtensionReceiver, jsExtensionReceiver,
arguments, arguments,
varargParameterIndex varargParameterIndex
@@ -183,21 +183,18 @@ fun translateCall(
} }
} }
internal fun argumentsAsSingleArray( fun argumentsWithVarargAsSingleArray(
additionalReceiver: JsExpression?, additionalReceiver: JsExpression?,
arguments: List<JsExpression>, arguments: List<JsExpression>,
varargParameterIndex: Int? varargParameterIndex: Int,
): JsExpression { ): JsExpression {
// External vararg arguments should be represented in JS as multiple "plain" arguments (opposed to arrays in Kotlin) // External vararg arguments should be represented in JS as multiple "plain" arguments (opposed to arrays in Kotlin)
// We are using `Function.prototype.apply` function to pass all arguments as a single array. // We are using `Function.prototype.apply` function to pass all arguments as a single array.
// For this purpose are concatenating non-vararg arguments with vararg. // For this purpose are concatenating non-vararg arguments with vararg.
var varargArgument: JsExpression? = null var arraysForConcat: MutableList<JsExpression> = mutableListOf<JsExpression>().apply {
val additionalSize = additionalReceiver?.let { 1 } ?: 0 additionalReceiver?.let { add(it) }
// size + 1 because arguments size + potential additionalReceiver }
val nonVarArgs: MutableList<JsExpression> = val concatElements: MutableList<JsExpression> = mutableListOf()
ArrayList<JsExpression>(arguments.size + additionalSize).apply {
additionalReceiver?.let { add(it) }
}
arguments arguments
.forEachIndexed { index, argument -> .forEachIndexed { index, argument ->
@@ -205,25 +202,34 @@ internal fun argumentsAsSingleArray(
// Call `Array.prototype.slice` on vararg arguments in order to convert array-like objects into proper arrays // Call `Array.prototype.slice` on vararg arguments in order to convert array-like objects into proper arrays
varargParameterIndex -> { varargParameterIndex -> {
varargArgument = if (argument is JsArrayLiteral) { concatElements.add(JsArrayLiteral(arraysForConcat))
arraysForConcat = mutableListOf()
val varargArgument = if (argument is JsArrayLiteral) {
argument argument
} else { } else {
val arraySliceCall = JsNameRef("call", JsNameRef("slice", JsArrayLiteral())) val arraySliceCall = JsNameRef("call", JsNameRef("slice", JsArrayLiteral()))
JsInvocation(arraySliceCall, argument) JsInvocation(arraySliceCall, argument)
} }
concatElements.add(varargArgument)
} }
else -> nonVarArgs.add(argument) else -> {
arraysForConcat.add(argument)
}
} }
} }
val nonVarArgArrayLiteral = JsArrayLiteral(nonVarArgs) if (arraysForConcat.isNotEmpty() || concatElements.isEmpty()) {
return varargArgument?.let { concatElements.add(JsArrayLiteral(arraysForConcat))
JsInvocation( }
JsNameRef("concat", nonVarArgArrayLiteral),
it return concatElements.singleOrNull()
?: JsInvocation(
JsNameRef("concat", concatElements.first()),
concatElements.drop(1)
) )
} ?: nonVarArgArrayLiteral
} }
fun IrFunction.varargParameterIndex() = valueParameters.indexOfFirst { it.varargElementType != null } fun IrFunction.varargParameterIndex() = valueParameters.indexOfFirst { it.varargElementType != null }