[FIR] Reorganize processing of candidates in MemberScopeTowerLevel

First collect all candidates and only then consume them. This is needed
  for further handling of overridable candidates from smartcasts
This commit is contained in:
Dmitriy Novozhilov
2022-03-14 15:42:00 +03:00
committed by teamcity
parent ebb292849f
commit 0025d170d1
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.resolve.typeForQualifier import org.jetbrains.kotlin.fir.resolve.typeForQualifier
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirDefaultStarImportingScope import org.jetbrains.kotlin.fir.scopes.impl.FirDefaultStarImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
@@ -90,9 +91,26 @@ class MemberScopeTowerLevel(
output: TowerScopeLevelProcessor<T>, output: TowerScopeLevelProcessor<T>,
processScopeMembers: FirScope.(processor: (T) -> Unit) -> Unit processScopeMembers: FirScope.(processor: (T) -> Unit) -> Unit
): ProcessResult { ): ProcessResult {
var empty = true
val scope = dispatchReceiverValue.scope(session, scopeSession) ?: return ProcessResult.SCOPE_EMPTY val scope = dispatchReceiverValue.scope(session, scopeSession) ?: return ProcessResult.SCOPE_EMPTY
scope.processScopeMembers { candidate -> var (empty, candidates) = scope.collectCandidates(processScopeMembers)
consumeCandidates(output, candidates.map { scope to it })
if (extensionReceiver == null) {
val withSynthetic = FirSyntheticPropertiesScope(session, scope)
withSynthetic.processScopeMembers { symbol ->
empty = false
output.consumeCandidate(symbol, dispatchReceiverValue, null, scope)
}
}
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
}
private fun <T : FirBasedSymbol<*>> FirTypeScope.collectCandidates(
processScopeMembers: FirScope.(processor: (T) -> Unit) -> Unit
): Pair<Boolean, List<T>> {
var empty = true
val result = mutableListOf<T>()
processScopeMembers { candidate ->
empty = false empty = false
if (candidate is FirCallableSymbol<*> && if (candidate is FirCallableSymbol<*> &&
(implicitExtensionInvokeMode || candidate.hasConsistentExtensionReceiver(extensionReceiver)) (implicitExtensionInvokeMode || candidate.hasConsistentExtensionReceiver(extensionReceiver))
@@ -101,7 +119,22 @@ class MemberScopeTowerLevel(
if ((fir as? FirConstructor)?.isInner == false) { if ((fir as? FirConstructor)?.isInner == false) {
return@processScopeMembers return@processScopeMembers
} }
result += candidate
} else if (candidate is FirClassLikeSymbol<*>) {
result += candidate
}
}
return empty to result
}
private fun <T : FirBasedSymbol<*>> consumeCandidates(
output: TowerScopeLevelProcessor<T>,
candidatesWithScope: List<Pair<FirScope, T>>
) {
for ((scope, candidate) in candidatesWithScope) {
if (candidate is FirCallableSymbol<*> &&
(implicitExtensionInvokeMode || candidate.hasConsistentExtensionReceiver(extensionReceiver))
) {
output.consumeCandidate( output.consumeCandidate(
candidate, dispatchReceiverValue, candidate, dispatchReceiverValue,
extensionReceiverValue = extensionReceiver, extensionReceiverValue = extensionReceiver,
@@ -120,15 +153,6 @@ class MemberScopeTowerLevel(
output.consumeCandidate(candidate, null, extensionReceiver, scope) output.consumeCandidate(candidate, null, extensionReceiver, scope)
} }
} }
if (extensionReceiver == null) {
val withSynthetic = FirSyntheticPropertiesScope(session, scope)
withSynthetic.processScopeMembers { symbol ->
empty = false
output.consumeCandidate(symbol, dispatchReceiverValue, null, scope)
}
}
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
} }
override fun processFunctionsByName( override fun processFunctionsByName(