fun convertFunctionDeclaration()

in compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt [1940:2113]


    fun convertFunctionDeclaration(functionDeclaration: LighterASTNode): FirStatement {
        var modifiers: ModifierList? = null
        var identifier: String? = null
        var valueParametersList: LighterASTNode? = null
        var isReturnType = false
        var receiverTypeNode: LighterASTNode? = null
        var returnType: FirTypeRef? = null
        val typeConstraints = mutableListOf<TypeConstraint>()
        var block: LighterASTNode? = null
        var expression: LighterASTNode? = null
        var hasEqToken = false
        var typeParameterList: LighterASTNode? = null
        var outerContractDescription: FirContractDescription? = null
        functionDeclaration.getChildNodeByType(IDENTIFIER)?.let {
            identifier = it.asText
        }

        val isLocal = isCallableLocal(functionDeclaration) { getParent() }
        val functionSource = functionDeclaration.toFirSourceElement()
        val isAnonymousFunction = identifier == null && isLocal
        val functionName = identifier.nameAsSafeName()
        val functionSymbol: FirFunctionSymbol<*> = if (isAnonymousFunction) {
            FirAnonymousFunctionSymbol()
        } else {
            FirNamedFunctionSymbol(callableIdForName(functionName))
        }

        withContainerSymbol(functionSymbol, isLocal) {
            val target: FirFunctionTarget
            functionDeclaration.forEachChildren {
                when (it.tokenType) {
                    MODIFIER_LIST -> {
                        modifiers = convertModifierList(it)
                    }
                    TYPE_PARAMETER_LIST -> typeParameterList = it
                    VALUE_PARAMETER_LIST -> valueParametersList = it //must convert later, because it can contain "return"
                    COLON -> isReturnType = true
                    TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverTypeNode = it
                    TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
                    CONTRACT_EFFECT_LIST -> outerContractDescription = obtainContractDescription(it)
                    BLOCK -> block = it
                    EQ -> hasEqToken = true
                    else -> if (it.isExpression()) expression = it
                }
            }

            val calculatedModifiers = modifiers ?: ModifierList()

            if (returnType == null) {
                returnType =
                    if (block != null || !hasEqToken) implicitUnitType
                    else implicitType
            }

            val receiverTypeCalculator = receiverTypeNode?.let { { convertType(it) } }
            val functionBuilder = if (isAnonymousFunction) {
                FirAnonymousFunctionBuilder().apply {
                    source = functionSource
                    receiverParameter = receiverTypeCalculator?.let { createReceiverParameter(it, baseModuleData, functionSymbol) }
                    symbol = functionSymbol as FirAnonymousFunctionSymbol
                    isLambda = false
                    hasExplicitParameterList = true
                    label = context.getLastLabel(functionDeclaration)
                    val labelName = label?.name ?: context.calleeNamesForLambda.lastOrNull()?.identifier
                    target = FirFunctionTarget(labelName = labelName, isLambda = false)

                    val isExpect = calculatedModifiers.hasExpect() || context.containerIsExpect
                    val isActual = calculatedModifiers.hasActual()
                    val isOverride = calculatedModifiers.hasOverride()
                    val isOperator = calculatedModifiers.hasOperator()
                    val isInfix = calculatedModifiers.hasInfix()
                    val isInline = calculatedModifiers.hasInline()
                    val isTailRec = calculatedModifiers.hasTailrec()
                    val isExternal = calculatedModifiers.hasExternal()
                    val isSuspend = calculatedModifiers.hasSuspend()

                    if (isExpect || isActual || isOverride || isOperator || isInfix || isInline || isTailRec || isExternal || isSuspend) {
                        status = FirResolvedDeclarationStatusImpl.DEFAULT_STATUS_FOR_STATUSLESS_DECLARATIONS.copy(
                            isExpect = isExpect,
                            isActual = isActual,
                            isOverride = isOverride,
                            isOperator = isOperator,
                            isInfix = isInfix,
                            isInline = isInline,
                            isTailRec = isTailRec,
                            isExternal = isExternal,
                            isSuspend = isSuspend,
                        )
                    }
                }
            } else {
                val labelName =
                    context.getLastLabel(functionDeclaration)?.name ?: runIf(!functionName.isSpecial) { functionName.identifier }
                target = FirFunctionTarget(labelName, isLambda = false)
                FirNamedFunctionBuilder().apply {
                    source = functionSource
                    receiverParameter = receiverTypeCalculator?.let { createReceiverParameter(it, baseModuleData, functionSymbol) }
                    name = functionName
                    this.isLocal = context.inLocalContext
                    status = FirDeclarationStatusImpl(
                        if (isLocal) Visibilities.Local else calculatedModifiers.getVisibility(),
                        calculatedModifiers.getModality(isClassOrObject = false)
                    ).apply {
                        isExpect = calculatedModifiers.hasExpect() || context.containerIsExpect
                        isActual = calculatedModifiers.hasActual()
                        isOverride = calculatedModifiers.hasOverride()
                        isOperator = calculatedModifiers.hasOperator()
                        isInfix = calculatedModifiers.hasInfix()
                        isInline = calculatedModifiers.hasInline()
                        isTailRec = calculatedModifiers.hasTailrec()
                        isExternal = calculatedModifiers.hasExternal()
                        isSuspend = calculatedModifiers.hasSuspend()
                    }

                    symbol = functionSymbol as FirNamedFunctionSymbol
                    dispatchReceiverType = runIf(!isLocal) { currentDispatchReceiverType() }
                }
            }

            val firTypeParameters = mutableListOf<FirTypeParameter>()
            typeParameterList?.let { firTypeParameters += convertTypeParameters(it, typeConstraints, functionSymbol) }

            val function = functionBuilder.apply {
                moduleData = baseModuleData
                origin = FirDeclarationOrigin.Source
                returnTypeRef = returnType

                context.firFunctionTargets += target
                modifiers?.convertAnnotationsTo(annotations)
                typeParameters += firTypeParameters

                withCapturedTypeParameters(true, functionSource, typeParameters) {
                    contextParameters.addContextParameters(modifiers?.contextLists, functionSymbol)

                    valueParametersList?.let { list ->
                        valueParameters += convertValueParameters(
                            list,
                            functionSymbol,
                            if (isAnonymousFunction) ValueParameterDeclaration.LAMBDA else ValueParameterDeclaration.FUNCTION
                        ).map { it.firValueParameter }
                    }

                    val allowLegacyContractDescription = outerContractDescription == null
                    val bodyWithContractDescription = withForcedLocalContext(
                        forceKeepingTheBodyInHeaderMode = functionBuilder.status.isInline || functionBuilder.returnTypeRef is FirImplicitTypeRef
                    ) {
                        convertFunctionBody(block, expression, allowLegacyContractDescription)
                    }
                    this.body = bodyWithContractDescription.first
                    val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
                    contractDescription?.let {
                        if (this is FirNamedFunctionBuilder) {
                            this.contractDescription = it
                        } else if (this is FirAnonymousFunctionBuilder) {
                            this.contractDescription = it
                        }
                    }
                }
                context.firFunctionTargets.removeLast()
            }.build().also {
                target.bind(it)
                fillDanglingConstraintsTo(firTypeParameters, typeConstraints, it)
            }

            return if (function is FirAnonymousFunction) {
                buildAnonymousFunctionExpression {
                    source = functionSource
                    anonymousFunction = function
                }
            } else {
                function
            }
        }
    }