From bf2e17b133ba90530275a29a9212162995ec391a Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Wed, 29 Jul 2020 22:23:35 +0300 Subject: [PATCH] [FIR] Extract invoke processing from TowerLevelHandler --- .../tower/FirInvokeResolveTowerExtension.kt | 388 ++++++++++ .../calls/tower/FirTowerResolveTask.kt | 417 +++++++++++ .../resolve/calls/tower/FirTowerResolver.kt | 63 +- .../calls/tower/FirTowerResolverSession.kt | 664 ------------------ .../fir/resolve/calls/tower/TowerGroup.kt | 14 +- .../resolve/calls/tower/TowerLevelHandler.kt | 59 +- .../calls/tower/TowerResolveManager.kt | 5 - .../p-3/pos/1.4.fir.kt | 4 +- .../p-3/neg/1.1.fir.kt | 2 +- .../p-3/pos/1.4.fir.kt | 12 +- 10 files changed, 883 insertions(+), 745 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt delete mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolverSession.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt new file mode 100644 index 00000000000..07d5af371b0 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt @@ -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().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 + ) +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt new file mode 100644 index 00000000000..8c8ad4c923c --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt @@ -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() != 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() + val implicitReceiverValuesWithEmptyScopes = mutableSetOf>() + + 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>, + emptyScopes: MutableSet + ) { + 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, + ) +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolver.kt index d3fca207afe..074f2443d2a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolver.kt @@ -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 ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolverSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolverSession.kt deleted file mode 100644 index 1e6e9865560..00000000000 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolverSession.kt +++ /dev/null @@ -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 by lazy(LazyThreadSafetyMode.NONE) { - val localScopesBase = components.towerDataContext.localScopes - val result = ArrayList() - 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 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() - val implicitReceiverValuesWithEmptyScopes = mutableSetOf>() - - 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>, - emptyScopes: MutableSet - ) { - 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() != 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().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) -} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt index 8020acc1431..bf091f7276f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt @@ -26,6 +26,8 @@ sealed class TowerGroupKind(private val index: Int) : Comparable 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; } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt index 0c014b0f4fc..4480c0ecdea 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt @@ -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 { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerResolveManager.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerResolveManager.kt index 2f5505a0fb5..0fe3d592f1e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerResolveManager.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerResolveManager.kt @@ -70,8 +70,3 @@ class TowerResolveManager private constructor(private val shouldStopAtTheLevel: } } } - -enum class InvokeResolveMode { - IMPLICIT_CALL_ON_GIVEN_RECEIVER, - RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION -} diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-3/pos/1.4.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-3/pos/1.4.fir.kt index e9454331052..831352ed67a 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-3/pos/1.4.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-3/pos/1.4.fir.kt @@ -60,8 +60,8 @@ class Case4() : I { I.invoke("") invoke("") invoke("") - I("") - I("") + I("") + I("") Case4("") Case4("") } diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/resolving-callable-references/bidirectional-resolution-for-callable-calls/p-3/neg/1.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/resolving-callable-references/bidirectional-resolution-for-callable-calls/p-3/neg/1.1.fir.kt index 497a847ab43..a6de1866748 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/resolving-callable-references/bidirectional-resolution-for-callable-calls/p-3/neg/1.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/resolving-callable-references/bidirectional-resolution-for-callable-calls/p-3/neg/1.1.fir.kt @@ -55,7 +55,7 @@ class Case3() : I { fun case() { I.invoke(::x) - I(::x) + I(::x) Case3(::x) } } diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/resolving-callable-references/bidirectional-resolution-for-callable-calls/p-3/pos/1.4.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/resolving-callable-references/bidirectional-resolution-for-callable-calls/p-3/pos/1.4.fir.kt index 0628e99016d..1b24c7ea824 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/resolving-callable-references/bidirectional-resolution-for-callable-calls/p-3/pos/1.4.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/resolving-callable-references/bidirectional-resolution-for-callable-calls/p-3/pos/1.4.fir.kt @@ -66,13 +66,13 @@ class Case3() : I { I.invoke(::y) I.invoke(::y) - I(::x) - I(::x) - I(::x) + I(")!>::x) + I(::x) + I(::x) - I(::y) - I(::y) - I(::y) + I(")!>::y) + I(::y) + I(::y) Case3(")!>::x) Case3(::x)