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