[JS IR BE] Basic support for external varargs
This commit is contained in:
+1
@@ -391,6 +391,7 @@ class DefaultParameterCleaner constructor(val context: CommonBackendContext) : F
|
|||||||
// TODO this implementation is exponential
|
// TODO this implementation is exponential
|
||||||
private fun IrFunction.needsDefaultArgumentsLowering(skipInlineMethods: Boolean): Boolean {
|
private fun IrFunction.needsDefaultArgumentsLowering(skipInlineMethods: Boolean): Boolean {
|
||||||
if (isInline && skipInlineMethods) return false
|
if (isInline && skipInlineMethods) return false
|
||||||
|
if (isEffectivelyExternal()) return false
|
||||||
if (valueParameters.any { it.defaultValue != null }) return true
|
if (valueParameters.any { it.defaultValue != null }) return true
|
||||||
|
|
||||||
if (this !is IrSimpleFunction) return false
|
if (this !is IrSimpleFunction) return false
|
||||||
|
|||||||
+67
-5
@@ -162,9 +162,17 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
val targetName = context.getNameForSymbol(target.symbol)
|
val targetName = context.getNameForSymbol(target.symbol)
|
||||||
val qPrototype = JsNameRef(targetName, prototypeOf(qualifierName))
|
val qPrototype = JsNameRef(targetName, prototypeOf(qualifierName))
|
||||||
val callRef = JsNameRef(Namer.CALL_FUNCTION, qPrototype)
|
val callRef = JsNameRef(Namer.CALL_FUNCTION, qPrototype)
|
||||||
return JsInvocation(callRef, jsDispatchReceiver?.let { listOf(it) + arguments } ?: arguments)
|
return JsInvocation(callRef, jsDispatchReceiver?.let { receiver -> 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) {
|
return if (function is IrConstructor) {
|
||||||
// Inline class primary constructor takes a single value of to
|
// Inline class primary constructor takes a single value of to
|
||||||
// initialize underlying property.
|
// initialize underlying property.
|
||||||
@@ -177,12 +185,66 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
// Argument value constructs unboxed inline class instance
|
// Argument value constructs unboxed inline class instance
|
||||||
arguments.single()
|
arguments.single()
|
||||||
} else {
|
} else {
|
||||||
JsNew(context.getNameForSymbol(symbol).makeRef(), arguments)
|
JsNew(ref, arguments)
|
||||||
|
}
|
||||||
|
} else if (isExternalVararg) {
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// For this purpose are concatenating non-vararg arguments with vararg.
|
||||||
|
// TODO: Don't use `Function.prototype.apply` when number of arguments is known at compile time (e.g. there are no spread operators)
|
||||||
|
val arrayConcat = JsNameRef("concat", JsArrayLiteral())
|
||||||
|
val arraySliceCall = JsNameRef("call", JsNameRef("slice", JsArrayLiteral()))
|
||||||
|
|
||||||
|
val argumentsAsSingleArray = JsInvocation(
|
||||||
|
arrayConcat,
|
||||||
|
listOfNotNull(jsExtensionReceiver) + arguments.mapIndexed { index, argument ->
|
||||||
|
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 {
|
} else {
|
||||||
val symbolName = context.getNameForSymbol(symbol)
|
JsInvocation(ref, listOfNotNull(jsExtensionReceiver) + arguments)
|
||||||
val ref = if (jsDispatchReceiver != null) JsNameRef(symbolName, jsDispatchReceiver) else JsNameRef(symbolName)
|
|
||||||
JsInvocation(ref, jsExtensionReceiver?.let { listOf(jsExtensionReceiver) + arguments } ?: arguments)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1283
|
// EXPECTED_REACHABLE_NODES: 1283
|
||||||
// MODULE_KIND: AMD
|
// MODULE_KIND: AMD
|
||||||
@JsModule("bar")
|
@JsModule("bar")
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1281
|
// EXPECTED_REACHABLE_NODES: 1281
|
||||||
import Test.test
|
import Test.test
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1314
|
// EXPECTED_REACHABLE_NODES: 1314
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user