diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirTowerResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirTowerResolver.kt index f8adf17a710..ec54be98922 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirTowerResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirTowerResolver.kt @@ -79,12 +79,12 @@ class FirTowerResolver( return implicitReceivers } - private fun runResolverForQualifierReceiver( + private suspend fun runResolverForQualifierReceiver( info: CallInfo, collector: CandidateCollector, resolvedQualifier: FirResolvedQualifier, manager: TowerResolveManager - ): CandidateCollector { + ) { val qualifierScopes = if (resolvedQualifier.classId == null) { listOf( FirExplicitSimpleImportingScope( @@ -107,7 +107,6 @@ class FirTowerResolver( manager.processLevel( ScopeTowerLevel(session, components, qualifierScope), info.noStubReceiver(), TowerGroup.Qualifier(depth) ) - if (collector.isSuccess()) return collector } if (resolvedQualifier.classId != null) { @@ -124,15 +123,13 @@ class FirTowerResolver( } } - manager.processQueuedLevelsForInvoke(groupLimit = TowerGroup.Last) - return collector } - private fun runResolverForNoReceiver( + private suspend fun runResolverForNoReceiver( info: CallInfo, collector: CandidateCollector, manager: TowerResolveManager - ): CandidateCollector { + ) { val shouldProcessExtensionsBeforeMembers = info.callKind == CallKind.Function && info.name in HIDES_MEMBERS_NAME_LIST if (shouldProcessExtensionsBeforeMembers) { @@ -145,7 +142,6 @@ class FirTowerResolver( session, components, topLevelScope, extensionReceiver = implicitReceiverValue, extensionsOnly = true ), info, TowerGroup.TopPrioritized(index).Implicit(depth) ) - if (collector.isSuccess()) return collector } } } @@ -155,7 +151,6 @@ class FirTowerResolver( val result = manager.processLevel( ScopeTowerLevel(session, components, localScope), info, TowerGroup.Local(index) ) - if (collector.isSuccess()) return collector if (result != ProcessorAction.NONE) { nonEmptyLocalScopes += localScope } @@ -171,7 +166,6 @@ class FirTowerResolver( session, components, dispatchReceiver = implicitReceiverValue, scopeSession = components.scopeSession ), info, parentGroup.Member ) - if (collector.isSuccess()) return collector if (implicitResult == ProcessorAction.NONE) { implicitReceiverValuesWithEmptyScopes += implicitReceiverValue } @@ -181,7 +175,6 @@ class FirTowerResolver( session, components, localScope, extensionReceiver = implicitReceiverValue ), info, parentGroup.Local(localIndex) ) - if (collector.isSuccess()) return collector } for ((implicitDispatchReceiverValue, usable, dispatchDepth) in implicitReceivers) { if (!usable) continue @@ -195,7 +188,6 @@ class FirTowerResolver( scopeSession = components.scopeSession ), info, parentGroup.Implicit(dispatchDepth) ) - if (collector.isSuccess()) return collector } for ((topIndex, topLevelScope) in topLevelScopes.withIndex()) { if (topLevelScope in emptyTopLevelScopes) continue @@ -204,7 +196,6 @@ class FirTowerResolver( session, components, topLevelScope, extensionReceiver = implicitReceiverValue ), info, parentGroup.Top(topIndex) ) - if (collector.isSuccess()) return collector if (result == ProcessorAction.NONE) { emptyTopLevelScopes += topLevelScope } @@ -232,19 +223,15 @@ class FirTowerResolver( manager.processLevel( ScopeTowerLevel(session, components, topLevelScope), info, TowerGroup.Top(index) ) - if (collector.isSuccess()) return collector } - - manager.processQueuedLevelsForInvoke(groupLimit = TowerGroup.Last) - return collector } - private fun runResolverForExpressionReceiver( + private suspend fun runResolverForExpressionReceiver( info: CallInfo, collector: CandidateCollector, receiver: FirExpression, manager: TowerResolveManager - ): CandidateCollector { + ) { val explicitReceiverValue = ExpressionReceiverValue(receiver) val shouldProcessExtensionsBeforeMembers = @@ -257,7 +244,6 @@ class FirTowerResolver( session, components, topLevelScope, extensionReceiver = explicitReceiverValue, extensionsOnly = true ), info, TowerGroup.TopPrioritized(index), ExplicitReceiverKind.EXTENSION_RECEIVER ) - if (collector.isSuccess()) return collector } } @@ -266,40 +252,33 @@ class FirTowerResolver( session, components, dispatchReceiver = explicitReceiverValue, scopeSession = components.scopeSession ), info, TowerGroup.Member, ExplicitReceiverKind.DISPATCH_RECEIVER ) - if (collector.isSuccess()) return collector val shouldProcessExplicitReceiverScopeOnly = info.callKind == CallKind.Function && info.explicitReceiver?.typeRef?.coneTypeSafe() != null if (shouldProcessExplicitReceiverScopeOnly) { // Special case (integer literal type) - return collector + return } val nonEmptyLocalScopes = mutableListOf() for ((index, localScope) in localScopes.withIndex()) { - manager.enqueueLevelForInvoke( - ScopeTowerLevel(session, components, localScope), info, TowerGroup.Local(index), - InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION - ) val result = manager.processLevel( ScopeTowerLevel( session, components, localScope, extensionReceiver = explicitReceiverValue ), info, TowerGroup.Local(index), ExplicitReceiverKind.EXTENSION_RECEIVER ) - if (collector.isSuccess()) return collector if (result != ProcessorAction.NONE) { nonEmptyLocalScopes += localScope } + manager.processLevelForPropertyWithInvoke( + ScopeTowerLevel(session, components, localScope), info, TowerGroup.Local(index) + ) } for ((implicitReceiverValue, usableAsValue, depth) in implicitReceivers) { if (!usableAsValue) continue // NB: companions are processed via implicitReceiverValues! val parentGroup = TowerGroup.Implicit(depth) - manager.enqueueLevelForInvoke( - MemberScopeTowerLevel( - session, components, dispatchReceiver = implicitReceiverValue, scopeSession = components.scopeSession - ), info, parentGroup.Member, InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION - ) + manager.processLevel( MemberScopeTowerLevel( session, components, @@ -307,137 +286,138 @@ class FirTowerResolver( scopeSession = components.scopeSession ), info, parentGroup.Member, ExplicitReceiverKind.EXTENSION_RECEIVER ) - if (collector.isSuccess()) return collector + manager.processLevelForPropertyWithInvoke( + MemberScopeTowerLevel( + session, components, dispatchReceiver = implicitReceiverValue, scopeSession = components.scopeSession + ), info, parentGroup.Member + ) for ((localIndex, localScope) in nonEmptyLocalScopes.withIndex()) { - manager.enqueueLevelForInvoke( + manager.processLevelForPropertyWithInvoke( ScopeTowerLevel( session, components, localScope, extensionReceiver = implicitReceiverValue - ), info, parentGroup.Local(localIndex), InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION + ), info, parentGroup.Local(localIndex) ) } for ((implicitDispatchReceiverValue, usable, dispatchDepth) in implicitReceivers) { if (!usable) continue - manager.enqueueLevelForInvoke( + manager.processLevelForPropertyWithInvoke( MemberScopeTowerLevel( session, components, dispatchReceiver = implicitDispatchReceiverValue, extensionReceiver = implicitReceiverValue, scopeSession = components.scopeSession - ), info, parentGroup.Implicit(dispatchDepth), - InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION + ), info, parentGroup.Implicit(dispatchDepth) ) } for ((topIndex, topLevelScope) in topLevelScopes.withIndex()) { - manager.enqueueLevelForInvoke( + manager.processLevelForPropertyWithInvoke( ScopeTowerLevel( session, components, topLevelScope, extensionReceiver = implicitReceiverValue - ), info, parentGroup.Top(topIndex), InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION + ), info, parentGroup.Top(topIndex) ) } } for ((index, topLevelScope) in topLevelScopes.withIndex()) { - manager.enqueueLevelForInvoke( - ScopeTowerLevel(session, components, topLevelScope), info, TowerGroup.Top(index), - InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION - ) + manager.processLevel( ScopeTowerLevel( session, components, topLevelScope, extensionReceiver = explicitReceiverValue ), info, TowerGroup.Top(index), ExplicitReceiverKind.EXTENSION_RECEIVER ) - if (collector.isSuccess()) return collector + manager.processLevelForPropertyWithInvoke( + ScopeTowerLevel(session, components, topLevelScope), info, TowerGroup.Top(index) + ) } - manager.processQueuedLevelsForInvoke(groupLimit = TowerGroup.Last) - return collector } - private fun runResolverForSuperReceiver( + private suspend fun runResolverForSuperReceiver( info: CallInfo, collector: CandidateCollector, superTypeRef: FirTypeRef, manager: TowerResolveManager - ): CandidateCollector { + ) { val scope = when (superTypeRef) { is FirResolvedTypeRef -> superTypeRef.type.scope(session, components.scopeSession) is FirComposedSuperTypeRef -> FirCompositeScope( superTypeRef.superTypeRefs.mapNotNullTo(mutableListOf()) { it.type.scope(session, components.scopeSession) } ) else -> null - } ?: return collector + } ?: return manager.processLevel( ScopeTowerLevel( session, components, scope ), info, TowerGroup.Member, explicitReceiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER ) - return collector } - internal fun enqueueResolverForInvoke( + internal suspend fun runResolverForInvoke( info: CallInfo, invokeReceiverValue: ExpressionReceiverValue, manager: TowerResolveManager ) { - manager.enqueueLevelForInvoke( + manager.processLevel( MemberScopeTowerLevel( session, components, dispatchReceiver = invokeReceiverValue, scopeSession = components.scopeSession - ), info, TowerGroup.Member, - InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER, - ExplicitReceiverKind.DISPATCH_RECEIVER + ), + info, TowerGroup.Member, + ExplicitReceiverKind.DISPATCH_RECEIVER, + InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER ) for ((index, localScope) in localScopes.withIndex()) { - manager.enqueueLevelForInvoke( + manager.processLevel( ScopeTowerLevel( session, components, localScope, extensionReceiver = invokeReceiverValue - ), info, TowerGroup.Local(index), - InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER, - ExplicitReceiverKind.EXTENSION_RECEIVER + ), + info, TowerGroup.Local(index), + ExplicitReceiverKind.EXTENSION_RECEIVER, + InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER ) } for ((implicitReceiverValue, usable, depth) in implicitReceivers) { if (!usable) continue // NB: companions are processed via implicitReceiverValues! val parentGroup = TowerGroup.Implicit(depth) - manager.enqueueLevelForInvoke( + manager.processLevel( MemberScopeTowerLevel( session, components, dispatchReceiver = implicitReceiverValue, extensionReceiver = invokeReceiverValue, scopeSession = components.scopeSession ), info, parentGroup.Member, - InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER, - ExplicitReceiverKind.EXTENSION_RECEIVER + ExplicitReceiverKind.EXTENSION_RECEIVER, + InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER ) } for ((index, topLevelScope) in topLevelScopes.withIndex()) { - manager.enqueueLevelForInvoke( + manager.processLevel( ScopeTowerLevel( session, components, topLevelScope, extensionReceiver = invokeReceiverValue ), info, TowerGroup.Top(index), - InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER, - ExplicitReceiverKind.EXTENSION_RECEIVER + ExplicitReceiverKind.EXTENSION_RECEIVER, + InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER ) } } // Here we already know extension receiver for invoke, and it's stated in info as first argument - internal fun enqueueResolverForBuiltinInvokeExtensionWithExplicitArgument( + internal suspend fun runResolverForBuiltinInvokeExtensionWithExplicitArgument( info: CallInfo, invokeReceiverValue: ExpressionReceiverValue, manager: TowerResolveManager ) { - manager.enqueueLevelForInvoke( + manager.processLevel( MemberScopeTowerLevel( session, components, dispatchReceiver = invokeReceiverValue, scopeSession = components.scopeSession ), info, TowerGroup.Member, - InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER, - ExplicitReceiverKind.DISPATCH_RECEIVER + ExplicitReceiverKind.DISPATCH_RECEIVER, + InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER ) } // Here we don't know extension receiver for invoke, assuming it's one of implicit receivers - internal fun enqueueResolverForBuiltinInvokeExtensionWithImplicitArgument( + internal suspend fun runResolverForBuiltinInvokeExtensionWithImplicitArgument( info: CallInfo, invokeReceiverValue: ExpressionReceiverValue, manager: TowerResolveManager @@ -445,15 +425,15 @@ class FirTowerResolver( for ((implicitReceiverValue, usable, depth) in implicitReceivers) { if (!usable) continue val parentGroup = TowerGroup.Implicit(depth) - manager.enqueueLevelForInvoke( + manager.processLevel( MemberScopeTowerLevel( session, components, dispatchReceiver = invokeReceiverValue, extensionReceiver = implicitReceiverValue, implicitExtensionInvokeMode = true, scopeSession = components.scopeSession ), info, parentGroup.InvokeExtension, - InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER, - ExplicitReceiverKind.DISPATCH_RECEIVER + ExplicitReceiverKind.DISPATCH_RECEIVER, + InvokeResolveMode.IMPLICIT_CALL_ON_GIVEN_RECEIVER ) } } @@ -482,19 +462,23 @@ class FirTowerResolver( } } - return when (val receiver = info.explicitReceiver) { - is FirResolvedQualifier -> runResolverForQualifierReceiver(info, collector, receiver, manager) - null -> runResolverForNoReceiver(info, collector, manager) - else -> { + + + when (val receiver = info.explicitReceiver) { + is FirResolvedQualifier -> manager.enqueueResolverTask { runResolverForQualifierReceiver(info, collector, receiver, manager) } + null -> manager.enqueueResolverTask { runResolverForNoReceiver(info, collector, manager) } + else -> run { if (receiver is FirQualifiedAccessExpression) { val calleeReference = receiver.calleeReference if (calleeReference is FirSuperReference) { - return runResolverForSuperReceiver(info, collector, receiver.typeRef, manager) + return@run manager.enqueueResolverTask { runResolverForSuperReceiver(info, collector, receiver.typeRef, manager) } } } - runResolverForExpressionReceiver(info, collector, receiver, manager) + manager.enqueueResolverTask { runResolverForExpressionReceiver(info, collector, receiver, manager) } } } + manager.runTasks() + return collector } fun reset() { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerInvokeResolveQuery.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerInvokeResolveQuery.kt deleted file mode 100644 index 65a947f04b2..00000000000 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerInvokeResolveQuery.kt +++ /dev/null @@ -1,25 +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 - -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind - -internal class TowerInvokeResolveQuery( - val towerLevel: SessionBasedTowerLevel, - val callInfo: CallInfo, - val explicitReceiverKind: ExplicitReceiverKind, - val group: TowerGroup, - val mode: InvokeResolveMode -) : Comparable { - override fun compareTo(other: TowerInvokeResolveQuery): Int { - return group.compareTo(other.group) - } -} - -enum class InvokeResolveMode { - IMPLICIT_CALL_ON_GIVEN_RECEIVER, - RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION -} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerResolveManager.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerResolveManager.kt index 24500bf97ae..d34f998c1f5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerResolveManager.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerResolveManager.kt @@ -22,11 +22,11 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.util.OperatorNameConventions import java.util.* +import kotlin.coroutines.* class TowerResolveManager internal constructor(private val towerResolver: FirTowerResolver) { - private val queue = PriorityQueue() - private var group = TowerGroup.Start + private val queue = PriorityQueue() lateinit var candidateFactory: CandidateFactory @@ -199,26 +199,33 @@ class TowerResolveManager internal constructor(private val towerResolver: FirTow invokeOnGivenReceiverCandidateFactory = CandidateFactory(towerResolver.components, invokeFunctionInfo) when { invokeBuiltinExtensionMode -> { - towerResolver.enqueueResolverForBuiltinInvokeExtensionWithExplicitArgument( - invokeFunctionInfo, explicitReceiver, this@TowerResolveManager - ) + enqueueResolverTask { + towerResolver.runResolverForBuiltinInvokeExtensionWithExplicitArgument( + invokeFunctionInfo, explicitReceiver, this@TowerResolveManager + ) + } } useImplicitReceiverAsBuiltinInvokeArgument -> { - towerResolver.enqueueResolverForBuiltinInvokeExtensionWithImplicitArgument( - invokeFunctionInfo, explicitReceiver, this@TowerResolveManager - ) - towerResolver.enqueueResolverForInvoke( - invokeFunctionInfo, explicitReceiver, this@TowerResolveManager - ) + enqueueResolverTask { + towerResolver.runResolverForBuiltinInvokeExtensionWithImplicitArgument( + invokeFunctionInfo, explicitReceiver, this@TowerResolveManager + ) + } + enqueueResolverTask { + towerResolver.runResolverForInvoke( + invokeFunctionInfo, explicitReceiver, this@TowerResolveManager + ) + } } else -> { - towerResolver.enqueueResolverForInvoke( - invokeFunctionInfo, explicitReceiver, this@TowerResolveManager - ) + enqueueResolverTask { + towerResolver.runResolverForInvoke( + invokeFunctionInfo, explicitReceiver, this@TowerResolveManager + ) + } } } } - processQueuedLevelsForInvoke() } } CallKind.CallableReference -> { @@ -260,47 +267,85 @@ class TowerResolveManager internal constructor(private val towerResolver: FirTow fun reset() { queue.clear() - group = TowerGroup.Start } - fun processLevel( + + private suspend fun suspendResolverTask(group: TowerGroup) = suspendCoroutine { queue += SuspendedResolverTask(it, group) } + + private suspend fun requestGroup(requested: TowerGroup) { + val peeked = queue.peek() + + // Task ordering should be FIFO + // Here, if peeked have equal group it means that it came first to this function, so should be processed before us + if (peeked != null && peeked.group <= requested) { + suspendResolverTask(requested) + } + } + + private suspend fun stopResolverTask(): Nothing = suspendCoroutine { } + + suspend fun processLevel( towerLevel: SessionBasedTowerLevel, callInfo: CallInfo, group: TowerGroup, - explicitReceiverKind: ExplicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER + explicitReceiverKind: ExplicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, + invokeResolveMode: InvokeResolveMode? = null ): ProcessorAction { - assert(group > this.group) { - "Incorrect TowerGroup processing order (c) Mikhail Glukhikh" - } - this.group = group + requestGroup(group) + val result = with(LevelHandler(callInfo, explicitReceiverKind, group)) { - towerLevel.handleLevel() + towerLevel.handleLevel(invokeResolveMode) } - processQueuedLevelsForInvoke() + + if (resultCollector.isSuccess()) stopResolverTask() + return result } - fun enqueueLevelForInvoke( + + suspend fun processLevelForPropertyWithInvoke( towerLevel: SessionBasedTowerLevel, callInfo: CallInfo, group: TowerGroup, - mode: InvokeResolveMode, explicitReceiverKind: ExplicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER ) { if (callInfo.callKind == CallKind.Function) { - queue.add(TowerInvokeResolveQuery(towerLevel, callInfo, explicitReceiverKind, group, mode)) + processLevel(towerLevel, callInfo, group, explicitReceiverKind, InvokeResolveMode.RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION) } } - fun processQueuedLevelsForInvoke(groupLimit: TowerGroup = this.group) { - while (queue.isNotEmpty()) { - if (queue.peek().group > groupLimit) { - break - } - val query = queue.poll() - with(LevelHandler(query.callInfo, query.explicitReceiverKind, query.group)) { - query.towerLevel.handleLevel(invokeResolveMode = query.mode) - } + data class SuspendedResolverTask(val continuation: Continuation, val group: TowerGroup): Comparable { + override fun compareTo(other: SuspendedResolverTask): Int { + return group.compareTo(other.group) } } + + fun enqueueResolverTask(group: TowerGroup = TowerGroup.Start, task: suspend () -> Unit) { + val continuation = task.createCoroutine( + object : Continuation { + override val context: CoroutineContext + get() = EmptyCoroutineContext + + override fun resumeWith(result: Result) { + result.getOrThrow() + } + } + ) + + queue += SuspendedResolverTask(continuation, group) + } + + fun runTasks() { + while (queue.isNotEmpty()) { + queue.poll().continuation.resume(Unit) + if (resultCollector.isSuccess()) return + } + } + +} + + +enum class InvokeResolveMode { + IMPLICIT_CALL_ON_GIVEN_RECEIVER, + RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION } diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/kt3772.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/kt3772.fir.kt index fe070fc191d..5e9a39f6280 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/kt3772.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/kt3772.fir.kt @@ -20,7 +20,7 @@ val D.attr: B fun main() { val b = D() - b.attr {} // overload resolution ambiguity + b.attr {} // overload resolution ambiguity val d = b.attr d {} // no error