Suspend resolution sequence on first inapplicability report
This commit is contained in:
committed by
Mikhail Glukhikh
parent
cb76ea5d14
commit
94dca1d467
@@ -36,6 +36,9 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import java.util.*
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.createCoroutineUnintercepted
|
||||
|
||||
class CallInfo(
|
||||
val callKind: CallKind,
|
||||
@@ -55,15 +58,34 @@ class CallInfo(
|
||||
|
||||
interface CheckerSink {
|
||||
fun reportApplicability(new: CandidateApplicability)
|
||||
suspend fun yield()
|
||||
suspend fun yieldApplicability(new: CandidateApplicability) {
|
||||
reportApplicability(new)
|
||||
yield()
|
||||
}
|
||||
|
||||
val components: InferenceComponents
|
||||
|
||||
suspend fun yieldIfNeed()
|
||||
}
|
||||
|
||||
|
||||
class CheckerSinkImpl(override val components: InferenceComponents) : CheckerSink {
|
||||
class CheckerSinkImpl(override val components: InferenceComponents, var continuation: Continuation<Unit>? = null) : CheckerSink {
|
||||
var current = CandidateApplicability.RESOLVED
|
||||
override fun reportApplicability(new: CandidateApplicability) {
|
||||
if (new < current) current = new
|
||||
}
|
||||
|
||||
override suspend fun yield() = kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn<Unit> {
|
||||
continuation = it
|
||||
kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
override suspend fun yieldIfNeed() {
|
||||
if (current < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||
yield()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -627,6 +649,9 @@ enum class CandidateApplicability {
|
||||
RESOLVED
|
||||
}
|
||||
|
||||
|
||||
var ID = ""
|
||||
|
||||
class CandidateCollector(val callInfo: CallInfo, val components: InferenceComponents) {
|
||||
|
||||
val groupNumbers = mutableListOf<Int>()
|
||||
@@ -648,12 +673,30 @@ class CandidateCollector(val callInfo: CallInfo, val components: InferenceCompon
|
||||
): CandidateApplicability {
|
||||
|
||||
val sink = CheckerSinkImpl(components)
|
||||
var finished = false
|
||||
sink.continuation = suspend {
|
||||
for (stage in callInfo.callKind.sequence()) {
|
||||
stage.check(candidate, sink, 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
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
callInfo.callKind.sequence().forEach {
|
||||
it.check(candidate, sink, callInfo)
|
||||
|
||||
|
||||
while (!finished) {
|
||||
sink.continuation!!.resume(Unit)
|
||||
if (sink.current < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return sink.current
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystem
|
||||
|
||||
|
||||
internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val declaration = candidate.symbol.firUnsafe<FirDeclaration>()
|
||||
if (declaration !is FirCallableMemberDeclaration || declaration.typeParameters.isEmpty()) {
|
||||
candidate.substitutor = ConeSubstitutor.Empty
|
||||
@@ -35,7 +35,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||
|
||||
// bad function -- error on declaration side
|
||||
if (csBuilder.hasContradiction) {
|
||||
sink.reportApplicability(CandidateApplicability.INAPPLICABLE) //TODO: auto report it
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE) //TODO: auto report it
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -28,26 +28,26 @@ import java.lang.IllegalStateException
|
||||
|
||||
|
||||
abstract class ResolutionStage {
|
||||
abstract fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo)
|
||||
abstract suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo)
|
||||
}
|
||||
|
||||
abstract class CheckerStage : ResolutionStage()
|
||||
|
||||
internal object CheckExplicitReceiverConsistency : ResolutionStage() {
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val receiverKind = candidate.explicitReceiverKind
|
||||
val explicitReceiver = callInfo.explicitReceiver
|
||||
// TODO: add invoke cases
|
||||
when (receiverKind) {
|
||||
NO_EXPLICIT_RECEIVER -> {
|
||||
if (explicitReceiver != null && explicitReceiver !is FirResolvedQualifier)
|
||||
return sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER)
|
||||
return sink.yieldApplicability(CandidateApplicability.WRONG_RECEIVER)
|
||||
}
|
||||
EXTENSION_RECEIVER, DISPATCH_RECEIVER -> {
|
||||
if (explicitReceiver == null) return sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER)
|
||||
if (explicitReceiver == null) return sink.yieldApplicability(CandidateApplicability.WRONG_RECEIVER)
|
||||
}
|
||||
BOTH_RECEIVERS -> {
|
||||
if (explicitReceiver == null) return sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER)
|
||||
if (explicitReceiver == null) return sink.yieldApplicability(CandidateApplicability.WRONG_RECEIVER)
|
||||
// Here we should also check additional invoke receiver
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
|
||||
|
||||
abstract fun ExplicitReceiverKind.shouldBeResolvedAsImplicit(): Boolean
|
||||
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val receiverParameterValue = candidate.getReceiverValue()
|
||||
val explicitReceiverExpression = callInfo.explicitReceiver
|
||||
val explicitReceiverKind = candidate.explicitReceiverKind
|
||||
@@ -121,21 +121,21 @@ internal sealed class CheckReceivers : ResolutionStage() {
|
||||
}
|
||||
|
||||
internal object MapArguments : ResolutionStage() {
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val symbol = candidate.symbol as? FirFunctionSymbol ?: return sink.reportApplicability(CandidateApplicability.HIDDEN)
|
||||
val function = symbol.firUnsafe<FirFunction>()
|
||||
val processor = FirCallArgumentsProcessor(function, callInfo.arguments)
|
||||
val mappingResult = processor.process()
|
||||
candidate.argumentMapping = mappingResult.argumentMapping
|
||||
if (!mappingResult.isSuccess) {
|
||||
return sink.reportApplicability(CandidateApplicability.PARAMETER_MAPPING_ERROR)
|
||||
return sink.yieldApplicability(CandidateApplicability.PARAMETER_MAPPING_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal object CheckArguments : CheckerStage() {
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val argumentMapping =
|
||||
candidate.argumentMapping ?: throw IllegalStateException("Argument should be already mapped while checking arguments!")
|
||||
for ((argument, parameter) in argumentMapping) {
|
||||
@@ -147,16 +147,16 @@ internal object CheckArguments : CheckerStage() {
|
||||
typeProvider = callInfo.typeProvider,
|
||||
sink = sink
|
||||
)
|
||||
}
|
||||
|
||||
if (candidate.system.hasContradiction) {
|
||||
sink.reportApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
if (candidate.system.hasContradiction) {
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
}
|
||||
sink.yield()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object DiscriminateSynthetics : CheckerStage() {
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
if (candidate.symbol is SyntheticSymbol) {
|
||||
sink.reportApplicability(CandidateApplicability.SYNTHETIC_RESOLVED)
|
||||
}
|
||||
@@ -174,7 +174,7 @@ internal object CheckVisibility : CheckerStage() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val symbol = candidate.symbol
|
||||
val declaration = symbol.firSafeNullable<FirMemberDeclaration>()
|
||||
if (declaration != null && !declaration.visibility.isPublicAPI) {
|
||||
@@ -200,7 +200,7 @@ internal object CheckVisibility : CheckerStage() {
|
||||
}
|
||||
|
||||
if (!visible) {
|
||||
sink.reportApplicability(CandidateApplicability.HIDDEN)
|
||||
sink.yieldApplicability(CandidateApplicability.HIDDEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user