[JS IR BE] Implement vararg in JS BE
This commit is contained in:
+41
@@ -526,6 +526,47 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : FunctionLowerin
|
||||
return KeptResult
|
||||
}
|
||||
|
||||
override fun visitVararg(expression: IrVararg, data: VisitData): VisitResult {
|
||||
var decomposed = 0
|
||||
|
||||
val arguments = expression.elements.map {
|
||||
val expr = (it as? IrSpreadElement)?.expression ?: it as IrExpression
|
||||
Pair(it, expr.accept(this, data).applyIfChanged { decomposed++ })
|
||||
}
|
||||
|
||||
if (decomposed == 0) return KeptResult
|
||||
|
||||
val newStatements = mutableListOf<IrStatement>()
|
||||
val newArguments = arguments.map { (original, result) ->
|
||||
if (decomposed == 0) original
|
||||
else {
|
||||
val originalExpression = (original as? IrSpreadElement)?.expression ?: original as IrExpression
|
||||
val newExpression = result.runIfChangedOrDefault(originalExpression) {
|
||||
newStatements += statements
|
||||
decomposed--
|
||||
resultValue
|
||||
}
|
||||
val wrapVar = makeTempVar(expression.varargElementType)
|
||||
newStatements += JsIrBuilder.buildVar(wrapVar).apply { initializer = newExpression }
|
||||
val newValue = JsIrBuilder.buildGetValue(wrapVar)
|
||||
if (original is IrSpreadElement) {
|
||||
IrSpreadElementImpl(original.startOffset, original.endOffset, newValue)
|
||||
} else {
|
||||
newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val newExpression = IrVarargImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
expression.type,
|
||||
expression.varargElementType,
|
||||
newArguments)
|
||||
|
||||
return DecomposedResult(newStatements, newExpression)
|
||||
}
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: VisitData): VisitResult {
|
||||
var decomposed = 0
|
||||
|
||||
|
||||
+47
@@ -19,6 +19,53 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
|
||||
|
||||
override fun visitVararg(expression: IrVararg, context: JsGenerationContext): JsExpression {
|
||||
// TODO: perform the dark magic below in the separated lowering
|
||||
if (expression.elements.size == 1) {
|
||||
val element = expression.elements[0]
|
||||
if (element is IrSpreadElement) {
|
||||
// special case, invoke slice()
|
||||
val expr = element.expression.accept(this, context)
|
||||
return JsInvocation(JsNameRef(Namer.SLICE_FUNCTION, expr))
|
||||
}
|
||||
}
|
||||
|
||||
var arrayLiteralElements = mutableListOf<JsExpression>()
|
||||
val concatArguments = mutableListOf<JsExpression>()
|
||||
var qualifier: JsExpression? = null
|
||||
|
||||
expression.elements.forEach {
|
||||
if (it is IrSpreadElement) {
|
||||
val expr = it.expression.accept(this, context)
|
||||
if (qualifier == null) {
|
||||
if (arrayLiteralElements.isEmpty()) {
|
||||
qualifier = JsNameRef(Namer.CONCAT_FUNCTION, expr)
|
||||
} else {
|
||||
val dispatch = JsArrayLiteral(arrayLiteralElements)
|
||||
arrayLiteralElements = mutableListOf()
|
||||
qualifier = JsNameRef(Namer.CONCAT_FUNCTION, dispatch)
|
||||
concatArguments.add(expr)
|
||||
}
|
||||
} else {
|
||||
if (arrayLiteralElements.isNotEmpty()) {
|
||||
concatArguments.add(JsArrayLiteral(arrayLiteralElements))
|
||||
arrayLiteralElements = mutableListOf()
|
||||
}
|
||||
concatArguments.add(expr)
|
||||
}
|
||||
} else {
|
||||
arrayLiteralElements.add(it.accept(this, context))
|
||||
}
|
||||
}
|
||||
|
||||
return qualifier?.let {
|
||||
if (arrayLiteralElements.isNotEmpty()) {
|
||||
concatArguments.add(JsArrayLiteral(arrayLiteralElements))
|
||||
}
|
||||
return JsInvocation(it, concatArguments)
|
||||
} ?: JsArrayLiteral(arrayLiteralElements)
|
||||
}
|
||||
|
||||
override fun visitExpressionBody(body: IrExpressionBody, context: JsGenerationContext): JsExpression =
|
||||
body.expression.accept(this, context)
|
||||
|
||||
|
||||
@@ -34,6 +34,9 @@ object Namer {
|
||||
val CALL_FUNCTION = "call"
|
||||
val APPLY_FUNCTION = "apply"
|
||||
|
||||
val SLICE_FUNCTION = "slice"
|
||||
val CONCAT_FUNCTION = "concat"
|
||||
|
||||
val UNREACHABLE_NAME = "\$unreachable"
|
||||
|
||||
val OUTER_FIELD_NAME = "\$outer"
|
||||
|
||||
Reference in New Issue
Block a user