diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt index f0cc6287f14..0d30338a23c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt @@ -391,6 +391,7 @@ class DefaultParameterCleaner constructor(val context: CommonBackendContext) : F // TODO this implementation is exponential private fun IrFunction.needsDefaultArgumentsLowering(skipInlineMethods: Boolean): Boolean { if (isInline && skipInlineMethods) return false + if (isEffectivelyExternal()) return false if (valueParameters.any { it.defaultValue != null }) return true if (this !is IrSimpleFunction) return false diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt index a5410bdccac..a8f9b92d555 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt @@ -162,9 +162,17 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer listOf(receiver) + arguments } ?: arguments) } + val varargParameterIndex = function.valueParameters.indexOfFirst { it.varargElementType != null } + val isExternalVararg = function.isEffectivelyExternal() && varargParameterIndex != -1 + + val symbolName = context.getNameForSymbol(symbol) + val ref = if (function is IrSimpleFunction && jsDispatchReceiver != null) JsNameRef(symbolName, jsDispatchReceiver) else JsNameRef( + symbolName + ) + return if (function is IrConstructor) { // Inline class primary constructor takes a single value of to // initialize underlying property. @@ -177,12 +185,66 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer + when (index) { + + // Call `Array.prototype.slice` on vararg arguments in order to convert array-like objects into proper arrays + // TODO: Optimize for proper arrays + varargParameterIndex -> JsInvocation(arraySliceCall, argument) + + // TODO: Don't wrap non-array-like arguments with array literal + // TODO: Wrap adjacent non-vararg arguments in a single array literal + else -> JsArrayLiteral(listOf(argument)) + } + } + ) + + if (function is IrSimpleFunction && jsDispatchReceiver != null) { + // TODO: Do not create IIFE when receiver expression is simple or has no side effects + // TODO: Do not create IIFE at all? (Currently there is no reliable way to create temporary variable in current scope) + val receiverName = context.currentScope.declareFreshName("\$externalVarargReceiverTmp") + val receiverRef = receiverName.makeRef() + JsInvocation( + // Create scope for temporary variable holding dispatch receiver + // It is used both during method reference and passing `this` value to `apply` function. + JsFunction( + context.currentScope, + JsBlock( + JsVars(JsVars.JsVar(receiverName, jsDispatchReceiver)), + JsReturn( + JsInvocation( + JsNameRef("apply", JsNameRef(symbolName, receiverRef)), + listOf( + receiverRef, + argumentsAsSingleArray + ) + ) + ) + ), + "VarargIIFE" + ) + ) + } else { + JsInvocation( + JsNameRef("apply", JsNameRef(symbolName)), + listOf(JsNullLiteral(), argumentsAsSingleArray) + ) } } else { - val symbolName = context.getNameForSymbol(symbol) - val ref = if (jsDispatchReceiver != null) JsNameRef(symbolName, jsDispatchReceiver) else JsNameRef(symbolName) - JsInvocation(ref, jsExtensionReceiver?.let { listOf(jsExtensionReceiver) + arguments } ?: arguments) + JsInvocation(ref, listOfNotNull(jsExtensionReceiver) + arguments) } } diff --git a/js/js.translator/testData/box/jsModule/topLevelVarargFun.kt b/js/js.translator/testData/box/jsModule/topLevelVarargFun.kt index c830c4800fd..ef9f66f25d1 100644 --- a/js/js.translator/testData/box/jsModule/topLevelVarargFun.kt +++ b/js/js.translator/testData/box/jsModule/topLevelVarargFun.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // EXPECTED_REACHABLE_NODES: 1283 // MODULE_KIND: AMD @JsModule("bar") diff --git a/js/js.translator/testData/box/native/objectFunWithVararg.kt b/js/js.translator/testData/box/native/objectFunWithVararg.kt index f7dec09bffd..94433915ba8 100644 --- a/js/js.translator/testData/box/native/objectFunWithVararg.kt +++ b/js/js.translator/testData/box/native/objectFunWithVararg.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // EXPECTED_REACHABLE_NODES: 1281 import Test.test diff --git a/js/js.translator/testData/box/native/vararg.kt b/js/js.translator/testData/box/native/vararg.kt index 2d6ca57542b..17e268149fc 100644 --- a/js/js.translator/testData/box/native/vararg.kt +++ b/js/js.translator/testData/box/native/vararg.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // EXPECTED_REACHABLE_NODES: 1314 package foo