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
}
}
}