Fix exceptions caused by cyclic dependency between ModuleDescriptor and JvmBuiltIns

^KT-39105 Fixed
^KT-42001 Fixed

See also EA-216604 and EA-211562
This commit is contained in:
Denis.Zharkov
2020-12-22 18:26:52 +03:00
parent 5a8dc00a0d
commit 7b9f6c1560
8 changed files with 90 additions and 48 deletions
@@ -53,25 +53,35 @@ class JvmBuiltIns(storageManager: StorageManager, kind: Kind) : KotlinBuiltIns(s
FALLBACK,
}
// Module containing JDK classes or having them among dependencies
private var ownerModuleDescriptor: ModuleDescriptor? = null
private var isAdditionalBuiltInsFeatureSupported: Boolean = true
class Settings(
// Module containing JDK classes or having them among dependencies
val ownerModuleDescriptor: ModuleDescriptor,
val isAdditionalBuiltInsFeatureSupported: Boolean,
)
private var settingsComputation: (() -> Settings)? = null
fun setPostponedSettingsComputation(computation: () -> Settings) {
assert(settingsComputation == null) { "JvmBuiltins repeated initialization" }
settingsComputation = computation
}
fun initialize(moduleDescriptor: ModuleDescriptor, isAdditionalBuiltInsFeatureSupported: Boolean) {
assert(ownerModuleDescriptor == null) { "JvmBuiltins repeated initialization" }
this.ownerModuleDescriptor = moduleDescriptor
this.isAdditionalBuiltInsFeatureSupported = isAdditionalBuiltInsFeatureSupported
setPostponedSettingsComputation {
Settings(moduleDescriptor, isAdditionalBuiltInsFeatureSupported)
}
}
val customizer: JvmBuiltInsCustomizer by storageManager.createLazyValue {
JvmBuiltInsCustomizer(
builtInsModule, storageManager,
{ ownerModuleDescriptor.sure { "JvmBuiltins has not been initialized properly" } },
{
ownerModuleDescriptor.sure { "JvmBuiltins has not been initialized properly" }
isAdditionalBuiltInsFeatureSupported
}
)
builtInsModule, storageManager
) {
settingsComputation
.sure { "JvmBuiltins instance has not been initialized properly" }
.invoke().also {
settingsComputation = null
}
}
}
init {
@@ -50,19 +50,17 @@ import java.util.*
class JvmBuiltInsCustomizer(
private val moduleDescriptor: ModuleDescriptor,
storageManager: StorageManager,
deferredOwnerModuleDescriptor: () -> ModuleDescriptor,
isAdditionalBuiltInsFeatureSupported: () -> Boolean
settingsComputation: () -> JvmBuiltIns.Settings,
) : AdditionalClassPartsProvider, PlatformDependentDeclarationFilter {
private val j2kClassMapper = JavaToKotlinClassMapper
private val ownerModuleDescriptor: ModuleDescriptor by lazy(deferredOwnerModuleDescriptor)
private val isAdditionalBuiltInsFeatureSupported: Boolean by lazy(isAdditionalBuiltInsFeatureSupported)
private val settings by storageManager.createLazyValue(settingsComputation)
private val mockSerializableType = storageManager.createMockJavaIoSerializableType()
private val cloneableType by storageManager.createLazyValue {
ownerModuleDescriptor.findNonGenericClassAcrossDependencies(
settings.ownerModuleDescriptor.findNonGenericClassAcrossDependencies(
JvmBuiltInClassDescriptorFactory.CLONEABLE_CLASS_ID,
NotFoundClasses(storageManager, ownerModuleDescriptor)
NotFoundClasses(storageManager, settings.ownerModuleDescriptor)
).defaultType
}
@@ -119,7 +117,7 @@ class JvmBuiltInsCustomizer(
)
}
if (!isAdditionalBuiltInsFeatureSupported) return emptyList()
if (!settings.isAdditionalBuiltInsFeatureSupported) return emptyList()
return getAdditionalFunctions(classDescriptor) {
it.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS)
@@ -158,7 +156,7 @@ class JvmBuiltInsCustomizer(
}
override fun getFunctionsNames(classDescriptor: ClassDescriptor): Set<Name> {
if (!isAdditionalBuiltInsFeatureSupported) return emptySet()
if (!settings.isAdditionalBuiltInsFeatureSupported) return emptySet()
// NB: It's just an approximation that could be calculated relatively fast
// More precise computation would look like `getAdditionalFunctions` (and the measurements show that it would be rather slow)
return classDescriptor.getJavaAnalogue()?.unsubstitutedMemberScope?.getFunctionNames() ?: emptySet()
@@ -270,11 +268,11 @@ class JvmBuiltInsCustomizer(
if (!fqName.isSafe) return null
val javaAnalogueFqName = JavaToKotlinClassMap.mapKotlinToJava(fqName)?.asSingleFqName() ?: return null
return ownerModuleDescriptor.resolveClassByFqName(javaAnalogueFqName, NoLookupLocation.FROM_BUILTINS) as? LazyJavaClassDescriptor
return settings.ownerModuleDescriptor.resolveClassByFqName(javaAnalogueFqName, NoLookupLocation.FROM_BUILTINS) as? LazyJavaClassDescriptor
}
override fun getConstructors(classDescriptor: ClassDescriptor): Collection<ClassConstructorDescriptor> {
if (classDescriptor.kind != ClassKind.CLASS || !isAdditionalBuiltInsFeatureSupported) return emptyList()
if (classDescriptor.kind != ClassKind.CLASS || !settings.isAdditionalBuiltInsFeatureSupported) return emptyList()
val javaAnalogueDescriptor = classDescriptor.getJavaAnalogue() ?: return emptyList()
@@ -317,7 +315,7 @@ class JvmBuiltInsCustomizer(
val javaAnalogueClassDescriptor = classDescriptor.getJavaAnalogue() ?: return true
if (!functionDescriptor.annotations.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME)) return true
if (!isAdditionalBuiltInsFeatureSupported) return false
if (!settings.isAdditionalBuiltInsFeatureSupported) return false
val jvmDescriptor = functionDescriptor.computeJvmDescriptor()
return javaAnalogueClassDescriptor
@@ -14,6 +14,7 @@ import com.intellij.util.PathUtil
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
@@ -53,7 +55,12 @@ class CommonPlatformKindResolution : IdePlatformKindResolution {
override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?): BuiltInsCacheKey = BuiltInsCacheKey.DefaultBuiltInsKey
override fun createBuiltIns(moduleInfo: ModuleInfo, projectContext: ProjectContext, sdkDependency: SdkInfo?): KotlinBuiltIns {
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?
): KotlinBuiltIns {
return DefaultBuiltIns.Instance
}
@@ -23,12 +23,14 @@ import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
@@ -41,7 +43,12 @@ interface IdePlatformKindResolution {
val kind: IdePlatformKind<*>
fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?): BuiltInsCacheKey
fun createBuiltIns(moduleInfo: ModuleInfo, projectContext: ProjectContext, sdkDependency: SdkInfo?): KotlinBuiltIns
fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?
): KotlinBuiltIns
fun createResolverForModuleFactory(
settings: PlatformAnalysisParameters,
@@ -88,4 +95,4 @@ interface IdePlatformKindResolution {
}
val IdePlatformKind<*>.resolution: IdePlatformKindResolution
get() = IdePlatformKindResolution.getResolution(this)
get() = IdePlatformKindResolution.getResolution(this)
@@ -14,12 +14,14 @@ import com.intellij.util.PathUtil
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
@@ -53,7 +55,12 @@ class JsPlatformKindResolution : IdePlatformKindResolution {
return BuiltInsCacheKey.DefaultBuiltInsKey
}
override fun createBuiltIns(moduleInfo: ModuleInfo, projectContext: ProjectContext, sdkDependency: SdkInfo?): KotlinBuiltIns {
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?
): KotlinBuiltIns {
return DefaultBuiltIns.Instance
}
@@ -13,13 +13,16 @@ import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.idea.caches.resolve.supportsAdditionalBuiltInsMembers
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
@@ -52,9 +55,23 @@ class JvmPlatformKindResolution : IdePlatformKindResolution {
return if (sdkInfo != null) CacheKeyBySdk(sdkInfo.sdk) else BuiltInsCacheKey.DefaultBuiltInsKey
}
override fun createBuiltIns(moduleInfo: ModuleInfo, projectContext: ProjectContext, sdkDependency: SdkInfo?): KotlinBuiltIns {
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?
): KotlinBuiltIns {
return if (sdkDependency != null)
JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER)
JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER).apply {
setPostponedSettingsComputation {
// SDK should be present, otherwise we wouldn't have created JvmBuiltIns in createBuiltIns
val sdkDescriptor = resolverForProject.descriptorForModule(sdkDependency)
val isAdditionalBuiltInsFeaturesSupported =
moduleInfo.supportsAdditionalBuiltInsMembers(projectContext.project)
JvmBuiltIns.Settings(sdkDescriptor, isAdditionalBuiltInsFeaturesSupported)
}
}
else
DefaultBuiltIns.Instance
}
@@ -10,7 +10,6 @@ import com.intellij.openapi.util.ModificationTracker
import org.jetbrains.kotlin.analyzer.*
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
import org.jetbrains.kotlin.caches.resolve.CompositeAnalyzerServices
import org.jetbrains.kotlin.caches.resolve.CompositeResolverForModuleFactory
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
@@ -145,21 +144,12 @@ class IdeaResolverForProject(
val cachedBuiltIns = cache[key]
if (cachedBuiltIns != null) return@compute cachedBuiltIns
// Note #1: we can't use .getOrPut, because we have to put builtIns into map *before* initialization
// Note #2: it's OK to put not-initialized built-ins into public map, because access to [cache] is guarded by storageManager.lock
val newBuiltIns = module.platform.idePlatformKind.resolution.createBuiltIns(module, projectContextFromSdkResolver, sdk)
cache[key] = newBuiltIns
if (newBuiltIns is JvmBuiltIns) {
// SDK should be present, otherwise we wouldn't have created JvmBuiltIns in createBuiltIns
val sdkDescriptor = resolverForSdk.descriptorForModule(sdk!!)
val isAdditionalBuiltInsFeaturesSupported = module.supportsAdditionalBuiltInsMembers(projectContextFromSdkResolver.project)
newBuiltIns.initialize(sdkDescriptor, isAdditionalBuiltInsFeaturesSupported)
}
return@compute newBuiltIns
module.platform.idePlatformKind.resolution
.createBuiltIns(module, projectContextFromSdkResolver, resolverForSdk, sdk)
.also {
// TODO: MemoizedFunction should be used here instead, but for proper we also need a module (for LV settings) that is not contained in the key
cache[key] = it
}
}
}
@@ -14,6 +14,7 @@ import com.intellij.util.PathUtil
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin
import org.jetbrains.kotlin.ide.konan.analyzer.NativeResolverForModuleFactory
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.project.lazyClosure
@@ -94,8 +96,12 @@ class NativePlatformKindResolution : IdePlatformKindResolution {
override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?): BuiltInsCacheKey = NativeBuiltInsCacheKey
override fun createBuiltIns(moduleInfo: ModuleInfo, projectContext: ProjectContext, sdkDependency: SdkInfo?) =
createKotlinNativeBuiltIns(moduleInfo, projectContext)
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?
) = createKotlinNativeBuiltIns(moduleInfo, projectContext)
private fun createKotlinNativeBuiltIns(moduleInfo: ModuleInfo, projectContext: ProjectContext): KotlinBuiltIns {
val stdlibInfo = moduleInfo.findNativeStdlib() ?: return DefaultBuiltIns.Instance