Skip to content

Commit 630e2b2

Browse files
committed
Elide function / method bodies in LT2FIR during header compilation.
^KT-78422
1 parent 796d6eb commit 630e2b2

File tree

3 files changed

+51
-17
lines changed

3 files changed

+51
-17
lines changed

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

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
5656
import org.jetbrains.kotlin.util.getChildren
5757
import org.jetbrains.kotlin.utils.addToStdlib.runIf
5858
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
59+
import org.jetbrains.kotlin.config.AnalysisFlags
5960

6061
class LightTreeRawFirDeclarationBuilder(
6162
session: FirSession,
@@ -65,6 +66,7 @@ class LightTreeRawFirDeclarationBuilder(
6566
) : AbstractLightTreeRawFirBuilder(session, tree, context) {
6667

6768
private val expressionConverter = LightTreeRawFirExpressionBuilder(session, tree, this, context)
69+
private val headerMode = session.languageVersionSettings.getFlag(AnalysisFlags.headerMode)
6870

6971
/**
7072
* [org.jetbrains.kotlin.parsing.KotlinParsing.parseFile]
@@ -133,21 +135,33 @@ class LightTreeRawFirDeclarationBuilder(
133135
/**
134136
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlockExpression
135137
*/
136-
fun convertBlockExpression(block: LighterASTNode): FirBlock {
137-
return convertBlockExpressionWithoutBuilding(block).build()
138+
fun convertBlockExpression(
139+
block: LighterASTNode,
140+
convertOnlyFirstStatement: Boolean = false,
141+
): FirBlock {
142+
return convertBlockExpressionWithoutBuilding(block, convertOnlyFirstStatement = convertOnlyFirstStatement).build()
138143
}
139144

140-
fun convertBlockExpressionWithoutBuilding(block: LighterASTNode, kind: KtFakeSourceElementKind? = null): FirBlockBuilder {
145+
/**
146+
* @param convertOnlyFirstStatement Convert only the first statement of the block, which can be a contract, for header generation.
147+
*/
148+
fun convertBlockExpressionWithoutBuilding(
149+
block: LighterASTNode,
150+
kind: KtFakeSourceElementKind? = null,
151+
convertOnlyFirstStatement: Boolean = false
152+
): FirBlockBuilder {
141153
val firStatements = block.forEachChildrenReturnList { node, container ->
142-
when (node.tokenType) {
143-
CLASS, OBJECT_DECLARATION -> container += convertClass(node) as FirStatement
144-
FUN -> container += convertFunctionDeclaration(node)
145-
KtNodeTypes.PROPERTY -> container += convertPropertyDeclaration(node) as FirStatement
146-
DESTRUCTURING_DECLARATION -> container +=
147-
convertDestructingDeclaration(node).toFirDestructingDeclaration(this, baseModuleData)
148-
TYPEALIAS -> container += convertTypeAlias(node) as FirStatement
149-
CLASS_INITIALIZER -> shouldNotBeCalled("CLASS_INITIALIZER expected to be processed during class body conversion")
150-
else -> if (node.isExpression()) container += expressionConverter.getAsFirStatement(node)
154+
if (!convertOnlyFirstStatement || container.isEmpty()) {
155+
when (node.tokenType) {
156+
CLASS, OBJECT_DECLARATION -> container += convertClass(node) as FirStatement
157+
FUN -> container += convertFunctionDeclaration(node)
158+
KtNodeTypes.PROPERTY -> container += convertPropertyDeclaration(node) as FirStatement
159+
DESTRUCTURING_DECLARATION -> container +=
160+
convertDestructingDeclaration(node).toFirDestructingDeclaration(this, baseModuleData)
161+
TYPEALIAS -> container += convertTypeAlias(node) as FirStatement
162+
CLASS_INITIALIZER -> shouldNotBeCalled("CLASS_INITIALIZER expected to be processed during class body conversion")
163+
else -> if (node.isExpression()) container += expressionConverter.getAsFirStatement(node)
164+
}
151165
}
152166
}
153167
return FirBlockBuilder().apply {
@@ -2099,9 +2113,10 @@ class LightTreeRawFirDeclarationBuilder(
20992113
expression: LighterASTNode?,
21002114
allowLegacyContractDescription: Boolean
21012115
): Pair<FirBlock?, FirContractDescription?> {
2116+
val generateHeader = headerMode && !context.forceKeepingTheBodyInHeaderMode
21022117
return when {
21032118
blockNode != null -> {
2104-
val block = convertBlock(blockNode)
2119+
val block = convertBlock(blockNode, convertOnlyFirstStatement = generateHeader)
21052120
val contractDescription = runIf(allowLegacyContractDescription) {
21062121
val blockSource = block.source
21072122
val diagnostic = when {
@@ -2111,7 +2126,11 @@ class LightTreeRawFirDeclarationBuilder(
21112126
}
21122127
processLegacyContractDescription(block, diagnostic)
21132128
}
2114-
block to contractDescription
2129+
if (generateHeader) {
2130+
return buildEmptyExpressionBlock() to contractDescription
2131+
} else {
2132+
block to contractDescription
2133+
}
21152134
}
21162135
expression != null -> FirSingleExpressionBlock(
21172136
expressionConverter.getAsFirExpression<FirExpression>(expression, "Function has no body (but should)").toReturn()
@@ -2133,15 +2152,18 @@ class LightTreeRawFirDeclarationBuilder(
21332152
/**
21342153
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlock
21352154
*/
2136-
fun convertBlock(block: LighterASTNode?): FirBlock {
2155+
fun convertBlock(
2156+
block: LighterASTNode?,
2157+
convertOnlyFirstStatement: Boolean = false,
2158+
): FirBlock {
21372159
if (block == null) return buildEmptyExpressionBlock()
21382160
if (block.tokenType != BLOCK) {
21392161
return FirSingleExpressionBlock(
21402162
expressionConverter.getAsFirStatement(block)
21412163
)
21422164
}
21432165

2144-
return convertBlockExpression(block)
2166+
return convertBlockExpression(block, convertOnlyFirstStatement)
21452167
}
21462168

21472169
/**

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
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.isInline
1214
import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue
15+
import org.jetbrains.kotlin.fir.declarations.utils.isNonLocal
1316
import org.jetbrains.kotlin.fir.declarations.utils.visibility
1417
import org.jetbrains.kotlin.fir.expressions.FirBlock
1518
import org.jetbrains.kotlin.fir.expressions.FirStatement
@@ -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,14 @@ 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.isNonLocal &&
436+
!namedFunction.isInline &&
437+
namedFunction.returnTypeRef !is FirImplicitTypeRef
438+
) {
439+
namedFunction.replaceBody(null)
440+
}
429441

430442
namedFunction.transformStatus(this, resolvedStatus)
431443
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)