K2/Native: support cinterop forward declarations

Support importing synthetic declarations from "magic" forward
declaration packages:
- cnames.structs
- objcnames.classes
- objcnames.protocols

So this is a rough equivalent to the forward declarations module
made of ForwardDeclarationsPackageFragmentDescriptor in K1.

Unlike K1 implementation, this K2 one doesn't allow importing
a declaration that wasn't actually forward-declared in a C/Objective-C
header available through a cinterop klib dependency.
This commit is contained in:
Svyatoslav Scherbina
2023-02-10 20:17:05 +00:00
committed by Space Team
parent 1936efed11
commit b19058caef
3 changed files with 176 additions and 9 deletions
@@ -38,8 +38,16 @@ object FirNativeSessionFactory : FirAbstractSessionFactory() {
registerExtraComponents,
createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } },
createProviders = { session, builtinsModuleData, kotlinScopeProvider ->
val forwardDeclarationsModuleData = BinaryModuleData.createDependencyModuleData(
Name.special("<forward declarations>"),
moduleDataProvider.platform,
moduleDataProvider.analyzerServices,
).apply {
bindSession(session)
}
listOf(
KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, resolvedLibraries),
NativeForwardDeclarationsSymbolProvider(session, forwardDeclarationsModuleData, kotlinScopeProvider, resolvedLibraries),
FirBuiltinSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
FirExtensionSyntheticFunctionInterfaceProvider(session, builtinsModuleData, kotlinScopeProvider),
FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
@@ -0,0 +1,148 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.session
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass
import org.jetbrains.kotlin.fir.declarations.getDeprecationsProvider
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.constructClassType
import org.jetbrains.kotlin.library.includedForwardDeclarations
import org.jetbrains.kotlin.library.isInterop
import org.jetbrains.kotlin.library.metadata.impl.ForwardDeclarationKind
import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class NativeForwardDeclarationsSymbolProvider(
session: FirSession,
private val forwardDeclarationsModuleData: FirModuleData,
private val kotlinScopeProvider: FirKotlinScopeProvider,
private val resolvedLibraries: Collection<KotlinResolvedLibrary>,
) : FirSymbolProvider(session) {
private companion object {
private val validPackages = ForwardDeclarationKind.packageFqNameToKind.keys
}
private val includedForwardDeclarations: Set<ClassId> by lazy {
buildSet {
for (resolvedLibrary in resolvedLibraries) {
val library = resolvedLibrary.library
if (!library.isInterop) continue
for (fqName in library.includedForwardDeclarations) {
val classId = ClassId.topLevel(FqName(fqName))
if (classId.packageFqName in validPackages) add(classId)
}
}
}
}
private val includedForwardDeclarationsByPackage: Map<FqName, Set<String>> by lazy {
buildMap<FqName, MutableSet<String>> {
for (classId in includedForwardDeclarations) {
getOrPut(classId.packageFqName) { mutableSetOf() }
.add(classId.shortClassName.asString())
}
}
}
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
if (classId !in includedForwardDeclarations) return null
if (classId.isNestedClass) return null
return syntheticForwardDeclarationClassCache.getValue(classId)
}
private val syntheticForwardDeclarationClassCache =
session.firCachesFactory.createCache(::createSyntheticForwardDeclarationClass)
private fun createSyntheticForwardDeclarationClass(classId: ClassId): FirClassLikeSymbol<*>? {
val forwardDeclarationKind = ForwardDeclarationKind.packageFqNameToKind[classId.packageFqName] ?: return null
val symbol = FirRegularClassSymbol(classId)
buildRegularClass {
moduleData = forwardDeclarationsModuleData
origin = FirDeclarationOrigin.Synthetic
check(!classId.isNestedClass) { "Expected top-level class when building forward declaration, got $classId" }
name = classId.shortClassName
status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.FINAL,
EffectiveVisibility.Public
).apply {
// This will be wrong if we support exported forward declarations.
// See https://youtrack.jetbrains.com/issue/KT-51377 for more details.
isExpect = false
isActual = false
isCompanion = false
isInner = false
isData = false
isInline = false
isExternal = false
isFun = false
}
classKind = forwardDeclarationKind.classKind
scopeProvider = kotlinScopeProvider
this.symbol = symbol
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
superTypeRefs += buildResolvedTypeRef {
type = ConeClassLikeLookupTagImpl(forwardDeclarationKind.superClassId)
.constructClassType(emptyArray(), isNullable = false)
}
}.apply {
replaceDeprecationsProvider(getDeprecationsProvider(session))
}
return symbol
}
@FirSymbolProviderInternals
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
}
@FirSymbolProviderInternals
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
}
@FirSymbolProviderInternals
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
}
override fun getPackage(fqName: FqName): FqName? {
if (fqName in includedForwardDeclarationsByPackage) {
return fqName
}
return null
}
override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set<String> {
return includedForwardDeclarationsByPackage[packageFqName].orEmpty()
}
override fun computePackageSetWithTopLevelCallables(): Set<String> = emptySet()
override fun computeCallableNamesInPackage(packageFqName: FqName): Set<Name> = emptySet()
}
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.metadata.*
import org.jetbrains.kotlin.library.metadata.resolver.KotlinLibraryResolveResult
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
@@ -120,22 +121,18 @@ class KlibResolvedModuleDescriptorsFactoryImpl(
val module = createDescriptorOptionalBuiltsIns(FORWARD_DECLARATIONS_MODULE_NAME, storageManager, builtIns, SyntheticModulesOrigin)
fun createPackage(fqName: FqName, supertypeName: String, classKind: ClassKind) =
fun createPackage(forwardDeclarationKind: ForwardDeclarationKind) =
ForwardDeclarationsPackageFragmentDescriptor(
storageManager,
module,
fqName,
Name.identifier(supertypeName),
classKind,
forwardDeclarationKind.packageFqName,
Name.identifier(forwardDeclarationKind.superClassName),
forwardDeclarationKind.classKind,
isExpect
)
val packageFragmentProvider = PackageFragmentProviderImpl(
listOf(
createPackage(ForwardDeclarationsFqNames.cNamesStructs, "COpaque", ClassKind.CLASS),
createPackage(ForwardDeclarationsFqNames.objCNamesClasses, "ObjCObjectBase", ClassKind.CLASS),
createPackage(ForwardDeclarationsFqNames.objCNamesProtocols, "ObjCObject", ClassKind.INTERFACE)
)
ForwardDeclarationKind.values().map { createPackage(it) }
)
module.initialize(packageFragmentProvider)
@@ -235,3 +232,17 @@ object ForwardDeclarationsFqNames {
val syntheticPackages = setOf(cNames, objCNames)
}
enum class ForwardDeclarationKind(val packageFqName: FqName, val superClassName: String, val classKind: ClassKind) {
CNAMES_STRUCTS(ForwardDeclarationsFqNames.cNamesStructs, "COpaque", ClassKind.CLASS),
OBJCNAMES_CLASSES(ForwardDeclarationsFqNames.objCNamesClasses, "ObjCObjectBase", ClassKind.CLASS),
OBJCNAMES_PROTOCOLS(ForwardDeclarationsFqNames.objCNamesProtocols, "ObjCObject", ClassKind.INTERFACE)
;
val superClassId = ClassId.topLevel(ForwardDeclarationsFqNames.cInterop.child(Name.identifier(superClassName)))
companion object {
val packageFqNameToKind: Map<FqName, ForwardDeclarationKind> = ForwardDeclarationKind.values().associateBy { it.packageFqName }
}
}