[klib] Add an option to write out header klibs

The header klib is supposed to only contain the public abi of the module
similar to jvm-abi-gen. It is intended to be used as a dependency for other
klib compilations instead of the full klib for compilation avoidance.

^KT-60807
This commit is contained in:
Johan Bay
2023-05-09 14:29:21 +02:00
committed by Space Team
parent 829e0675f4
commit 0a612e4268
90 changed files with 1374 additions and 76 deletions
@@ -74,6 +74,7 @@ class FirElementSerializer private constructor(
private val serializeTypeTableToFunction: Boolean,
private val typeApproximator: AbstractTypeApproximator,
private val languageVersionSettings: LanguageVersionSettings,
private val produceHeaderKlib: Boolean,
) {
private val contractSerializer = FirContractSerializer()
private val providedDeclarationsService = session.providedDeclarationsForMetadataService
@@ -89,7 +90,8 @@ class FirElementSerializer private constructor(
fun addDeclaration(declaration: FirDeclaration, onUnsupportedDeclaration: (FirDeclaration) -> Unit) {
if (declaration is FirMemberDeclaration) {
if (!declaration.shouldBeSerialized(actualizedExpectDeclarations)) return
if (!declaration.isNotExpectOrShouldBeSerialized(actualizedExpectDeclarations)) return
if (!declaration.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)) return
when (declaration) {
is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(it) }
is FirSimpleFunction -> functionProto(declaration)?.let { builder.addFunction(it) }
@@ -178,6 +180,7 @@ class FirElementSerializer private constructor(
*/
if (regularClass != null && regularClass.classKind != ClassKind.ENUM_ENTRY) {
for (constructor in regularClass.constructors()) {
if (!constructor.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)) continue
builder.addConstructor(constructorProto(constructor))
}
@@ -203,6 +206,7 @@ class FirElementSerializer private constructor(
for (declaration in callableMembers) {
if (declaration !is FirEnumEntry && declaration.isStatic) continue // ??? Miss values() & valueOf()
if (!declaration.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)) continue
when (declaration) {
is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(it) }
is FirSimpleFunction -> functionProto(declaration)?.let { builder.addFunction(it) }
@@ -1042,7 +1046,7 @@ class FirElementSerializer private constructor(
FirElementSerializer(
session, scopeSession, declaration, Interner(typeParameters), extension,
typeTable, versionRequirementTable, serializeTypeTableToFunction = false,
typeApproximator, languageVersionSettings
typeApproximator, languageVersionSettings, produceHeaderKlib
)
val stringTable: FirElementAwareStringTable
@@ -1148,6 +1152,7 @@ class FirElementSerializer private constructor(
extension: FirSerializerExtension,
typeApproximator: AbstractTypeApproximator,
languageVersionSettings: LanguageVersionSettings,
produceHeaderKlib: Boolean = false,
): FirElementSerializer =
FirElementSerializer(
session, scopeSession, null,
@@ -1155,6 +1160,7 @@ class FirElementSerializer private constructor(
serializeTypeTableToFunction = false,
typeApproximator,
languageVersionSettings,
produceHeaderKlib,
)
@JvmStatic
@@ -1171,6 +1177,7 @@ class FirElementSerializer private constructor(
versionRequirementTable = null, serializeTypeTableToFunction = true,
typeApproximator,
languageVersionSettings,
produceHeaderKlib = false,
)
@JvmStatic
@@ -1182,16 +1189,17 @@ class FirElementSerializer private constructor(
parentSerializer: FirElementSerializer?,
typeApproximator: AbstractTypeApproximator,
languageVersionSettings: LanguageVersionSettings,
produceHeaderKlib: Boolean = false,
): FirElementSerializer {
val parentClassId = klass.symbol.classId.outerClassId
val parent = if (parentClassId != null && !parentClassId.isLocal) {
val parentClass = session.symbolProvider.getClassLikeSymbolByClassId(parentClassId)!!.fir as FirRegularClass
parentSerializer ?: create(
session, scopeSession, parentClass, extension, null, typeApproximator,
languageVersionSettings,
languageVersionSettings, produceHeaderKlib
)
} else {
createTopLevel(session, scopeSession, extension, typeApproximator, languageVersionSettings)
createTopLevel(session, scopeSession, extension, typeApproximator, languageVersionSettings, produceHeaderKlib)
}
// Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
@@ -1212,6 +1220,7 @@ class FirElementSerializer private constructor(
serializeTypeTableToFunction = false,
typeApproximator,
languageVersionSettings,
produceHeaderKlib,
)
for (typeParameter in klass.typeParameters) {
if (typeParameter !is FirTypeParameter) continue
@@ -22,12 +22,14 @@ fun serializeSingleFirFile(
actualizedExpectDeclarations: Set<FirDeclaration>?,
serializerExtension: FirKLibSerializerExtension,
languageVersionSettings: LanguageVersionSettings,
produceHeaderKlib: Boolean = false,
): ProtoBuf.PackageFragment {
val approximator = TypeApproximatorForMetadataSerializer(session)
val packageSerializer = FirElementSerializer.createTopLevel(
session, scopeSession, serializerExtension,
approximator,
languageVersionSettings
languageVersionSettings,
produceHeaderKlib
)
// TODO: typealiases (see klib serializer)
@@ -40,13 +42,16 @@ fun serializeSingleFirFile(
fun List<FirClassSymbol<*>>.makeClassesProtoWithNested() {
val classSymbols = this
.filter { it.fir.shouldBeSerialized(actualizedExpectDeclarations) }
.filter {
it.fir.isNotExpectOrShouldBeSerialized(actualizedExpectDeclarations) &&
it.fir.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)
}
.sortedBy { it.classId.asFqNameString() }
for (symbol in classSymbols) {
val klass = symbol.fir
val classSerializer = FirElementSerializer.create(
session, scopeSession, klass, serializerExtension, null,
approximator, languageVersionSettings
approximator, languageVersionSettings, produceHeaderKlib
)
val index = classSerializer.stringTable.getFqNameIndex(klass)
@@ -60,7 +65,8 @@ fun serializeSingleFirFile(
}
val hasTopLevelDeclarations = file.declarations.any {
it is FirMemberDeclaration && it.shouldBeSerialized(actualizedExpectDeclarations) &&
it is FirMemberDeclaration && it.isNotExpectOrShouldBeSerialized(actualizedExpectDeclarations) &&
it.isNotPrivateOrShouldBeSerialized(produceHeaderKlib) &&
(it is FirProperty || it is FirSimpleFunction || it is FirTypeAlias)
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
@@ -47,6 +48,10 @@ fun ConeKotlinType.suspendFunctionTypeToFunctionTypeWithContinuation(session: Fi
)
}
fun FirMemberDeclaration.shouldBeSerialized(actualizedExpectDeclaration: Set<FirDeclaration>?): Boolean {
fun FirMemberDeclaration.isNotExpectOrShouldBeSerialized(actualizedExpectDeclaration: Set<FirDeclaration>?): Boolean {
return !isExpect || actualizedExpectDeclaration == null || this !in actualizedExpectDeclaration
}
fun FirMemberDeclaration.isNotPrivateOrShouldBeSerialized(produceHeaderKlib: Boolean): Boolean {
return !produceHeaderKlib || visibility.isPublicAPI
}