[FIR] Extract invoke processing from TowerLevelHandler

This commit is contained in:
Simon Ogorodnik
2020-07-29 22:23:35 +03:00
parent 96f100381a
commit bf2e17b133
10 changed files with 883 additions and 745 deletions
@@ -0,0 +1,388 @@
/*
* 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.tower
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.builder.FirQualifiedAccessExpressionBuilder
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.firUnsafe
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.fir.types.isExtensionFunctionType
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.util.OperatorNameConventions
internal class FirInvokeResolveTowerExtension(
private val components: BodyResolveComponents,
private val manager: TowerResolveManager,
private val candidateFactoriesAndCollectors: CandidateFactoriesAndCollectors
) {
fun enqueueResolveTasksForQualifier(info: CallInfo, receiver: FirResolvedQualifier) {
if (info.callKind != CallKind.Function) return
enqueueBothInvokeReceiverTasks(
info,
invokeAction = { task, receiverInfo ->
task.runResolverForQualifierReceiver(receiverInfo, receiver)
},
invokeExtensionAction = { task, receiverInfo ->
task.runResolverForNoReceiver(receiverInfo)
}
)
}
fun enqueueResolveTasksForNoReceiver(info: CallInfo) {
if (info.callKind != CallKind.Function) return
val invokeReceiverVariableInfo = info.replaceWithVariableAccess()
enqueueInvokeReceiverTask(
info,
invokeReceiverVariableInfo,
invokeBuiltinExtensionMode = false
) {
it.runResolverForNoReceiver(invokeReceiverVariableInfo)
}
}
fun enqueueResolveTasksForExpressionReceiver(info: CallInfo, receiver: FirExpression) {
if (info.callKind != CallKind.Function) return
enqueueBothInvokeReceiverTasks(
info,
invokeAction = { task, receiverInfo ->
task.runResolverForExpressionReceiver(receiverInfo, receiver)
},
invokeExtensionAction = { task, receiverInfo ->
task.runResolverForNoReceiver(receiverInfo)
}
)
}
private inline fun enqueueBothInvokeReceiverTasks(
originalCallInfo: CallInfo,
crossinline invokeAction: suspend (FirTowerResolveTask, CallInfo) -> Unit,
crossinline invokeExtensionAction: suspend (FirTowerResolveTask, CallInfo) -> Unit
) {
val invokeReceiverVariableInfo = originalCallInfo.replaceWithVariableAccess()
val invokeReceiverVariableWithNoReceiverInfo = invokeReceiverVariableInfo.replaceExplicitReceiver(null)
val towerDataElementsForName = TowerDataElementsForName(invokeReceiverVariableInfo.name, components.towerDataContext)
enqueueInvokeReceiverTask(
originalCallInfo,
invokeReceiverVariableInfo,
towerDataElementsForName = towerDataElementsForName,
invokeBuiltinExtensionMode = false
) {
invokeAction(it, invokeReceiverVariableInfo)
}
enqueueInvokeReceiverTask(
originalCallInfo,
invokeReceiverVariableWithNoReceiverInfo,
towerDataElementsForName = towerDataElementsForName,
invokeBuiltinExtensionMode = true
) {
invokeExtensionAction(it, invokeReceiverVariableWithNoReceiverInfo)
}
}
private inline fun enqueueInvokeReceiverTask(
info: CallInfo,
invokeReceiverInfo: CallInfo,
towerDataElementsForName: TowerDataElementsForName = TowerDataElementsForName(invokeReceiverInfo.name, components.towerDataContext),
invokeBuiltinExtensionMode: Boolean,
crossinline task: suspend (FirTowerResolveTask) -> Unit
) {
val collector = CandidateCollector(components, components.resolutionStageRunner)
val invokeReceiverProcessor = InvokeReceiverResolveTask(
components,
manager,
towerDataElementsForName,
collector,
CandidateFactory(components, invokeReceiverInfo),
onSuccessfulLevel = { towerGroup ->
enqueueResolverTasksForInvokeReceiverCandidates(
invokeBuiltinExtensionMode, info,
receiverGroup = towerGroup,
collector
)
collector.newDataSet()
}
)
manager.enqueueResolverTask {
task(invokeReceiverProcessor)
}
}
private fun enqueueResolverTasksForInvokeReceiverCandidates(
extensionInvokeOnActualReceiver: Boolean,
info: CallInfo,
receiverGroup: TowerGroup,
collector: CandidateCollector
) {
val invokeBuiltinExtensionMode: Boolean = extensionInvokeOnActualReceiver
for (invokeReceiverCandidate in collector.bestCandidates()) {
val symbol = invokeReceiverCandidate.symbol
if (symbol !is FirCallableSymbol<*> && symbol !is FirClassLikeSymbol<*>) continue
val isExtensionFunctionType =
(symbol as? FirCallableSymbol<*>)?.fir?.returnTypeRef?.isExtensionFunctionType(components.session) == true
if (invokeBuiltinExtensionMode && !isExtensionFunctionType) {
continue
}
val extensionReceiverExpression = invokeReceiverCandidate.extensionReceiverExpression()
val useImplicitReceiverAsBuiltinInvokeArgument =
!invokeBuiltinExtensionMode && isExtensionFunctionType &&
invokeReceiverCandidate.explicitReceiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
val invokeReceiverExpression =
components.createExplicitReceiverForInvoke(
invokeReceiverCandidate, info, invokeBuiltinExtensionMode, extensionReceiverExpression
)
val invokeFunctionInfo =
info.copy(
explicitReceiver = invokeReceiverExpression, name = OperatorNameConventions.INVOKE,
candidateForCommonInvokeReceiver = invokeReceiverCandidate.takeUnless { invokeBuiltinExtensionMode }
).let {
when {
invokeBuiltinExtensionMode -> it.withReceiverAsArgument(info.explicitReceiver!!)
else -> it
}
}
val explicitReceiver = ExpressionReceiverValue(invokeReceiverExpression)
enqueueResolverTasksForInvoke(
invokeFunctionInfo,
explicitReceiver,
invokeBuiltinExtensionMode,
useImplicitReceiverAsBuiltinInvokeArgument,
receiverGroup
)
}
}
private fun enqueueResolverTasksForInvoke(
invokeFunctionInfo: CallInfo,
explicitReceiver: ExpressionReceiverValue,
invokeBuiltinExtensionMode: Boolean,
useImplicitReceiverAsBuiltinInvokeArgument: Boolean,
receiverGroup: TowerGroup
) {
val invokeOnGivenReceiverCandidateFactory = CandidateFactory(components, invokeFunctionInfo)
val task = InvokeFunctionResolveTask(
components,
manager,
TowerDataElementsForName(invokeFunctionInfo.name, components.towerDataContext),
receiverGroup,
candidateFactoriesAndCollectors.resultCollector,
invokeOnGivenReceiverCandidateFactory,
candidateFactoriesAndCollectors.stubReceiverCandidateFactory
)
if (invokeBuiltinExtensionMode) {
manager.enqueueResolverTask {
task.runResolverForBuiltinInvokeExtensionWithExplicitArgument(
invokeFunctionInfo, explicitReceiver,
TowerGroup.EmptyRoot
)
}
} else {
if (useImplicitReceiverAsBuiltinInvokeArgument) {
manager.enqueueResolverTask {
task.runResolverForBuiltinInvokeExtensionWithImplicitArgument(
invokeFunctionInfo, explicitReceiver,
TowerGroup.EmptyRoot
)
}
}
manager.enqueueResolverTask {
task.runResolverForInvoke(
invokeFunctionInfo, explicitReceiver,
TowerGroup.EmptyRoot
)
}
}
}
}
private fun BodyResolveComponents.createExplicitReceiverForInvoke(
candidate: Candidate,
info: CallInfo,
invokeBuiltinExtensionMode: Boolean,
extensionReceiverExpression: FirExpression
): FirExpression {
return when (val symbol = candidate.symbol) {
is FirCallableSymbol<*> -> createExplicitReceiverForInvokeByCallable(
candidate, info, invokeBuiltinExtensionMode, extensionReceiverExpression, symbol
)
is FirRegularClassSymbol -> buildResolvedQualifierForClass(symbol, sourceElement = null)
is FirTypeAliasSymbol -> {
val type = symbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session)
val expansionRegularClass = type.lookupTag.toSymbol(session)?.fir as? FirRegularClass
buildResolvedQualifierForClass(expansionRegularClass!!.symbol, sourceElement = symbol.fir.source)
}
else -> throw AssertionError()
}
}
private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable(
candidate: Candidate,
info: CallInfo,
invokeBuiltinExtensionMode: Boolean,
extensionReceiverExpression: FirExpression,
symbol: FirCallableSymbol<*>
): FirExpression {
return FirQualifiedAccessExpressionBuilder().apply {
calleeReference = FirNamedReferenceWithCandidate(
null,
symbol.callableId.callableName,
candidate
)
dispatchReceiver = candidate.dispatchReceiverExpression()
this.typeRef = returnTypeCalculator.tryCalculateReturnType(symbol.firUnsafe())
if (!invokeBuiltinExtensionMode) {
extensionReceiver = extensionReceiverExpression
// NB: this should fix problem in DFA (KT-36014)
explicitReceiver = info.explicitReceiver
}
}.build().let(::transformQualifiedAccessUsingSmartcastInfo)
}
private class InvokeReceiverResolveTask(
components: BodyResolveComponents,
manager: TowerResolveManager,
towerDataElementsForName: TowerDataElementsForName,
collector: CandidateCollector,
candidateFactory: CandidateFactory,
private val onSuccessfulLevel: (TowerGroup) -> Unit
) : FirTowerResolveTask(
components,
manager,
towerDataElementsForName,
collector,
candidateFactory,
stubReceiverCandidateFactory = null
) {
override fun interceptTowerGroup(towerGroup: TowerGroup): TowerGroup =
towerGroup.InvokeResolvePriority(InvokeResolvePriority.INVOKE_RECEIVER)
override fun onSuccessfulLevel(towerGroup: TowerGroup) {
this.onSuccessfulLevel.invoke(towerGroup)
}
}
private class InvokeFunctionResolveTask(
components: BodyResolveComponents,
manager: TowerResolveManager,
towerDataElementsForName: TowerDataElementsForName,
private val receiverGroup: TowerGroup,
collector: CandidateCollector,
candidateFactory: CandidateFactory,
stubReceiverCandidateFactory: CandidateFactory? = null
) : FirBaseTowerResolveTask(
components,
manager,
towerDataElementsForName,
collector,
candidateFactory,
stubReceiverCandidateFactory
) {
override fun interceptTowerGroup(towerGroup: TowerGroup): TowerGroup =
maxOf(towerGroup.InvokeResolvePriority(InvokeResolvePriority.COMMON_INVOKE), receiverGroup)
suspend fun runResolverForInvoke(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
parentGroupForInvokeCandidates: TowerGroup
) {
processLevelForRegularInvoke(
invokeReceiverValue.toMemberScopeTowerLevel(),
info, parentGroupForInvokeCandidates.Member,
ExplicitReceiverKind.DISPATCH_RECEIVER
)
enumerateTowerLevels(
onScope = { scope, group ->
processLevelForRegularInvoke(
scope.toScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, group,
ExplicitReceiverKind.EXTENSION_RECEIVER
)
},
onImplicitReceiver = { receiver, group ->
// NB: companions are processed via implicitReceiverValues!
processLevelForRegularInvoke(
receiver.toMemberScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, group.Member,
ExplicitReceiverKind.EXTENSION_RECEIVER
)
}
)
}
// Here we already know extension receiver for invoke, and it's stated in info as first argument
suspend fun runResolverForBuiltinInvokeExtensionWithExplicitArgument(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
parentGroupForInvokeCandidates: TowerGroup
) {
processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(),
info, parentGroupForInvokeCandidates.Member.InvokeResolvePriority(InvokeResolvePriority.INVOKE_EXTENSION),
ExplicitReceiverKind.DISPATCH_RECEIVER
)
}
// Here we don't know extension receiver for invoke, assuming it's one of implicit receivers
suspend fun runResolverForBuiltinInvokeExtensionWithImplicitArgument(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
parentGroupForInvokeCandidates: TowerGroup
) {
for ((depth, implicitReceiverValue) in towerDataElementsForName.implicitReceivers) {
val towerGroup =
parentGroupForInvokeCandidates
.Implicit(depth)
.InvokeExtension
.InvokeResolvePriority(InvokeResolvePriority.INVOKE_EXTENSION)
processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(
extensionReceiver = implicitReceiverValue,
implicitExtensionInvokeMode = true
),
info, towerGroup,
ExplicitReceiverKind.DISPATCH_RECEIVER
)
}
}
private suspend fun processLevelForRegularInvoke(
towerLevel: SessionBasedTowerLevel,
callInfo: CallInfo,
group: TowerGroup,
explicitReceiverKind: ExplicitReceiverKind
) = processLevel(
towerLevel, callInfo,
group.InvokeResolvePriority(InvokeResolvePriority.COMMON_INVOKE),
explicitReceiverKind
)
}
@@ -0,0 +1,417 @@
/*
* 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.tower
import org.jetbrains.kotlin.fir.asReversedFrozen
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.scopes.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.descriptorUtil.HIDES_MEMBERS_NAME_LIST
import java.util.*
internal class TowerDataElementsForName(
name: Name,
towerDataContext: FirTowerDataContext
) {
val nonLocalTowerDataElements = towerDataContext.nonLocalTowerDataElements.asReversedFrozen()
val reversedFilteredLocalScopes by lazy(LazyThreadSafetyMode.NONE) {
@OptIn(ExperimentalStdlibApi::class)
buildList {
val localScopesBase = towerDataContext.localScopes
val lastIndex = localScopesBase.lastIndex
for (i in lastIndex downTo 0) {
val localScope = localScopesBase[i]
if (localScope.mayContainName(name)) {
add(IndexedValue(lastIndex - i, localScope))
}
}
}
}
val implicitReceivers by lazy(LazyThreadSafetyMode.NONE) {
nonLocalTowerDataElements.mapIndexedNotNull { index, towerDataElement ->
towerDataElement.implicitReceiver?.let { receiver -> IndexedValue(index, receiver) }
}
}
}
internal abstract class FirBaseTowerResolveTask(
protected val components: BodyResolveComponents,
private val manager: TowerResolveManager,
protected val towerDataElementsForName: TowerDataElementsForName,
private val collector: CandidateCollector,
private val candidateFactory: CandidateFactory,
private val stubReceiverCandidateFactory: CandidateFactory? = null
) {
protected val session get() = components.session
private val handler: TowerLevelHandler = TowerLevelHandler()
open fun interceptTowerGroup(towerGroup: TowerGroup) = towerGroup
open fun onSuccessfulLevel(towerGroup: TowerGroup) {}
protected suspend inline fun processLevel(
towerLevel: SessionBasedTowerLevel,
callInfo: CallInfo,
group: TowerGroup,
explicitReceiverKind: ExplicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
onEmptyLevel: () -> Unit = {}
) {
if (processLevel(towerLevel, callInfo, group, explicitReceiverKind)) {
onEmptyLevel()
}
}
protected fun FirScope.toScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
extensionsOnly: Boolean = false,
includeInnerConstructors: Boolean = true
): ScopeTowerLevel = ScopeTowerLevel(
session, components, this,
extensionReceiver, extensionsOnly, includeInnerConstructors
)
protected fun ReceiverValue.toMemberScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
implicitExtensionInvokeMode: Boolean = false
) = MemberScopeTowerLevel(
session, components, this,
extensionReceiver, implicitExtensionInvokeMode,
scopeSession = components.scopeSession
)
protected inline fun enumerateTowerLevels(
parentGroup: TowerGroup = TowerGroup.EmptyRoot,
onScope: (FirScope, TowerGroup) -> Unit,
onImplicitReceiver: (ImplicitReceiverValue<*>, TowerGroup) -> Unit,
) {
for ((index, localScope) in towerDataElementsForName.reversedFilteredLocalScopes) {
onScope(localScope, parentGroup.Local(index))
}
for ((depth, lexical) in towerDataElementsForName.nonLocalTowerDataElements.withIndex()) {
if (!lexical.isLocal && lexical.scope != null) {
onScope(lexical.scope, parentGroup.NonLocal(depth))
}
val receiver = lexical.implicitReceiver
if (receiver != null && receiver !is InaccessibleImplicitReceiverValue) {
onImplicitReceiver(receiver, parentGroup.Implicit(depth))
}
}
}
/**
* @return true if level is empty
*/
private suspend fun processLevel(
towerLevel: SessionBasedTowerLevel,
callInfo: CallInfo,
group: TowerGroup,
explicitReceiverKind: ExplicitReceiverKind
): Boolean {
val finalGroup = interceptTowerGroup(group)
manager.requestGroup(finalGroup)
val result = handler.handleLevel(
collector,
candidateFactory,
stubReceiverCandidateFactory,
callInfo,
explicitReceiverKind,
finalGroup,
towerLevel
)
if (collector.isSuccess()) onSuccessfulLevel(finalGroup)
return result == ProcessorAction.NONE
}
}
internal open class FirTowerResolveTask(
components: BodyResolveComponents,
manager: TowerResolveManager,
towerDataElementsForName: TowerDataElementsForName,
collector: CandidateCollector,
candidateFactory: CandidateFactory,
stubReceiverCandidateFactory: CandidateFactory? = null
) : FirBaseTowerResolveTask(
components,
manager,
towerDataElementsForName,
collector,
candidateFactory,
stubReceiverCandidateFactory
) {
suspend fun runResolverForQualifierReceiver(
info: CallInfo,
resolvedQualifier: FirResolvedQualifier
) {
val qualifierReceiver = createQualifierReceiver(resolvedQualifier, session, components.scopeSession)
when {
info.isPotentialQualifierPart -> {
processClassifierScope(info, qualifierReceiver, prioritized = true)
processQualifierScopes(info, qualifierReceiver)
}
else -> {
processQualifierScopes(info, qualifierReceiver)
processClassifierScope(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, parentGroup = TowerGroup.QualifierValue)
}
} else {
if (typeRef !is FirImplicitBuiltinTypeRef) {
runResolverForExpressionReceiver(info, resolvedQualifier, parentGroup = TowerGroup.QualifierValue)
}
}
}
}
private suspend fun processQualifierScopes(
info: CallInfo, qualifierReceiver: QualifierReceiver?
) {
if (qualifierReceiver == null) return
val callableScope = qualifierReceiver.callableScope() ?: return
processLevel(
callableScope.toScopeTowerLevel(includeInnerConstructors = false),
info.noStubReceiver(), TowerGroup.Qualifier
)
}
private suspend fun processClassifierScope(
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
val group = if (prioritized) TowerGroup.ClassifierPrioritized else TowerGroup.Classifier
processLevel(
scope.toScopeTowerLevel(includeInnerConstructors = false), info.noStubReceiver(),
group
)
}
suspend fun runResolverForExpressionReceiver(
info: CallInfo,
receiver: FirExpression,
parentGroup: TowerGroup = TowerGroup.EmptyRoot
) {
val explicitReceiverValue = ExpressionReceiverValue(receiver)
processExtensionsThatHideMembers(info, explicitReceiverValue, parentGroup)
// Member scope of expression receiver
processLevel(
explicitReceiverValue.toMemberScopeTowerLevel(), info, parentGroup.Member, ExplicitReceiverKind.DISPATCH_RECEIVER
)
val shouldProcessExplicitReceiverScopeOnly =
info.callKind == CallKind.Function && info.explicitReceiver?.typeRef?.coneTypeSafe<ConeIntegerLiteralType>() != null
if (shouldProcessExplicitReceiverScopeOnly) {
// Special case (integer literal type)
return
}
enumerateTowerLevels(
parentGroup = parentGroup,
onScope = { scope, group ->
processScopeForExplicitReceiver(
scope,
explicitReceiverValue,
info,
group
)
},
onImplicitReceiver = { implicitReceiverValue, group ->
processCombinationOfReceivers(implicitReceiverValue, explicitReceiverValue, info, group)
}
)
}
suspend fun runResolverForNoReceiver(
info: CallInfo
) {
processExtensionsThatHideMembers(info, explicitReceiverValue = null)
val emptyScopes = mutableSetOf<FirScope>()
val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>()
enumerateTowerLevels(
onScope = l@{ scope, group ->
// 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 && scope in emptyScopes) return@l
processLevel(
scope.toScopeTowerLevel(), info, group,
onEmptyLevel = {
emptyScopes += scope
}
)
},
onImplicitReceiver = { receiver, group ->
processCandidatesWithGivenImplicitReceiverAsValue(
receiver,
info,
group,
implicitReceiverValuesWithEmptyScopes,
emptyScopes
)
}
)
}
suspend fun runResolverForSuperReceiver(
info: CallInfo,
superTypeRef: FirTypeRef
) {
val scope = when (superTypeRef) {
is FirResolvedTypeRef -> superTypeRef.type.scope(session, components.scopeSession)
is FirComposedSuperTypeRef -> FirCompositeScope(
superTypeRef.superTypeRefs.mapNotNull { it.type.scope(session, components.scopeSession) }
)
else -> null
} ?: return
processLevel(
scope.toScopeTowerLevel(),
info, TowerGroup.Member, explicitReceiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER
)
}
private suspend fun processExtensionsThatHideMembers(
info: CallInfo,
explicitReceiverValue: ReceiverValue?,
parentGroup: TowerGroup = TowerGroup.EmptyRoot
) {
val shouldProcessExtensionsBeforeMembers =
info.callKind == CallKind.Function && info.name in HIDES_MEMBERS_NAME_LIST
if (!shouldProcessExtensionsBeforeMembers) return
val importingScopes = components.fileImportsScope.asReversed()
for ((index, topLevelScope) in importingScopes.withIndex()) {
if (explicitReceiverValue != null) {
processHideMembersLevel(
explicitReceiverValue, topLevelScope, info, index, depth = null,
ExplicitReceiverKind.EXTENSION_RECEIVER, parentGroup
)
} else {
for ((depth, implicitReceiverValue) in towerDataElementsForName.implicitReceivers) {
processHideMembersLevel(
implicitReceiverValue, topLevelScope, info, index, depth,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, parentGroup
)
}
}
}
}
private suspend fun processScopeForExplicitReceiver(
scope: FirScope,
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo,
towerGroup: TowerGroup,
) {
processLevel(
scope.toScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, towerGroup, ExplicitReceiverKind.EXTENSION_RECEIVER
)
}
private suspend fun processCombinationOfReceivers(
implicitReceiverValue: ImplicitReceiverValue<*>,
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo,
parentGroup: TowerGroup
) {
// Member extensions
processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, parentGroup.Member, ExplicitReceiverKind.EXTENSION_RECEIVER
)
}
private suspend fun processCandidatesWithGivenImplicitReceiverAsValue(
receiver: ImplicitReceiverValue<*>,
info: CallInfo,
parentGroup: TowerGroup,
implicitReceiverValuesWithEmptyScopes: MutableSet<ImplicitReceiverValue<*>>,
emptyScopes: MutableSet<FirScope>
) {
processLevel(
receiver.toMemberScopeTowerLevel(), info, parentGroup.Member,
onEmptyLevel = {
implicitReceiverValuesWithEmptyScopes += receiver
}
)
enumerateTowerLevels(
parentGroup,
onScope = l@{ scope, group ->
if (scope in emptyScopes) return@l
processLevel(
scope.toScopeTowerLevel(extensionReceiver = receiver),
info, group,
onEmptyLevel = {
emptyScopes += scope
}
)
},
onImplicitReceiver = l@{ implicitReceiverValue, group ->
if (implicitReceiverValue in implicitReceiverValuesWithEmptyScopes) return@l
processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = receiver),
info, group
)
}
)
}
private suspend fun processHideMembersLevel(
receiverValue: ReceiverValue,
topLevelScope: FirScope,
info: CallInfo,
index: Int,
depth: Int?,
explicitReceiverKind: ExplicitReceiverKind,
parentGroup: TowerGroup
) = processLevel(
topLevelScope.toScopeTowerLevel(
extensionReceiver = receiverValue, extensionsOnly = true
),
info,
parentGroup.TopPrioritized(index).let { if (depth != null) it.Implicit(depth) else it },
explicitReceiverKind,
)
}
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.fir.resolve.calls.tower
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.calls.*
import org.jetbrains.kotlin.fir.resolve.scope
@@ -27,13 +30,51 @@ class FirTowerResolver(
): CandidateCollector {
val candidateFactoriesAndCollectors = buildCandidateFactoriesAndCollectors(info, collector)
val towerResolverSession = FirTowerResolverSession(components, manager, candidateFactoriesAndCollectors, info)
towerResolverSession.runResolution(info)
enqueueResolutionTasks(components, manager, candidateFactoriesAndCollectors, info)
manager.runTasks()
return collector
}
private fun enqueueResolutionTasks(
components: BodyResolveComponents,
manager: TowerResolveManager,
candidateFactoriesAndCollectors: CandidateFactoriesAndCollectors,
info: CallInfo
) {
val invokeResolveTowerExtension = FirInvokeResolveTowerExtension(components, manager, candidateFactoriesAndCollectors)
val mainTask = FirTowerResolveTask(
components,
manager,
TowerDataElementsForName(info.name, components.towerDataContext),
candidateFactoriesAndCollectors.resultCollector,
candidateFactoriesAndCollectors.candidateFactory,
candidateFactoriesAndCollectors.stubReceiverCandidateFactory
)
when (val receiver = info.explicitReceiver) {
is FirResolvedQualifier -> {
manager.enqueueResolverTask { mainTask.runResolverForQualifierReceiver(info, receiver) }
invokeResolveTowerExtension.enqueueResolveTasksForQualifier(info, receiver)
}
null -> {
manager.enqueueResolverTask { mainTask.runResolverForNoReceiver(info) }
invokeResolveTowerExtension.enqueueResolveTasksForNoReceiver(info)
}
else -> {
if (receiver is FirQualifiedAccessExpression) {
val calleeReference = receiver.calleeReference
if (calleeReference is FirSuperReference) {
return manager.enqueueResolverTask { mainTask.runResolverForSuperReceiver(info, receiver.typeRef) }
}
}
manager.enqueueResolverTask { mainTask.runResolverForExpressionReceiver(info, receiver) }
invokeResolveTowerExtension.enqueueResolveTasksForExpressionReceiver(info, receiver)
}
}
}
fun runResolverForDelegatingConstructor(
info: CallInfo,
constructedType: ConeClassLikeType
@@ -79,26 +120,10 @@ class FirTowerResolver(
else
null
var invokeReceiverCollector: CandidateCollector? = null
var invokeReceiverCandidateFactory: CandidateFactory? = null
var invokeBuiltinExtensionReceiverCandidateFactory: CandidateFactory? = null
if (info.callKind == CallKind.Function) {
invokeReceiverCollector = CandidateCollector(components, components.resolutionStageRunner)
invokeReceiverCandidateFactory = CandidateFactory(components, info.replaceWithVariableAccess())
if (info.explicitReceiver != null) {
with(invokeReceiverCandidateFactory) {
invokeBuiltinExtensionReceiverCandidateFactory = replaceCallInfo(callInfo.replaceExplicitReceiver(null))
}
}
}
return CandidateFactoriesAndCollectors(
candidateFactory,
collector,
stubReceiverCandidateFactory,
invokeReceiverCandidateFactory,
invokeReceiverCollector,
invokeBuiltinExtensionReceiverCandidateFactory
stubReceiverCandidateFactory
)
}
@@ -1,664 +0,0 @@
/*
* 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.tower
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.asReversedFrozen
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
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.expressions.builder.FirQualifiedAccessExpressionBuilder
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.firUnsafe
import org.jetbrains.kotlin.fir.scopes.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
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
import org.jetbrains.kotlin.util.OperatorNameConventions
class FirTowerResolverSession internal constructor(
private val components: BodyResolveComponents,
private val manager: TowerResolveManager,
private val candidateFactoriesAndCollectors: CandidateFactoriesAndCollectors,
private val mainCallInfo: CallInfo,
) {
private data class ImplicitReceiver(
val receiver: ImplicitReceiverValue<*>,
val depth: Int
)
private val session: FirSession get() = components.session
private val localScopes: List<FirScope> by lazy(LazyThreadSafetyMode.NONE) {
val localScopesBase = components.towerDataContext.localScopes
val result = ArrayList<FirScope>()
for (i in localScopesBase.lastIndex downTo 0) {
val localScope = localScopesBase[i]
if (localScope.mayContainName(mainCallInfo.name)
|| (mainCallInfo.callKind == CallKind.Function && localScope.mayContainName(OperatorNameConventions.INVOKE))
) {
result.add(localScope)
}
}
result
}
private val nonLocalTowerDataElements = components.towerDataContext.nonLocalTowerDataElements.asReversedFrozen()
private val implicitReceivers: List<ImplicitReceiver> by lazy(LazyThreadSafetyMode.NONE) {
nonLocalTowerDataElements.withIndex().mapNotNull { (index, element) ->
element.implicitReceiver?.let { ImplicitReceiver(it, index) }
}
}
fun runResolution(info: CallInfo) {
when (val receiver = info.explicitReceiver) {
is FirResolvedQualifier -> manager.enqueueResolverTask { runResolverForQualifierReceiver(info, receiver) }
null -> manager.enqueueResolverTask { runResolverForNoReceiver(info) }
else -> run {
if (receiver is FirQualifiedAccessExpression) {
val calleeReference = receiver.calleeReference
if (calleeReference is FirSuperReference) {
return@run manager.enqueueResolverTask { runResolverForSuperReceiver(info, receiver.typeRef) }
}
}
manager.enqueueResolverTask { runResolverForExpressionReceiver(info, receiver) }
}
}
}
private suspend fun processLevel(
towerLevel: SessionBasedTowerLevel,
callInfo: CallInfo,
group: TowerGroup,
explicitReceiverKind: ExplicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
invokeResolveMode: InvokeResolveMode? = null,
candidateFactory: CandidateFactory = candidateFactoriesAndCollectors.candidateFactory,
// Non-trivial only for qualifier receiver, because there we should prioritize invokes that were found
// at Qualifier scopes above candidates found in QualifierAsExpression receiver
useParentGroupForInvokes: Boolean = false
): ProcessorAction {
manager.requestGroup(group)
val levelHandler = TowerLevelHandler()
return levelHandler.handleLevel(
callInfo, explicitReceiverKind, group,
candidateFactoriesAndCollectors, towerLevel, invokeResolveMode, candidateFactory
) {
enqueueResolverTasksForInvokeReceiverCandidates(
invokeResolveMode, callInfo,
parentGroupForInvokeCandidates = if (useParentGroupForInvokes) group else TowerGroup.EmptyRoot
)
}
}
private suspend fun processLevelForPropertyWithInvokeExtension(
towerLevel: SessionBasedTowerLevel,
callInfo: CallInfo,
group: TowerGroup
) {
if (callInfo.callKind == CallKind.Function) {
processLevel(
towerLevel,
callInfo,
group,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION
)
}
}
private fun FirScope.toScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
extensionsOnly: Boolean = false,
includeInnerConstructors: Boolean = true
): ScopeTowerLevel = ScopeTowerLevel(
session, components, this,
extensionReceiver, extensionsOnly, includeInnerConstructors
)
private fun ReceiverValue.toMemberScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
implicitExtensionInvokeMode: Boolean = false
) = MemberScopeTowerLevel(
session, components, this,
extensionReceiver, implicitExtensionInvokeMode,
scopeSession = components.scopeSession
)
private suspend fun processQualifierScopes(
info: CallInfo, qualifierReceiver: QualifierReceiver?
) {
if (qualifierReceiver == null) return
val callableScope = qualifierReceiver.callableScope() ?: return
processLevel(
callableScope.toScopeTowerLevel(includeInnerConstructors = false),
info.noStubReceiver(), TowerGroup.Qualifier,
useParentGroupForInvokes = true,
)
}
private suspend fun processClassifierScope(
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
val group = if (prioritized) TowerGroup.ClassifierPrioritized else TowerGroup.Classifier
processLevel(
scope.toScopeTowerLevel(includeInnerConstructors = false), info.noStubReceiver(),
group,
useParentGroupForInvokes = true,
)
}
private suspend fun runResolverForQualifierReceiver(
info: CallInfo,
resolvedQualifier: FirResolvedQualifier
) {
val qualifierReceiver = createQualifierReceiver(resolvedQualifier, session, components.scopeSession)
when {
info.isPotentialQualifierPart -> {
processClassifierScope(info, qualifierReceiver, prioritized = true)
processQualifierScopes(info, qualifierReceiver)
}
else -> {
processQualifierScopes(info, qualifierReceiver)
processClassifierScope(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)
}
} else {
if (typeRef !is FirImplicitBuiltinTypeRef) {
runResolverForExpressionReceiver(info, resolvedQualifier)
}
}
}
}
private suspend fun runResolverForNoReceiver(
info: CallInfo
) {
processExtensionsThatHideMembers(info, explicitReceiverValue = null)
val emptyScopes = mutableSetOf<FirScope>()
val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>()
enumerateTowerLevels(
onScope = l@{ scope, group ->
// 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 && scope in emptyScopes) return@l
processLevel(
scope.toScopeTowerLevel(), info, group
)
},
onImplicitReceiver = { receiver, group ->
processCandidatesWithGivenImplicitReceiverAsValue(
receiver,
info,
group,
implicitReceiverValuesWithEmptyScopes,
emptyScopes
)
}
)
}
private suspend fun processExtensionsThatHideMembers(
info: CallInfo,
explicitReceiverValue: ReceiverValue?
) {
val shouldProcessExtensionsBeforeMembers =
info.callKind == CallKind.Function && info.name in HIDES_MEMBERS_NAME_LIST
if (!shouldProcessExtensionsBeforeMembers) return
val importingScopes = components.fileImportsScope.asReversed()
for ((index, topLevelScope) in importingScopes.withIndex()) {
if (explicitReceiverValue != null) {
processHideMembersLevel(
explicitReceiverValue, topLevelScope, info, index, depth = null,
ExplicitReceiverKind.EXTENSION_RECEIVER
)
} else {
for ((implicitReceiverValue, depth) in implicitReceivers) {
processHideMembersLevel(
implicitReceiverValue, topLevelScope, info, index, depth,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
)
}
}
}
}
private suspend fun processHideMembersLevel(
receiverValue: ReceiverValue,
topLevelScope: FirScope,
info: CallInfo,
index: Int,
depth: Int?,
explicitReceiverKind: ExplicitReceiverKind
) = processLevel(
topLevelScope.toScopeTowerLevel(
extensionReceiver = receiverValue, extensionsOnly = true
),
info,
TowerGroup.TopPrioritized(index).let { if (depth != null) it.Implicit(depth) else it },
explicitReceiverKind,
)
private suspend fun processCandidatesWithGivenImplicitReceiverAsValue(
receiver: ImplicitReceiverValue<*>,
info: CallInfo,
parentGroup: TowerGroup,
implicitReceiverValuesWithEmptyScopes: MutableSet<ImplicitReceiverValue<*>>,
emptyScopes: MutableSet<FirScope>
) {
val implicitResult = processLevel(
receiver.toMemberScopeTowerLevel(), info, parentGroup.Member
)
if (implicitResult == ProcessorAction.NONE) {
implicitReceiverValuesWithEmptyScopes += receiver
}
enumerateTowerLevels(
parentGroup,
onScope = l@{ scope, group ->
if (scope in emptyScopes) return@l
val result = processLevel(
scope.toScopeTowerLevel(extensionReceiver = receiver),
info, group
)
if (result == ProcessorAction.NONE) {
emptyScopes += scope
}
},
onImplicitReceiver = l@{ implicitReceiverValue, group ->
if (implicitReceiverValue in implicitReceiverValuesWithEmptyScopes) return@l
processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = receiver),
info, group
)
}
)
}
private suspend fun runResolverForExpressionReceiver(
info: CallInfo,
receiver: FirExpression
) {
val explicitReceiverValue = ExpressionReceiverValue(receiver)
processExtensionsThatHideMembers(info, explicitReceiverValue)
// Member scope of expression receiver
processLevel(
explicitReceiverValue.toMemberScopeTowerLevel(), info, TowerGroup.Member, ExplicitReceiverKind.DISPATCH_RECEIVER
)
val shouldProcessExplicitReceiverScopeOnly =
info.callKind == CallKind.Function && info.explicitReceiver?.typeRef?.coneTypeSafe<ConeIntegerLiteralType>() != null
if (shouldProcessExplicitReceiverScopeOnly) {
// Special case (integer literal type)
return
}
enumerateTowerLevels(
onScope = { scope, group ->
processScopeForExplicitReceiver(
scope,
explicitReceiverValue,
info,
group
)
},
onImplicitReceiver = { implicitReceiverValue, group ->
processCombinationOfReceivers(implicitReceiverValue, explicitReceiverValue, info, group)
}
)
}
private inline fun enumerateTowerLevels(
parentGroup: TowerGroup = TowerGroup.EmptyRoot,
onScope: (FirScope, TowerGroup) -> Unit,
onImplicitReceiver: (ImplicitReceiverValue<*>, TowerGroup) -> Unit,
) {
for ((index, localScope) in localScopes.withIndex()) {
onScope(localScope, parentGroup.Local(index))
}
for ((depth, lexical) in nonLocalTowerDataElements.withIndex()) {
if (!lexical.isLocal && lexical.scope != null) {
onScope(lexical.scope, parentGroup.NonLocal(depth))
}
val receiver = lexical.implicitReceiver
if (receiver !is InaccessibleImplicitReceiverValue) {
receiver?.let { implicitReceiverValue ->
onImplicitReceiver(implicitReceiverValue, parentGroup.Implicit(depth))
}
}
}
}
private suspend fun processScopeForExplicitReceiver(
scope: FirScope,
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo,
towerGroup: TowerGroup,
): ProcessorAction {
val result = processLevel(
scope.toScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, towerGroup, ExplicitReceiverKind.EXTENSION_RECEIVER
)
processLevelForPropertyWithInvokeExtension(
scope.toScopeTowerLevel(), info, towerGroup
)
return result
}
private suspend fun processCombinationOfReceivers(
implicitReceiverValue: ImplicitReceiverValue<*>,
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo,
parentGroup: TowerGroup
) {
// Member extensions
processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, parentGroup.Member, ExplicitReceiverKind.EXTENSION_RECEIVER
)
// properties for invoke on implicit receiver
processLevelForPropertyWithInvokeExtension(
implicitReceiverValue.toMemberScopeTowerLevel(), info, parentGroup.Member
)
enumerateTowerLevels(
onScope = { scope, group ->
processLevelForPropertyWithInvokeExtension(
scope.toScopeTowerLevel(extensionReceiver = implicitReceiverValue),
info, group
)
},
onImplicitReceiver = { receiver, group ->
processLevelForPropertyWithInvokeExtension(
receiver.toMemberScopeTowerLevel(extensionReceiver = implicitReceiverValue),
info, group
)
}
)
}
private suspend fun runResolverForSuperReceiver(
info: CallInfo,
superTypeRef: FirTypeRef
) {
val scope = when (superTypeRef) {
is FirResolvedTypeRef -> superTypeRef.type.scope(session, components.scopeSession)
is FirComposedSuperTypeRef -> FirCompositeScope(
superTypeRef.superTypeRefs.mapNotNull { it.type.scope(session, components.scopeSession) }
)
else -> null
} ?: return
processLevel(
scope.toScopeTowerLevel(),
info, TowerGroup.Member, explicitReceiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER
)
}
private suspend fun runResolverForInvoke(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
invokeOnGivenReceiverCandidateFactory: CandidateFactory,
parentGroupForInvokeCandidates: TowerGroup
) {
processLevelForRegularInvoke(
invokeReceiverValue.toMemberScopeTowerLevel(),
info, parentGroupForInvokeCandidates.Member,
ExplicitReceiverKind.DISPATCH_RECEIVER,
invokeOnGivenReceiverCandidateFactory
)
enumerateTowerLevels(
onScope = { scope, group ->
processLevelForRegularInvoke(
scope.toScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, group,
ExplicitReceiverKind.EXTENSION_RECEIVER,
invokeOnGivenReceiverCandidateFactory
)
},
onImplicitReceiver = { receiver, group ->
// NB: companions are processed via implicitReceiverValues!
processLevelForRegularInvoke(
receiver.toMemberScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, group.Member,
ExplicitReceiverKind.EXTENSION_RECEIVER,
invokeOnGivenReceiverCandidateFactory
)
}
)
}
private suspend fun processLevelForRegularInvoke(
towerLevel: SessionBasedTowerLevel,
callInfo: CallInfo,
group: TowerGroup,
explicitReceiverKind: ExplicitReceiverKind,
candidateFactory: CandidateFactory
) = processLevel(
towerLevel, callInfo,
group.InvokeResolvePriority(InvokeResolvePriority.COMMON_INVOKE),
explicitReceiverKind, InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER, candidateFactory
)
// Here we already know extension receiver for invoke, and it's stated in info as first argument
private suspend fun runResolverForBuiltinInvokeExtensionWithExplicitArgument(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
invokeOnGivenReceiverCandidateFactory: CandidateFactory,
parentGroupForInvokeCandidates: TowerGroup
) {
processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(),
info, parentGroupForInvokeCandidates.Member.InvokeResolvePriority(InvokeResolvePriority.INVOKE_EXTENSION),
ExplicitReceiverKind.DISPATCH_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER,
invokeOnGivenReceiverCandidateFactory
)
}
// Here we don't know extension receiver for invoke, assuming it's one of implicit receivers
private suspend fun runResolverForBuiltinInvokeExtensionWithImplicitArgument(
info: CallInfo,
invokeReceiverValue: ExpressionReceiverValue,
invokeOnGivenReceiverCandidateFactory: CandidateFactory,
parentGroupForInvokeCandidates: TowerGroup
) {
for ((implicitReceiverValue, depth) in implicitReceivers) {
val towerGroup =
parentGroupForInvokeCandidates
.Implicit(depth)
.InvokeExtension
.InvokeResolvePriority(InvokeResolvePriority.INVOKE_EXTENSION)
processLevel(
invokeReceiverValue.toMemberScopeTowerLevel(
extensionReceiver = implicitReceiverValue,
implicitExtensionInvokeMode = true
),
info, towerGroup,
ExplicitReceiverKind.DISPATCH_RECEIVER,
InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER,
invokeOnGivenReceiverCandidateFactory
)
}
}
private fun enqueueResolverTasksForInvokeReceiverCandidates(
invokeResolveMode: InvokeResolveMode?,
info: CallInfo,
parentGroupForInvokeCandidates: TowerGroup
) {
val invokeBuiltinExtensionMode = invokeResolveMode == InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION
for (invokeReceiverCandidate in candidateFactoriesAndCollectors.invokeReceiverCollector!!.bestCandidates()) {
val returnTypeRef = when (val symbol = invokeReceiverCandidate.symbol) {
is FirTypeAliasSymbol -> symbol.fir.expandedTypeRef
is FirCallableSymbol<*> -> symbol.fir.returnTypeRef
is FirRegularClassSymbol -> null
else -> continue
}
val isExtensionFunctionType = returnTypeRef?.isExtensionFunctionType(components.session) == true
if (invokeBuiltinExtensionMode && !isExtensionFunctionType) {
continue
}
val extensionReceiverExpression = invokeReceiverCandidate.extensionReceiverExpression()
val useImplicitReceiverAsBuiltinInvokeArgument =
!invokeBuiltinExtensionMode && isExtensionFunctionType &&
invokeReceiverCandidate.explicitReceiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
val invokeReceiverExpression =
components.createExplicitReceiverForInvoke(
invokeReceiverCandidate, info, invokeBuiltinExtensionMode, extensionReceiverExpression
)
val invokeFunctionInfo =
info.copy(
explicitReceiver = invokeReceiverExpression, name = OperatorNameConventions.INVOKE,
candidateForCommonInvokeReceiver = invokeReceiverCandidate.takeUnless { invokeBuiltinExtensionMode }
).let {
when {
invokeBuiltinExtensionMode -> it.withReceiverAsArgument(info.explicitReceiver!!)
else -> it
}
}
val explicitReceiver = ExpressionReceiverValue(invokeReceiverExpression)
enqueueResolverTasksForInvoke(
invokeFunctionInfo,
explicitReceiver,
invokeBuiltinExtensionMode,
useImplicitReceiverAsBuiltinInvokeArgument,
parentGroupForInvokeCandidates
)
}
}
private fun enqueueResolverTasksForInvoke(
invokeFunctionInfo: CallInfo,
explicitReceiver: ExpressionReceiverValue,
invokeBuiltinExtensionMode: Boolean,
useImplicitReceiverAsBuiltinInvokeArgument: Boolean,
parentGroupForInvokeCandidates: TowerGroup
) {
val invokeOnGivenReceiverCandidateFactory = CandidateFactory(components, invokeFunctionInfo)
if (invokeBuiltinExtensionMode) {
manager.enqueueResolverTask {
runResolverForBuiltinInvokeExtensionWithExplicitArgument(
invokeFunctionInfo, explicitReceiver, invokeOnGivenReceiverCandidateFactory,
parentGroupForInvokeCandidates
)
}
return
}
if (useImplicitReceiverAsBuiltinInvokeArgument) {
manager.enqueueResolverTask {
runResolverForBuiltinInvokeExtensionWithImplicitArgument(
invokeFunctionInfo, explicitReceiver, invokeOnGivenReceiverCandidateFactory,
parentGroupForInvokeCandidates
)
}
}
manager.enqueueResolverTask {
runResolverForInvoke(
invokeFunctionInfo, explicitReceiver, invokeOnGivenReceiverCandidateFactory,
parentGroupForInvokeCandidates
)
}
}
}
private fun BodyResolveComponents.createExplicitReceiverForInvoke(
candidate: Candidate,
info: CallInfo,
invokeBuiltinExtensionMode: Boolean,
extensionReceiverExpression: FirExpression
): FirExpression {
return when (val symbol = candidate.symbol) {
is FirCallableSymbol<*> -> createExplicitReceiverForInvokeByCallable(
candidate, info, invokeBuiltinExtensionMode, extensionReceiverExpression, symbol
)
is FirRegularClassSymbol -> buildResolvedQualifierForClass(symbol, sourceElement = null)
is FirTypeAliasSymbol -> {
val type = symbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session)
val expansionRegularClass = type.lookupTag.toSymbol(session)?.fir as? FirRegularClass
buildResolvedQualifierForClass(expansionRegularClass!!.symbol, sourceElement = symbol.fir.source)
}
else -> throw AssertionError()
}
}
private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable(
candidate: Candidate,
info: CallInfo,
invokeBuiltinExtensionMode: Boolean,
extensionReceiverExpression: FirExpression,
symbol: FirCallableSymbol<*>
): FirExpression {
return FirQualifiedAccessExpressionBuilder().apply {
calleeReference = FirNamedReferenceWithCandidate(
null,
symbol.callableId.callableName,
candidate
)
dispatchReceiver = candidate.dispatchReceiverExpression()
this.typeRef = returnTypeCalculator.tryCalculateReturnType(symbol.firUnsafe())
if (!invokeBuiltinExtensionMode) {
extensionReceiver = extensionReceiverExpression
// NB: this should fix problem in DFA (KT-36014)
explicitReceiver = info.explicitReceiver
}
}.build().let(::transformQualifiedAccessUsingSmartcastInfo)
}
@@ -26,6 +26,8 @@ sealed class TowerGroupKind(private val index: Int) : Comparable<TowerGroupKind>
object InvokeExtension : TowerGroupKind(60)
object QualifierValue : TowerGroupKind(70)
object Last : TowerGroupKind(Integer.MAX_VALUE)
override fun compareTo(other: TowerGroupKind): Int {
@@ -64,6 +66,8 @@ private constructor(
val Classifier = kindOf(TowerGroupKind.Classifier)
val QualifierValue = kindOf(TowerGroupKind.QualifierValue)
val Member = kindOf(TowerGroupKind.Member)
fun Local(depth: Int) = kindOf(TowerGroupKind.Local(depth))
@@ -87,6 +91,8 @@ private constructor(
val InvokeExtension get() = kindOf(TowerGroupKind.InvokeExtension)
fun TopPrioritized(depth: Int) = kindOf(TowerGroupKind.TopPrioritized(depth))
// Treating `a.foo()` common calls as more prioritized than `a.foo.invoke()`
// It's not the same as TowerGroupKind because it's not about tower levels, but rather a different dimension semantically.
// It could be implemented via another TowerGroupKind, but it's not clear what priority should be assigned to the new TowerGroupKind
@@ -127,8 +133,14 @@ private constructor(
result = 31 * result + invokeResolvePriority.hashCode()
return result
}
override fun toString(): String {
return "TowerGroup(kinds=${kinds.contentToString()}, invokeResolvePriority=$invokeResolvePriority)"
}
}
enum class InvokeResolvePriority {
NONE, COMMON_INVOKE, INVOKE_EXTENSION;
NONE, INVOKE_RECEIVER, COMMON_INVOKE, INVOKE_EXTENSION;
}
@@ -25,16 +25,8 @@ internal class CandidateFactoriesAndCollectors(
// Callable references
val stubReceiverCandidateFactory: CandidateFactory?,
// invoke receivers
val invokeReceiverCandidateFactory: CandidateFactory?,
val invokeReceiverCollector: CandidateCollector?,
// invokeExtensionReceivers
val invokeBuiltinExtensionReceiverCandidateFactory: CandidateFactory?
)
typealias EnqueueTasksForInvokeReceiverCandidates = () -> Unit
internal class TowerLevelHandler {
@@ -42,61 +34,34 @@ internal class TowerLevelHandler {
private var processResult = ProcessorAction.NONE
fun handleLevel(
collector: CandidateCollector,
candidateFactory: CandidateFactory,
stubReceiverCandidateFactory: CandidateFactory? = null,
info: CallInfo,
explicitReceiverKind: ExplicitReceiverKind,
group: TowerGroup,
candidateFactoriesAndCollectors: CandidateFactoriesAndCollectors,
towerLevel: SessionBasedTowerLevel,
invokeResolveMode: InvokeResolveMode?,
candidateFactory: CandidateFactory,
enqueueResolverTasksForInvokeReceiverCandidates: EnqueueTasksForInvokeReceiverCandidates
towerLevel: SessionBasedTowerLevel
): ProcessorAction {
val resultCollector = candidateFactoriesAndCollectors.resultCollector
processResult = ProcessorAction.NONE
val processor =
TowerScopeLevelProcessor(
info.explicitReceiver,
explicitReceiverKind,
resultCollector,
collector,
candidateFactory,
group
)
when (info.callKind) {
CallKind.VariableAccess -> {
towerLevel.processProperties(info.name, processor)
if (!resultCollector.isSuccess()) {
if (!collector.isSuccess()) {
towerLevel.processObjectsAsVariables(info.name, processor)
}
}
CallKind.Function -> {
val invokeBuiltinExtensionMode =
invokeResolveMode == InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION
if (!invokeBuiltinExtensionMode) {
towerLevel.processFunctions(info.name, processor)
}
if (invokeResolveMode == InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER ||
resultCollector.isSuccess()
) {
return processResult
}
val invokeReceiverProcessor = TowerScopeLevelProcessor(
info.explicitReceiver,
explicitReceiverKind,
candidateFactoriesAndCollectors.invokeReceiverCollector!!,
if (invokeBuiltinExtensionMode) candidateFactoriesAndCollectors.invokeBuiltinExtensionReceiverCandidateFactory!!
else candidateFactoriesAndCollectors.invokeReceiverCandidateFactory!!,
group
)
candidateFactoriesAndCollectors.invokeReceiverCollector.newDataSet()
towerLevel.processProperties(info.name, invokeReceiverProcessor)
towerLevel.processObjectsAsVariables(info.name, invokeReceiverProcessor)
if (candidateFactoriesAndCollectors.invokeReceiverCollector.isSuccess()) {
enqueueResolverTasksForInvokeReceiverCandidates()
}
towerLevel.processFunctions(info.name, processor)
}
CallKind.CallableReference -> {
val stubReceiver = info.stubReceiver
@@ -109,13 +74,13 @@ internal class TowerLevelHandler {
} else {
ExplicitReceiverKind.EXTENSION_RECEIVER
},
resultCollector,
candidateFactoriesAndCollectors.stubReceiverCandidateFactory!!, group
collector,
stubReceiverCandidateFactory!!, group
)
val towerLevelWithStubReceiver = towerLevel.replaceReceiverValue(stubReceiverValue)
towerLevelWithStubReceiver.processFunctionsAndProperties(info.name, stubProcessor)
// NB: we don't perform this for implicit Unit
if (!resultCollector.isSuccess() && info.explicitReceiver?.typeRef !is FirImplicitBuiltinTypeRef) {
if (!collector.isSuccess() && info.explicitReceiver?.typeRef !is FirImplicitBuiltinTypeRef) {
towerLevel.processFunctionsAndProperties(info.name, processor)
}
} else {
@@ -70,8 +70,3 @@ class TowerResolveManager private constructor(private val shouldStopAtTheLevel:
}
}
}
enum class InvokeResolveMode {
IMPLICIT_CALL_ON_GIVEN_RECEIVER,
RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION
}
@@ -60,8 +60,8 @@ class Case4() : I {
I.invoke("")
<!DEBUG_INFO_CALL("fqName: Case4.Companion.invoke; typeCall: operator function")!>invoke("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any")!>invoke("")<!>
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!><!UNRESOLVED_REFERENCE!>I<!>("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Unresolved name: I")!><!UNRESOLVED_REFERENCE!>I<!>("")<!>
<!DEBUG_INFO_CALL("fqName: I.Companion.invoke; typeCall: variable&invoke")!>I("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>I("")<!>
<!DEBUG_INFO_CALL("fqName: Case4.Companion.invoke; typeCall: variable&invoke")!>Case4("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any")!>Case4("")<!>
}
@@ -55,7 +55,7 @@ class Case3() : I {
fun case() {
I.<!AMBIGUITY!>invoke<!>(<!UNRESOLVED_REFERENCE!>::x<!>)
<!UNRESOLVED_REFERENCE!>I<!>(<!UNRESOLVED_REFERENCE!>::x<!>)
<!AMBIGUITY!>I<!>(<!UNRESOLVED_REFERENCE!>::x<!>)
<!AMBIGUITY!>Case3<!>(<!UNRESOLVED_REFERENCE!>::x<!>)
}
}
@@ -66,13 +66,13 @@ class Case3() : I {
I.invoke(::y)
I.invoke(::y)
<!UNRESOLVED_REFERENCE!>I<!>(<!DEBUG_INFO_EXPRESSION_TYPE("Type is unknown"), UNRESOLVED_REFERENCE!>::x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Unresolved name: I")!><!UNRESOLVED_REFERENCE!>I<!>(<!UNRESOLVED_REFERENCE!>::x<!>)<!>
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!><!UNRESOLVED_REFERENCE!>I<!>(<!UNRESOLVED_REFERENCE!>::x<!>)<!>
I(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KProperty0<kotlin.String>")!>::x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit")!>I(::x)<!>
<!DEBUG_INFO_CALL("fqName: I.Companion.invoke; typeCall: variable&invoke")!>I(::x)<!>
<!UNRESOLVED_REFERENCE!>I<!>(<!DEBUG_INFO_EXPRESSION_TYPE("Type is unknown"), UNRESOLVED_REFERENCE!>::y<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Unresolved name: I")!><!UNRESOLVED_REFERENCE!>I<!>(<!UNRESOLVED_REFERENCE!>::y<!>)<!>
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!><!UNRESOLVED_REFERENCE!>I<!>(<!UNRESOLVED_REFERENCE!>::y<!>)<!>
I(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction0<kotlin.String>")!>::y<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit")!>I(::y)<!>
<!DEBUG_INFO_CALL("fqName: I.Companion.invoke; typeCall: variable&invoke")!>I(::y)<!>
Case3(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KProperty0<kotlin.String>")!>::x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any")!>Case3(::x)<!>