FIR: Extract FirTowerResolverSession

The idea of that class is separating lots of data from a component
to a short-living instance
This commit is contained in:
Denis Zharkov
2020-03-27 14:37:41 +03:00
parent 60cbc5fa39
commit f8227e4cb9
3 changed files with 579 additions and 545 deletions
@@ -5,538 +5,16 @@
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isCompanion
import org.jetbrains.kotlin.fir.declarations.isInner
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.scopes.impl.FirStaticScope
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.descriptorUtil.HIDES_MEMBERS_NAME_LIST
class FirTowerResolver(
val typeCalculator: ReturnTypeCalculator,
val components: BodyResolveComponents,
resolutionStageRunner: ResolutionStageRunner,
) {
private val localScopes: List<FirLocalScope> get() = components.localScopes.asReversed()
private val topLevelScopes: List<FirScope>
get() {
if (components.typeParametersScopes.isEmpty()) return components.fileImportsScope.asReversed()
return components.typeParametersScopes.asReversed() + components.fileImportsScope.asReversed()
}
private val session: FirSession get() = components.session
private val collector = CandidateCollector(components, resolutionStageRunner)
private val manager = TowerResolveManager()
private lateinit var implicitReceivers: List<ImplicitReceiver>
private lateinit var implicitReceiversUsableAsValues: List<ImplicitReceiver>
private data class ImplicitReceiver(
val receiver: ImplicitReceiverValue<*>,
val depth: Int,
val usableAsValue: Boolean
)
private fun prepareImplicitReceivers(implicitReceiverValues: List<ImplicitReceiverValue<*>>) {
var depth = 0
var firstDispatchValue = true
val explicitCompanions = mutableListOf<FirRegularClassSymbol>()
val implicitReceiversUsableAsValues = mutableListOf<ImplicitReceiver>()
implicitReceivers = implicitReceiverValues.mapNotNull { receiverValue ->
val usableAsValue = when (receiverValue) {
is ImplicitExtensionReceiverValue -> true
is ImplicitDispatchReceiverValue -> {
val symbol = receiverValue.boundSymbol
val klass = symbol.fir as? FirRegularClass
if (!receiverValue.implicitCompanion && klass?.isCompanion == true) {
explicitCompanions += klass.symbol
}
if (firstDispatchValue && !receiverValue.inDelegated) {
if (!receiverValue.implicitCompanion &&
klass?.isInner == false &&
!symbol.classId.isLocal
) {
firstDispatchValue = false
}
true
} else {
symbol.fir.classKind == ClassKind.OBJECT && !receiverValue.inDelegated
}
}
}
if (receiverValue is ImplicitDispatchReceiverValue && receiverValue.implicitCompanion && receiverValue.boundSymbol in explicitCompanions) {
null
} else {
ImplicitReceiver(receiverValue, depth++, usableAsValue).also {
if (usableAsValue) {
implicitReceiversUsableAsValues.add(it)
}
}
}
}
this.implicitReceiversUsableAsValues = implicitReceiversUsableAsValues
}
private fun FirScope.toScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
extensionsOnly: Boolean = false,
noInnerConstructors: Boolean = false
): ScopeTowerLevel = ScopeTowerLevel(
session, components, this,
extensionReceiver, extensionsOnly, noInnerConstructors
)
private fun ReceiverValue.toMemberScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
implicitExtensionInvokeMode: Boolean = false
) = MemberScopeTowerLevel(
session, components, this,
extensionReceiver, implicitExtensionInvokeMode,
scopeSession = components.scopeSession
)
private suspend fun processQualifierScopes(
manager: TowerResolveManager,
info: CallInfo, qualifierReceiver: QualifierReceiver?
) {
if (qualifierReceiver == null) return
for ((depth, qualifierScope) in qualifierReceiver.callableScopes().withIndex()) {
manager.processLevel(
qualifierScope.toScopeTowerLevel(noInnerConstructors = true),
info.noStubReceiver(), TowerGroup.Qualifier(depth)
)
}
}
private suspend fun processClassifierScope(
manager: TowerResolveManager,
info: CallInfo, qualifierReceiver: QualifierReceiver?, prioritized: Boolean
) {
if (qualifierReceiver == null) return
if (info.callKind != CallKind.CallableReference &&
qualifierReceiver is ClassQualifierReceiver &&
qualifierReceiver.classSymbol != qualifierReceiver.originalSymbol
) return
val scope = qualifierReceiver.classifierScope() ?: return
manager.processLevel(
scope.toScopeTowerLevel(noInnerConstructors = true), info.noStubReceiver(),
if (prioritized) TowerGroup.ClassifierPrioritized else TowerGroup.Classifier
)
}
private suspend fun runResolverForQualifierReceiver(
info: CallInfo,
resolvedQualifier: FirResolvedQualifier,
manager: TowerResolveManager
) {
val qualifierReceiver = createQualifierReceiver(resolvedQualifier, session, components.scopeSession)
when {
info.isPotentialQualifierPart -> {
processClassifierScope(manager, info, qualifierReceiver, prioritized = true)
processQualifierScopes(manager, info, qualifierReceiver)
}
else -> {
processQualifierScopes(manager, info, qualifierReceiver)
processClassifierScope(manager, info, qualifierReceiver, prioritized = false)
}
}
if (resolvedQualifier.symbol != null) {
val typeRef = resolvedQualifier.typeRef
// NB: yet built-in Unit is used for "no-value" type
if (info.callKind == CallKind.CallableReference) {
if (info.stubReceiver != null || typeRef !is FirImplicitBuiltinTypeRef) {
runResolverForExpressionReceiver(info, resolvedQualifier, manager)
}
} else {
if (typeRef !is FirImplicitBuiltinTypeRef) {
runResolverForExpressionReceiver(info, resolvedQualifier, manager)
}
}
}
}
private suspend fun runResolverForNoReceiver(
info: CallInfo,
manager: TowerResolveManager
) {
manager.processExtensionsThatHideMembers(info, explicitReceiverValue = null)
val nonEmptyLocalScopes = mutableListOf<FirLocalScope>()
manager.processLocalScopesWithNoReceiver(info, nonEmptyLocalScopes)
val emptyTopLevelScopes = mutableSetOf<FirScope>()
manager.processImplicitReceiversWithNoExplicit(info, nonEmptyLocalScopes, emptyTopLevelScopes)
manager.processTopLevelScopesNoReceiver(info, emptyTopLevelScopes)
}
private suspend fun TowerResolveManager.processExtensionsThatHideMembers(
info: CallInfo,
explicitReceiverValue: ReceiverValue?
) {
val shouldProcessExtensionsBeforeMembers =
info.callKind == CallKind.Function && info.name in HIDES_MEMBERS_NAME_LIST
if (!shouldProcessExtensionsBeforeMembers) return
for ((index, topLevelScope) in topLevelScopes.withIndex()) {
if (explicitReceiverValue != null) {
processHideMembersLevel(explicitReceiverValue, topLevelScope, info, index, depth = null)
} else {
for ((implicitReceiverValue, depth) in implicitReceiversUsableAsValues) {
processHideMembersLevel(implicitReceiverValue, topLevelScope, info, index, depth)
}
}
}
}
private suspend fun TowerResolveManager.processHideMembersLevel(
receiverValue: ReceiverValue,
topLevelScope: FirScope,
info: CallInfo,
index: Int,
depth: Int?
) = processLevel(
topLevelScope.toScopeTowerLevel(
extensionReceiver = receiverValue, extensionsOnly = true
),
info, TowerGroup.TopPrioritized(index).let { if (depth != null) it.Implicit(depth) else it }
)
private suspend fun TowerResolveManager.processLocalScopesWithNoReceiver(
info: CallInfo,
nonEmptyLocalScopes: MutableList<FirLocalScope>
) {
for ((index, localScope) in localScopes.withIndex()) {
val result = processLevel(
localScope.toScopeTowerLevel(), info, TowerGroup.Local(index)
)
if (result != ProcessorAction.NONE) {
nonEmptyLocalScopes += localScope
}
}
}
private suspend fun TowerResolveManager.processImplicitReceiversWithNoExplicit(
info: CallInfo,
nonEmptyLocalScopes: MutableList<FirLocalScope>,
emptyTopLevelScopes: MutableSet<FirScope>
) {
val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>()
for ((implicitReceiverValue, depth, usableAsValue) in implicitReceivers) {
// NB: companions are processed via implicitReceiverValues!
val parentGroup = TowerGroup.Implicit(depth)
if (usableAsValue) {
processCandidatesWithGivenImplicitReceiverAsValue(
implicitReceiverValue,
this,
info,
parentGroup,
implicitReceiverValuesWithEmptyScopes,
nonEmptyLocalScopes,
emptyTopLevelScopes
)
}
if (implicitReceiverValue is ImplicitDispatchReceiverValue) {
val scope = implicitReceiverValue.scope(session, components.scopeSession)
if (scope != null) {
processLevel(
FirStaticScope(scope).toScopeTowerLevel(),
info, parentGroup.Static(depth)
)
}
}
}
}
private suspend fun processCandidatesWithGivenImplicitReceiverAsValue(
receiver: ImplicitReceiverValue<*>,
manager: TowerResolveManager,
info: CallInfo,
parentGroup: TowerGroup,
implicitReceiverValuesWithEmptyScopes: MutableSet<ImplicitReceiverValue<*>>,
nonEmptyLocalScopes: List<FirLocalScope>,
emptyTopLevelScopes: MutableSet<FirScope>
) {
val implicitResult = manager.processLevel(
receiver.toMemberScopeTowerLevel(), info, parentGroup.Member
)
if (implicitResult == ProcessorAction.NONE) {
implicitReceiverValuesWithEmptyScopes += receiver
}
for ((localIndex, localScope) in nonEmptyLocalScopes.withIndex()) {
manager.processLevel(
localScope.toScopeTowerLevel(extensionReceiver = receiver),
info, parentGroup.Local(localIndex)
)
}
for ((implicitDispatchReceiverValue, dispatchDepth) in implicitReceiversUsableAsValues) {
if (implicitDispatchReceiverValue in implicitReceiverValuesWithEmptyScopes) continue
manager.processLevel(
implicitDispatchReceiverValue.toMemberScopeTowerLevel(extensionReceiver = receiver),
info, parentGroup.Implicit(dispatchDepth)
)
}
for ((topIndex, topLevelScope) in topLevelScopes.withIndex()) {
if (topLevelScope in emptyTopLevelScopes) continue
val result = manager.processLevel(
topLevelScope.toScopeTowerLevel(extensionReceiver = receiver),
info, parentGroup.Top(topIndex)
)
if (result == ProcessorAction.NONE) {
emptyTopLevelScopes += topLevelScope
}
}
}
private suspend fun TowerResolveManager.processTopLevelScopesNoReceiver(
info: CallInfo,
emptyTopLevelScopes: Collection<FirScope>
) {
for ((index, topLevelScope) in topLevelScopes.withIndex()) {
// NB: this check does not work for variables
// because we do not search for objects if we have extension receiver
if (info.callKind != CallKind.VariableAccess && topLevelScope in emptyTopLevelScopes) continue
processLevel(
topLevelScope.toScopeTowerLevel(), info, TowerGroup.Top(index)
)
}
}
private suspend fun runResolverForExpressionReceiver(
info: CallInfo,
receiver: FirExpression,
manager: TowerResolveManager
) {
val explicitReceiverValue = ExpressionReceiverValue(receiver)
manager.processExtensionsThatHideMembers(info, explicitReceiverValue)
manager.processMembersForExplicitReceiver(explicitReceiverValue, info)
val shouldProcessExplicitReceiverScopeOnly =
info.callKind == CallKind.Function && info.explicitReceiver?.typeRef?.coneTypeSafe<ConeIntegerLiteralType>() != null
if (shouldProcessExplicitReceiverScopeOnly) {
// Special case (integer literal type)
return
}
val nonEmptyLocalScopes = mutableListOf<FirLocalScope>()
for ((index, localScope) in localScopes.withIndex()) {
if (manager.processScopeForExplicitReceiver(
localScope,
explicitReceiverValue,
info,
TowerGroup.Local(index)
) != ProcessorAction.NONE
) {
nonEmptyLocalScopes += localScope
}
}
for ((implicitReceiverValue, depth) in implicitReceiversUsableAsValues) {
processCombinationOfReceivers(manager, implicitReceiverValue, explicitReceiverValue, info, depth, nonEmptyLocalScopes)
}
for ((index, topLevelScope) in topLevelScopes.withIndex()) {
manager.processScopeForExplicitReceiver(
topLevelScope,
explicitReceiverValue,
info,
TowerGroup.Top(index)
)
}
}
private suspend fun TowerResolveManager.processScopeForExplicitReceiver(
scope: FirScope,
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo,
towerGroup: TowerGroup,
): ProcessorAction {
val result = processLevel(
scope.toScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, towerGroup, ExplicitReceiverKind.EXTENSION_RECEIVER
)
processLevelForPropertyWithInvoke(
scope.toScopeTowerLevel(), info, towerGroup
)
return result
}
private suspend fun TowerResolveManager.processMembersForExplicitReceiver(
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo
) {
processLevel(
explicitReceiverValue.toMemberScopeTowerLevel(), info, TowerGroup.Member, ExplicitReceiverKind.DISPATCH_RECEIVER
)
}
private suspend fun processCombinationOfReceivers(
manager: TowerResolveManager,
implicitReceiverValue: ImplicitReceiverValue<*>,
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo,
depth: Int,
nonEmptyLocalScopes: MutableList<FirLocalScope>
) {
// NB: companions are processed via implicitReceiverValues!
val parentGroup = TowerGroup.Implicit(depth)
// Member extensions
manager.processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, parentGroup.Member, ExplicitReceiverKind.EXTENSION_RECEIVER
)
// properties for invoke on implicit receiver
manager.processLevelForPropertyWithInvoke(
implicitReceiverValue.toMemberScopeTowerLevel(), info, parentGroup.Member
)
for ((localIndex, localScope) in nonEmptyLocalScopes.withIndex()) {
manager.processLevelForPropertyWithInvoke(
localScope.toScopeTowerLevel(extensionReceiver = implicitReceiverValue),
info, parentGroup.Local(localIndex)
)
}
for ((implicitDispatchReceiverValue, dispatchDepth) in implicitReceiversUsableAsValues) {
manager.processLevelForPropertyWithInvoke(
implicitDispatchReceiverValue.toMemberScopeTowerLevel(extensionReceiver = implicitReceiverValue),
info, parentGroup.Implicit(dispatchDepth)
)
}
for ((topIndex, topLevelScope) in topLevelScopes.withIndex()) {
manager.processLevelForPropertyWithInvoke(
topLevelScope.toScopeTowerLevel(extensionReceiver = implicitReceiverValue),
info, parentGroup.Top(topIndex)
)
}
}
private suspend fun runResolverForSuperReceiver(
info: CallInfo,
superTypeRef: FirTypeRef,
manager: TowerResolveManager
) {
val scope = when (superTypeRef) {
is FirResolvedTypeRef -> superTypeRef.type.scope(session, components.scopeSession)
is FirComposedSuperTypeRef -> FirCompositeScope(
superTypeRef.superTypeRefs.mapNotNullTo(mutableListOf()) { it.type.scope(session, components.scopeSession) }
)
else -> null
} ?: return
manager.processLevel(
scope.toScopeTowerLevel(),
info, TowerGroup.Member, explicitReceiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER
)
}
internal suspend fun runResolverForInvoke(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
manager: TowerResolveManager
) {
manager.processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(),
info, TowerGroup.Member,
ExplicitReceiverKind.DISPATCH_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
for ((index, localScope) in localScopes.withIndex()) {
manager.processLevel(
localScope.toScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, TowerGroup.Local(index),
ExplicitReceiverKind.EXTENSION_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
for ((implicitReceiverValue, depth) in implicitReceiversUsableAsValues) {
// NB: companions are processed via implicitReceiverValues!
val parentGroup = TowerGroup.Implicit(depth)
manager.processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, parentGroup.Member,
ExplicitReceiverKind.EXTENSION_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
for ((index, topLevelScope) in topLevelScopes.withIndex()) {
manager.processLevel(
topLevelScope.toScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, TowerGroup.Top(index),
ExplicitReceiverKind.EXTENSION_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
}
// Here we already know extension receiver for invoke, and it's stated in info as first argument
internal suspend fun runResolverForBuiltinInvokeExtensionWithExplicitArgument(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
manager: TowerResolveManager
) {
manager.processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(),
info, TowerGroup.Member,
ExplicitReceiverKind.DISPATCH_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
// Here we don't know extension receiver for invoke, assuming it's one of implicit receivers
internal suspend fun runResolverForBuiltinInvokeExtensionWithImplicitArgument(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
manager: TowerResolveManager
) {
for ((implicitReceiverValue, depth) in implicitReceiversUsableAsValues) {
val parentGroup = TowerGroup.Implicit(depth)
manager.processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(
extensionReceiver = implicitReceiverValue,
implicitExtensionInvokeMode = true
),
info, parentGroup.InvokeExtension,
ExplicitReceiverKind.DISPATCH_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
}
fun runResolver(
implicitReceiverValues: List<ImplicitReceiverValue<*>>,
@@ -544,30 +22,19 @@ class FirTowerResolver(
collector: CandidateCollector = this.collector,
manager: TowerResolveManager = this.manager
): CandidateCollector {
// TODO: add flag receiver / non-receiver position
prepareImplicitReceivers(implicitReceiverValues)
manager.callResolutionContext = buildCallResolutionContext(info, collector)
val towerResolverSession = FirTowerResolverSession(components, implicitReceiverValues)
manager.callResolutionContext = buildCallResolutionContext(info, collector, towerResolverSession)
towerResolverSession.runResolve(manager, info)
when (val receiver = info.explicitReceiver) {
is FirResolvedQualifier -> manager.enqueueResolverTask { runResolverForQualifierReceiver(info, receiver, manager) }
null -> manager.enqueueResolverTask { runResolverForNoReceiver(info, manager) }
else -> run {
if (receiver is FirQualifiedAccessExpression) {
val calleeReference = receiver.calleeReference
if (calleeReference is FirSuperReference) {
return@run manager.enqueueResolverTask { runResolverForSuperReceiver(info, receiver.typeRef, manager) }
}
}
manager.enqueueResolverTask { runResolverForExpressionReceiver(info, receiver, manager) }
}
}
manager.runTasks()
return collector
}
private fun buildCallResolutionContext(
info: CallInfo,
collector: CandidateCollector
collector: CandidateCollector,
towerResolverSession: FirTowerResolverSession
): CallResolutionContext {
val candidateFactory = CandidateFactory(components, info)
val stubReceiverCandidateFactory =
@@ -596,7 +63,8 @@ class FirTowerResolver(
invokeBuiltinExtensionReceiverCandidateFactory,
stubReceiverCandidateFactory,
invokeReceiverCollector,
this
this,
towerResolverSession
)
}
@@ -0,0 +1,564 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isCompanion
import org.jetbrains.kotlin.fir.declarations.isInner
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.scopes.impl.FirStaticScope
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.descriptorUtil.HIDES_MEMBERS_NAME_LIST
class FirTowerResolverSession(
val components: BodyResolveComponents,
implicitReceiverValues: List<ImplicitReceiverValue<*>>,
) {
private data class ImplicitReceiver(
val receiver: ImplicitReceiverValue<*>,
val depth: Int,
val usableAsValue: Boolean
)
private val session: FirSession get() = components.session
private val implicitReceivers: List<ImplicitReceiver>
private val implicitReceiversUsableAsValues: List<ImplicitReceiver>
init {
val (implicitReceivers, implicitReceiversUsableAsValues) = prepareImplicitReceivers(implicitReceiverValues)
this.implicitReceivers = implicitReceivers
this.implicitReceiversUsableAsValues = implicitReceiversUsableAsValues
}
private val localScopes: List<FirLocalScope> = components.localScopes.asReversed()
private val topLevelScopes: List<FirScope> =
if (components.typeParametersScopes.isEmpty())
components.fileImportsScope.asReversed()
else
components.typeParametersScopes.asReversed() + components.fileImportsScope.asReversed()
fun runResolve(manager: TowerResolveManager, info: CallInfo) {
when (val receiver = info.explicitReceiver) {
is FirResolvedQualifier -> manager.enqueueResolverTask { runResolverForQualifierReceiver(info, receiver, manager) }
null -> manager.enqueueResolverTask { runResolverForNoReceiver(info, manager) }
else -> run {
if (receiver is FirQualifiedAccessExpression) {
val calleeReference = receiver.calleeReference
if (calleeReference is FirSuperReference) {
return@run manager.enqueueResolverTask { runResolverForSuperReceiver(info, receiver.typeRef, manager) }
}
}
manager.enqueueResolverTask { runResolverForExpressionReceiver(info, receiver, manager) }
}
}
}
private fun FirScope.toScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
extensionsOnly: Boolean = false,
noInnerConstructors: Boolean = false
): ScopeTowerLevel = ScopeTowerLevel(
session, components, this,
extensionReceiver, extensionsOnly, noInnerConstructors
)
private fun ReceiverValue.toMemberScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
implicitExtensionInvokeMode: Boolean = false
) = MemberScopeTowerLevel(
session, components, this,
extensionReceiver, implicitExtensionInvokeMode,
scopeSession = components.scopeSession
)
private suspend fun processQualifierScopes(
manager: TowerResolveManager,
info: CallInfo, qualifierReceiver: QualifierReceiver?
) {
if (qualifierReceiver == null) return
for ((depth, qualifierScope) in qualifierReceiver.callableScopes().withIndex()) {
manager.processLevel(
qualifierScope.toScopeTowerLevel(noInnerConstructors = true),
info.noStubReceiver(), TowerGroup.Qualifier(depth)
)
}
}
private suspend fun processClassifierScope(
manager: TowerResolveManager,
info: CallInfo, qualifierReceiver: QualifierReceiver?, prioritized: Boolean
) {
if (qualifierReceiver == null) return
if (info.callKind != CallKind.CallableReference &&
qualifierReceiver is ClassQualifierReceiver &&
qualifierReceiver.classSymbol != qualifierReceiver.originalSymbol
) return
val scope = qualifierReceiver.classifierScope() ?: return
manager.processLevel(
scope.toScopeTowerLevel(noInnerConstructors = true), info.noStubReceiver(),
if (prioritized) TowerGroup.ClassifierPrioritized else TowerGroup.Classifier
)
}
private suspend fun runResolverForQualifierReceiver(
info: CallInfo,
resolvedQualifier: FirResolvedQualifier,
manager: TowerResolveManager
) {
val qualifierReceiver = createQualifierReceiver(resolvedQualifier, session, components.scopeSession)
when {
info.isPotentialQualifierPart -> {
processClassifierScope(manager, info, qualifierReceiver, prioritized = true)
processQualifierScopes(manager, info, qualifierReceiver)
}
else -> {
processQualifierScopes(manager, info, qualifierReceiver)
processClassifierScope(manager, info, qualifierReceiver, prioritized = false)
}
}
if (resolvedQualifier.symbol != null) {
val typeRef = resolvedQualifier.typeRef
// NB: yet built-in Unit is used for "no-value" type
if (info.callKind == CallKind.CallableReference) {
if (info.stubReceiver != null || typeRef !is FirImplicitBuiltinTypeRef) {
runResolverForExpressionReceiver(info, resolvedQualifier, manager)
}
} else {
if (typeRef !is FirImplicitBuiltinTypeRef) {
runResolverForExpressionReceiver(info, resolvedQualifier, manager)
}
}
}
}
private suspend fun runResolverForNoReceiver(
info: CallInfo,
manager: TowerResolveManager
) {
manager.processExtensionsThatHideMembers(info, explicitReceiverValue = null)
val nonEmptyLocalScopes = mutableListOf<FirLocalScope>()
manager.processLocalScopesWithNoReceiver(info, nonEmptyLocalScopes)
val emptyTopLevelScopes = mutableSetOf<FirScope>()
manager.processImplicitReceiversWithNoExplicit(info, nonEmptyLocalScopes, emptyTopLevelScopes)
manager.processTopLevelScopesNoReceiver(info, emptyTopLevelScopes)
}
private suspend fun TowerResolveManager.processExtensionsThatHideMembers(
info: CallInfo,
explicitReceiverValue: ReceiverValue?
) {
val shouldProcessExtensionsBeforeMembers =
info.callKind == CallKind.Function && info.name in HIDES_MEMBERS_NAME_LIST
if (!shouldProcessExtensionsBeforeMembers) return
for ((index, topLevelScope) in topLevelScopes.withIndex()) {
if (explicitReceiverValue != null) {
processHideMembersLevel(explicitReceiverValue, topLevelScope, info, index, depth = null)
} else {
for ((implicitReceiverValue, depth) in implicitReceiversUsableAsValues) {
processHideMembersLevel(implicitReceiverValue, topLevelScope, info, index, depth)
}
}
}
}
private suspend fun TowerResolveManager.processHideMembersLevel(
receiverValue: ReceiverValue,
topLevelScope: FirScope,
info: CallInfo,
index: Int,
depth: Int?
) = processLevel(
topLevelScope.toScopeTowerLevel(
extensionReceiver = receiverValue, extensionsOnly = true
),
info, TowerGroup.TopPrioritized(index).let { if (depth != null) it.Implicit(depth) else it }
)
private suspend fun TowerResolveManager.processLocalScopesWithNoReceiver(
info: CallInfo,
nonEmptyLocalScopes: MutableList<FirLocalScope>
) {
for ((index, localScope) in localScopes.withIndex()) {
val result = processLevel(
localScope.toScopeTowerLevel(), info, TowerGroup.Local(index)
)
if (result != ProcessorAction.NONE) {
nonEmptyLocalScopes += localScope
}
}
}
private suspend fun TowerResolveManager.processImplicitReceiversWithNoExplicit(
info: CallInfo,
nonEmptyLocalScopes: MutableList<FirLocalScope>,
emptyTopLevelScopes: MutableSet<FirScope>
) {
val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>()
for ((implicitReceiverValue, depth, usableAsValue) in implicitReceivers) {
// NB: companions are processed via implicitReceiverValues!
val parentGroup = TowerGroup.Implicit(depth)
if (usableAsValue) {
processCandidatesWithGivenImplicitReceiverAsValue(
implicitReceiverValue,
this,
info,
parentGroup,
implicitReceiverValuesWithEmptyScopes,
nonEmptyLocalScopes,
emptyTopLevelScopes
)
}
if (implicitReceiverValue is ImplicitDispatchReceiverValue) {
val scope = implicitReceiverValue.scope(session, components.scopeSession)
if (scope != null) {
processLevel(
FirStaticScope(scope).toScopeTowerLevel(),
info, parentGroup.Static(depth)
)
}
}
}
}
private suspend fun processCandidatesWithGivenImplicitReceiverAsValue(
receiver: ImplicitReceiverValue<*>,
manager: TowerResolveManager,
info: CallInfo,
parentGroup: TowerGroup,
implicitReceiverValuesWithEmptyScopes: MutableSet<ImplicitReceiverValue<*>>,
nonEmptyLocalScopes: List<FirLocalScope>,
emptyTopLevelScopes: MutableSet<FirScope>
) {
val implicitResult = manager.processLevel(
receiver.toMemberScopeTowerLevel(), info, parentGroup.Member
)
if (implicitResult == ProcessorAction.NONE) {
implicitReceiverValuesWithEmptyScopes += receiver
}
for ((localIndex, localScope) in nonEmptyLocalScopes.withIndex()) {
manager.processLevel(
localScope.toScopeTowerLevel(extensionReceiver = receiver),
info, parentGroup.Local(localIndex)
)
}
for ((implicitDispatchReceiverValue, dispatchDepth) in implicitReceiversUsableAsValues) {
if (implicitDispatchReceiverValue in implicitReceiverValuesWithEmptyScopes) continue
manager.processLevel(
implicitDispatchReceiverValue.toMemberScopeTowerLevel(extensionReceiver = receiver),
info, parentGroup.Implicit(dispatchDepth)
)
}
for ((topIndex, topLevelScope) in topLevelScopes.withIndex()) {
if (topLevelScope in emptyTopLevelScopes) continue
val result = manager.processLevel(
topLevelScope.toScopeTowerLevel(extensionReceiver = receiver),
info, parentGroup.Top(topIndex)
)
if (result == ProcessorAction.NONE) {
emptyTopLevelScopes += topLevelScope
}
}
}
private suspend fun TowerResolveManager.processTopLevelScopesNoReceiver(
info: CallInfo,
emptyTopLevelScopes: Collection<FirScope>
) {
for ((index, topLevelScope) in topLevelScopes.withIndex()) {
// NB: this check does not work for variables
// because we do not search for objects if we have extension receiver
if (info.callKind != CallKind.VariableAccess && topLevelScope in emptyTopLevelScopes) continue
processLevel(
topLevelScope.toScopeTowerLevel(), info, TowerGroup.Top(index)
)
}
}
private suspend fun runResolverForExpressionReceiver(
info: CallInfo,
receiver: FirExpression,
manager: TowerResolveManager
) {
val explicitReceiverValue = ExpressionReceiverValue(receiver)
manager.processExtensionsThatHideMembers(info, explicitReceiverValue)
manager.processMembersForExplicitReceiver(explicitReceiverValue, info)
val shouldProcessExplicitReceiverScopeOnly =
info.callKind == CallKind.Function && info.explicitReceiver?.typeRef?.coneTypeSafe<ConeIntegerLiteralType>() != null
if (shouldProcessExplicitReceiverScopeOnly) {
// Special case (integer literal type)
return
}
val nonEmptyLocalScopes = mutableListOf<FirLocalScope>()
for ((index, localScope) in localScopes.withIndex()) {
if (manager.processScopeForExplicitReceiver(
localScope,
explicitReceiverValue,
info,
TowerGroup.Local(index)
) != ProcessorAction.NONE
) {
nonEmptyLocalScopes += localScope
}
}
for ((implicitReceiverValue, depth) in implicitReceiversUsableAsValues) {
processCombinationOfReceivers(manager, implicitReceiverValue, explicitReceiverValue, info, depth, nonEmptyLocalScopes)
}
for ((index, topLevelScope) in topLevelScopes.withIndex()) {
manager.processScopeForExplicitReceiver(
topLevelScope,
explicitReceiverValue,
info,
TowerGroup.Top(index)
)
}
}
private suspend fun TowerResolveManager.processScopeForExplicitReceiver(
scope: FirScope,
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo,
towerGroup: TowerGroup,
): ProcessorAction {
val result = processLevel(
scope.toScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, towerGroup, ExplicitReceiverKind.EXTENSION_RECEIVER
)
processLevelForPropertyWithInvoke(
scope.toScopeTowerLevel(), info, towerGroup
)
return result
}
private suspend fun TowerResolveManager.processMembersForExplicitReceiver(
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo
) {
processLevel(
explicitReceiverValue.toMemberScopeTowerLevel(), info, TowerGroup.Member, ExplicitReceiverKind.DISPATCH_RECEIVER
)
}
private suspend fun processCombinationOfReceivers(
manager: TowerResolveManager,
implicitReceiverValue: ImplicitReceiverValue<*>,
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo,
depth: Int,
nonEmptyLocalScopes: MutableList<FirLocalScope>
) {
// NB: companions are processed via implicitReceiverValues!
val parentGroup = TowerGroup.Implicit(depth)
// Member extensions
manager.processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, parentGroup.Member, ExplicitReceiverKind.EXTENSION_RECEIVER
)
// properties for invoke on implicit receiver
manager.processLevelForPropertyWithInvoke(
implicitReceiverValue.toMemberScopeTowerLevel(), info, parentGroup.Member
)
for ((localIndex, localScope) in nonEmptyLocalScopes.withIndex()) {
manager.processLevelForPropertyWithInvoke(
localScope.toScopeTowerLevel(extensionReceiver = implicitReceiverValue),
info, parentGroup.Local(localIndex)
)
}
for ((implicitDispatchReceiverValue, dispatchDepth) in implicitReceiversUsableAsValues) {
manager.processLevelForPropertyWithInvoke(
implicitDispatchReceiverValue.toMemberScopeTowerLevel(extensionReceiver = implicitReceiverValue),
info, parentGroup.Implicit(dispatchDepth)
)
}
for ((topIndex, topLevelScope) in topLevelScopes.withIndex()) {
manager.processLevelForPropertyWithInvoke(
topLevelScope.toScopeTowerLevel(extensionReceiver = implicitReceiverValue),
info, parentGroup.Top(topIndex)
)
}
}
private suspend fun runResolverForSuperReceiver(
info: CallInfo,
superTypeRef: FirTypeRef,
manager: TowerResolveManager
) {
val scope = when (superTypeRef) {
is FirResolvedTypeRef -> superTypeRef.type.scope(session, components.scopeSession)
is FirComposedSuperTypeRef -> FirCompositeScope(
superTypeRef.superTypeRefs.mapNotNullTo(mutableListOf()) { it.type.scope(session, components.scopeSession) }
)
else -> null
} ?: return
manager.processLevel(
scope.toScopeTowerLevel(),
info, TowerGroup.Member, explicitReceiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER
)
}
internal suspend fun runResolverForInvoke(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
manager: TowerResolveManager
) {
manager.processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(),
info, TowerGroup.Member,
ExplicitReceiverKind.DISPATCH_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
for ((index, localScope) in localScopes.withIndex()) {
manager.processLevel(
localScope.toScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, TowerGroup.Local(index),
ExplicitReceiverKind.EXTENSION_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
for ((implicitReceiverValue, depth) in implicitReceiversUsableAsValues) {
// NB: companions are processed via implicitReceiverValues!
val parentGroup = TowerGroup.Implicit(depth)
manager.processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, parentGroup.Member,
ExplicitReceiverKind.EXTENSION_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
for ((index, topLevelScope) in topLevelScopes.withIndex()) {
manager.processLevel(
topLevelScope.toScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, TowerGroup.Top(index),
ExplicitReceiverKind.EXTENSION_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
}
// Here we already know extension receiver for invoke, and it's stated in info as first argument
internal suspend fun runResolverForBuiltinInvokeExtensionWithExplicitArgument(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
manager: TowerResolveManager
) {
manager.processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(),
info, TowerGroup.Member,
ExplicitReceiverKind.DISPATCH_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
// Here we don't know extension receiver for invoke, assuming it's one of implicit receivers
internal suspend fun runResolverForBuiltinInvokeExtensionWithImplicitArgument(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
manager: TowerResolveManager
) {
for ((implicitReceiverValue, depth) in implicitReceiversUsableAsValues) {
val parentGroup = TowerGroup.Implicit(depth)
manager.processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(
extensionReceiver = implicitReceiverValue,
implicitExtensionInvokeMode = true
),
info, parentGroup.InvokeExtension,
ExplicitReceiverKind.DISPATCH_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER
)
}
}
private companion object {
private fun prepareImplicitReceivers(
implicitReceiverValues: List<ImplicitReceiverValue<*>>
): Pair<List<ImplicitReceiver>, List<ImplicitReceiver>> {
var depth = 0
var firstDispatchValue = true
val explicitCompanions = mutableListOf<FirRegularClassSymbol>()
val implicitReceiversUsableAsValues = mutableListOf<ImplicitReceiver>()
val implicitReceivers = implicitReceiverValues.mapNotNull { receiverValue ->
val usableAsValue = when (receiverValue) {
is ImplicitExtensionReceiverValue -> true
is ImplicitDispatchReceiverValue -> {
val symbol = receiverValue.boundSymbol
val klass = symbol.fir as? FirRegularClass
if (!receiverValue.implicitCompanion && klass?.isCompanion == true) {
explicitCompanions += klass.symbol
}
if (firstDispatchValue && !receiverValue.inDelegated) {
if (!receiverValue.implicitCompanion &&
klass?.isInner == false &&
!symbol.classId.isLocal
) {
firstDispatchValue = false
}
true
} else {
symbol.fir.classKind == ClassKind.OBJECT && !receiverValue.inDelegated
}
}
}
if (receiverValue is ImplicitDispatchReceiverValue && receiverValue.implicitCompanion && receiverValue.boundSymbol in explicitCompanions) {
null
} else {
ImplicitReceiver(receiverValue, depth++, usableAsValue).also {
if (usableAsValue) {
implicitReceiversUsableAsValues.add(it)
}
}
}
}
return implicitReceivers to implicitReceiversUsableAsValues
}
}
}
@@ -31,7 +31,8 @@ internal class CallResolutionContext(
val invokeBuiltinExtensionReceiverCandidateFactory: CandidateFactory?,
val stubReceiverCandidateFactory: CandidateFactory?,
val invokeReceiverCollector: CandidateCollector?,
val towerResolver: FirTowerResolver
val towerResolver: FirTowerResolver,
val towerResolverSession: FirTowerResolverSession
) {
// TODO: Get rid of the property, storing state here looks like a hack
internal lateinit var invokeOnGivenReceiverCandidateFactory: CandidateFactory
@@ -47,6 +48,7 @@ internal class LevelHandler(
private val resultCollector: CandidateCollector get() = callResolutionContext.resultCollector
private val towerResolver: FirTowerResolver get() = callResolutionContext.towerResolver
private val towerResolverSession: FirTowerResolverSession get() = callResolutionContext.towerResolverSession
private fun enqueueResolverTask(group: TowerGroup = TowerGroup.Start, task: suspend () -> Unit) =
manager.enqueueResolverTask(group, task)
@@ -203,26 +205,26 @@ internal class LevelHandler(
when {
invokeBuiltinExtensionMode -> {
enqueueResolverTask {
towerResolver.runResolverForBuiltinInvokeExtensionWithExplicitArgument(
towerResolverSession.runResolverForBuiltinInvokeExtensionWithExplicitArgument(
invokeFunctionInfo, explicitReceiver, manager
)
}
}
useImplicitReceiverAsBuiltinInvokeArgument -> {
enqueueResolverTask {
towerResolver.runResolverForBuiltinInvokeExtensionWithImplicitArgument(
towerResolverSession.runResolverForBuiltinInvokeExtensionWithImplicitArgument(
invokeFunctionInfo, explicitReceiver, manager
)
}
enqueueResolverTask {
towerResolver.runResolverForInvoke(
towerResolverSession.runResolverForInvoke(
invokeFunctionInfo, explicitReceiver, manager
)
}
}
else -> {
enqueueResolverTask {
towerResolver.runResolverForInvoke(
towerResolverSession.runResolverForInvoke(
invokeFunctionInfo, explicitReceiver, manager
)
}