Filter out inapplicable local scopes in call resolution

The idea is that resolution has an approximate complexity
close to (n + n*m) * 3
Where n is a number of scopes, m is a number of receivers
and 3-constant is used because each of these combinations
runs through 3 processors for functions.

And while call resolver seems to be a hot spot, it should be
useful to decreate the value of n
This commit is contained in:
Denis Zharkov
2017-08-15 13:20:30 +07:00
parent 94356e891b
commit fb80e19b88
4 changed files with 29 additions and 19 deletions
@@ -168,10 +168,10 @@ class NewResolutionOldInference(
val processor = kind.createTowerProcessor(this, nameToResolve, tracing, scopeTower, detailedReceiver, context) val processor = kind.createTowerProcessor(this, nameToResolve, tracing, scopeTower, detailedReceiver, context)
if (context.collectAllCandidates) { if (context.collectAllCandidates) {
return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor)) return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor, nameToResolve))
} }
var candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference) var candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference, name = nameToResolve)
// Temporary hack to resolve 'rem' as 'mod' if the first is do not present // Temporary hack to resolve 'rem' as 'mod' if the first is do not present
val emptyOrInapplicableCandidates = candidates.isEmpty() || val emptyOrInapplicableCandidates = candidates.isEmpty() ||
@@ -179,7 +179,7 @@ class NewResolutionOldInference(
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) { if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name] val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context) val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
candidates = towerResolver.runResolve(scopeTower, processorForDeprecatedName, useOrder = kind != ResolutionKind.CallableReference) candidates = towerResolver.runResolve(scopeTower, processorForDeprecatedName, useOrder = kind != ResolutionKind.CallableReference, name = deprecatedName)
} }
if (candidates.isEmpty()) { if (candidates.isEmpty()) {
@@ -55,11 +55,11 @@ class KotlinCallResolver(
} }
if (collectAllCandidates) { if (collectAllCandidates) {
val allCandidates = towerResolver.collectAllCandidates(scopeTower, processor) val allCandidates = towerResolver.collectAllCandidates(scopeTower, processor, kotlinCall.name)
return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks) return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks)
} }
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED) val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED, name = kotlinCall.name)
return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates) return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
} }
@@ -115,7 +115,7 @@ class CallableReferenceResolver(
): Set<CallableReferenceCandidate> { ): Set<CallableReferenceCandidate> {
val factory = CallableReferencesCandidateFactory(callableReference, callComponents, scopeTower, compatibilityChecker, expectedType) val factory = CallableReferencesCandidateFactory(callableReference, callComponents, scopeTower, compatibilityChecker, expectedType)
val processor = createCallableReferenceProcessor(factory) val processor = createCallableReferenceProcessor(factory)
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = true) val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = true, name = callableReference.rhsName)
return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates( return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates(
candidates, candidates,
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
@@ -16,12 +16,15 @@
package org.jetbrains.kotlin.resolve.calls.tower package org.jetbrains.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.ImportingScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScope 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.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.* import java.util.*
interface Candidate { interface Candidate {
@@ -74,14 +77,16 @@ class TowerResolver {
fun <C: Candidate> runResolve( fun <C: Candidate> runResolve(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
useOrder: Boolean useOrder: Boolean,
): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector(), useOrder) name: Name
): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector(), useOrder, name)
fun <C: Candidate> collectAllCandidates( fun <C: Candidate> collectAllCandidates(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
processor: ScopeTowerProcessor<C> processor: ScopeTowerProcessor<C>,
name: Name
): Collection<C> ): Collection<C>
= scopeTower.run(processor, AllCandidatesCollector(), false) = scopeTower.run(processor, AllCandidatesCollector(), false, name)
private fun ImplicitScopeTower.createNonLocalLevels(): List<ScopeTowerLevel> { private fun ImplicitScopeTower.createNonLocalLevels(): List<ScopeTowerLevel> {
val result = ArrayList<ScopeTowerLevel>() val result = ArrayList<ScopeTowerLevel>()
@@ -103,14 +108,11 @@ class TowerResolver {
private fun <C : Candidate> ImplicitScopeTower.run( private fun <C : Candidate> ImplicitScopeTower.run(
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>, resultCollector: ResultCollector<C>,
useOrder: Boolean useOrder: Boolean,
name: Name
): Collection<C> { ): Collection<C> {
fun TowerData.process() = processTowerData(processor, resultCollector, useOrder, this) fun TowerData.process() = processTowerData(processor, resultCollector, useOrder, this)
val localLevels = lexicalScope.parentsWithSelf.
filterIsInstance<LexicalScope>().filter { it.kind.withLocalDescriptors }.
map { ScopeBasedTowerLevel(this@run, it) }
// Lazy calculation // Lazy calculation
var nonLocalLevels: Collection<ScopeTowerLevel>? = null var nonLocalLevels: Collection<ScopeTowerLevel>? = null
val hidesMembersLevel = HidesMembersTowerLevel(this) val hidesMembersLevel = HidesMembersTowerLevel(this)
@@ -123,6 +125,11 @@ class TowerResolver {
// synthetic property for explicit receiver // synthetic property for explicit receiver
TowerData.TowerLevel(syntheticLevel).process()?.let { return it } TowerData.TowerLevel(syntheticLevel).process()?.let { return it }
val localLevels =
lexicalScope.parentsWithSelf.
filterIsInstance<LexicalScope>().filter { it.kind.withLocalDescriptors && it.mayFitForName(name) }.
map { ScopeBasedTowerLevel(this@run, it) }.toList()
// local non-extensions or extension for explicit receiver // local non-extensions or extension for explicit receiver
for (localLevel in localLevels) { for (localLevel in localLevels) {
TowerData.TowerLevel(localLevel).process()?.let { return it } TowerData.TowerLevel(localLevel).process()?.let { return it }
@@ -173,6 +180,9 @@ class TowerResolver {
return resultCollector.getFinalCandidates() return resultCollector.getFinalCandidates()
} }
private fun ResolutionScope.mayFitForName(name: Name) =
!definitelyDoesNotContainName(name) || !definitelyDoesNotContainName(OperatorNameConventions.INVOKE)
fun <C : Candidate> runWithEmptyTowerData( fun <C : Candidate> runWithEmptyTowerData(
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>, resultCollector: ResultCollector<C>,