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
This commit is contained in:
Denis Zharkov
2017-08-24 11:21:03 +03:00
parent 265794e712
commit b1387b2ae7
5 changed files with 160 additions and 37 deletions
@@ -50,6 +50,8 @@ interface ScopeTowerLevel {
fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver> fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver>
fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver> fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver>
fun recordLookup(name: Name)
} }
interface CandidateWithBoundDispatchReceiver { interface CandidateWithBoundDispatchReceiver {
@@ -27,12 +27,14 @@ import java.util.*
abstract class AbstractInvokeTowerProcessor<C : Candidate>( abstract class AbstractInvokeTowerProcessor<C : Candidate>(
protected val factoryProviderForInvoke: CandidateFactoryProviderForInvoke<C>, protected val factoryProviderForInvoke: CandidateFactoryProviderForInvoke<C>,
private val variableProcessor: ScopeTowerProcessor<C> protected val variableProcessor: ScopeTowerProcessor<C>
) : ScopeTowerProcessor<C> { ) : ScopeTowerProcessor<C> {
// todo optimize it // todo optimize it
private val previousData = ArrayList<TowerData>() private val previousData = ArrayList<TowerData>()
private val invokeProcessors: MutableList<Collection<VariableInvokeProcessor>> = ArrayList() private val invokeProcessors: MutableList<Collection<VariableInvokeProcessor>> = ArrayList()
protected fun hasInvokeProcessors() = invokeProcessors.isNotEmpty()
private inner class VariableInvokeProcessor( private inner class VariableInvokeProcessor(
var variableCandidate: C, var variableCandidate: C,
val invokeProcessor: ScopeTowerProcessor<C> val invokeProcessor: ScopeTowerProcessor<C>
@@ -42,6 +44,10 @@ abstract class AbstractInvokeTowerProcessor<C : Candidate>(
= invokeProcessor.process(data).map { candidateGroup -> = invokeProcessor.process(data).map { candidateGroup ->
candidateGroup.map { factoryProviderForInvoke.transformCandidate(variableCandidate, it) } candidateGroup.map { factoryProviderForInvoke.transformCandidate(variableCandidate, it) }
} }
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
invokeProcessor.recordLookups(skippedData, name)
}
} }
private fun createVariableInvokeProcessor(variableCandidate: C): VariableInvokeProcessor? = private fun createVariableInvokeProcessor(variableCandidate: C): VariableInvokeProcessor? =
@@ -110,6 +116,17 @@ class InvokeTowerProcessor<C : Candidate>(
override fun mayDataBeApplicable(data: TowerData) = override fun mayDataBeApplicable(data: TowerData) =
data == TowerData.Empty || data is TowerData.TowerLevel data == TowerData.Empty || data is TowerData.TowerLevel
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
variableProcessor.recordLookups(skippedData, name)
if (!hasInvokeProcessors()) return
skippedData.forEach {
if (it is TowerData.TowerLevel) {
it.level.recordLookup(OperatorNameConventions.INVOKE)
}
}
}
} }
class InvokeExtensionTowerProcessor<C : Candidate>( class InvokeExtensionTowerProcessor<C : Candidate>(
@@ -131,6 +148,10 @@ class InvokeExtensionTowerProcessor<C : Candidate>(
} }
override fun mayDataBeApplicable(data: TowerData): Boolean = data == TowerData.Empty || data is TowerData.OnlyImplicitReceiver override fun mayDataBeApplicable(data: TowerData): Boolean = data == TowerData.Empty || data is TowerData.OnlyImplicitReceiver
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
variableProcessor.recordLookups(skippedData, name)
}
} }
private class InvokeExtensionScopeTowerProcessor<C : Candidate>( private class InvokeExtensionScopeTowerProcessor<C : Candidate>(
@@ -150,6 +171,9 @@ private class InvokeExtensionScopeTowerProcessor<C : Candidate>(
return emptyList() return emptyList()
} }
// No lookups happen in `simpleProcess`
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {}
} }
// todo debug info // todo debug info
@@ -28,6 +28,8 @@ class KnownResultProcessor<out C>(
): ScopeTowerProcessor<C> { ): ScopeTowerProcessor<C> {
override fun process(data: TowerData) override fun process(data: TowerData)
= if (data == TowerData.Empty) listOfNotNull(result.takeIf { it.isNotEmpty() }) else emptyList() = if (data == TowerData.Empty) listOfNotNull(result.takeIf { it.isNotEmpty() }) else emptyList()
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {}
} }
// use this if processors priority is important // use this if processors priority is important
@@ -35,6 +37,11 @@ class PrioritizedCompositeScopeTowerProcessor<out C>(
vararg val processors: ScopeTowerProcessor<C> vararg val processors: ScopeTowerProcessor<C>
) : ScopeTowerProcessor<C> { ) : ScopeTowerProcessor<C> {
override fun process(data: TowerData): List<Collection<C>> = processors.flatMap { it.process(data) } override fun process(data: TowerData): List<Collection<C>> = processors.flatMap { it.process(data) }
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
processors.forEach { it.recordLookups(skippedData, name) }
}
} }
// use this if all processors has same priority // use this if all processors has same priority
@@ -42,6 +49,10 @@ class SamePriorityCompositeScopeTowerProcessor<out C>(
private vararg val processors: SimpleScopeTowerProcessor<C> private vararg val processors: SimpleScopeTowerProcessor<C>
): SimpleScopeTowerProcessor<C> { ): SimpleScopeTowerProcessor<C> {
override fun simpleProcess(data: TowerData): Collection<C> = processors.flatMap { it.simpleProcess(data) } override fun simpleProcess(data: TowerData): Collection<C> = processors.flatMap { it.simpleProcess(data) }
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
processors.forEach { it.recordLookups(skippedData, name) }
}
} }
internal abstract class AbstractSimpleScopeTowerProcessor<C: Candidate>( internal abstract class AbstractSimpleScopeTowerProcessor<C: Candidate>(
@@ -84,6 +95,14 @@ internal class ExplicitReceiverScopeTowerProcessor<C: Candidate>(
} }
return extensions return extensions
} }
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
for (data in skippedData) {
if (data is TowerData.TowerLevel) {
data.level.recordLookup(name)
}
}
}
} }
private class QualifierScopeTowerProcessor<C: Candidate>( private class QualifierScopeTowerProcessor<C: Candidate>(
@@ -103,6 +122,9 @@ private class QualifierScopeTowerProcessor<C: Candidate>(
} }
return staticMembers return staticMembers
} }
// QualifierScopeTowerProcessor works only with TowerData.Empty that should not be ignored
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {}
} }
private class NoExplicitReceiverScopeTowerProcessor<C: Candidate>( private class NoExplicitReceiverScopeTowerProcessor<C: Candidate>(
@@ -132,6 +154,14 @@ private class NoExplicitReceiverScopeTowerProcessor<C: Candidate>(
else -> emptyList() else -> emptyList()
} }
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
for (data in skippedData) {
when (data) {
is TowerData.TowerLevel -> data.level.recordLookup(name)
is TowerData.BothTowerLevelAndImplicitReceiver -> data.level.recordLookup(name)
}
}
}
} }
private fun <C : Candidate> createSimpleProcessorWithoutClassValueReceiver( private fun <C : Candidate> createSimpleProcessorWithoutClassValueReceiver(
@@ -87,10 +87,6 @@ internal class MemberScopeTowerLevel(
private val syntheticScopes = scopeTower.syntheticScopes private val syntheticScopes = scopeTower.syntheticScopes
fun definitelyDoesNotContainName(name: Name) =
(dispatchReceiver.possibleTypes + dispatchReceiver.receiverValue.type)
.all { !it.isDynamic() && it.memberScope.definitelyDoesNotContainName(name) }
private fun collectMembers( private fun collectMembers(
getMembers: ResolutionScope.(KotlinType?) -> Collection<CallableDescriptor> getMembers: ResolutionScope.(KotlinType?) -> Collection<CallableDescriptor>
): Collection<CandidateWithBoundDispatchReceiver> { ): Collection<CandidateWithBoundDispatchReceiver> {
@@ -173,6 +169,13 @@ internal class MemberScopeTowerLevel(
syntheticScopes.collectSyntheticMemberFunctions(listOfNotNull(it), name, location) 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) { internal class QualifierScopeTowerLevel(scopeTower: ImplicitScopeTower, val qualifier: QualifierReceiver) : AbstractScopeTowerLevel(scopeTower) {
@@ -193,6 +196,8 @@ internal class QualifierScopeTowerLevel(scopeTower: ImplicitScopeTower, val qual
qualifier.staticScope).map { qualifier.staticScope).map {
createCandidateDescriptor(it, dispatchReceiver = null) createCandidateDescriptor(it, dispatchReceiver = null)
} }
override fun recordLookup(name: Name) {}
} }
// KT-3335 Creating imported super class' inner class fails in codegen // KT-3335 Creating imported super class' inner class fails in codegen
@@ -220,6 +225,10 @@ internal open class ScopeBasedTowerLevel protected constructor(
resolutionScope).map { resolutionScope).map {
createCandidateDescriptor(it, dispatchReceiver = null) createCandidateDescriptor(it, dispatchReceiver = null)
} }
override fun recordLookup(name: Name) {
resolutionScope.recordLookup(name, location)
}
} }
internal class ImportingScopeBasedTowerLevel( internal class ImportingScopeBasedTowerLevel(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
@@ -251,6 +260,10 @@ internal class SyntheticScopeBasedTowerLevel(
extensionReceiver: ReceiverValueWithSmartCastInfo? extensionReceiver: ReceiverValueWithSmartCastInfo?
): Collection<CandidateWithBoundDispatchReceiver> = ): Collection<CandidateWithBoundDispatchReceiver> =
emptyList() emptyList()
override fun recordLookup(name: Name) {
}
} }
internal class HidesMembersTowerLevel(scopeTower: ImplicitScopeTower): AbstractScopeTowerLevel(scopeTower) { internal class HidesMembersTowerLevel(scopeTower: ImplicitScopeTower): AbstractScopeTowerLevel(scopeTower) {
@@ -276,6 +289,8 @@ internal class HidesMembersTowerLevel(scopeTower: ImplicitScopeTower): AbstractS
createCandidateDescriptor(it, dispatchReceiver = null) createCandidateDescriptor(it, dispatchReceiver = null)
} }
} }
override fun recordLookup(name: Name) {}
} }
private fun KotlinType.getClassifierFromMeAndSuperclasses(name: Name, location: LookupLocation): ClassifierDescriptor? { private fun KotlinType.getClassifierFromMeAndSuperclasses(name: Name, location: LookupLocation): ClassifierDescriptor? {
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.resolve.calls.tower package org.jetbrains.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name 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
@@ -26,10 +25,10 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.ResolutionScope 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.types.KotlinType
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.yieldIfNotNull
import java.util.* import java.util.*
import kotlin.coroutines.experimental.buildSequence
interface Candidate { interface Candidate {
// this operation should be very fast // this operation should be very fast
@@ -69,6 +68,8 @@ interface ScopeTowerProcessor<out C> {
// Candidates with matched receivers (dispatch receiver was already matched in ScopeTowerLevel) // Candidates with matched receivers (dispatch receiver was already matched in ScopeTowerLevel)
// Candidates in one groups have same priority, first group has highest priority. // Candidates in one groups have same priority, first group has highest priority.
fun process(data: TowerData): List<Collection<C>> fun process(data: TowerData): List<Collection<C>>
fun recordLookups(skippedData: Collection<TowerData>, name: Name)
} }
interface SimpleScopeTowerProcessor<out C> : ScopeTowerProcessor<C> { interface SimpleScopeTowerProcessor<out C> : ScopeTowerProcessor<C> {
@@ -92,21 +93,49 @@ class TowerResolver {
): Collection<C> ): Collection<C>
= scopeTower.run(processor, AllCandidatesCollector(), false, name) = scopeTower.run(processor, AllCandidatesCollector(), false, name)
private fun ImplicitScopeTower.createNonLocalLevels(name: Name): Sequence<ScopeTowerLevel> = buildSequence { private data class ScopeLevelsAndSkippedForLookups(
val levelsToProcess: Collection<ScopeTowerLevel>,
val levelsToSkip: Collection<ScopeTowerLevel>
)
private fun ImplicitScopeTower.createNonLocalLevels(name: Name): ScopeLevelsAndSkippedForLookups {
val mainResult = mutableListOf<ScopeTowerLevel>()
val skippedLevels = mutableListOf<ScopeTowerLevel>()
fun addLevel(scopeTowerLevel: ScopeTowerLevel, mayFitForName: Boolean) {
if (mayFitForName) {
mainResult.add(scopeTowerLevel)
}
else {
skippedLevels.add(scopeTowerLevel)
}
}
lexicalScope.parentsWithSelf.forEach { scope -> lexicalScope.parentsWithSelf.forEach { scope ->
if (scope is LexicalScope) { if (scope is LexicalScope) {
if (!scope.kind.withLocalDescriptors && scope.mayFitForName(name, location)) { if (!scope.kind.withLocalDescriptors) {
yield(ScopeBasedTowerLevel(this@createNonLocalLevels, scope)) addLevel(
ScopeBasedTowerLevel(this@createNonLocalLevels, scope),
scope.mayFitForName(name)
)
} }
getImplicitReceiver(scope)?.let { 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)) { else {
yield(ImportingScopeBasedTowerLevel(this@createNonLocalLevels, scope as ImportingScope)) addLevel(
ImportingScopeBasedTowerLevel(this@createNonLocalLevels, scope as ImportingScope),
scope.mayFitForName(name)
)
} }
} }
return ScopeLevelsAndSkippedForLookups(mainResult, skippedLevels)
} }
private fun <C : Candidate> ImplicitScopeTower.run( private fun <C : Candidate> ImplicitScopeTower.run(
@@ -115,7 +144,23 @@ class TowerResolver {
useOrder: Boolean, useOrder: Boolean,
name: Name name: Name
): Collection<C> { ): Collection<C> {
fun TowerData.process() = processTowerData(processor, resultCollector, useOrder, this) val skippedDataForLookup = mutableListOf<TowerData>()
fun recordLookups() {
processor.recordLookups(skippedDataForLookup, name)
}
fun TowerData.process() = processTowerData(processor, resultCollector, useOrder, this)?.also {
recordLookups()
}
fun TowerData.process(mayFitForName: Boolean): Collection<C>? {
if (!mayFitForName) {
skippedDataForLookup.add(this)
return null
}
return process()
}
// Lazy calculation // Lazy calculation
var nonLocalLevels: Collection<ScopeTowerLevel>? = null var nonLocalLevels: Collection<ScopeTowerLevel>? = null
@@ -134,7 +179,7 @@ class TowerResolver {
val localLevels = val localLevels =
lexicalScope.parentsWithSelf. lexicalScope.parentsWithSelf.
filterIsInstance<LexicalScope>().filter { it.kind.withLocalDescriptors && it.mayFitForName(name, location) }. filterIsInstance<LexicalScope>().filter { it.kind.withLocalDescriptors && it.mayFitForName(name) }.
map { ScopeBasedTowerLevel(this@run, it) }.toList() map { ScopeBasedTowerLevel(this@run, it) }.toList()
// local non-extensions or extension for explicit receiver // local non-extensions or extension for explicit receiver
@@ -145,8 +190,9 @@ class TowerResolver {
for (scope in lexicalScope.parentsWithSelf) { for (scope in lexicalScope.parentsWithSelf) {
if (scope is LexicalScope) { if (scope is LexicalScope) {
// statics // statics
if (!scope.kind.withLocalDescriptors && scope.mayFitForName(name, location)) { if (!scope.kind.withLocalDescriptors) {
TowerData.TowerLevel(ScopeBasedTowerLevel(this, scope)).process()?.let { return it } TowerData.TowerLevel(ScopeBasedTowerLevel(this, scope))
.process(scope.mayFitForName(name))?.let { return it }
} }
val implicitReceiver = getImplicitReceiver(scope) val implicitReceiver = getImplicitReceiver(scope)
@@ -157,9 +203,8 @@ class TowerResolver {
} }
// members of implicit receiver or member extension for explicit receiver // members of implicit receiver or member extension for explicit receiver
MemberScopeTowerLevel(this, implicitReceiver).takeIf { it.mayFitForName(name) }?.let { TowerData.TowerLevel(MemberScopeTowerLevel(this, implicitReceiver))
TowerData.TowerLevel(it).process()?.let { return it } .process(implicitReceiver.mayFitForName(name))?.let { return it }
}
// synthetic properties // synthetic properties
TowerData.BothTowerLevelAndImplicitReceiver(syntheticLevel, implicitReceiver).process()?.let { return it } TowerData.BothTowerLevelAndImplicitReceiver(syntheticLevel, implicitReceiver).process()?.let { return it }
@@ -172,32 +217,39 @@ class TowerResolver {
TowerData.BothTowerLevelAndImplicitReceiver(localLevel, implicitReceiver).process()?.let { return it } TowerData.BothTowerLevelAndImplicitReceiver(localLevel, implicitReceiver).process()?.let { return it }
} }
// extension for implicit receiver if (nonLocalLevels == null) {
if (nonLocalLevels == null) { val (toProcess, toSkip) = createNonLocalLevels(name)
nonLocalLevels = arrayListOf() nonLocalLevels = toProcess
for (nonLocalLevel in createNonLocalLevels(name)) { toSkip.mapTo(skippedDataForLookup) { TowerData.BothTowerLevelAndImplicitReceiver(it, implicitReceiver) }
TowerData.BothTowerLevelAndImplicitReceiver(nonLocalLevel, implicitReceiver).process()?.let { return it }
nonLocalLevels.add(nonLocalLevel)
}
} }
else {
for (nonLocalLevel in nonLocalLevels) { // extension for implicit receiver
TowerData.BothTowerLevelAndImplicitReceiver(nonLocalLevel, implicitReceiver).process()?.let { return it } for (nonLocalLevel in nonLocalLevels) {
} TowerData.BothTowerLevelAndImplicitReceiver(nonLocalLevel, implicitReceiver).process()?.let { return it }
} }
} }
} }
else if (scope.mayFitForName(name, location)) { else {
// functions with no receiver or extension for explicit receiver TowerData.TowerLevel(ImportingScopeBasedTowerLevel(this, scope as ImportingScope))
TowerData.TowerLevel(ImportingScopeBasedTowerLevel(this, scope as ImportingScope)).process()?.let { return it } .process(scope.mayFitForName(name))?.let { return it }
} }
} }
recordLookups()
return resultCollector.getFinalCandidates() return resultCollector.getFinalCandidates()
} }
private fun MemberScopeTowerLevel.mayFitForName(name: Name) = private fun ReceiverValueWithSmartCastInfo.mayFitForName(name: Name): Boolean {
!definitelyDoesNotContainName(name) || !definitelyDoesNotContainName(OperatorNameConventions.INVOKE) 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) = private fun ResolutionScope.mayFitForName(name: Name) =
!definitelyDoesNotContainName(name) || !definitelyDoesNotContainName(OperatorNameConventions.INVOKE) !definitelyDoesNotContainName(name) || !definitelyDoesNotContainName(OperatorNameConventions.INVOKE)