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)
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
val emptyOrInapplicableCandidates = candidates.isEmpty() ||
@@ -179,7 +179,7 @@ class NewResolutionOldInference(
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
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()) {
@@ -55,11 +55,11 @@ class KotlinCallResolver(
}
if (collectAllCandidates) {
val allCandidates = towerResolver.collectAllCandidates(scopeTower, processor)
val allCandidates = towerResolver.collectAllCandidates(scopeTower, processor, kotlinCall.name)
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)
}
@@ -115,7 +115,7 @@ class CallableReferenceResolver(
): Set<CallableReferenceCandidate> {
val factory = CallableReferencesCandidateFactory(callableReference, callComponents, scopeTower, compatibilityChecker, expectedType)
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(
candidates,
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
@@ -16,12 +16,15 @@
package org.jetbrains.kotlin.resolve.calls.tower
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.scopes.ImportingScope
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.util.OperatorNameConventions
import java.util.*
interface Candidate {
@@ -74,14 +77,16 @@ class TowerResolver {
fun <C: Candidate> runResolve(
scopeTower: ImplicitScopeTower,
processor: ScopeTowerProcessor<C>,
useOrder: Boolean
): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector(), useOrder)
useOrder: Boolean,
name: Name
): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector(), useOrder, name)
fun <C: Candidate> collectAllCandidates(
scopeTower: ImplicitScopeTower,
processor: ScopeTowerProcessor<C>
processor: ScopeTowerProcessor<C>,
name: Name
): Collection<C>
= scopeTower.run(processor, AllCandidatesCollector(), false)
= scopeTower.run(processor, AllCandidatesCollector(), false, name)
private fun ImplicitScopeTower.createNonLocalLevels(): List<ScopeTowerLevel> {
val result = ArrayList<ScopeTowerLevel>()
@@ -103,14 +108,11 @@ class TowerResolver {
private fun <C : Candidate> ImplicitScopeTower.run(
processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>,
useOrder: Boolean
useOrder: Boolean,
name: Name
): Collection<C> {
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
var nonLocalLevels: Collection<ScopeTowerLevel>? = null
val hidesMembersLevel = HidesMembersTowerLevel(this)
@@ -123,6 +125,11 @@ class TowerResolver {
// synthetic property for explicit receiver
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
for (localLevel in localLevels) {
TowerData.TowerLevel(localLevel).process()?.let { return it }
@@ -173,6 +180,9 @@ class TowerResolver {
return resultCollector.getFinalCandidates()
}
private fun ResolutionScope.mayFitForName(name: Name) =
!definitelyDoesNotContainName(name) || !definitelyDoesNotContainName(OperatorNameConventions.INVOKE)
fun <C : Candidate> runWithEmptyTowerData(
processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>,
@@ -234,7 +244,7 @@ class TowerResolver {
val firstGroupWithResolved = candidateGroups.firstOrNull {
it.any { it.resultingApplicability == ResolutionCandidateApplicability.RESOLVED }
} ?: return null
return firstGroupWithResolved.filter { it.resultingApplicability == ResolutionCandidateApplicability.RESOLVED }
}
@@ -261,8 +271,8 @@ class TowerResolver {
return moreSuitableGroup.filter { it.resultingApplicability == groupApplicability }
}
private val Collection<C>.groupApplicability get() =
minBy { it.resultingApplicability }?.resultingApplicability ?: ResolutionCandidateApplicability.HIDDEN
private val Collection<C>.groupApplicability get() =
minBy { it.resultingApplicability }?.resultingApplicability ?: ResolutionCandidateApplicability.HIDDEN
}
}