diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateCollector.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateCollector.kt index 0e22e9bd35d..2b1165be5a5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateCollector.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateCollector.kt @@ -8,9 +8,8 @@ package org.jetbrains.kotlin.fir.resolve.calls import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerGroup import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability -import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability.K2_DSL_SCOPE_VIOLATION -import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability.K2_SYNTHETIC_RESOLVED import org.jetbrains.kotlin.resolve.calls.tower.isSuccess +import org.jetbrains.kotlin.resolve.calls.tower.shouldStopResolve open class CandidateCollector( val components: BodyResolveComponents, @@ -53,7 +52,7 @@ open class CandidateCollector( shouldStopResolve && bestGroup < group private val shouldStopResolve: Boolean - get() = currentApplicability == K2_DSL_SCOPE_VIOLATION || currentApplicability >= K2_SYNTHETIC_RESOLVED + get() = currentApplicability.shouldStopResolve val isSuccess: Boolean get() = currentApplicability.isSuccess diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt index 8a0e3516971..934078efc05 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt @@ -25,7 +25,7 @@ enum class CandidateApplicability { // Below has isSuccess = true RESOLVED_LOW_PRIORITY, K2_PROPERTY_AS_OPERATOR, // using property of functional type as an operator. From resolution perspective, this is considered successful. - RESOLVED_NEED_PRESERVE_COMPATIBILITY, // call resolved successfully, but using new features that changes resolve + RESOLVED_NEED_PRESERVE_COMPATIBILITY, // call resolved successfully, but using new features that change resolve // Tower resolve does not go to further scopes if candidate with applicability below is found @@ -34,5 +34,16 @@ enum class CandidateApplicability { RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate } +/** + * This property determines that the considered candidate is "successful" in terms of having no resolve errors. + * Note that it does not necessarily mean tower resolve should stop on this candidate. + */ val CandidateApplicability.isSuccess: Boolean - get() = this >= CandidateApplicability.RESOLVED_LOW_PRIORITY + get() = this >= CandidateApplicability.RESOLVED_LOW_PRIORITY && this != CandidateApplicability.K1_RESOLVED_WITH_ERROR + +/** + * This property determines that tower resolve should stop on the candidate/group with this applicability + * and should not go to further scope levels. Note that candidate can still have error(s). + */ +val CandidateApplicability.shouldStopResolve: Boolean + get() = this == CandidateApplicability.K2_DSL_SCOPE_VIOLATION || this >= CandidateApplicability.K2_SYNTHETIC_RESOLVED diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/candidate/ResolutionCandidate.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/candidate/ResolutionCandidate.kt index 63d9b32b075..ac2e3b67f2d 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/candidate/ResolutionCandidate.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/candidate/ResolutionCandidate.kt @@ -29,9 +29,13 @@ sealed class ResolutionCandidate : Candidate, KotlinDiagnosticsHolder { override val isSuccessful: Boolean get() { processParts(stopOnFirstError = true) - return resultingApplicabilities.minOrNull()!!.isSuccess && !getSystem().hasContradiction + // Note: candidate with K1_RESOLVED_WITH_ERROR is exceptionally treated as successful + return resultingApplicabilities.minOrNull()!!.isSuccessOrSuccessWithError && !getSystem().hasContradiction } + private val CandidateApplicability.isSuccessOrSuccessWithError: Boolean + get() = this >= CandidateApplicability.RESOLVED_LOW_PRIORITY + override val resultingApplicability: CandidateApplicability get() { processParts(stopOnFirstError = false) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt index b8c473fb0d3..518f4756a45 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt @@ -424,30 +424,30 @@ class TowerResolver { if (!isSuccessful) return null var compatibilityCandidate: C? = null var compatibilityGroup: Collection? = null - var firstGroupWithResolved: Collection? = null + var shouldStopGroup: Collection? = null outer@ for (group in candidateGroups) { for (candidate in group) { - if (isSuccessfulCandidate(candidate)) { - firstGroupWithResolved = group + if (shouldStopResolveOnCandidate(candidate)) { + shouldStopGroup = group break@outer } - if (compatibilityCandidate == null && isSuccessfulPreserveCompatibility(candidate)) { + if (compatibilityCandidate == null && isPreserveCompatibilityCandidate(candidate)) { compatibilityGroup = group compatibilityCandidate = candidate } } } - if (firstGroupWithResolved == null) return null + if (shouldStopGroup == null) return null if (compatibilityCandidate != null - && compatibilityGroup !== firstGroupWithResolved + && compatibilityGroup !== shouldStopGroup && needToReportCompatibilityWarning(compatibilityCandidate) ) { - firstGroupWithResolved.forEach { it.addCompatibilityWarning(compatibilityCandidate) } + shouldStopGroup.forEach { it.addCompatibilityWarning(compatibilityCandidate) } } - return firstGroupWithResolved.filter(::isSuccessfulCandidate) + return shouldStopGroup.filter(::shouldStopResolveOnCandidate) } private fun needToReportCompatibilityWarning(candidate: C) = candidate is ResolutionCandidate && @@ -455,12 +455,11 @@ class TowerResolver { (it.constraintSystemError as? LowerPriorityToPreserveCompatibility)?.needToReportWarning == true } - private fun isSuccessfulCandidate(candidate: C): Boolean { - return candidate.resultingApplicability == CandidateApplicability.RESOLVED - || candidate.resultingApplicability == CandidateApplicability.K1_RESOLVED_WITH_ERROR + private fun shouldStopResolveOnCandidate(candidate: C): Boolean { + return candidate.resultingApplicability.shouldStopResolve } - private fun isSuccessfulPreserveCompatibility(candidate: C): Boolean = + private fun isPreserveCompatibilityCandidate(candidate: C): Boolean = candidate.resultingApplicability == CandidateApplicability.RESOLVED_NEED_PRESERVE_COMPATIBILITY override fun pushCandidates(candidates: Collection) {