[FIR] Refactor tower resolver to coroutines

This commit is contained in:
simon.ogorodnik
2020-02-11 13:35:29 +03:00
parent 695558465d
commit d775852781
4 changed files with 146 additions and 142 deletions
@@ -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<ConeIntegerLiteralType>() != null
if (shouldProcessExplicitReceiverScopeOnly) {
// Special case (integer literal type)
return collector
return
}
val nonEmptyLocalScopes = mutableListOf<FirLocalScope>()
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() {
@@ -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<TowerInvokeResolveQuery> {
override fun compareTo(other: TowerInvokeResolveQuery): Int {
return group.compareTo(other.group)
}
}
enum class InvokeResolveMode {
IMPLICIT_CALL_ON_GIVEN_RECEIVER,
RECEIVER_FOR_INVOKE_BUILTIN_EXTENSION
}
@@ -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<TowerInvokeResolveQuery>()
private var group = TowerGroup.Start
private val queue = PriorityQueue<SuspendedResolverTask>()
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<Unit> { 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<Unit>, val group: TowerGroup): Comparable<SuspendedResolverTask> {
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<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(result: Result<Unit>) {
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
}
@@ -20,7 +20,7 @@ val D.attr: B
fun main() {
val b = D()
b.<!AMBIGUITY!>attr<!> {} // overload resolution ambiguity
b.attr {} // overload resolution ambiguity
val d = b.attr
d {} // no error