From 94dca1d467180a85189cd37e5d3dbf30bd1ba740 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Tue, 21 May 2019 17:55:29 +0300 Subject: [PATCH] Suspend resolution sequence on first inapplicability report --- .../kotlin/fir/resolve/calls/CallResolver.kt | 51 +++++++++++++++++-- ...CreateFreshTypeVariableSubstitutorStage.kt | 4 +- .../kotlin/fir/resolve/calls/ResolverParts.kt | 32 ++++++------ 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt index caf3bf8f845..a269202996d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt @@ -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? = null) : CheckerSink { var current = CandidateApplicability.RESOLVED override fun reportApplicability(new: CandidateApplicability) { if (new < current) current = new } + + override suspend fun yield() = kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn { + 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() @@ -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 { + override val context: CoroutineContext + get() = EmptyCoroutineContext + + override fun resumeWith(result: Result) { + 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 } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt index 8c963fdf883..25e117f72a1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt @@ -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() 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 } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt index 8c480936026..faa70cd07d2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt @@ -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() 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() if (declaration != null && !declaration.visibility.isPublicAPI) { @@ -200,7 +200,7 @@ internal object CheckVisibility : CheckerStage() { } if (!visible) { - sink.reportApplicability(CandidateApplicability.HIDDEN) + sink.yieldApplicability(CandidateApplicability.HIDDEN) } } }