Skip to content

Commit 4a33595

Browse files
committed
Elide function / method bodies in LT2FIR during header compilation.
^KT-78422
1 parent 535e938 commit 4a33595

File tree

3 files changed

+44
-21
lines changed

3 files changed

+44
-21
lines changed

compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
5757
import org.jetbrains.kotlin.util.getChildren
5858
import org.jetbrains.kotlin.utils.addToStdlib.runIf
5959
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
60+
import org.jetbrains.kotlin.config.AnalysisFlags
6061

6162
class LightTreeRawFirDeclarationBuilder(
6263
session: FirSession,
@@ -66,6 +67,7 @@ class LightTreeRawFirDeclarationBuilder(
6667
) : AbstractLightTreeRawFirBuilder(session, tree, context) {
6768

6869
private val expressionConverter = LightTreeRawFirExpressionBuilder(session, tree, this, context)
70+
private val headerMode = session.languageVersionSettings.getFlag(AnalysisFlags.headerMode)
6971

7072
/**
7173
* [org.jetbrains.kotlin.parsing.KotlinParsing.parseFile]
@@ -134,21 +136,23 @@ class LightTreeRawFirDeclarationBuilder(
134136
/**
135137
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlockExpression
136138
*/
137-
fun convertBlockExpression(block: LighterASTNode): FirBlock {
138-
return convertBlockExpressionWithoutBuilding(block).build()
139+
fun convertBlockExpression(block: LighterASTNode, generateHeader: Boolean = false): FirBlock {
140+
return convertBlockExpressionWithoutBuilding(block, generateHeader = generateHeader).build()
139141
}
140142

141-
fun convertBlockExpressionWithoutBuilding(block: LighterASTNode, kind: KtFakeSourceElementKind? = null): FirBlockBuilder {
143+
fun convertBlockExpressionWithoutBuilding(block: LighterASTNode, kind: KtFakeSourceElementKind? = null, generateHeader: Boolean = false): FirBlockBuilder {
142144
val firStatements = block.forEachChildrenReturnList { node, container ->
143-
when (node.tokenType) {
144-
CLASS, OBJECT_DECLARATION -> container += convertClass(node) as FirStatement
145-
FUN -> container += convertFunctionDeclaration(node)
146-
KtNodeTypes.PROPERTY -> container += convertPropertyDeclaration(node) as FirStatement
147-
DESTRUCTURING_DECLARATION -> container +=
148-
convertDestructingDeclaration(node).toFirDestructingDeclaration(this, baseModuleData)
149-
TYPEALIAS -> container += convertTypeAlias(node) as FirStatement
150-
CLASS_INITIALIZER -> shouldNotBeCalled("CLASS_INITIALIZER expected to be processed during class body conversion")
151-
else -> if (node.isExpression()) container += expressionConverter.getAsFirStatement(node)
145+
if (!generateHeader || container.isEmpty()) { // Take only the first statement which could be a contract for header generation.
146+
when (node.tokenType) {
147+
CLASS, OBJECT_DECLARATION -> container += convertClass(node) as FirStatement
148+
FUN -> container += convertFunctionDeclaration(node)
149+
KtNodeTypes.PROPERTY -> container += convertPropertyDeclaration(node) as FirStatement
150+
DESTRUCTURING_DECLARATION -> container +=
151+
convertDestructingDeclaration(node).toFirDestructingDeclaration(this, baseModuleData)
152+
TYPEALIAS -> container += convertTypeAlias(node) as FirStatement
153+
CLASS_INITIALIZER -> shouldNotBeCalled("CLASS_INITIALIZER expected to be processed during class body conversion")
154+
else -> if (node.isExpression()) container += expressionConverter.getAsFirStatement(node)
155+
}
152156
}
153157
}
154158
return FirBlockBuilder().apply {
@@ -688,7 +692,9 @@ class LightTreeRawFirDeclarationBuilder(
688692
}
689693
}
690694
}.also {
691-
it.isFromInlineFunction = context.containedWithinInlineFunction
695+
if (context.containedWithinInlineFunction) {
696+
it.isFromInlineFunction = true
697+
}
692698
if (classNode.getParent()?.elementType == KtStubElementTypes.CLASS_BODY) {
693699
it.initContainingClassForLocalAttr()
694700
}
@@ -2061,8 +2067,9 @@ class LightTreeRawFirDeclarationBuilder(
20612067

20622068
val allowLegacyContractDescription = outerContractDescription == null
20632069
val containedWithinInlineFunction = context.containedWithinInlineFunction || functionBuilder.status.isInline
2070+
val generateHeaders = headerMode && !containedWithinInlineFunction && (returnTypeRef !is FirImplicitTypeRef)
20642071
val bodyWithContractDescription = withForcedLocalContext(containedWithinInlineFunction) {
2065-
convertFunctionBody(block, expression, allowLegacyContractDescription)
2072+
convertFunctionBody(block, expression, allowLegacyContractDescription, generateHeaders)
20662073
}
20672074
this.body = bodyWithContractDescription.first
20682075
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
@@ -2076,7 +2083,9 @@ class LightTreeRawFirDeclarationBuilder(
20762083
}
20772084
context.firFunctionTargets.removeLast()
20782085
}.build().also {
2079-
it.isFromInlineFunction = context.containedWithinInlineFunction
2086+
if (context.containedWithinInlineFunction) {
2087+
it.isFromInlineFunction = true
2088+
}
20802089
target.bind(it)
20812090
fillDanglingConstraintsTo(firTypeParameters, typeConstraints, it)
20822091
}
@@ -2100,11 +2109,12 @@ class LightTreeRawFirDeclarationBuilder(
21002109
private fun convertFunctionBody(
21012110
blockNode: LighterASTNode?,
21022111
expression: LighterASTNode?,
2103-
allowLegacyContractDescription: Boolean
2112+
allowLegacyContractDescription: Boolean,
2113+
generateHeader: Boolean = false,
21042114
): Pair<FirBlock?, FirContractDescription?> {
21052115
return when {
21062116
blockNode != null -> {
2107-
val block = convertBlock(blockNode)
2117+
val block = convertBlock(blockNode, generateHeader)
21082118
val contractDescription = runIf(allowLegacyContractDescription) {
21092119
val blockSource = block.source
21102120
val diagnostic = when {
@@ -2114,7 +2124,11 @@ class LightTreeRawFirDeclarationBuilder(
21142124
}
21152125
processLegacyContractDescription(block, diagnostic)
21162126
}
2117-
block to contractDescription
2127+
if (generateHeader) {
2128+
return buildEmptyExpressionBlock() to contractDescription
2129+
} else {
2130+
block to contractDescription
2131+
}
21182132
}
21192133
expression != null -> FirSingleExpressionBlock(
21202134
expressionConverter.getAsFirExpression<FirExpression>(expression, "Function has no body (but should)").toReturn()
@@ -2136,15 +2150,15 @@ class LightTreeRawFirDeclarationBuilder(
21362150
/**
21372151
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlock
21382152
*/
2139-
fun convertBlock(block: LighterASTNode?): FirBlock {
2153+
fun convertBlock(block: LighterASTNode?, generateHeader: Boolean = false): FirBlock {
21402154
if (block == null) return buildEmptyExpressionBlock()
21412155
if (block.tokenType != BLOCK) {
21422156
return FirSingleExpressionBlock(
21432157
expressionConverter.getAsFirStatement(block)
21442158
)
21452159
}
21462160

2147-
return convertBlockExpression(block)
2161+
return convertBlockExpression(block, generateHeader)
21482162
}
21492163

21502164
/**

compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
package org.jetbrains.kotlin.fir.resolve.transformers
77

8+
import org.jetbrains.kotlin.config.AnalysisFlags
89
import org.jetbrains.kotlin.descriptors.Visibilities
910
import org.jetbrains.kotlin.fir.*
1011
import org.jetbrains.kotlin.fir.declarations.*
1112
import org.jetbrains.kotlin.fir.declarations.utils.componentFunctionSymbol
13+
import org.jetbrains.kotlin.fir.declarations.utils.isFromInlineFunction
14+
import org.jetbrains.kotlin.fir.declarations.utils.isInline
1215
import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue
1316
import org.jetbrains.kotlin.fir.declarations.utils.visibility
1417
import org.jetbrains.kotlin.fir.expressions.FirBlock
@@ -18,6 +21,7 @@ import org.jetbrains.kotlin.fir.resolve.toSymbol
1821
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.LocalClassesNavigationInfo
1922
import org.jetbrains.kotlin.fir.symbols.impl.*
2023
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
24+
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
2125
import org.jetbrains.kotlin.fir.types.FirTypeRef
2226
import org.jetbrains.kotlin.fir.types.coneType
2327
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
@@ -426,6 +430,11 @@ abstract class AbstractFirStatusResolveTransformer(
426430
isLocal = false,
427431
overriddenFunctions.map { it.status as FirResolvedDeclarationStatus },
428432
)
433+
// Once the modality is determined, we can remove the body.
434+
if (session.languageVersionSettings.getFlag(AnalysisFlags.headerMode)
435+
&& namedFunction.isFromInlineFunction != true && !namedFunction.isInline && namedFunction.returnTypeRef !is FirImplicitTypeRef) {
436+
namedFunction.replaceBody(null)
437+
}
429438

430439
namedFunction.transformStatus(this, resolvedStatus)
431440
transformDeclaration(namedFunction, data) as FirStatement

compiler/tests-compiler-utils/testFixtures/org/jetbrains/kotlin/fir/session/FirSessionFactoryHelper.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ object FirSessionFactoryHelper {
108108

109109
override fun isPreRelease(): Boolean = stub()
110110

111-
override fun <T> getFlag(flag: AnalysisFlag<T>): T = stub()
111+
override fun <T> getFlag(flag: AnalysisFlag<T>): T = flag.defaultValue
112112

113113
override val apiVersion: ApiVersion
114114
get() = stub()

0 commit comments

Comments
 (0)