From 017f640f26e29f1b1d0909d89e812aca9173691c Mon Sep 17 00:00:00 2001 From: Ilya Muradyan Date: Thu, 4 Jun 2020 13:43:31 +0300 Subject: [PATCH] Allow skipping extensions resolution for implicit receivers --- .../compiler/TopDownAnalyzerFacadeForJVM.kt | 10 +++-- .../kotlin/frontend/java/di/injection.kt | 5 ++- .../calls/tower/NewResolutionOldInference.kt | 4 +- .../resolve/calls/tower/PSICallResolver.kt | 2 + .../resolve/calls/tower/ImplicitScopeTower.kt | 6 +++ .../ImplicitsExtensionsResolutionFilter.kt | 29 ++++++++++++++ .../resolve/calls/tower/TowerResolver.kt | 38 +++++++++++++------ 7 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitsExtensionsResolutionFilter.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt index 70e1a890e26..9c5eed0c1d6 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt @@ -66,6 +66,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.calls.tower.ImplicitsExtensionsResolutionFilter import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension @@ -135,7 +136,8 @@ object TopDownAnalyzerFacadeForJVM { declarationProviderFactory: (StorageManager, Collection) -> DeclarationProviderFactory, targetEnvironment: TargetEnvironment = CompilerEnvironment, sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files), - klibList: List = emptyList() + klibList: List = emptyList(), + implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter? = null ): ComponentProvider { val jvmTarget = configuration.get(JVMConfigurationKeys.JVM_TARGET, JvmTarget.DEFAULT) val languageVersionSettings = configuration.languageVersionSettings @@ -186,7 +188,8 @@ object TopDownAnalyzerFacadeForJVM { targetEnvironment, lookupTracker, expectActualTracker, packagePartProvider(dependencyScope), languageVersionSettings, useBuiltInsProvider = true, - configureJavaClassFinder = configureJavaClassFinder + configureJavaClassFinder = configureJavaClassFinder, + implicitsResolutionFilter = implicitsResolutionFilter ) moduleClassResolver.compiledCodeResolver = dependenciesContainer.get() @@ -220,7 +223,8 @@ object TopDownAnalyzerFacadeForJVM { partProvider, languageVersionSettings, useBuiltInsProvider = true, configureJavaClassFinder = configureJavaClassFinder, - javaClassTracker = configuration[JVMConfigurationKeys.JAVA_CLASSES_TRACKER] + javaClassTracker = configuration[JVMConfigurationKeys.JAVA_CLASSES_TRACKER], + implicitsResolutionFilter = implicitsResolutionFilter ).apply { initJvmBuiltInsForTopDownAnalysis() (partProvider as? IncrementalPackagePartProvider)?.deserializationConfiguration = get() 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 bef3b2dcd29..13b5d813fd9 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 @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.calls.tower.ImplicitsExtensionsResolutionFilter import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.JvmDiagnosticComponents import org.jetbrains.kotlin.resolve.jvm.multiplatform.OptionalAnnotationPackageFragmentProvider @@ -63,7 +64,8 @@ fun createContainerForLazyResolveWithJava( languageVersionSettings: LanguageVersionSettings, useBuiltInsProvider: Boolean, configureJavaClassFinder: (StorageComponentContainer.() -> Unit)? = null, - javaClassTracker: JavaClassesTracker? = null + javaClassTracker: JavaClassesTracker? = null, + implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter? = null, ): StorageComponentContainer = createContainer("LazyResolveWithJava", JvmPlatformAnalyzerServices) { configureModule(moduleContext, jvmPlatform, JvmPlatformAnalyzerServices, bindingTrace, languageVersionSettings) @@ -73,6 +75,7 @@ fun createContainerForLazyResolveWithJava( useInstance(moduleContentScope) useInstance(packagePartProvider) useInstance(declarationProviderFactory) + useInstanceIfNotNull(implicitsResolutionFilter) useInstance(VirtualFileFinderFactory.getInstance(moduleContext.project).create(moduleContentScope)) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt index 3ee71ac61df..df8c21de02a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt @@ -74,6 +74,7 @@ class NewResolutionOldInference( private val coroutineInferenceSupport: CoroutineInferenceSupport, private val deprecationResolver: DeprecationResolver, private val typeApproximator: TypeApproximator, + private val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter, private val callResolver: CallResolver, private val candidateInterceptor: CandidateInterceptor ) { @@ -174,7 +175,7 @@ class NewResolutionOldInference( val dynamicScope = dynamicCallableDescriptors.createDynamicDescriptorScope(context.call, context.scope.ownerDescriptor) val scopeTower = ImplicitScopeTowerImpl( - context, dynamicScope, syntheticScopes, context.call.createLookupLocation(), typeApproximator, callResolver, candidateInterceptor + context, dynamicScope, syntheticScopes, context.call.createLookupLocation(), typeApproximator, implicitsResolutionFilter, callResolver, candidateInterceptor ) val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem) @@ -362,6 +363,7 @@ class NewResolutionOldInference( override val syntheticScopes: SyntheticScopes, override val location: LookupLocation, override val typeApproximator: TypeApproximator, + override val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter, val callResolver: CallResolver, val candidateInterceptor: CandidateInterceptor ) : ImplicitScopeTower { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index b8a87f497cf..b54d41b8ddb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -61,6 +61,7 @@ class PSICallResolver( private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer, private val kotlinCallResolver: KotlinCallResolver, private val typeApproximator: TypeApproximator, + private val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter, private val argumentTypeResolver: ArgumentTypeResolver, private val effectSystem: EffectSystem, private val constantExpressionEvaluator: ConstantExpressionEvaluator, @@ -393,6 +394,7 @@ class PSICallResolver( override val isNewInferenceEnabled: Boolean get() = context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) override val lexicalScope: LexicalScope get() = context.scope override val typeApproximator: TypeApproximator get() = this@PSICallResolver.typeApproximator + override val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter get() = this@PSICallResolver.implicitsResolutionFilter private val cache = HashMap() override fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt index adf3366ac45..a970d6dbd15 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.* import org.jetbrains.kotlin.resolve.scopes.* import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo +import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeApproximator @@ -44,6 +45,11 @@ interface ImplicitScopeTower { val typeApproximator: TypeApproximator + val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter + + fun allScopesWithImplicitsResolutionInfo(): Sequence = + implicitsResolutionFilter.getScopesWithInfo(lexicalScope.parentsWithSelf) + fun interceptFunctionCandidates( resolutionScope: ResolutionScope, name: Name, diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitsExtensionsResolutionFilter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitsExtensionsResolutionFilter.kt new file mode 100644 index 00000000000..18ec33cf411 --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitsExtensionsResolutionFilter.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2020 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.resolve.calls.tower + +import org.jetbrains.kotlin.container.DefaultImplementation +import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope + +@DefaultImplementation(ImplicitsExtensionsResolutionFilter.Default::class) +interface ImplicitsExtensionsResolutionFilter { + fun getScopesWithInfo( + scopes: Sequence + ): Sequence + + object Default : ImplicitsExtensionsResolutionFilter { + override fun getScopesWithInfo( + scopes: Sequence + ): Sequence = scopes.map { scope -> + ScopeWithImplicitsExtensionsResolutionInfo(scope, true) + } + } +} + +class ScopeWithImplicitsExtensionsResolutionInfo( + val scope: HierarchicalScope, + val resolveExtensionsForImplicitReceiver: Boolean, +) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt index 3045c1a2132..7e1bc8a2723 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.descriptorUtil.HIDES_MEMBERS_NAME_LIST +import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.ResolutionScope @@ -185,7 +186,7 @@ class TowerResolver { TowerData.TowerLevel(localLevel).process()?.let { return it } } - for (scope in implicitScopeTower.lexicalScope.parentsWithSelf) { + fun processScope(scope: HierarchicalScope, resolveExtensionsForImplicitReceiver: Boolean): Collection? { if (scope is LexicalScope) { // statics if (!scope.kind.withLocalDescriptors) { @@ -194,12 +195,23 @@ class TowerResolver { } implicitScopeTower.getImplicitReceiver(scope) - ?.let(this::processImplicitReceiver) + ?.let { processImplicitReceiver(it, resolveExtensionsForImplicitReceiver) } ?.let { return it } } else { TowerData.TowerLevel(ImportingScopeBasedTowerLevel(implicitScopeTower, scope as ImportingScope)) .process(scope.mayFitForName(name))?.let { return it } } + return null + } + + if (implicitScopeTower.implicitsResolutionFilter === ImplicitsExtensionsResolutionFilter.Default) { + for (scope in implicitScopeTower.lexicalScope.parentsWithSelf) { + processScope(scope, true)?.let { return it } + } + } else { + for (scopeInfo in implicitScopeTower.allScopesWithImplicitsResolutionInfo()) { + processScope(scopeInfo.scope, scopeInfo.resolveExtensionsForImplicitReceiver)?.let { return it } + } } recordLookups() @@ -207,7 +219,7 @@ class TowerResolver { return resultCollector.getFinalCandidates() } - private fun processImplicitReceiver(implicitReceiver: ReceiverValueWithSmartCastInfo): Collection? { + private fun processImplicitReceiver(implicitReceiver: ReceiverValueWithSmartCastInfo, resolveExtensions: Boolean): Collection? { if (isNameForHidesMember) { // hides members extensions TowerData.BothTowerLevelAndImplicitReceiver(hidesMembersLevel, implicitReceiver).process()?.let { return it } @@ -220,17 +232,19 @@ class TowerResolver { // synthetic properties TowerData.BothTowerLevelAndImplicitReceiver(syntheticLevel, implicitReceiver).process()?.let { return it } - // invokeExtension on local variable - TowerData.OnlyImplicitReceiver(implicitReceiver).process()?.let { return it } + if (resolveExtensions) { + // invokeExtension on local variable + TowerData.OnlyImplicitReceiver(implicitReceiver).process()?.let { return it } - // local extensions for implicit receiver - for (localLevel in localLevels) { - TowerData.BothTowerLevelAndImplicitReceiver(localLevel, implicitReceiver).process()?.let { return it } - } + // local extensions for implicit receiver + for (localLevel in localLevels) { + TowerData.BothTowerLevelAndImplicitReceiver(localLevel, implicitReceiver).process()?.let { return it } + } - // extension for implicit receiver - for (nonLocalLevel in nonLocalLevels) { - TowerData.BothTowerLevelAndImplicitReceiver(nonLocalLevel, implicitReceiver).process()?.let { return it } + // extension for implicit receiver + for (nonLocalLevel in nonLocalLevels) { + TowerData.BothTowerLevelAndImplicitReceiver(nonLocalLevel, implicitReceiver).process()?.let { return it } + } } return null