[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
|
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 {
|
override fun visitStringConcatenation(expression: IrStringConcatenation, data: VisitData): VisitResult {
|
||||||
var decomposed = 0
|
var decomposed = 0
|
||||||
|
|
||||||
|
|||||||
+47
@@ -19,6 +19,53 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
|||||||
|
|
||||||
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
|
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 =
|
override fun visitExpressionBody(body: IrExpressionBody, context: JsGenerationContext): JsExpression =
|
||||||
body.expression.accept(this, context)
|
body.expression.accept(this, context)
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ object Namer {
|
|||||||
val CALL_FUNCTION = "call"
|
val CALL_FUNCTION = "call"
|
||||||
val APPLY_FUNCTION = "apply"
|
val APPLY_FUNCTION = "apply"
|
||||||
|
|
||||||
|
val SLICE_FUNCTION = "slice"
|
||||||
|
val CONCAT_FUNCTION = "concat"
|
||||||
|
|
||||||
val UNREACHABLE_NAME = "\$unreachable"
|
val UNREACHABLE_NAME = "\$unreachable"
|
||||||
|
|
||||||
val OUTER_FIELD_NAME = "\$outer"
|
val OUTER_FIELD_NAME = "\$outer"
|
||||||
|
|||||||
Reference in New Issue
Block a user