[FIR] Extract ResolutionStageRunner component

That component is responsible to run all resolution stages on candidate
  and calculating resulting applicability.

This is needed for completion of `when` and `try` as function calls
This commit is contained in:
Dmitriy Novozhilov
2019-07-25 17:46:30 +03:00
committed by Mikhail Glukhikh
parent 8bbb60df25
commit 53404e5dac
6 changed files with 70 additions and 46 deletions
@@ -41,7 +41,8 @@ class FirCallResolver(
private val scopes: List<FirScope>,
private val localScopes: List<FirScope>,
private val implicitReceiverStack: List<ImplicitReceiverValue>,
private val qualifiedResolver: FirQualifiedNameResolver
private val qualifiedResolver: FirQualifiedNameResolver,
private val resolutionStageRunner: ResolutionStageRunner
) : BodyResolveComponents by transformer {
fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?, file: FirFile): FirFunctionCall {
@@ -66,7 +67,7 @@ class FirCallResolver(
file,
transformer.container
) { it.resultType }
val resolver = CallResolver(returnTypeCalculator, inferenceComponents)
val resolver = CallResolver(returnTypeCalculator, inferenceComponents, resolutionStageRunner)
resolver.callInfo = info
resolver.scopes = (scopes + localScopes).asReversed()
@@ -156,7 +157,7 @@ class FirCallResolver(
file,
transformer.container
) { it.resultType }
val resolver = CallResolver(returnTypeCalculator, inferenceComponents)
val resolver = CallResolver(returnTypeCalculator, inferenceComponents, resolutionStageRunner)
resolver.callInfo = info
resolver.scopes = (scopes + localScopes).asReversed()
@@ -14,7 +14,11 @@ enum class TowerDataKind {
TOWER_LEVEL
}
class CallResolver(val typeCalculator: ReturnTypeCalculator, val components: InferenceComponents) {
class CallResolver(
val typeCalculator: ReturnTypeCalculator,
val components: InferenceComponents,
val resolutionStageRunner: ResolutionStageRunner
) {
var callInfo: CallInfo? = null
var scopes: List<FirScope>? = null
@@ -51,7 +55,7 @@ class CallResolver(val typeCalculator: ReturnTypeCalculator, val components: Inf
return group
}
val collector by lazy { CandidateCollector(components) }
val collector by lazy { CandidateCollector(components, resolutionStageRunner) }
lateinit var towerDataConsumer: TowerDataConsumer
private lateinit var implicitReceiverValues: List<ImplicitReceiverValue>
@@ -9,14 +9,11 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirQualifiedAccessExpressionImp
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.util.OperatorNameConventions
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.intrinsics.createCoroutineUnintercepted
import kotlin.coroutines.resume
open class CandidateCollector(val components: InferenceComponents) {
open class CandidateCollector(
val components: InferenceComponents,
val resolutionStageRunner: ResolutionStageRunner
) {
val groupNumbers = mutableListOf<Int>()
val candidates = mutableListOf<Candidate>()
@@ -28,37 +25,8 @@ open class CandidateCollector(val components: InferenceComponents) {
currentApplicability = CandidateApplicability.HIDDEN
}
private fun getApplicability(
group: Int,
candidate: Candidate
): CandidateApplicability {
val sink = CheckerSinkImpl(components)
var finished = false
sink.continuation = suspend {
for (stage in candidate.callInfo.callKind.sequence()) {
stage.check(candidate, sink, candidate.callInfo)
}
}.createCoroutineUnintercepted(completion = object : Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(result: Result<Unit>) {
result.exceptionOrNull()?.let { throw it }
finished = true
}
})
while (!finished) {
sink.continuation!!.resume(Unit)
if (sink.current < CandidateApplicability.SYNTHETIC_RESOLVED) {
break
}
}
return sink.current
}
open fun consumeCandidate(group: Int, candidate: Candidate): CandidateApplicability {
val applicability = getApplicability(group, candidate)
val applicability = resolutionStageRunner.processCandidate(candidate)
if (applicability > currentApplicability) {
groupNumbers.clear()
@@ -103,8 +71,9 @@ class InvokeReceiverCandidateCollector(
val callResolver: CallResolver,
val invokeCallInfo: CallInfo,
components: InferenceComponents,
val invokeConsumer: AccumulatingTowerDataConsumer
) : CandidateCollector(components) {
val invokeConsumer: AccumulatingTowerDataConsumer,
resolutionStageRunner: ResolutionStageRunner
) : CandidateCollector(components, resolutionStageRunner) {
override fun consumeCandidate(group: Int, candidate: Candidate): CandidateApplicability {
val applicability = super.consumeCandidate(group, candidate)
@@ -94,7 +94,8 @@ fun createFunctionConsumer(
callResolver,
invokeCallInfo = callInfo,
components = inferenceComponents,
invokeConsumer = this
invokeConsumer = this,
resolutionStageRunner = resultCollector.resolutionStageRunner
)
)
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2019 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 kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.intrinsics.createCoroutineUnintercepted
import kotlin.coroutines.resume
class ResolutionStageRunner(val components: InferenceComponents) {
fun processCandidate(candidate: Candidate): CandidateApplicability {
val sink = CheckerSinkImpl(components)
var finished = false
sink.continuation = suspend {
for (stage in candidate.callInfo.callKind.sequence()) {
stage.check(candidate, sink, candidate.callInfo)
}
}.createCoroutineUnintercepted(completion = object : Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(result: Result<Unit>) {
result.exceptionOrNull()?.let { throw it }
finished = true
}
})
while (!finished) {
sink.continuation!!.resume(Unit)
if (sink.current < CandidateApplicability.SYNTHETIC_RESOLVED) {
break
}
}
return sink.current
}
}
@@ -71,7 +71,16 @@ open class FirBodyResolveTransformer(
private val callCompleter: FirCallCompleter = FirCallCompleter(this, inferenceComponents)
private val qualifiedResolver: FirQualifiedNameResolver = FirQualifiedNameResolver(this)
private val callResolver: FirCallResolver = FirCallResolver(this, inferenceComponents, scopes, localScopes, implicitReceiverStack, qualifiedResolver)
private val resolutionStageRunner: ResolutionStageRunner = ResolutionStageRunner(inferenceComponents)
private val callResolver: FirCallResolver = FirCallResolver(
this,
inferenceComponents,
scopes,
localScopes,
implicitReceiverStack,
qualifiedResolver,
resolutionStageRunner
)
override fun transformFile(file: FirFile, data: Any?): CompositeTransformResult<FirFile> {
packageFqName = file.packageFqName