From b1387b2ae7b187b25541ecbde46096369e519054 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 24 Aug 2017 11:21:03 +0300 Subject: [PATCH] Make call resolution responsible for calling recordLookups The idea is that all tower levels are partitioned into two groups: - ones that may contain the target name or INVOKE; they're processed as usual - ones that can't contain the name; they're simply skipped until the end of resolution process when it's being passed to scope processors to allow them record necessary lookups --- .../resolve/calls/tower/ImplicitScopeTower.kt | 2 + .../resolve/calls/tower/InvokeProcessors.kt | 26 +++- .../calls/tower/ScopeTowerProcessors.kt | 30 +++++ .../kotlin/resolve/calls/tower/TowerLevels.kt | 23 +++- .../resolve/calls/tower/TowerResolver.kt | 116 +++++++++++++----- 5 files changed, 160 insertions(+), 37 deletions(-) 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 7f0d0baa6c9..4838ce435ac 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 @@ -50,6 +50,8 @@ interface ScopeTowerLevel { fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection + + fun recordLookup(name: Name) } interface CandidateWithBoundDispatchReceiver { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt index 30cb6720378..15211751e74 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt @@ -27,12 +27,14 @@ import java.util.* abstract class AbstractInvokeTowerProcessor( protected val factoryProviderForInvoke: CandidateFactoryProviderForInvoke, - private val variableProcessor: ScopeTowerProcessor + protected val variableProcessor: ScopeTowerProcessor ) : ScopeTowerProcessor { // todo optimize it private val previousData = ArrayList() private val invokeProcessors: MutableList> = ArrayList() + protected fun hasInvokeProcessors() = invokeProcessors.isNotEmpty() + private inner class VariableInvokeProcessor( var variableCandidate: C, val invokeProcessor: ScopeTowerProcessor @@ -42,6 +44,10 @@ abstract class AbstractInvokeTowerProcessor( = invokeProcessor.process(data).map { candidateGroup -> candidateGroup.map { factoryProviderForInvoke.transformCandidate(variableCandidate, it) } } + + override fun recordLookups(skippedData: Collection, name: Name) { + invokeProcessor.recordLookups(skippedData, name) + } } private fun createVariableInvokeProcessor(variableCandidate: C): VariableInvokeProcessor? = @@ -110,6 +116,17 @@ class InvokeTowerProcessor( override fun mayDataBeApplicable(data: TowerData) = data == TowerData.Empty || data is TowerData.TowerLevel + + override fun recordLookups(skippedData: Collection, name: Name) { + variableProcessor.recordLookups(skippedData, name) + if (!hasInvokeProcessors()) return + + skippedData.forEach { + if (it is TowerData.TowerLevel) { + it.level.recordLookup(OperatorNameConventions.INVOKE) + } + } + } } class InvokeExtensionTowerProcessor( @@ -131,6 +148,10 @@ class InvokeExtensionTowerProcessor( } override fun mayDataBeApplicable(data: TowerData): Boolean = data == TowerData.Empty || data is TowerData.OnlyImplicitReceiver + + override fun recordLookups(skippedData: Collection, name: Name) { + variableProcessor.recordLookups(skippedData, name) + } } private class InvokeExtensionScopeTowerProcessor( @@ -150,6 +171,9 @@ private class InvokeExtensionScopeTowerProcessor( return emptyList() } + + // No lookups happen in `simpleProcess` + override fun recordLookups(skippedData: Collection, name: Name) {} } // todo debug info diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt index 84320fc7506..5208d4440a5 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt @@ -28,6 +28,8 @@ class KnownResultProcessor( ): ScopeTowerProcessor { override fun process(data: TowerData) = if (data == TowerData.Empty) listOfNotNull(result.takeIf { it.isNotEmpty() }) else emptyList() + + override fun recordLookups(skippedData: Collection, name: Name) {} } // use this if processors priority is important @@ -35,6 +37,11 @@ class PrioritizedCompositeScopeTowerProcessor( vararg val processors: ScopeTowerProcessor ) : ScopeTowerProcessor { override fun process(data: TowerData): List> = processors.flatMap { it.process(data) } + + override fun recordLookups(skippedData: Collection, name: Name) { + processors.forEach { it.recordLookups(skippedData, name) } + } + } // use this if all processors has same priority @@ -42,6 +49,10 @@ class SamePriorityCompositeScopeTowerProcessor( private vararg val processors: SimpleScopeTowerProcessor ): SimpleScopeTowerProcessor { override fun simpleProcess(data: TowerData): Collection = processors.flatMap { it.simpleProcess(data) } + override fun recordLookups(skippedData: Collection, name: Name) { + processors.forEach { it.recordLookups(skippedData, name) } + } + } internal abstract class AbstractSimpleScopeTowerProcessor( @@ -84,6 +95,14 @@ internal class ExplicitReceiverScopeTowerProcessor( } return extensions } + + override fun recordLookups(skippedData: Collection, name: Name) { + for (data in skippedData) { + if (data is TowerData.TowerLevel) { + data.level.recordLookup(name) + } + } + } } private class QualifierScopeTowerProcessor( @@ -103,6 +122,9 @@ private class QualifierScopeTowerProcessor( } return staticMembers } + + // QualifierScopeTowerProcessor works only with TowerData.Empty that should not be ignored + override fun recordLookups(skippedData: Collection, name: Name) {} } private class NoExplicitReceiverScopeTowerProcessor( @@ -132,6 +154,14 @@ private class NoExplicitReceiverScopeTowerProcessor( else -> emptyList() } + override fun recordLookups(skippedData: Collection, name: Name) { + for (data in skippedData) { + when (data) { + is TowerData.TowerLevel -> data.level.recordLookup(name) + is TowerData.BothTowerLevelAndImplicitReceiver -> data.level.recordLookup(name) + } + } + } } private fun createSimpleProcessorWithoutClassValueReceiver( diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt index 01961771ce0..a1bae96f1be 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt @@ -87,10 +87,6 @@ internal class MemberScopeTowerLevel( private val syntheticScopes = scopeTower.syntheticScopes - fun definitelyDoesNotContainName(name: Name) = - (dispatchReceiver.possibleTypes + dispatchReceiver.receiverValue.type) - .all { !it.isDynamic() && it.memberScope.definitelyDoesNotContainName(name) } - private fun collectMembers( getMembers: ResolutionScope.(KotlinType?) -> Collection ): Collection { @@ -173,6 +169,13 @@ internal class MemberScopeTowerLevel( syntheticScopes.collectSyntheticMemberFunctions(listOfNotNull(it), name, location) } } + + override fun recordLookup(name: Name) { + dispatchReceiver.receiverValue.type.memberScope.recordLookup(name, location) + dispatchReceiver.possibleTypes.forEach { + it.memberScope.recordLookup(name, location) + } + } } internal class QualifierScopeTowerLevel(scopeTower: ImplicitScopeTower, val qualifier: QualifierReceiver) : AbstractScopeTowerLevel(scopeTower) { @@ -193,6 +196,8 @@ internal class QualifierScopeTowerLevel(scopeTower: ImplicitScopeTower, val qual qualifier.staticScope).map { createCandidateDescriptor(it, dispatchReceiver = null) } + + override fun recordLookup(name: Name) {} } // KT-3335 Creating imported super class' inner class fails in codegen @@ -220,6 +225,10 @@ internal open class ScopeBasedTowerLevel protected constructor( resolutionScope).map { createCandidateDescriptor(it, dispatchReceiver = null) } + + override fun recordLookup(name: Name) { + resolutionScope.recordLookup(name, location) + } } internal class ImportingScopeBasedTowerLevel( scopeTower: ImplicitScopeTower, @@ -251,6 +260,10 @@ internal class SyntheticScopeBasedTowerLevel( extensionReceiver: ReceiverValueWithSmartCastInfo? ): Collection = emptyList() + + override fun recordLookup(name: Name) { + + } } internal class HidesMembersTowerLevel(scopeTower: ImplicitScopeTower): AbstractScopeTowerLevel(scopeTower) { @@ -276,6 +289,8 @@ internal class HidesMembersTowerLevel(scopeTower: ImplicitScopeTower): AbstractS createCandidateDescriptor(it, dispatchReceiver = null) } } + + override fun recordLookup(name: Name) {} } private fun KotlinType.getClassifierFromMeAndSuperclasses(name: Name, location: LookupLocation): ClassifierDescriptor? { 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 c54e043e0bd..4d25b29d7cd 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 @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.resolve.calls.tower -import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind @@ -26,10 +25,10 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.ResolutionScope 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.isDynamic import org.jetbrains.kotlin.util.OperatorNameConventions -import org.jetbrains.kotlin.utils.yieldIfNotNull import java.util.* -import kotlin.coroutines.experimental.buildSequence interface Candidate { // this operation should be very fast @@ -69,6 +68,8 @@ interface ScopeTowerProcessor { // Candidates with matched receivers (dispatch receiver was already matched in ScopeTowerLevel) // Candidates in one groups have same priority, first group has highest priority. fun process(data: TowerData): List> + + fun recordLookups(skippedData: Collection, name: Name) } interface SimpleScopeTowerProcessor : ScopeTowerProcessor { @@ -92,21 +93,49 @@ class TowerResolver { ): Collection = scopeTower.run(processor, AllCandidatesCollector(), false, name) - private fun ImplicitScopeTower.createNonLocalLevels(name: Name): Sequence = buildSequence { + private data class ScopeLevelsAndSkippedForLookups( + val levelsToProcess: Collection, + val levelsToSkip: Collection + ) + + private fun ImplicitScopeTower.createNonLocalLevels(name: Name): ScopeLevelsAndSkippedForLookups { + val mainResult = mutableListOf() + val skippedLevels = mutableListOf() + + fun addLevel(scopeTowerLevel: ScopeTowerLevel, mayFitForName: Boolean) { + if (mayFitForName) { + mainResult.add(scopeTowerLevel) + } + else { + skippedLevels.add(scopeTowerLevel) + } + } + lexicalScope.parentsWithSelf.forEach { scope -> if (scope is LexicalScope) { - if (!scope.kind.withLocalDescriptors && scope.mayFitForName(name, location)) { - yield(ScopeBasedTowerLevel(this@createNonLocalLevels, scope)) + if (!scope.kind.withLocalDescriptors) { + addLevel( + ScopeBasedTowerLevel(this@createNonLocalLevels, scope), + scope.mayFitForName(name) + ) } getImplicitReceiver(scope)?.let { - yieldIfNotNull(MemberScopeTowerLevel(this@createNonLocalLevels, it).takeIf { it.mayFitForName(name) }) + addLevel( + MemberScopeTowerLevel(this@createNonLocalLevels, it), + it.mayFitForName(name) + ) } } - else if (scope.mayFitForName(name, location)) { - yield(ImportingScopeBasedTowerLevel(this@createNonLocalLevels, scope as ImportingScope)) + else { + addLevel( + ImportingScopeBasedTowerLevel(this@createNonLocalLevels, scope as ImportingScope), + scope.mayFitForName(name) + ) } } + + return ScopeLevelsAndSkippedForLookups(mainResult, skippedLevels) } private fun ImplicitScopeTower.run( @@ -115,7 +144,23 @@ class TowerResolver { useOrder: Boolean, name: Name ): Collection { - fun TowerData.process() = processTowerData(processor, resultCollector, useOrder, this) + val skippedDataForLookup = mutableListOf() + + fun recordLookups() { + processor.recordLookups(skippedDataForLookup, name) + } + + fun TowerData.process() = processTowerData(processor, resultCollector, useOrder, this)?.also { + recordLookups() + } + + fun TowerData.process(mayFitForName: Boolean): Collection? { + if (!mayFitForName) { + skippedDataForLookup.add(this) + return null + } + return process() + } // Lazy calculation var nonLocalLevels: Collection? = null @@ -134,7 +179,7 @@ class TowerResolver { val localLevels = lexicalScope.parentsWithSelf. - filterIsInstance().filter { it.kind.withLocalDescriptors && it.mayFitForName(name, location) }. + filterIsInstance().filter { it.kind.withLocalDescriptors && it.mayFitForName(name) }. map { ScopeBasedTowerLevel(this@run, it) }.toList() // local non-extensions or extension for explicit receiver @@ -145,8 +190,9 @@ class TowerResolver { for (scope in lexicalScope.parentsWithSelf) { if (scope is LexicalScope) { // statics - if (!scope.kind.withLocalDescriptors && scope.mayFitForName(name, location)) { - TowerData.TowerLevel(ScopeBasedTowerLevel(this, scope)).process()?.let { return it } + if (!scope.kind.withLocalDescriptors) { + TowerData.TowerLevel(ScopeBasedTowerLevel(this, scope)) + .process(scope.mayFitForName(name))?.let { return it } } val implicitReceiver = getImplicitReceiver(scope) @@ -157,9 +203,8 @@ class TowerResolver { } // members of implicit receiver or member extension for explicit receiver - MemberScopeTowerLevel(this, implicitReceiver).takeIf { it.mayFitForName(name) }?.let { - TowerData.TowerLevel(it).process()?.let { return it } - } + TowerData.TowerLevel(MemberScopeTowerLevel(this, implicitReceiver)) + .process(implicitReceiver.mayFitForName(name))?.let { return it } // synthetic properties TowerData.BothTowerLevelAndImplicitReceiver(syntheticLevel, implicitReceiver).process()?.let { return it } @@ -172,32 +217,39 @@ class TowerResolver { TowerData.BothTowerLevelAndImplicitReceiver(localLevel, implicitReceiver).process()?.let { return it } } - // extension for implicit receiver - if (nonLocalLevels == null) { - nonLocalLevels = arrayListOf() - for (nonLocalLevel in createNonLocalLevels(name)) { - TowerData.BothTowerLevelAndImplicitReceiver(nonLocalLevel, implicitReceiver).process()?.let { return it } - nonLocalLevels.add(nonLocalLevel) - } + if (nonLocalLevels == null) { + val (toProcess, toSkip) = createNonLocalLevels(name) + nonLocalLevels = toProcess + toSkip.mapTo(skippedDataForLookup) { TowerData.BothTowerLevelAndImplicitReceiver(it, implicitReceiver) } } - else { - 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 } } } } - else if (scope.mayFitForName(name, location)) { - // functions with no receiver or extension for explicit receiver - TowerData.TowerLevel(ImportingScopeBasedTowerLevel(this, scope as ImportingScope)).process()?.let { return it } + else { + TowerData.TowerLevel(ImportingScopeBasedTowerLevel(this, scope as ImportingScope)) + .process(scope.mayFitForName(name))?.let { return it } } } + recordLookups() + return resultCollector.getFinalCandidates() } - private fun MemberScopeTowerLevel.mayFitForName(name: Name) = - !definitelyDoesNotContainName(name) || !definitelyDoesNotContainName(OperatorNameConventions.INVOKE) + private fun ReceiverValueWithSmartCastInfo.mayFitForName(name: Name): Boolean { + if (receiverValue.type.mayFitForName(name)) return true + if (possibleTypes.isEmpty()) return false + return possibleTypes.any { it.mayFitForName(name) } + } + + private fun KotlinType.mayFitForName(name: Name) = + isDynamic() || + !memberScope.definitelyDoesNotContainName(name) || + !memberScope.definitelyDoesNotContainName(OperatorNameConventions.INVOKE) private fun ResolutionScope.mayFitForName(name: Name) = !definitelyDoesNotContainName(name) || !definitelyDoesNotContainName(OperatorNameConventions.INVOKE)