All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.backend.wasm.lower.WasmVarargExpressionLowering.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.backend.wasm.lower

import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irComposite
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irInt
import org.jetbrains.kotlin.ir.builders.irTemporary
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrVararg
import org.jetbrains.kotlin.ir.expressions.IrVarargElement
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.primaryConstructor
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name

internal class WasmVarargExpressionLowering(
    private val context: WasmBackendContext
) : FileLoweringPass, IrElementTransformerVoidWithContext() {
    val symbols = context.wasmSymbols

    override fun lower(irFile: IrFile) {
        irFile.transformChildrenVoid(this)
    }

    override fun visitVararg(expression: IrVararg): IrExpression {
        val irVararg = super.visitVararg(expression) as IrVararg
        val builder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol)
        val arrayClass = irVararg.type.classOrNull!!.owner
        val primaryConstructor = arrayClass.primaryConstructor!!
        val setMethod = arrayClass.declarations.filterIsInstance().find {
            it.name == Name.identifier("set")
        }!!
        return builder.irComposite(irVararg) {
            val arrayTempVariable = irTemporary(
                value = irCall(primaryConstructor).apply {
                    putValueArgument(0, irInt(irVararg.elements.size))
                    if (primaryConstructor.typeParameters.isNotEmpty()) {
                        check(primaryConstructor.typeParameters.size == 1)
                        putTypeArgument(0, irVararg.varargElementType)
                    }
                },
                nameHint = "array_tmp"
            )
            for ((index: Int, element: IrVarargElement) in irVararg.elements.withIndex()) {
                check(element is IrExpression) {
                    "TODO: Support $element as vararg elements"
                }

                +irCall(setMethod).apply {
                    dispatchReceiver = irGet(arrayTempVariable)
                    putValueArgument(0, irInt(index))
                    putValueArgument(1, element)
                }
            }
            +irGet(arrayTempVariable)
        }
    }

    override fun visitFunctionAccess(expression: IrFunctionAccessExpression) =
        transformFunctionAccessExpression(expression)

    private fun transformFunctionAccessExpression(expression: IrFunctionAccessExpression): IrExpression {
        expression.transformChildrenVoid()
        val builder by lazy { context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol) }

        // Replace empty vararg arguments with empty array construction
        for (argumentIdx in 0 until expression.valueArgumentsCount) {
            val argument = expression.getValueArgument(argumentIdx)
            val parameter = expression.symbol.owner.valueParameters[argumentIdx]
            val varargElementType = parameter.varargElementType
            if (argument == null && varargElementType != null) {
                val arrayClass = parameter.type.classOrNull!!.owner
                val primaryConstructor = arrayClass.primaryConstructor!!
                val emptyArrayCall = with(builder) {
                    irCall(primaryConstructor).apply {
                        putValueArgument(0, irInt(0))
                        if (primaryConstructor.typeParameters.isNotEmpty()) {
                            check(primaryConstructor.typeParameters.size == 1)
                            putTypeArgument(0, parameter.varargElementType)
                        }
                    }
                }
                expression.putValueArgument(argumentIdx, emptyArrayCall)
            }
        }
        return expression
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy