[FIR] Extract SyntheticFunctionsCache from builtins provider into separate one

This is needed because now set of available synthetic functional interfaces
  depends on session, because each module can contain different plugins,
  which provide different kinds of functional types
This commit is contained in:
Dmitriy Novozhilov
2023-01-18 16:48:25 +02:00
committed by Space Team
parent e0c8f2354a
commit 87a9103cc6
12 changed files with 316 additions and 186 deletions
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirBuiltinsAn
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirBuiltinsAndCloneableSession
import org.jetbrains.kotlin.analysis.project.structure.KtBuiltinsModule
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.PrivateSessionConstructor
import org.jetbrains.kotlin.fir.SessionConfiguration
@@ -18,22 +19,22 @@ import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCloneableSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirExtensionSyntheticFunctionalInterfaceProvider
import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped
import org.jetbrains.kotlin.fir.resolve.transformers.FirDummyCompilerLazyDeclarationResolver
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.session.registerCommonComponents
import org.jetbrains.kotlin.fir.session.registerCommonComponentsAfterExtensionsAreConfigured
import org.jetbrains.kotlin.fir.session.registerCommonJavaComponents
import org.jetbrains.kotlin.fir.session.registerModuleData
import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver
import java.util.concurrent.ConcurrentHashMap
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.fir.resolve.transformers.FirDummyCompilerLazyDeclarationResolver
import org.jetbrains.kotlin.fir.session.registerCommonComponentsAfterExtensionsAreConfigured
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.isCommon
import org.jetbrains.kotlin.platform.isJs
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import java.util.concurrent.ConcurrentHashMap
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
class LLFirBuiltinsSessionFactory(
@@ -63,6 +64,7 @@ class LLFirBuiltinsSessionFactory(
register(FirKotlinScopeProvider::class, kotlinScopeProvider)
val symbolProvider = createCompositeSymbolProvider(this) {
add(LLFirBuiltinSymbolProvider(this@session, moduleData, kotlinScopeProvider))
add(FirExtensionSyntheticFunctionalInterfaceProvider(this@session, moduleData, kotlinScopeProvider))
add(FirCloneableSymbolProvider(this@session, moduleData, kotlinScopeProvider))
}
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper
import org.jetbrains.kotlin.fir.extensions.*
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.*
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirExtensionSyntheticFunctionalInterfaceProvider
import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.session.*
@@ -148,6 +149,7 @@ internal object LLFirSessionFactory {
}
val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope)
val syntheticFunctionalInterfaceProvider = FirExtensionSyntheticFunctionalInterfaceProvider(this, moduleData, scopeProvider)
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
@@ -157,6 +159,7 @@ internal object LLFirSessionFactory {
provider.symbolProvider,
switchableExtensionDeclarationsSymbolProvider,
javaSymbolProvider,
syntheticFunctionalInterfaceProvider,
),
)
)
@@ -130,3 +130,12 @@ abstract class ConeFunctionalTypeKind internal constructor(
override fun nonReflectKind(): ConeFunctionalTypeKind = SuspendFunction
}
}
val ConeFunctionalTypeKind.isBuiltin: Boolean
get() = when (this) {
ConeFunctionalTypeKind.Function,
ConeFunctionalTypeKind.KFunction,
ConeFunctionalTypeKind.SuspendFunction,
ConeFunctionalTypeKind.KSuspendFunction -> true
else -> false
}
@@ -16,9 +16,7 @@ import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.resolve.providers.DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCachingCompositeSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirLibrarySessionProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.resolve.providers.impl.*
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.incremental.components.EnumWhenTracker
@@ -79,6 +77,7 @@ abstract class FirAbstractSessionFactory {
createProviders: (
FirSession, FirKotlinScopeProvider, FirSymbolProvider,
FirSwitchableExtensionDeclarationsSymbolProvider?,
FirExtensionSyntheticFunctionalInterfaceProvider,
dependencies: List<FirSymbolProvider>,
) -> List<FirSymbolProvider>
): FirSession {
@@ -110,9 +109,14 @@ abstract class FirAbstractSessionFactory {
val dependencyProviders = computeDependencyProviderList(moduleData)
val generatedSymbolsProvider = FirSwitchableExtensionDeclarationsSymbolProvider.create(this)
val syntheticFunctionalInterfaceProvider = FirExtensionSyntheticFunctionalInterfaceProvider(this, moduleData, kotlinScopeProvider)
val providers = createProviders(
this, kotlinScopeProvider, firProvider.symbolProvider, generatedSymbolsProvider,
this,
kotlinScopeProvider,
firProvider.symbolProvider,
generatedSymbolsProvider,
syntheticFunctionalInterfaceProvider,
dependencyProviders,
)
@@ -104,7 +104,7 @@ object FirCommonSessionFactory : FirAbstractSessionFactory() {
it.registerNativeCheckers()
},
createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } },
createProviders = { session, kotlinScopeProvider, symbolProvider, generatedSymbolsProvider, dependencies ->
createProviders = { session, kotlinScopeProvider, symbolProvider, syntheticFunctionalInterfaceProvider, generatedSymbolsProvider, dependencies ->
var symbolProviderForBinariesFromIncrementalCompilation: MetadataSymbolProvider? = null
var optionalAnnotationClassesProviderForBinariesFromIncrementalCompilation: OptionalAnnotationClassesProvider? = null
incrementalCompilationContext?.let {
@@ -140,6 +140,7 @@ object FirCommonSessionFactory : FirAbstractSessionFactory() {
*(incrementalCompilationContext?.previousFirSessionsSymbolProviders?.toTypedArray() ?: emptyArray()),
symbolProviderForBinariesFromIncrementalCompilation,
generatedSymbolsProvider,
syntheticFunctionalInterfaceProvider,
javaSymbolProvider,
*dependencies.toTypedArray(),
optionalAnnotationClassesProviderForBinariesFromIncrementalCompilation,
@@ -151,4 +152,4 @@ object FirCommonSessionFactory : FirAbstractSessionFactory() {
}
}
}
}
}
@@ -44,10 +44,11 @@ object FirJsSessionFactory : FirAbstractSessionFactory() {
},
registerExtraCheckers = { it.registerJsCheckers() },
createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } },
createProviders = { _, _, symbolProvider, generatedSymbolsProvider, dependencies ->
createProviders = { _, _, symbolProvider, generatedSymbolsProvider, syntheticFunctionalInterfaceProvider, dependencies ->
listOfNotNull(
symbolProvider,
generatedSymbolsProvider,
syntheticFunctionalInterfaceProvider,
*dependencies.toTypedArray(),
)
}
@@ -78,6 +79,7 @@ object FirJsSessionFactory : FirAbstractSessionFactory() {
// TODO: consider using "poisoning" provider for builtins to ensure that proper ones are taken from dependencies
// NOTE: it requires precise filtering for true nuiltins, like Function*
FirBuiltinSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
FirExtensionSyntheticFunctionalInterfaceProvider(session, builtinsModuleData, kotlinScopeProvider),
)
}
)
@@ -58,6 +58,7 @@ object FirJvmSessionFactory : FirAbstractSessionFactory() {
projectEnvironment.getFirJavaFacade(session, moduleDataProvider.allModuleData.last(), scope)
),
FirBuiltinSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
FirExtensionSyntheticFunctionalInterfaceProvider(session, builtinsModuleData, kotlinScopeProvider),
FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
OptionalAnnotationClassesProvider(
session,
@@ -100,7 +101,7 @@ object FirJvmSessionFactory : FirAbstractSessionFactory() {
},
registerExtraCheckers = { it.registerJvmCheckers() },
createKotlinScopeProvider = { FirKotlinScopeProvider(::wrapScopeWithJvmMapped) },
createProviders = { session, kotlinScopeProvider, symbolProvider, generatedSymbolsProvider, dependencies ->
createProviders = { session, kotlinScopeProvider, symbolProvider, generatedSymbolsProvider, syntheticFunctionalInterfaceProvider, dependencies ->
var symbolProviderForBinariesFromIncrementalCompilation: JvmClassFileBasedSymbolProvider? = null
var optionalAnnotationClassesProviderForBinariesFromIncrementalCompilation: OptionalAnnotationClassesProvider? = null
incrementalCompilationContext?.let {
@@ -137,6 +138,7 @@ object FirJvmSessionFactory : FirAbstractSessionFactory() {
symbolProviderForBinariesFromIncrementalCompilation,
generatedSymbolsProvider,
javaSymbolProvider,
syntheticFunctionalInterfaceProvider,
*dependencies.toTypedArray(),
optionalAnnotationClassesProviderForBinariesFromIncrementalCompilation,
)
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirBuiltinSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCloneableSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirExtensionSyntheticFunctionalInterfaceProvider
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper
import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
@@ -40,6 +41,7 @@ object FirNativeSessionFactory : FirAbstractSessionFactory() {
listOf(
KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, resolvedLibraries),
FirBuiltinSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
FirExtensionSyntheticFunctionalInterfaceProvider(session, builtinsModuleData, kotlinScopeProvider),
FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
)
})
@@ -67,10 +69,11 @@ object FirNativeSessionFactory : FirAbstractSessionFactory() {
},
registerExtraCheckers = { it.registerNativeCheckers() },
createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } },
createProviders = { _, _, symbolProvider, generatedSymbolsProvider, dependencies ->
createProviders = { _, _, symbolProvider, generatedSymbolsProvider, syntheticFunctionalInterfaceProvider, dependencies ->
listOfNotNull(
symbolProvider,
generatedSymbolsProvider,
syntheticFunctionalInterfaceProvider,
*dependencies.toTypedArray(),
)
}
@@ -5,43 +5,33 @@
package org.jetbrains.kotlin.fir.resolve.providers.impl
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
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.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.utils.addDeclaration
import org.jetbrains.kotlin.fir.deserialization.FirBuiltinAnnotationDeserializer
import org.jetbrains.kotlin.fir.deserialization.FirConstDeserializer
import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext
import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.resolve.defaultType
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.*
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.io.InputStream
@ThreadSafeMutableState
@@ -50,8 +40,13 @@ open class FirBuiltinSymbolProvider(
val moduleData: FirModuleData,
val kotlinScopeProvider: FirKotlinScopeProvider
) : FirSymbolProvider(session) {
private val syntheticFunctionalInterfaceProvider = FirBuiltinSyntheticFunctionalInterfaceProvider(
session,
moduleData,
kotlinScopeProvider
)
private val allPackageFragments = loadBuiltIns().groupBy { it.fqName }
private val syntheticFunctionalInterfaceCache = SyntheticFunctionalInterfaceCache(session, moduleData, kotlinScopeProvider)
private fun loadBuiltIns(): List<BuiltInsPackageFragment> {
val classLoader = this::class.java.classLoader
@@ -73,7 +68,7 @@ open class FirBuiltinSymbolProvider(
override fun getClassLikeSymbolByClassId(classId: ClassId): FirRegularClassSymbol? {
return allPackageFragments[classId.packageFqName]?.firstNotNullOfOrNull {
it.getClassLikeSymbolByClassId(classId)
} ?: syntheticFunctionalInterfaceCache.tryGetSyntheticFunctionalInterface(classId)
} ?: syntheticFunctionalInterfaceProvider.getClassLikeSymbolByClassId(classId)
}
override fun computePackageSetWithTopLevelCallables(): Set<String> =
@@ -199,155 +194,3 @@ private data class BinaryVersionAndPackageFragment(
}
}
private class SyntheticFunctionalInterfaceCache(
private val session: FirSession,
private val moduleData: FirModuleData,
private val kotlinScopeProvider: FirKotlinScopeProvider
) {
private val syntheticFunctionalInterfaceCache =
moduleData.session.firCachesFactory.createCache(::createSyntheticFunctionalInterface)
fun tryGetSyntheticFunctionalInterface(classId: ClassId): FirRegularClassSymbol? {
return syntheticFunctionalInterfaceCache.getValue(classId)
}
private fun createSyntheticFunctionalInterface(classId: ClassId): FirRegularClassSymbol? {
return with(classId) {
val className = relativeClassName.asString()
val kind = session.functionalTypeService.getKindByClassNamePrefix(packageFqName, className) ?: return null
val prefix = kind.classNamePrefix
val arity = className.substring(prefix.length).toIntOrNull() ?: return null
FirRegularClassSymbol(classId).apply symbol@{
buildRegularClass klass@{
moduleData = this@SyntheticFunctionalInterfaceCache.moduleData
origin = FirDeclarationOrigin.BuiltIns
name = relativeClassName.shortName()
status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.ABSTRACT,
EffectiveVisibility.Public
).apply {
isExpect = false
isActual = false
isInner = false
isCompanion = false
isData = false
isInline = false
}
classKind = ClassKind.INTERFACE
scopeProvider = kotlinScopeProvider
symbol = this@symbol
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters.addAll(
(1..arity).map {
buildTypeParameter {
moduleData = this@SyntheticFunctionalInterfaceCache.moduleData
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.BuiltIns
name = Name.identifier("P$it")
symbol = FirTypeParameterSymbol()
containingDeclarationSymbol = this@symbol
variance = Variance.IN_VARIANCE
isReified = false
bounds += moduleData.session.builtinTypes.nullableAnyType
}
},
)
typeParameters.add(
buildTypeParameter {
moduleData = this@SyntheticFunctionalInterfaceCache.moduleData
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.BuiltIns
name = Name.identifier("R")
symbol = FirTypeParameterSymbol()
containingDeclarationSymbol = this@symbol
variance = Variance.OUT_VARIANCE
isReified = false
bounds += moduleData.session.builtinTypes.nullableAnyType
},
)
val name = OperatorNameConventions.INVOKE
val functionStatus = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.ABSTRACT,
EffectiveVisibility.Public
).apply {
isExpect = false
isActual = false
isOverride = false
isOperator = true
isInfix = false
isInline = false
isTailRec = false
isExternal = false
isSuspend =
kind == ConeFunctionalTypeKind.SuspendFunction ||
kind == ConeFunctionalTypeKind.KSuspendFunction
}
val typeArguments = typeParameters.map {
ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false).toFirResolvedTypeRef()
}
fun createSuperType(kind: ConeFunctionalTypeKind): FirResolvedTypeRef {
return kind.classId(arity).toLookupTag()
.constructClassType(typeArguments.map { it.type }.toTypedArray(), isNullable = false)
.toFirResolvedTypeRef()
}
if (kind.isReflectType) {
superTypeRefs += StandardClassIds.KFunction.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
.toFirResolvedTypeRef()
superTypeRefs += createSuperType(kind.nonReflectKind())
} else {
superTypeRefs += StandardClassIds.Function.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
.toFirResolvedTypeRef()
}
addDeclaration(
buildSimpleFunction {
moduleData = this@SyntheticFunctionalInterfaceCache.moduleData
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.BuiltIns
returnTypeRef = typeArguments.last()
this.name = name
status = functionStatus
symbol = FirNamedFunctionSymbol(
CallableId(packageFqName, relativeClassName, name)
)
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
valueParameters += typeArguments.dropLast(1).mapIndexed { index, typeArgument ->
val parameterName = Name.identifier("p${index + 1}")
buildValueParameter {
moduleData = this@SyntheticFunctionalInterfaceCache.moduleData
containingFunctionSymbol = this@buildSimpleFunction.symbol
origin = FirDeclarationOrigin.BuiltIns
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
returnTypeRef = typeArgument
this.name = parameterName
symbol = FirValueParameterSymbol(parameterName)
defaultValue = null
isCrossinline = false
isNoinline = false
isVararg = false
}
}
dispatchReceiverType = classId.defaultType(this@klass.typeParameters.map { it.symbol })
kind.annotationOnInvokeClassId?.let { annotationClassId ->
annotations += buildAnnotation {
annotationTypeRef = annotationClassId
.constructClassLikeType(emptyArray(), isNullable = false)
.toFirResolvedTypeRef()
argumentMapping = FirEmptyAnnotationArgumentMapping
}
}
}
)
}
}
}
}
private fun ConeFunctionalTypeKind.classId(arity: Int) = ClassId(packageFqName, numberedClassName(arity))
}
@@ -0,0 +1,245 @@
/*
* 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.resolve.providers.impl
import org.jetbrains.kotlin.descriptors.ClassKind
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.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.utils.addDeclaration
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.resolve.defaultType
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.*
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
/*
* Provides functional interfaces for functional kinds from compiler plugins
*/
class FirExtensionSyntheticFunctionalInterfaceProvider(
session: FirSession,
moduleData: FirModuleData,
kotlinScopeProvider: FirKotlinScopeProvider
) : FirSyntheticFunctionalInterfaceProviderBase(session, moduleData, kotlinScopeProvider) {
override fun ConeFunctionalTypeKind.isAcceptable(): Boolean {
return !this.isBuiltin
}
}
/*
* Provides kotlin.FunctionN, kotlin.coroutines.SuspendFunctionN, kotlin.reflect.KFunctionN and kotlin.reflect.KSuspendFunctionN
*/
class FirBuiltinSyntheticFunctionalInterfaceProvider(
session: FirSession,
moduleData: FirModuleData,
kotlinScopeProvider: FirKotlinScopeProvider
) : FirSyntheticFunctionalInterfaceProviderBase(session, moduleData, kotlinScopeProvider) {
override fun ConeFunctionalTypeKind.isAcceptable(): Boolean {
return this.isBuiltin
}
}
abstract class FirSyntheticFunctionalInterfaceProviderBase(
session: FirSession,
val moduleData: FirModuleData,
val kotlinScopeProvider: FirKotlinScopeProvider
) : FirSymbolProvider(session) {
override fun getClassLikeSymbolByClassId(classId: ClassId): FirRegularClassSymbol? {
return cache.getValue(classId)
}
@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? {
return fqName.takeIf { session.functionalTypeService.hasKindWithSpecificPackage(it) }
}
override fun computePackageSetWithTopLevelCallables(): Set<String> {
return emptySet()
}
/**
* This method has no sence for synthetic functional interfaces
*/
override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set<String>? {
return emptySet()
}
override fun computeCallableNamesInPackage(packageFqName: FqName): Set<Name>? {
return emptySet()
}
private val cache = moduleData.session.firCachesFactory.createCache(::createSyntheticFunctionalInterface)
protected abstract fun ConeFunctionalTypeKind.isAcceptable(): Boolean
private fun createSyntheticFunctionalInterface(classId: ClassId): FirRegularClassSymbol? {
return with(classId) {
val className = relativeClassName.asString()
val kind = session.functionalTypeService.getKindByClassNamePrefix(packageFqName, className) ?: return null
if (!kind.isAcceptable()) return null
val prefix = kind.classNamePrefix
val arity = className.substring(prefix.length).toIntOrNull() ?: return null
FirRegularClassSymbol(classId).apply symbol@{
buildRegularClass klass@{
moduleData = this@FirSyntheticFunctionalInterfaceProviderBase.moduleData
origin = FirDeclarationOrigin.BuiltIns
name = relativeClassName.shortName()
status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.ABSTRACT,
EffectiveVisibility.Public
).apply {
isExpect = false
isActual = false
isInner = false
isCompanion = false
isData = false
isInline = false
}
classKind = ClassKind.INTERFACE
scopeProvider = kotlinScopeProvider
symbol = this@symbol
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters.addAll(
(1..arity).map {
buildTypeParameter {
moduleData = this@FirSyntheticFunctionalInterfaceProviderBase.moduleData
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.BuiltIns
name = Name.identifier("P$it")
symbol = FirTypeParameterSymbol()
containingDeclarationSymbol = this@symbol
variance = Variance.IN_VARIANCE
isReified = false
bounds += moduleData.session.builtinTypes.nullableAnyType
}
},
)
typeParameters.add(
buildTypeParameter {
moduleData = this@FirSyntheticFunctionalInterfaceProviderBase.moduleData
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.BuiltIns
name = Name.identifier("R")
symbol = FirTypeParameterSymbol()
containingDeclarationSymbol = this@symbol
variance = Variance.OUT_VARIANCE
isReified = false
bounds += moduleData.session.builtinTypes.nullableAnyType
},
)
val name = OperatorNameConventions.INVOKE
val functionStatus = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.ABSTRACT,
EffectiveVisibility.Public
).apply {
isExpect = false
isActual = false
isOverride = false
isOperator = true
isInfix = false
isInline = false
isTailRec = false
isExternal = false
isSuspend =
kind == ConeFunctionalTypeKind.SuspendFunction ||
kind == ConeFunctionalTypeKind.KSuspendFunction
}
val typeArguments = typeParameters.map {
ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false).toFirResolvedTypeRef()
}
fun createSuperType(kind: ConeFunctionalTypeKind): FirResolvedTypeRef {
return kind.classId(arity).toLookupTag()
.constructClassType(typeArguments.map { it.type }.toTypedArray(), isNullable = false)
.toFirResolvedTypeRef()
}
if (kind.isReflectType) {
superTypeRefs += StandardClassIds.KFunction.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
.toFirResolvedTypeRef()
superTypeRefs += createSuperType(kind.nonReflectKind())
} else {
superTypeRefs += StandardClassIds.Function.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
.toFirResolvedTypeRef()
}
addDeclaration(
buildSimpleFunction {
moduleData = this@FirSyntheticFunctionalInterfaceProviderBase.moduleData
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.BuiltIns
returnTypeRef = typeArguments.last()
this.name = name
status = functionStatus
symbol = FirNamedFunctionSymbol(
CallableId(packageFqName, relativeClassName, name)
)
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
valueParameters += typeArguments.dropLast(1).mapIndexed { index, typeArgument ->
val parameterName = Name.identifier("p${index + 1}")
buildValueParameter {
moduleData = this@FirSyntheticFunctionalInterfaceProviderBase.moduleData
containingFunctionSymbol = this@buildSimpleFunction.symbol
origin = FirDeclarationOrigin.BuiltIns
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
returnTypeRef = typeArgument
this.name = parameterName
symbol = FirValueParameterSymbol(parameterName)
defaultValue = null
isCrossinline = false
isNoinline = false
isVararg = false
}
}
dispatchReceiverType = classId.defaultType(this@klass.typeParameters.map { it.symbol })
kind.annotationOnInvokeClassId?.let { annotationClassId ->
annotations += buildAnnotation {
annotationTypeRef = annotationClassId
.constructClassLikeType(emptyArray(), isNullable = false)
.toFirResolvedTypeRef()
argumentMapping = FirEmptyAnnotationArgumentMapping
}
}
}
)
}
}
}
}
private fun ConeFunctionalTypeKind.classId(arity: Int) = ClassId(packageFqName, numberedClassName(arity))
}
@@ -47,4 +47,8 @@ class FirFunctionalTypeKindServiceImpl(session: FirSession) : FirFunctionalTypeK
}
return null
}
override fun hasKindWithSpecificPackage(packageFqName: FqName): Boolean {
return packageFqName in knownKindsByPackageFqName
}
}
@@ -12,11 +12,19 @@ import org.jetbrains.kotlin.name.FqName
abstract class FirFunctionalTypeKindService : FirSessionComponent {
abstract fun getKindByClassNamePrefix(packageFqName: FqName, className: String): ConeFunctionalTypeKind?
abstract fun hasKindWithSpecificPackage(packageFqName: FqName): Boolean
/*
* Should be used only in places where session is unavaliable by default (e.g. in default cone type render)
*/
object Default : FirFunctionalTypeKindService() {
private val packages = listOf(
ConeFunctionalTypeKind.Function,
ConeFunctionalTypeKind.SuspendFunction,
ConeFunctionalTypeKind.KFunction,
ConeFunctionalTypeKind.KSuspendFunction,
).map { it.packageFqName }.toSet()
override fun getKindByClassNamePrefix(packageFqName: FqName, className: String): ConeFunctionalTypeKind? {
return when (FunctionClassKind.parseClassName(className, packageFqName)?.kind) {
FunctionClassKind.Function -> ConeFunctionalTypeKind.Function
@@ -26,6 +34,10 @@ abstract class FirFunctionalTypeKindService : FirSessionComponent {
null -> null
}
}
override fun hasKindWithSpecificPackage(packageFqName: FqName): Boolean {
return packageFqName in packages
}
}
}