diff --git a/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLDiagnosticsFirTestGenerated.java b/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLDiagnosticsFirTestGenerated.java index 2ccc3b59b2f26..4c371522cc167 100644 --- a/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLDiagnosticsFirTestGenerated.java +++ b/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLDiagnosticsFirTestGenerated.java @@ -5738,6 +5738,34 @@ public void testTypeParameters() { } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/headerMode") + @TestDataPath("$PROJECT_ROOT") + public class HeaderMode { + @Test + public void testAllFilesPresentInHeaderMode() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/headerMode"), Pattern.compile("^([^.]+)\\.kt(\\.can-freeze-ide)?$"), null, true); + } + + @Test + @TestMetadata("classDeclaration.kt") + public void testClassDeclaration() { + runTest("compiler/fir/analysis-tests/testData/resolve/headerMode/classDeclaration.kt"); + } + + @Test + @TestMetadata("functionDeclaration.kt") + public void testFunctionDeclaration() { + runTest("compiler/fir/analysis-tests/testData/resolve/headerMode/functionDeclaration.kt"); + } + + @Test + @TestMetadata("objectDeclaration.kt") + public void testObjectDeclaration() { + runTest("compiler/fir/analysis-tests/testData/resolve/headerMode/objectDeclaration.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/inference") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLPartialDiagnosticsFirTestGenerated.java b/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLPartialDiagnosticsFirTestGenerated.java index 46f9081a320b3..a9d5ad9ad49f2 100644 --- a/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLPartialDiagnosticsFirTestGenerated.java +++ b/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLPartialDiagnosticsFirTestGenerated.java @@ -5738,6 +5738,34 @@ public void testTypeParameters() { } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/headerMode") + @TestDataPath("$PROJECT_ROOT") + public class HeaderMode { + @Test + public void testAllFilesPresentInHeaderMode() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/headerMode"), Pattern.compile("^([^.]+)\\.kt(\\.can-freeze-ide)?$"), null, true); + } + + @Test + @TestMetadata("classDeclaration.kt") + public void testClassDeclaration() { + runTest("compiler/fir/analysis-tests/testData/resolve/headerMode/classDeclaration.kt"); + } + + @Test + @TestMetadata("functionDeclaration.kt") + public void testFunctionDeclaration() { + runTest("compiler/fir/analysis-tests/testData/resolve/headerMode/functionDeclaration.kt"); + } + + @Test + @TestMetadata("objectDeclaration.kt") + public void testObjectDeclaration() { + runTest("compiler/fir/analysis-tests/testData/resolve/headerMode/objectDeclaration.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/inference") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLReversedDiagnosticsFirTestGenerated.java b/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLReversedDiagnosticsFirTestGenerated.java index 5b927fcbaef4c..b3d3963603c67 100644 --- a/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLReversedDiagnosticsFirTestGenerated.java +++ b/analysis/low-level-api-fir/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLReversedDiagnosticsFirTestGenerated.java @@ -5738,6 +5738,34 @@ public void testTypeParameters() { } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/headerMode") + @TestDataPath("$PROJECT_ROOT") + public class HeaderMode { + @Test + public void testAllFilesPresentInHeaderMode() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/headerMode"), Pattern.compile("^([^.]+)\\.kt(\\.can-freeze-ide)?$"), null, true); + } + + @Test + @TestMetadata("classDeclaration.kt") + public void testClassDeclaration() { + runTest("compiler/fir/analysis-tests/testData/resolve/headerMode/classDeclaration.kt"); + } + + @Test + @TestMetadata("functionDeclaration.kt") + public void testFunctionDeclaration() { + runTest("compiler/fir/analysis-tests/testData/resolve/headerMode/functionDeclaration.kt"); + } + + @Test + @TestMetadata("objectDeclaration.kt") + public void testObjectDeclaration() { + runTest("compiler/fir/analysis-tests/testData/resolve/headerMode/objectDeclaration.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/inference") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/arguments/resources/kotlin-compiler-arguments.json b/compiler/arguments/resources/kotlin-compiler-arguments.json index e61c3793fcb5d..68390b726d5c3 100644 --- a/compiler/arguments/resources/kotlin-compiler-arguments.json +++ b/compiler/arguments/resources/kotlin-compiler-arguments.json @@ -2271,6 +2271,37 @@ "removedVersion": null } }, + { + "name": "Xheader-mode", + "shortName": null, + "deprecatedName": null, + "description": { + "current": "Enable header compilation mode.\nIn this mode, the compiler produces class files that only contain the 'skeleton' of the classes to be\ncompiled but the method bodies of all the implementations are empty. This is used to speed up parallel compilation\nbuild systems where header libraries can be used to replace downstream dependencies for which we only need to\nsee the type names and method signatures required to compile a given translation unit. Inline functions are still kept\nwith bodies.", + "valueInVersions": [] + }, + "delimiter": null, + "valueType": { + "type": "org.jetbrains.kotlin.arguments.dsl.types.BooleanType", + "isNullable": { + "current": false, + "valueInVersions": [] + }, + "defaultValue": { + "current": false, + "valueInVersions": [] + } + }, + "valueDescription": { + "current": null, + "valueInVersions": [] + }, + "releaseVersionsMetadata": { + "introducedVersion": "2.3.0", + "stabilizedVersion": null, + "deprecatedVersion": null, + "removedVersion": null + } + }, { "name": "Xignore-const-optimization-errors", "shortName": null, diff --git a/compiler/arguments/src/org/jetbrains/kotlin/arguments/description/CommonCompilerArguments.kt b/compiler/arguments/src/org/jetbrains/kotlin/arguments/description/CommonCompilerArguments.kt index 1ebf46f37279e..6d7aa9b155392 100644 --- a/compiler/arguments/src/org/jetbrains/kotlin/arguments/description/CommonCompilerArguments.kt +++ b/compiler/arguments/src/org/jetbrains/kotlin/arguments/description/CommonCompilerArguments.kt @@ -1167,4 +1167,21 @@ Warning: this flag is not intended for production use. If you want to configure introducedVersion = KotlinReleaseVersion.v1_0_0 ) } + + compilerArgument { + name = "Xheader-mode" + description = """ + Enable header compilation mode. + In this mode, the compiler produces class files that only contain the 'skeleton' of the classes to be + compiled but the method bodies of all the implementations are empty. This is used to speed up parallel compilation + build systems where header libraries can be used to replace downstream dependencies for which we only need to + see the type names and method signatures required to compile a given translation unit. Inline functions are still kept + with bodies. + """.trimIndent().asReleaseDependent() + valueType = BooleanType.defaultFalse + + lifecycle( + introducedVersion = KotlinReleaseVersion.v2_3_0 + ) + } } diff --git a/compiler/build-tools/kotlin-build-tools-api/gen/org/jetbrains/kotlin/buildtools/api/arguments/CommonCompilerArguments.kt b/compiler/build-tools/kotlin-build-tools-api/gen/org/jetbrains/kotlin/buildtools/api/arguments/CommonCompilerArguments.kt index 0866bfce9cdb0..b082d046a8c4b 100644 --- a/compiler/build-tools/kotlin-build-tools-api/gen/org/jetbrains/kotlin/buildtools/api/arguments/CommonCompilerArguments.kt +++ b/compiler/build-tools/kotlin-build-tools-api/gen/org/jetbrains/kotlin/buildtools/api/arguments/CommonCompilerArguments.kt @@ -317,6 +317,21 @@ public interface CommonCompilerArguments : CommonToolArguments { public val X_FRAGMENT_FRIEND_DEPENDENCY: CommonCompilerArgument?> = CommonCompilerArgument("X_FRAGMENT_FRIEND_DEPENDENCY", KotlinReleaseVersion(2, 3, 0)) + /** + * Enable header compilation mode. + * In this mode, the compiler produces class files that only contain the 'skeleton' of the classes to be + * compiled but the method bodies of all the implementations are empty. This is used to speed up parallel compilation + * build systems where header libraries can be used to replace downstream dependencies for which we only need to + * see the type names and method signatures required to compile a given translation unit. Inline functions are still kept + * with bodies. + * + * WARNING: this option is EXPERIMENTAL and it may be changed in the future without notice or may be removed entirely. + */ + @JvmField + @ExperimentalCompilerArgument + public val X_HEADER_MODE: CommonCompilerArgument = + CommonCompilerArgument("X_HEADER_MODE", KotlinReleaseVersion(2, 3, 0)) + /** * Ignore all compilation exceptions while optimizing some constant expressions. * diff --git a/compiler/build-tools/kotlin-build-tools-impl/gen/org/jetbrains/kotlin/buildtools/internal/arguments/CommonCompilerArgumentsImpl.kt b/compiler/build-tools/kotlin-build-tools-impl/gen/org/jetbrains/kotlin/buildtools/internal/arguments/CommonCompilerArgumentsImpl.kt index e03f83b232579..38b5fb126c483 100644 --- a/compiler/build-tools/kotlin-build-tools-impl/gen/org/jetbrains/kotlin/buildtools/internal/arguments/CommonCompilerArgumentsImpl.kt +++ b/compiler/build-tools/kotlin-build-tools-impl/gen/org/jetbrains/kotlin/buildtools/internal/arguments/CommonCompilerArgumentsImpl.kt @@ -63,6 +63,7 @@ import org.jetbrains.kotlin.buildtools.`internal`.arguments.CommonCompilerArgume import org.jetbrains.kotlin.buildtools.`internal`.arguments.CommonCompilerArgumentsImpl.Companion.X_FRAGMENT_FRIEND_DEPENDENCY import org.jetbrains.kotlin.buildtools.`internal`.arguments.CommonCompilerArgumentsImpl.Companion.X_FRAGMENT_REFINES import org.jetbrains.kotlin.buildtools.`internal`.arguments.CommonCompilerArgumentsImpl.Companion.X_FRAGMENT_SOURCES +import org.jetbrains.kotlin.buildtools.`internal`.arguments.CommonCompilerArgumentsImpl.Companion.X_HEADER_MODE import org.jetbrains.kotlin.buildtools.`internal`.arguments.CommonCompilerArgumentsImpl.Companion.X_IGNORE_CONST_OPTIMIZATION_ERRORS import org.jetbrains.kotlin.buildtools.`internal`.arguments.CommonCompilerArgumentsImpl.Companion.X_INLINE_CLASSES import org.jetbrains.kotlin.buildtools.`internal`.arguments.CommonCompilerArgumentsImpl.Companion.X_INTELLIJ_PLUGIN_ROOT @@ -193,6 +194,7 @@ internal abstract class CommonCompilerArgumentsImpl : CommonToolArgumentsImpl(), if (X_FRAGMENT_REFINES in this) { arguments.fragmentRefines = get(X_FRAGMENT_REFINES)} if (X_FRAGMENT_SOURCES in this) { arguments.fragmentSources = get(X_FRAGMENT_SOURCES)} if (X_FRAGMENTS in this) { arguments.fragments = get(X_FRAGMENTS)} + if (X_HEADER_MODE in this) { arguments.headerMode = get(X_HEADER_MODE)} if (X_IGNORE_CONST_OPTIMIZATION_ERRORS in this) { arguments.ignoreConstOptimizationErrors = get(X_IGNORE_CONST_OPTIMIZATION_ERRORS)} if (X_INLINE_CLASSES in this) { arguments.inlineClasses = get(X_INLINE_CLASSES)} if (X_INTELLIJ_PLUGIN_ROOT in this) { arguments.intellijPluginRoot = get(X_INTELLIJ_PLUGIN_ROOT)} @@ -290,6 +292,7 @@ internal abstract class CommonCompilerArgumentsImpl : CommonToolArgumentsImpl(), try { this[X_FRAGMENT_REFINES] = arguments.fragmentRefines } catch (_: NoSuchMethodError) { } try { this[X_FRAGMENT_SOURCES] = arguments.fragmentSources } catch (_: NoSuchMethodError) { } try { this[X_FRAGMENTS] = arguments.fragments } catch (_: NoSuchMethodError) { } + try { this[X_HEADER_MODE] = arguments.headerMode } catch (_: NoSuchMethodError) { } try { this[X_IGNORE_CONST_OPTIMIZATION_ERRORS] = arguments.ignoreConstOptimizationErrors } catch (_: NoSuchMethodError) { } try { this[X_INLINE_CLASSES] = arguments.inlineClasses } catch (_: NoSuchMethodError) { } try { this[X_INTELLIJ_PLUGIN_ROOT] = arguments.intellijPluginRoot } catch (_: NoSuchMethodError) { } @@ -472,6 +475,9 @@ internal abstract class CommonCompilerArgumentsImpl : CommonToolArgumentsImpl(), public val X_FRAGMENTS: CommonCompilerArgument?> = CommonCompilerArgument("X_FRAGMENTS") + public val X_HEADER_MODE: CommonCompilerArgument = + CommonCompilerArgument("X_HEADER_MODE") + public val X_IGNORE_CONST_OPTIMIZATION_ERRORS: CommonCompilerArgument = CommonCompilerArgument("X_IGNORE_CONST_OPTIMIZATION_ERRORS") diff --git a/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt b/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt index 17a28763b5108..64b0af66c2f18 100644 --- a/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt +++ b/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt @@ -490,6 +490,21 @@ The argument should be used only if the new compilation scheme is enabled with - field = value } + @Argument( + value = "-Xheader-mode", + description = """Enable header compilation mode. +In this mode, the compiler produces class files that only contain the 'skeleton' of the classes to be +compiled but the method bodies of all the implementations are empty. This is used to speed up parallel compilation +build systems where header libraries can be used to replace downstream dependencies for which we only need to +see the type names and method signatures required to compile a given translation unit. Inline functions are still kept +with bodies.""", + ) + var headerMode: Boolean = false + set(value) { + checkFrozen() + field = value + } + @Argument( value = "-Xignore-const-optimization-errors", description = "Ignore all compilation exceptions while optimizing some constant expressions.", diff --git a/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArgumentsCopyGenerated.kt b/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArgumentsCopyGenerated.kt index 62815e2be7994..11132b86c904e 100644 --- a/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArgumentsCopyGenerated.kt +++ b/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArgumentsCopyGenerated.kt @@ -47,6 +47,7 @@ fun copyCommonCompilerArguments(from: CommonCompilerArguments, to: CommonCompile to.fragmentRefines = from.fragmentRefines?.copyOf() to.fragmentSources = from.fragmentSources?.copyOf() to.fragments = from.fragments?.copyOf() + to.headerMode = from.headerMode to.ignoreConstOptimizationErrors = from.ignoreConstOptimizationErrors to.incrementalCompilation = from.incrementalCompilation to.inlineClasses = from.inlineClasses diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArgumentsConfigurator.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArgumentsConfigurator.kt index 545c9dc07dcb5..37edfbf016827 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArgumentsConfigurator.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArgumentsConfigurator.kt @@ -40,6 +40,7 @@ open class CommonCompilerArgumentsConfigurator { put(AnalysisFlags.allowFullyQualifiedNameInKClass, true) put(AnalysisFlags.dontWarnOnErrorSuppression, dontWarnOnErrorSuppression) put(AnalysisFlags.lenientMode, lenientMode) + put(AnalysisFlags.headerMode, headerMode) put(AnalysisFlags.hierarchicalMultiplatformCompilation, separateKmpCompilationScheme && multiPlatform) fillWarningLevelMap(arguments, collector) ReturnValueCheckerMode.fromString(returnValueChecker)?.also { put(AnalysisFlags.returnValueCheckerMode, it) } diff --git a/compiler/config/src/org/jetbrains/kotlin/config/AnalysisFlags.kt b/compiler/config/src/org/jetbrains/kotlin/config/AnalysisFlags.kt index bfc17bd7aca66..a71a90a41054a 100644 --- a/compiler/config/src/org/jetbrains/kotlin/config/AnalysisFlags.kt +++ b/compiler/config/src/org/jetbrains/kotlin/config/AnalysisFlags.kt @@ -95,6 +95,8 @@ object AnalysisFlags { val lenientMode by AnalysisFlag.Delegates.Boolean val hierarchicalMultiplatformCompilation by AnalysisFlag.Delegates.Boolean(defaultValue = false) + + val headerMode by AnalysisFlag.Delegates.Boolean } @Deprecated( diff --git a/compiler/fir/analysis-tests/testData/resolve/headerMode/classDeclaration.fir.txt b/compiler/fir/analysis-tests/testData/resolve/headerMode/classDeclaration.fir.txt new file mode 100644 index 0000000000000..a13d70a2e206f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/headerMode/classDeclaration.fir.txt @@ -0,0 +1,38 @@ +FILE: classDeclaration.kt + public final class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public final fun funA(): R|kotlin/String| + + public final inline fun funB(): R|kotlin/String| { + ^funB String(A.funB body) + } + + @R|kotlin/OptIn|(markerClass = vararg((Q|kotlin/contracts/ExperimentalContracts|))) public final fun isNotNull(value: R|kotlin/Any?|): R|kotlin/Boolean| + [R|Contract description] + < + Returns(TRUE) -> value != null + > + + + private final fun funC(): R|kotlin/String| + + public final fun funD(): R|kotlin/Int| + + } + public abstract interface B : R|kotlin/Any| { + public open fun funA(): R|kotlin/String| + + public abstract fun funB(): R|kotlin/String| + + } + public final class C : R|B| { + public constructor(): R|C| { + super() + } + + public open override fun funB(): R|kotlin/String| + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/headerMode/classDeclaration.kt b/compiler/fir/analysis-tests/testData/resolve/headerMode/classDeclaration.kt new file mode 100644 index 0000000000000..d0935a59d75fb --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/headerMode/classDeclaration.kt @@ -0,0 +1,45 @@ +// RUN_PIPELINE_TILL: BACKEND +// FIR_DUMP +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +class A { + fun funA(): String { + return "A.funA body" + } + + inline fun funB(): String { + return "A.funB body" + } + + @OptIn(ExperimentalContracts::class) + fun isNotNull(value: Any?): Boolean { + contract { + returns(true) implies (value != null) + } + return value != null + } + + private fun funC(): String { + return "A.funC body" + } + + fun funD() = 1 + 2 +} + +interface B { + fun funA(): String { + "B.funA body" + } + + fun funB(): String +} + +class C: B { + override fun funB(): String { + return "C.funB body" + } +} + +/* GENERATED_FIR_TAGS: classDeclaration, classReference, contractConditionalEffect, contracts, functionDeclaration, +inline, interfaceDeclaration, nullableType, override, stringLiteral */ diff --git a/compiler/fir/analysis-tests/testData/resolve/headerMode/functionDeclaration.fir.txt b/compiler/fir/analysis-tests/testData/resolve/headerMode/functionDeclaration.fir.txt new file mode 100644 index 0000000000000..437bfa60dc812 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/headerMode/functionDeclaration.fir.txt @@ -0,0 +1,13 @@ +FILE: functionDeclaration.kt + public final fun funA(): R|kotlin/String| + public final inline fun funB(): R|kotlin/String| { + ^funB String(funB body) + } + @R|kotlin/OptIn|(markerClass = vararg((Q|kotlin/contracts/ExperimentalContracts|))) public final fun isNotNull(value: R|kotlin/Any?|): R|kotlin/Boolean| + [R|Contract description] + < + Returns(TRUE) -> value != null + > + + private final fun funC(): R|kotlin/String| + public final fun funD(): R|kotlin/Int| diff --git a/compiler/fir/analysis-tests/testData/resolve/headerMode/functionDeclaration.kt b/compiler/fir/analysis-tests/testData/resolve/headerMode/functionDeclaration.kt new file mode 100644 index 0000000000000..e86ab9279838f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/headerMode/functionDeclaration.kt @@ -0,0 +1,29 @@ +// RUN_PIPELINE_TILL: BACKEND +// FIR_DUMP +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +fun funA(): String { + return "funA body" +} + +inline fun funB: String { + return "funB body" +} + +@OptIn(ExperimentalContracts::class) +fun isNotNull(value: Any?): Boolean { + contract { + returns(true) implies (value != null) + } + return value != null +} + +private fun funC(): String { + return "funC body" +} + +fun funD() = 1 + 2 + +/* GENERATED_FIR_TAGS: classReference, contractConditionalEffect, contracts, functionDeclaration, inline, nullableType, +stringLiteral */ diff --git a/compiler/fir/analysis-tests/testData/resolve/headerMode/objectDeclaration.fir.txt b/compiler/fir/analysis-tests/testData/resolve/headerMode/objectDeclaration.fir.txt new file mode 100644 index 0000000000000..3da4fa38b5a1f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/headerMode/objectDeclaration.fir.txt @@ -0,0 +1,24 @@ +FILE: objectDeclaration.kt + public final object A : R|kotlin/Any| { + private constructor(): R|A| { + super() + } + + public final fun funA(): R|kotlin/String| + + public final inline fun funB(): R|kotlin/String| { + ^funB String(A.funB body) + } + + @R|kotlin/OptIn|(markerClass = vararg((Q|kotlin/contracts/ExperimentalContracts|))) public final fun isNotNull(value: R|kotlin/Any?|): R|kotlin/Boolean| + [R|Contract description] + < + Returns(TRUE) -> value != null + > + + + private final fun funC(): R|kotlin/String| + + public final fun funD(): R|kotlin/Int| + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/headerMode/objectDeclaration.kt b/compiler/fir/analysis-tests/testData/resolve/headerMode/objectDeclaration.kt new file mode 100644 index 0000000000000..93a679fc9f311 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/headerMode/objectDeclaration.kt @@ -0,0 +1,31 @@ +// RUN_PIPELINE_TILL: BACKEND +// FIR_DUMP +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +object A { + fun funA(): String { + return "A.funA body" + } + + inline fun funB(): String { + return "A.funB body" + } + + @OptIn(ExperimentalContracts::class) + fun isNotNull(value: Any?): Boolean { + contract { + returns(true) implies (value != null) + } + return value != null + } + + private fun funC(): String { + return "A.funC body" + } + + fun funD() = 1 + 2 +} + +/* GENERATED_FIR_TAGS: classReference, contractConditionalEffect, contracts, functionDeclaration, inline, nullableType, +objectDeclaration, stringLiteral */ diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt index 6de5acc30c52f..6e87cf225e70e 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt @@ -79,6 +79,8 @@ data class Fir2IrActualizedResult( fun List.runPlatformCheckers(reporter: BaseDiagnosticsCollector) { val platformModule = this.last() val session = platformModule.session + // Skip checkers in header mode. + if (session.languageVersionSettings.getFlag(AnalysisFlags.headerMode)) return val scopeSession = platformModule.scopeSession val allFiles = this.flatMap { it.fir } diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/firUtils.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/firUtils.kt index 14e057025b84b..9ee4b9c8355fb 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/firUtils.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/firUtils.kt @@ -6,12 +6,14 @@ package org.jetbrains.kotlin.fir.pipeline import org.jetbrains.kotlin.KtSourceFile +import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind import org.jetbrains.kotlin.fir.builder.PsiRawFirBuilder import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl @@ -74,7 +76,10 @@ fun resolveAndCheckFir( diagnosticsReporter: BaseDiagnosticsCollector ): ModuleCompilerAnalyzedOutput { val (scopeSession, fir) = session.runResolution(firFiles) - session.runCheckers(scopeSession, fir, diagnosticsReporter, MppCheckerKind.Common) + // Skip checkers in header mode. + if (!session.languageVersionSettings.getFlag(AnalysisFlags.headerMode)) { + session.runCheckers(scopeSession, fir, diagnosticsReporter, MppCheckerKind.Common) + } return ModuleCompilerAnalyzedOutput(session, scopeSession, fir) } diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt index 68048ed228835..8828292cf7c7d 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.* import org.jetbrains.kotlin.ElementTypeUtils.isExpression import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.* @@ -56,6 +57,7 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes import org.jetbrains.kotlin.util.getChildren import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled +import org.jetbrains.kotlin.fir.declarations.utils.* class LightTreeRawFirDeclarationBuilder( session: FirSession, @@ -65,6 +67,7 @@ class LightTreeRawFirDeclarationBuilder( ) : AbstractLightTreeRawFirBuilder(session, tree, context) { private val expressionConverter = LightTreeRawFirExpressionBuilder(session, tree, this, context) + private val headerCompilationMode = session.languageVersionSettings.getFlag(AnalysisFlags.headerMode) /** * [org.jetbrains.kotlin.parsing.KotlinParsing.parseFile] @@ -95,11 +98,11 @@ class LightTreeRawFirDeclarationBuilder( packageDirective = convertPackageDirective(child).also { context.packageFqName = it.packageFqName } } IMPORT_LIST -> importList += convertImportDirectives(child) - CLASS -> firDeclarationList += convertClass(child) - FUN -> firDeclarationList += convertFunctionDeclaration(child) as FirDeclaration + CLASS -> firDeclarationList += convertClass(child, headerCompilationMode) + FUN -> firDeclarationList += convertFunctionDeclaration(child, headerCompilationMode) as FirDeclaration KtNodeTypes.PROPERTY -> firDeclarationList += convertPropertyDeclaration(child) TYPEALIAS -> firDeclarationList += convertTypeAlias(child) - OBJECT_DECLARATION -> firDeclarationList += convertClass(child) + OBJECT_DECLARATION -> firDeclarationList += convertClass(child, headerCompilationMode) DESTRUCTURING_DECLARATION -> { val initializer = buildFirDestructuringDeclarationInitializer(child) firDeclarationList += buildErrorNonLocalDestructuringDeclaration(child.toFirSourceElement(), initializer) @@ -134,21 +137,27 @@ class LightTreeRawFirDeclarationBuilder( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlockExpression */ - fun convertBlockExpression(block: LighterASTNode): FirBlock { - return convertBlockExpressionWithoutBuilding(block).build() + fun convertBlockExpression(block: LighterASTNode, generateHeaders: Boolean = false): FirBlock { + return convertBlockExpressionWithoutBuilding(block, generateHeaders = generateHeaders).build() } - fun convertBlockExpressionWithoutBuilding(block: LighterASTNode, kind: KtFakeSourceElementKind? = null): FirBlockBuilder { + fun convertBlockExpressionWithoutBuilding( + block: LighterASTNode, + kind: KtFakeSourceElementKind? = null, + generateHeaders: Boolean = false + ): FirBlockBuilder { val firStatements = block.forEachChildrenReturnList { node, container -> - when (node.tokenType) { - CLASS, OBJECT_DECLARATION -> container += convertClass(node) as FirStatement - FUN -> container += convertFunctionDeclaration(node) - KtNodeTypes.PROPERTY -> container += convertPropertyDeclaration(node) as FirStatement - DESTRUCTURING_DECLARATION -> container += - convertDestructingDeclaration(node).toFirDestructingDeclaration(this, baseModuleData) - TYPEALIAS -> container += convertTypeAlias(node) as FirStatement - CLASS_INITIALIZER -> shouldNotBeCalled("CLASS_INITIALIZER expected to be processed during class body conversion") - else -> if (node.isExpression()) container += expressionConverter.getAsFirStatement(node) + if (!generateHeaders || container.isEmpty()) { // Take only the first statement which could be a contract for header generation. + when (node.tokenType) { + CLASS, OBJECT_DECLARATION -> container += convertClass(node, generateHeaders) as FirStatement + FUN -> container += convertFunctionDeclaration(node) + KtNodeTypes.PROPERTY -> container += convertPropertyDeclaration(node) as FirStatement + DESTRUCTURING_DECLARATION -> container += + convertDestructingDeclaration(node).toFirDestructingDeclaration(this, baseModuleData) + TYPEALIAS -> container += convertTypeAlias(node) as FirStatement + CLASS_INITIALIZER -> shouldNotBeCalled("CLASS_INITIALIZER expected to be processed during class body conversion") + else -> if (node.isExpression()) container += expressionConverter.getAsFirStatement(node) + } } } return FirBlockBuilder().apply { @@ -457,7 +466,7 @@ class LightTreeRawFirDeclarationBuilder( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseClassOrObject */ - private fun convertClass(classNode: LighterASTNode): FirDeclaration { + private fun convertClass(classNode: LighterASTNode, generateHeaders: Boolean): FirDeclaration { var modifiers: ModifierList? = null var classKind: ClassKind = ClassKind.CLASS var identifier: String? = null @@ -633,7 +642,7 @@ class LightTreeRawFirDeclarationBuilder( //parse declarations classBody?.let { - addDeclarations(convertClassBody(it, classWrapper)) + addDeclarations(convertClassBody(it, classWrapper, generateHeaders)) } //parse data class @@ -693,6 +702,7 @@ class LightTreeRawFirDeclarationBuilder( } } }.also { + it.isHeader = generateHeaders if (classNode.getParent()?.elementType == KtStubElementTypes.CLASS_BODY) { it.initContainingClassForLocalAttr() } @@ -919,10 +929,14 @@ class LightTreeRawFirDeclarationBuilder( * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseClassBody * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseEnumClassBody */ - private fun convertClassBody(classBody: LighterASTNode, classWrapper: ClassWrapper?): List { + private fun convertClassBody( + classBody: LighterASTNode, + classWrapper: ClassWrapper?, + generateHeaders: Boolean = false + ): List { val modifierLists = mutableListOf() val firDeclarations = classBody.forEachChildrenReturnList { node, container -> - convertDeclarationFromClassBody(node, container, classWrapper, modifierLists) + convertDeclarationFromClassBody(node, container, classWrapper, modifierLists, generateHeaders) } convertDanglingModifierListsInClassBody(modifierLists, firDeclarations) @@ -934,14 +948,15 @@ class LightTreeRawFirDeclarationBuilder( container: MutableList, classWrapper: ClassWrapper?, modifierLists: MutableList, + generateHeaders: Boolean = false ) { when (node.tokenType) { ENUM_ENTRY -> container += convertEnumEntry(node, classWrapper!!) - CLASS -> container += convertClass(node) - FUN -> container += convertFunctionDeclaration(node) as FirDeclaration + CLASS -> container += convertClass(node, generateHeaders) + FUN -> container += convertFunctionDeclaration(node, generateHeaders) as FirDeclaration KtNodeTypes.PROPERTY -> container += convertPropertyDeclaration(node, classWrapper) TYPEALIAS -> container += convertTypeAlias(node) - OBJECT_DECLARATION -> container += convertClass(node) + OBJECT_DECLARATION -> container += convertClass(node, generateHeaders) CLASS_INITIALIZER -> container += convertAnonymousInitializer(node, classWrapper!!.classBuilder.ownerRegularOrAnonymousObjectSymbol) //anonymousInitializer SECONDARY_CONSTRUCTOR -> container += convertSecondaryConstructor(node, classWrapper!!) MODIFIER_LIST -> modifierLists += node @@ -1922,7 +1937,7 @@ class LightTreeRawFirDeclarationBuilder( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunction */ - fun convertFunctionDeclaration(functionDeclaration: LighterASTNode): FirStatement { + fun convertFunctionDeclaration(functionDeclaration: LighterASTNode, generateHeaders: Boolean = false): FirStatement { var modifiers: ModifierList? = null var identifier: String? = null var valueParametersList: LighterASTNode? = null @@ -1939,6 +1954,8 @@ class LightTreeRawFirDeclarationBuilder( identifier = it.asText } + var headerMode = generateHeaders + val isLocal = isCallableLocal(functionDeclaration) { getParent() } val functionSource = functionDeclaration.toFirSourceElement() val isAnonymousFunction = identifier == null && isLocal @@ -1970,6 +1987,11 @@ class LightTreeRawFirDeclarationBuilder( val calculatedModifiers = modifiers ?: ModifierList() + if (calculatedModifiers.hasInline()) { + // We need to disable header mode for inline functions. + headerMode = false + } + if (returnType == null) { returnType = if (block != null || !hasEqToken) implicitUnitType @@ -2065,7 +2087,12 @@ class LightTreeRawFirDeclarationBuilder( val allowLegacyContractDescription = outerContractDescription == null val bodyWithContractDescription = withForcedLocalContext { - convertFunctionBody(block, expression, allowLegacyContractDescription) + convertFunctionBody( + block, + expression, + allowLegacyContractDescription, + headerMode && (returnTypeRef !is FirImplicitTypeRef) + ) } this.body = bodyWithContractDescription.first val contractDescription = outerContractDescription ?: bodyWithContractDescription.second @@ -2079,6 +2106,7 @@ class LightTreeRawFirDeclarationBuilder( } context.firFunctionTargets.removeLast() }.build().also { + it.isHeader = headerMode target.bind(it) fillDanglingConstraintsTo(firTypeParameters, typeConstraints, it) } @@ -2102,11 +2130,12 @@ class LightTreeRawFirDeclarationBuilder( private fun convertFunctionBody( blockNode: LighterASTNode?, expression: LighterASTNode?, - allowLegacyContractDescription: Boolean + allowLegacyContractDescription: Boolean, + generateHeaders: Boolean = false, ): Pair { return when { blockNode != null -> { - val block = convertBlock(blockNode) + val block = convertBlock(blockNode, generateHeaders) val contractDescription = runIf(allowLegacyContractDescription) { val blockSource = block.source val diagnostic = when { @@ -2116,7 +2145,12 @@ class LightTreeRawFirDeclarationBuilder( } processLegacyContractDescription(block, diagnostic) } - block to contractDescription + if (generateHeaders) { + // Return an empty body, which will be removed after the status resolution. + buildEmptyExpressionBlock() to contractDescription // We want to preserve the contract info when processing as headers. + } else { + block to contractDescription + } } expression != null -> FirSingleExpressionBlock( expressionConverter.getAsFirExpression(expression, "Function has no body (but should)").toReturn() @@ -2138,7 +2172,7 @@ class LightTreeRawFirDeclarationBuilder( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlock */ - fun convertBlock(block: LighterASTNode?): FirBlock { + fun convertBlock(block: LighterASTNode?, generateHeaders: Boolean = false): FirBlock { if (block == null) return buildEmptyExpressionBlock() if (block.tokenType != BLOCK) { return FirSingleExpressionBlock( @@ -2146,7 +2180,7 @@ class LightTreeRawFirDeclarationBuilder( ) } - return convertBlockExpression(block) + return convertBlockExpression(block, generateHeaders) } /** diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt index 7a730ba6726f7..37e6bc73ddb61 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.componentFunctionSymbol +import org.jetbrains.kotlin.fir.declarations.utils.isHeader import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue import org.jetbrains.kotlin.fir.declarations.utils.visibility import org.jetbrains.kotlin.fir.expressions.FirBlock @@ -18,6 +19,7 @@ import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.LocalClassesNavigationInfo import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry @@ -426,6 +428,8 @@ abstract class AbstractFirStatusResolveTransformer( isLocal = false, overriddenFunctions.map { it.status as FirResolvedDeclarationStatus }, ) + // Once the modality is determined, we can remove the body. + if (simpleFunction.isHeader == true && simpleFunction.returnTypeRef !is FirImplicitTypeRef) simpleFunction.replaceBody(null) simpleFunction.transformStatus(this, resolvedStatus) transformDeclaration(simpleFunction, data) as FirStatement diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index fb5f59c006702..0cb45d5bcc83a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyBackingField import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField import org.jetbrains.kotlin.fir.declarations.utils.isConst +import org.jetbrains.kotlin.fir.declarations.utils.isHeader import org.jetbrains.kotlin.fir.declarations.utils.isInline import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.declarations.utils.isScriptTopLevelDeclaration @@ -1038,6 +1039,8 @@ open class FirDeclarationsResolveTransformer( } result.transformReturnTypeRef(transformer, ResolutionMode.UpdateImplicitTypeRef(returnTypeRef)) } + // Once the return type is resolved, the body can be removed. + if (result.isHeader == true) result.replaceBody(null) return result } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/declarationAttributes.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/declarationAttributes.kt index a442c6bb861d1..ace17713f161c 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/declarationAttributes.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/declarationAttributes.kt @@ -41,6 +41,7 @@ private object IsDeserializedPropertyFromAnnotation : FirDeclarationDataKey() private object IsDelegatedProperty : FirDeclarationDataKey() private object LambdaArgumentHoldsInTruths : FirDeclarationDataKey() private object FileNameForPluginGeneratedCallable : FirDeclarationDataKey() +private object IsHeader: FirDeclarationDataKey() var FirProperty.isFromVararg: Boolean? by FirDeclarationDataRegistry.data(IsFromVarargKey) var FirProperty.isReferredViaField: Boolean? by FirDeclarationDataRegistry.data(IsReferredViaField) @@ -52,6 +53,7 @@ var FirDeclaration.compilerPluginMetadata: Map? by FirDeclara var FirDeclaration.originalReplSnippetSymbol: FirReplSnippetSymbol? by FirDeclarationDataRegistry.data(OriginalReplSnippet) var FirAnonymousFunction.lambdaArgumentParent: FirQualifiedAccessExpression? by FirDeclarationDataRegistry.data(LambdaArgumentHoldsInTruths) var FirCallableDeclaration.fileNameForPluginGeneratedCallable: String? by FirDeclarationDataRegistry.data(FileNameForPluginGeneratedCallable) +var FirDeclaration.isHeader: Boolean? by FirDeclarationDataRegistry.data(IsHeader) var FirDeclaration.isScriptTopLevelDeclaration: Boolean? by FirDeclarationDataRegistry.data(ScriptTopLevelDeclaration) diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index b56fae4126616..e3dc4ea4ebcb8 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -26,9 +26,11 @@ import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.JvmBackendConfig +import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.VariableAccessorDescriptor @@ -216,7 +218,7 @@ class ExpressionCodegen( mv.visitCode() val startLabel = markNewLabel() val info = BlockInfo() - if (state.classBuilderMode.generateBodies) { + if (state.classBuilderMode.generateBodies && !state.configuration.languageVersionSettings.getFlag(AnalysisFlags.headerMode)) { if (irFunction.isMultifileBridge()) { // Multifile bridges need to have line number 1 to be filtered out by the intellij debugging filters. mv.visitLineNumber(1, startLabel) diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt index d14c1628ab448..b60c03e23b8ac 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt @@ -541,7 +541,8 @@ fun serializeModuleIntoKlib( dependencies = dependencies, createModuleSerializer = { irDiagnosticReporter -> JsIrModuleSerializer( - settings = IrSerializationSettings(configuration), + settings = IrSerializationSettings(configuration, publicAbiOnly = configuration.languageVersionSettings.getFlag( + AnalysisFlags.headerMode)), irDiagnosticReporter, irBuiltIns, ) { JsIrFileMetadata(moduleExportedNames[it]?.values?.toSmartList() ?: emptyList()) } diff --git a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/JvmIrSerializerSession.kt b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/JvmIrSerializerSession.kt index d38a143c4d733..007eb7812ca1e 100644 --- a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/JvmIrSerializerSession.kt +++ b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/JvmIrSerializerSession.kt @@ -9,8 +9,10 @@ import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable import org.jetbrains.kotlin.backend.common.serialization.IrFileSerializer import org.jetbrains.kotlin.backend.common.serialization.IrSerializationSettings import org.jetbrains.kotlin.backend.jvm.serialization.proto.JvmIr +import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.JvmSerializeIrMode +import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.visitors.IrVisitor @@ -26,6 +28,7 @@ class JvmIrSerializerSession( IrSerializationSettings( configuration = configuration, bodiesOnlyForInlines = mode == JvmSerializeIrMode.INLINE, + publicAbiOnly = configuration.languageVersionSettings.getFlag(AnalysisFlags.headerMode) ), declarationTable, ) { diff --git a/compiler/test-infrastructure/testFixtures/org/jetbrains/kotlin/test/builders/LanguageVersionSettingsBuilder.kt b/compiler/test-infrastructure/testFixtures/org/jetbrains/kotlin/test/builders/LanguageVersionSettingsBuilder.kt index 8ab8ba548f3b8..d438748817076 100644 --- a/compiler/test-infrastructure/testFixtures/org/jetbrains/kotlin/test/builders/LanguageVersionSettingsBuilder.kt +++ b/compiler/test-infrastructure/testFixtures/org/jetbrains/kotlin/test/builders/LanguageVersionSettingsBuilder.kt @@ -105,6 +105,7 @@ class LanguageVersionSettingsBuilder { analysisFlag(AnalysisFlags.dontWarnOnErrorSuppression, trueOrNull(LanguageSettingsDirectives.DONT_WARN_ON_ERROR_SUPPRESSION in directives)), analysisFlag(AnalysisFlags.stdlibCompilation, trueOrNull(LanguageSettingsDirectives.STDLIB_COMPILATION in directives)), analysisFlag(AnalysisFlags.lenientMode, trueOrNull(LanguageSettingsDirectives.LENIENT_MODE in directives)), + analysisFlag(AnalysisFlags.headerMode, trueOrNull(LanguageSettingsDirectives.HEADER_MODE in directives)), analysisFlag(JvmAnalysisFlags.jvmDefaultMode, directives.singleOrZeroValue(LanguageSettingsDirectives.JVM_DEFAULT_MODE)), analysisFlag(JvmAnalysisFlags.inheritMultifileParts, trueOrNull(LanguageSettingsDirectives.INHERIT_MULTIFILE_PARTS in directives)), diff --git a/compiler/test-infrastructure/testFixtures/org/jetbrains/kotlin/test/directives/LanguageSettingsDirectives.kt b/compiler/test-infrastructure/testFixtures/org/jetbrains/kotlin/test/directives/LanguageSettingsDirectives.kt index ad928b2a2fc0f..6c75438ac5012 100644 --- a/compiler/test-infrastructure/testFixtures/org/jetbrains/kotlin/test/directives/LanguageSettingsDirectives.kt +++ b/compiler/test-infrastructure/testFixtures/org/jetbrains/kotlin/test/directives/LanguageSettingsDirectives.kt @@ -142,6 +142,7 @@ object LanguageSettingsDirectives : SimpleDirectivesContainer() { val LINK_VIA_SIGNATURES_K1 by directive("Use linkage via signatures instead of descriptors on the K1 frontend") val USE_INLINE_SCOPES_NUMBERS by directive("Use inline scopes numbers for inline marker variables") val DONT_WARN_ON_ERROR_SUPPRESSION by directive("Don't emit warning when an error is suppressed") + val HEADER_MODE by directive("Enable header mode") // --------------------- Utils --------------------- diff --git a/compiler/tests-common-new/testFixtures/org/jetbrains/kotlin/test/configuration/BaseDiagnosticConfiguration.kt b/compiler/tests-common-new/testFixtures/org/jetbrains/kotlin/test/configuration/BaseDiagnosticConfiguration.kt index dabcae15ab6f8..878b3c76c80b7 100644 --- a/compiler/tests-common-new/testFixtures/org/jetbrains/kotlin/test/configuration/BaseDiagnosticConfiguration.kt +++ b/compiler/tests-common-new/testFixtures/org/jetbrains/kotlin/test/configuration/BaseDiagnosticConfiguration.kt @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.EXPLICIT_ import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.LANGUAGE import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.LANGUAGE_VERSION import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.RETURN_VALUE_CHECKER_MODE +import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.HEADER_MODE import org.jetbrains.kotlin.test.directives.configureFirParser import org.jetbrains.kotlin.test.frontend.classic.handlers.FirTestDataConsistencyHandler import org.jetbrains.kotlin.test.frontend.fir.* @@ -293,6 +294,12 @@ fun TestConfigurationBuilder.configureCommonDiagnosticTestPaths( LANGUAGE + "+NestedTypeAliases" } } + + forTestsMatching("compiler/fir/analysis-tests/testData/resolve/headerMode/*") { + defaultDirectives { + +HEADER_MODE + } + } } /** diff --git a/js/js.tests/tests/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt b/js/js.tests/tests/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt index a3e1bec603ea4..f7bf3eb652b53 100644 --- a/js/js.tests/tests/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt +++ b/js/js.tests/tests/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt @@ -502,7 +502,7 @@ class GenerateIrRuntime { val messageCollector = configuration.getNotNull(CommonConfigurationKeys.MESSAGE_COLLECTOR_KEY) return JsIrModuleSerializer( - settings = IrSerializationSettings(configuration), + settings = IrSerializationSettings(configuration, publicAbiOnly = configuration.languageVersionSettings.getFlag(AnalysisFlags.headerMode)), KtDiagnosticReporterWithImplicitIrBasedContext( DiagnosticReporterFactory.createPendingReporter(messageCollector), configuration.languageVersionSettings, diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt index d1ac4759963fb..a70c78021c63e 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt @@ -10,7 +10,9 @@ import org.jetbrains.kotlin.backend.konan.driver.phases.SerializerOutput import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.fir.reportToMessageCollector +import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.pipeline.Fir2KlibMetadataSerializer @@ -58,12 +60,12 @@ internal fun PhaseContext.firSerializerBase( dependencies = usedResolvedLibraries?.map { it.library as KonanLibrary }.orEmpty(), createModuleSerializer = { irDiagnosticReporter -> KonanIrModuleSerializer( - settings = IrSerializationSettings( - configuration = configuration, - publicAbiOnly = produceHeaderKlib, - ), - diagnosticReporter = irDiagnosticReporter, - irBuiltIns = fir2IrOutput?.fir2irActualizedResult?.irBuiltIns!!, + settings = IrSerializationSettings( + configuration = configuration, + publicAbiOnly = produceHeaderKlib || configuration.languageVersionSettings.getFlag(AnalysisFlags.headerMode), + ), + diagnosticReporter = irDiagnosticReporter, + irBuiltIns = fir2IrOutput?.fir2irActualizedResult?.irBuiltIns!!, ) }, ) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt index 6d3a282094c1e..9c3d7cde38e97 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMo import org.jetbrains.kotlin.backend.konan.PsiToIrOutput import org.jetbrains.kotlin.backend.konan.driver.PhaseContext import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer +import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -38,15 +39,15 @@ internal val SerializerPhase = createSimpleNamedCompilerPhase