From 602f642018f2f63c8b983bbcee403c21b76f5097 Mon Sep 17 00:00:00 2001 From: Dmitry Savvinov Date: Mon, 1 Apr 2019 13:00:47 +0300 Subject: [PATCH] [Injection] Make component containers composition more granular and flexible Previously, containers set-up was performed by calls to static functions like 'createContainerForLazyResolve', which would set-up whole container from scratch. This has several issues: - complicates code re-use and encourages copy-paste of one and the same set-up logic - complicates composition of multiplatform containers (because each set-up method relies on the fact that it should take an empty container and compose it completely) The idea of this commit is to split set-up methods into smaller ones, with finer areas of responsibility, which allows to re-use them in various scenarios (and, in particularly motivating composition of multiplatform container) --- .../common/CommonResolverForModuleFactory.kt | 59 +++++++++--------- .../kotlin/frontend/java/di/injection.kt | 53 ++++++++++------ .../jetbrains/kotlin/frontend/di/injection.kt | 39 +++++++++--- .../resolve/PlatformConfiguratorBase.kt | 62 +++++++++++-------- .../kotlin/frontend/js/di/injection.kt | 17 +++-- 5 files changed, 137 insertions(+), 93 deletions(-) diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/analyzer/common/CommonResolverForModuleFactory.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/analyzer/common/CommonResolverForModuleFactory.kt index 11cb4fa25cb..c0bc2797a31 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/analyzer/common/CommonResolverForModuleFactory.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/analyzer/common/CommonResolverForModuleFactory.kt @@ -19,24 +19,21 @@ package org.jetbrains.kotlin.analyzer.common import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.analyzer.* import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.platform.TargetPlatformVersion import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.get -import org.jetbrains.kotlin.container.useImpl -import org.jetbrains.kotlin.container.useInstance import org.jetbrains.kotlin.context.ModuleContext import org.jetbrains.kotlin.context.ProjectContext -import org.jetbrains.kotlin.contracts.ContractDeserializerImpl import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.container.useImpl +import org.jetbrains.kotlin.container.useInstance import org.jetbrains.kotlin.frontend.di.configureModule -import org.jetbrains.kotlin.incremental.components.ExpectActualTracker -import org.jetbrains.kotlin.incremental.components.LookupTracker +import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.CommonPlatforms @@ -141,7 +138,7 @@ object CommonResolverForModuleFactory : ResolverForModuleFactory() { val trace = CodeAnalyzerInitializer.getInstance(project).createTrace() val container = createContainerToResolveCommonCode( moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, metadataPartProvider, - languageVersionSettings + languageVersionSettings, CommonPlatforms.defaultCommonPlatform, CommonPlatformCompilerServices ) val packageFragmentProviders = listOf( @@ -151,35 +148,41 @@ object CommonResolverForModuleFactory : ResolverForModuleFactory() { return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container) } +} - private fun createContainerToResolveCommonCode( - moduleContext: ModuleContext, - bindingTrace: BindingTrace, - declarationProviderFactory: DeclarationProviderFactory, - moduleContentScope: GlobalSearchScope, - targetEnvironment: TargetEnvironment, - metadataPartProvider: MetadataPartProvider, - languageVersionSettings: LanguageVersionSettings - ): StorageComponentContainer = createContainer("ResolveCommonCode", CommonPlatformCompilerServices) { - configureModule(moduleContext, DefaultBuiltInPlatforms.commonPlatform, CommonPlatformCompilerServices, bindingTrace, languageVersionSettings) +private fun createContainerToResolveCommonCode( + moduleContext: ModuleContext, + bindingTrace: BindingTrace, + declarationProviderFactory: DeclarationProviderFactory, + moduleContentScope: GlobalSearchScope, + targetEnvironment: TargetEnvironment, + metadataPartProvider: MetadataPartProvider, + languageVersionSettings: LanguageVersionSettings, + platform: TargetPlatform, + compilerServices: PlatformDependentCompilerServices +): StorageComponentContainer = + createContainer("ResolveCommonCode", compilerServices) { + configureModule(moduleContext, platform, compilerServices, bindingTrace, languageVersionSettings) useInstance(moduleContentScope) - useInstance(LookupTracker.DO_NOTHING) - useInstance(ExpectActualTracker.DoNothing) - useImpl() - useImpl() - useImpl() - useImpl() - useInstance(metadataPartProvider) useInstance(declarationProviderFactory) - useImpl() - useImpl() + + configureStandardResolveComponents() + + configureCommonSpecificComponents() + useInstance(metadataPartProvider) useImpl() - val metadataFinderFactory = ServiceManager.getService(moduleContext.project, MetadataFinderFactory::class.java) - ?: error("No MetadataFinderFactory in project") + val metadataFinderFactory = ServiceManager.getService( + moduleContext.project, + MetadataFinderFactory::class.java + ) + ?: error("No MetadataFinderFactory in project") useInstance(metadataFinderFactory.create(moduleContentScope)) targetEnvironment.configure(this) } + +fun StorageComponentContainer.configureCommonSpecificComponents() { + useImpl() } \ No newline at end of file diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt index f8c337bd055..ff71e68a1f0 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt @@ -24,9 +24,10 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.container.* import org.jetbrains.kotlin.context.ModuleContext -import org.jetbrains.kotlin.contracts.ContractDeserializerImpl import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.frontend.di.configureIncrementalCompilation import org.jetbrains.kotlin.frontend.di.configureModule +import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.load.java.AbstractJavaClassFinder @@ -44,7 +45,6 @@ import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformCompilerServices import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer -import org.jetbrains.kotlin.resolve.lazy.ResolveSession import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory import org.jetbrains.kotlin.types.SubstitutingScopeProviderImpl @@ -66,21 +66,46 @@ fun createContainerForLazyResolveWithJava( ): StorageComponentContainer = createContainer("LazyResolveWithJava", JvmPlatformCompilerServices) { configureModule(moduleContext, jvmPlatform, JvmPlatformCompilerServices, bindingTrace, languageVersionSettings) + configureIncrementalCompilation(lookupTracker, expectActualTracker) + configureStandardResolveComponents() + useInstance(moduleContentScope) - useInstance(lookupTracker) - useInstance(expectActualTracker) - useImpl() - useImpl() + useInstance(packagePartProvider) + useInstance(declarationProviderFactory) + + useInstance(VirtualFileFinderFactory.getInstance(moduleContext.project).create(moduleContentScope)) + + configureJavaSpecificComponents( + moduleContext, moduleClassResolver, languageVersionSettings, configureJavaClassFinder, + javaClassTracker, useBuiltInsProvider + ) + + targetEnvironment.configure(this) + +}.apply { + initializeJavaSpecificComponents(bindingTrace) +} + +fun StorageComponentContainer.initializeJavaSpecificComponents(bindingTrace: BindingTrace) { + get().initialize(bindingTrace, get()) +} + +fun StorageComponentContainer.configureJavaSpecificComponents( + moduleContext: ModuleContext, + moduleClassResolver: ModuleClassResolver, + languageVersionSettings: LanguageVersionSettings, + configureJavaClassFinder: (StorageComponentContainer.() -> Unit)?, + javaClassTracker: JavaClassesTracker?, + useBuiltInsProvider: Boolean +) { useImpl() useImpl() - useInstance(VirtualFileFinderFactory.getInstance(moduleContext.project).create(moduleContentScope)) useInstance(JavaPropertyInitializerEvaluatorImpl) - useImpl() useImpl() useImpl() useInstance(InternalFlexibleTypeTransformer) - useImpl() useInstance(JavaDeprecationSettings) + useInstance(moduleClassResolver) if (configureJavaClassFinder != null) { configureJavaClassFinder() @@ -90,10 +115,6 @@ fun createContainerForLazyResolveWithJava( useImpl() } - useInstance(packagePartProvider) - useInstance(moduleClassResolver) - useInstance(declarationProviderFactory) - useInstance(languageVersionSettings.getFlag(JvmAnalysisFlags.jsr305)) if (useBuiltInsProvider) { @@ -106,16 +127,10 @@ fun createContainerForLazyResolveWithJava( JavaResolverSettings.create(isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)) ) - targetEnvironment.configure(this) - - useImpl() useImpl() useImpl() -}.apply { - get().initialize(bindingTrace, get()) } - fun ComponentProvider.initJvmBuiltInsForTopDownAnalysis() { get().initialize(get(), get()) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt b/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt index 1a29aaf1f1b..7f441d7d879 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt @@ -22,11 +22,10 @@ import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.useImpl import org.jetbrains.kotlin.container.useInstance import org.jetbrains.kotlin.context.ModuleContext +import org.jetbrains.kotlin.contracts.ContractDeserializerImpl import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.incremental.components.LookupTracker -import org.jetbrains.kotlin.platform.subplatformOfType -import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.platform.TargetPlatformVersion import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.calls.components.ClassicTypeSystemContextForCS @@ -35,7 +34,6 @@ import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionStatelessCallbac import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker import org.jetbrains.kotlin.resolve.lazy.* import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory -import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory import org.jetbrains.kotlin.types.SubstitutingScopeProviderImpl import org.jetbrains.kotlin.types.expressions.DeclarationScopeProviderForLocalClassifierAnalyzer import org.jetbrains.kotlin.types.expressions.LocalClassDescriptorHolder @@ -78,9 +76,32 @@ private fun StorageComponentContainer.configurePlatformIndependentComponents() { useImpl() useImpl() useImpl() + + useImpl() + useImpl() + useImpl() } +/** + * Actually, those should be present in 'configurePlatformIndependentComponents', + * but, unfortunately, this is currently impossible, because in some lightweight + * containers (see [createContainerForBodyResolve] and similar) some dependencies + * are missing + * + * If you're not doing some trickery with containers, you should use them. + */ +fun StorageComponentContainer.configureStandardResolveComponents() { + useImpl() + useImpl() + useImpl() +} + +fun StorageComponentContainer.configureIncrementalCompilation(lookupTracker: LookupTracker, expectActualTracker: ExpectActualTracker) { + useInstance(lookupTracker) + useInstance(expectActualTracker) +} + fun createContainerForBodyResolve( moduleContext: ModuleContext, bindingTrace: BindingTrace, @@ -163,13 +184,11 @@ fun createContainerForLazyResolve( ): StorageComponentContainer = createContainer("LazyResolve", compilerServices) { configureModule(moduleContext, platform, compilerServices, bindingTrace, languageVersionSettings) - useInstance(declarationProviderFactory) + configureStandardResolveComponents() + + useInstance(declarationProviderFactory) + useImpl() - useImpl() - useImpl() targetEnvironment.configure(this) - useImpl() - useImpl() - useImpl() -} \ No newline at end of file +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt index 0549370e12f..5fd29775f9b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt @@ -66,15 +66,24 @@ private val DEFAULT_CLASH_RESOLVERS = listOf> PlatformExtensionsClashResolver.FallbackToDefault(DynamicTypesSettings(), DynamicTypesSettings::class.java) ) +fun StorageComponentContainer.configureDefaultCheckers() { + DEFAULT_DECLARATION_CHECKERS.forEach { useInstance(it) } + DEFAULT_CALL_CHECKERS.forEach { useInstance(it) } + DEFAULT_TYPE_CHECKERS.forEach { useInstance(it) } + DEFAULT_CLASSIFIER_USAGE_CHECKERS.forEach { useInstance(it) } + DEFAULT_ANNOTATION_CHECKERS.forEach { useInstance(it) } + DEFAULT_CLASH_RESOLVERS.forEach { useClashResolver(it) } +} + abstract class PlatformConfiguratorBase( private val dynamicTypesSettings: DynamicTypesSettings? = null, - additionalDeclarationCheckers: List = emptyList(), - additionalCallCheckers: List = emptyList(), - additionalTypeCheckers: List = emptyList(), - additionalClassifierUsageCheckers: List = emptyList(), - additionalAnnotationCheckers: List = emptyList(), - additionalClashResolvers: List> = emptyList(), + private val additionalDeclarationCheckers: List = emptyList(), + private val additionalCallCheckers: List = emptyList(), + private val additionalTypeCheckers: List = emptyList(), + private val additionalClassifierUsageCheckers: List = emptyList(), + private val additionalAnnotationCheckers: List = emptyList(), + private val additionalClashResolvers: List> = emptyList(), private val identifierChecker: IdentifierChecker? = null, private val overloadFilter: OverloadFilter? = null, private val platformToKotlinClassMap: PlatformToKotlinClassMap? = null, @@ -82,33 +91,32 @@ abstract class PlatformConfiguratorBase( private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper? = null, private val declarationReturnTypeSanitizer: DeclarationReturnTypeSanitizer? = null ) : PlatformConfigurator { - private val declarationCheckers: List = DEFAULT_DECLARATION_CHECKERS + additionalDeclarationCheckers - private val callCheckers: List = DEFAULT_CALL_CHECKERS + additionalCallCheckers - private val typeCheckers: List = DEFAULT_TYPE_CHECKERS + additionalTypeCheckers - private val classifierUsageCheckers: List = - DEFAULT_CLASSIFIER_USAGE_CHECKERS + additionalClassifierUsageCheckers - private val annotationCheckers: List = DEFAULT_ANNOTATION_CHECKERS + additionalAnnotationCheckers - private val clashResolvers: List> = DEFAULT_CLASH_RESOLVERS + additionalClashResolvers - override val platformSpecificContainer = composeContainer(this::class.java.simpleName) { - useInstanceIfNotNull(dynamicTypesSettings) - declarationCheckers.forEach { useInstance(it) } - callCheckers.forEach { useInstance(it) } - typeCheckers.forEach { useInstance(it) } - classifierUsageCheckers.forEach { useInstance(it) } - annotationCheckers.forEach { useInstance(it) } - clashResolvers.forEach { useClashResolver(it) } - useInstanceIfNotNull(identifierChecker) - useInstanceIfNotNull(overloadFilter) - useInstanceIfNotNull(platformToKotlinClassMap) - useInstanceIfNotNull(delegationFilter) - useInstanceIfNotNull(overridesBackwardCompatibilityHelper) - useInstanceIfNotNull(declarationReturnTypeSanitizer) + configureDefaultCheckers() + configureExtensionsAndCheckers(this) } override fun configureModuleDependentCheckers(container: StorageComponentContainer) { container.useImpl() } + + private fun configureExtensionsAndCheckers(container: StorageComponentContainer) { + with(container) { + useInstanceIfNotNull(dynamicTypesSettings) + additionalDeclarationCheckers.forEach { useInstance(it) } + additionalCallCheckers.forEach { useInstance(it) } + additionalTypeCheckers.forEach { useInstance(it) } + additionalClassifierUsageCheckers.forEach { useInstance(it) } + additionalAnnotationCheckers.forEach { useInstance(it) } + additionalClashResolvers.forEach { useClashResolver(it) } + useInstanceIfNotNull(identifierChecker) + useInstanceIfNotNull(overloadFilter) + useInstanceIfNotNull(platformToKotlinClassMap) + useInstanceIfNotNull(delegationFilter) + useInstanceIfNotNull(overridesBackwardCompatibilityHelper) + useInstanceIfNotNull(declarationReturnTypeSanitizer) + } + } } fun createContainer(id: String, compilerServices: PlatformDependentCompilerServices, init: StorageComponentContainer.() -> Unit) = diff --git a/js/js.frontend/src/org/jetbrains/kotlin/frontend/js/di/injection.kt b/js/js.frontend/src/org/jetbrains/kotlin/frontend/js/di/injection.kt index e9bf3a0d903..f77abf0eec1 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/frontend/js/di/injection.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/frontend/js/di/injection.kt @@ -24,7 +24,9 @@ import org.jetbrains.kotlin.context.ModuleContext import org.jetbrains.kotlin.descriptors.PackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.frontend.di.configureIncrementalCompilation import org.jetbrains.kotlin.frontend.di.configureModule +import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.js.resolve.JsPlatformCompilerServices @@ -53,16 +55,13 @@ fun createTopDownAnalyzerForJs( languageVersionSettings ) - useInstance(declarationProviderFactory) - useImpl() - - CompilerEnvironment.configure(this) - useInstance(lookupTracker) - useInstance(expectActualTracker) - - useImpl() - useImpl() + configureIncrementalCompilation(lookupTracker, expectActualTracker) + configureStandardResolveComponents() useImpl() + + useInstance(declarationProviderFactory) + CompilerEnvironment.configure(this) + }.apply { val packagePartProviders = mutableListOf(get().packageFragmentProvider) val moduleDescriptor = get()