[FIR] Report ResolutionDiagnostics instead of applicability in resolve
This commit is contained in:
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
|
||||
fun Candidate.resolveArgumentExpression(
|
||||
@@ -202,7 +201,7 @@ fun Candidate.resolvePlainExpressionArgument(
|
||||
private fun Candidate.checkApplicabilityForIntegerOperatorCall(sink: CheckerSink, argument: FirExpression) {
|
||||
if (symbol.fir !is FirIntegerOperator) return
|
||||
if (argument !is FirConstExpression<*> && argument !is FirIntegerOperatorCall) {
|
||||
sink.reportApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
sink.reportDiagnostic(InapplicableCandidate)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +264,7 @@ private fun checkApplicabilityForArgumentType(
|
||||
if (expectedType == null) return
|
||||
if (isReceiver && isDispatch) {
|
||||
if (!expectedType.isNullable && argumentType.isMarkedNullable) {
|
||||
sink.reportApplicability(CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER)
|
||||
sink.reportDiagnostic(InapplicableWrongReceiver)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -278,10 +277,10 @@ private fun checkApplicabilityForArgumentType(
|
||||
val nullableExpectedType = expectedType.withNullability(ConeNullability.NULLABLE, sink.components.session.typeContext)
|
||||
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) {
|
||||
sink.reportApplicability(CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER) // TODO
|
||||
sink.reportDiagnostic(InapplicableWrongReceiver) // TODO
|
||||
} else {
|
||||
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
||||
sink.reportApplicability(CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER)
|
||||
sink.reportDiagnostic(InapplicableWrongReceiver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import kotlin.coroutines.Continuation
|
||||
|
||||
abstract class CheckerSink {
|
||||
abstract fun reportApplicability(new: CandidateApplicability)
|
||||
abstract fun reportDiagnostic(diagnostic: ResolutionDiagnostic)
|
||||
|
||||
abstract val components: InferenceComponents
|
||||
|
||||
@@ -29,8 +29,8 @@ suspend inline fun CheckerSink.yieldIfNeed() {
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun CheckerSink.yieldApplicability(new: CandidateApplicability) {
|
||||
reportApplicability(new)
|
||||
suspend inline fun CheckerSink.yieldDiagnostic(diagnostic: ResolutionDiagnostic) {
|
||||
reportDiagnostic(diagnostic)
|
||||
yieldIfNeed()
|
||||
}
|
||||
|
||||
@@ -39,11 +39,17 @@ class CheckerSinkImpl(
|
||||
var continuation: Continuation<Unit>? = null,
|
||||
val stopOnFirstError: Boolean = true
|
||||
) : CheckerSink() {
|
||||
var current = CandidateApplicability.RESOLVED
|
||||
var currentApplicability = CandidateApplicability.RESOLVED
|
||||
private set
|
||||
|
||||
override fun reportApplicability(new: CandidateApplicability) {
|
||||
if (new < current) current = new
|
||||
private val _diagnostics: MutableList<ResolutionDiagnostic> = mutableListOf()
|
||||
|
||||
val diagnostics: List<ResolutionDiagnostic>
|
||||
get() = _diagnostics
|
||||
|
||||
override fun reportDiagnostic(diagnostic: ResolutionDiagnostic) {
|
||||
_diagnostics += diagnostic
|
||||
if (diagnostic.applicability < currentApplicability) currentApplicability = diagnostic.applicability
|
||||
}
|
||||
|
||||
@PrivateForInline
|
||||
@@ -53,6 +59,6 @@ class CheckerSinkImpl(
|
||||
}
|
||||
|
||||
override val needYielding: Boolean
|
||||
get() = stopOnFirstError && !current.isSuccess
|
||||
get() = stopOnFirstError && !currentApplicability.isSuccess
|
||||
|
||||
}
|
||||
|
||||
+1
-2
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirTypePlaceholderProjection
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
|
||||
internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
@@ -37,7 +36,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||
|
||||
// bad function -- error on declaration side
|
||||
if (csBuilder.hasContradiction) {
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE) //TODO: auto report it
|
||||
sink.yieldDiagnostic(InapplicableCandidate) //TODO: auto report it
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -50,3 +50,11 @@ class NameNotFound(
|
||||
override val argument: FirExpression,
|
||||
val function: FirFunction<*>
|
||||
) : InapplicableArgumentDiagnostic()
|
||||
|
||||
object InapplicableCandidate : ResolutionDiagnostic(CandidateApplicability.INAPPLICABLE)
|
||||
|
||||
object HiddenCandidate : ResolutionDiagnostic(CandidateApplicability.HIDDEN)
|
||||
|
||||
object ResolvedWithLowPriority : ResolutionDiagnostic(CandidateApplicability.RESOLVED_LOW_PRIORITY)
|
||||
|
||||
object InapplicableWrongReceiver : ResolutionDiagnostic(CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER)
|
||||
|
||||
+3
-2
@@ -36,10 +36,11 @@ class ResolutionStageRunner(val components: InferenceComponents) {
|
||||
|
||||
while (!finished) {
|
||||
sink.continuation!!.resume(Unit)
|
||||
if (!sink.current.isSuccess) {
|
||||
if (!sink.currentApplicability.isSuccess) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return sink.current
|
||||
candidate.diagnostics += sink.diagnostics
|
||||
return sink.currentApplicability
|
||||
}
|
||||
}
|
||||
|
||||
+13
-22
@@ -28,9 +28,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.min
|
||||
|
||||
|
||||
abstract class ResolutionStage {
|
||||
abstract suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo)
|
||||
@@ -46,17 +43,17 @@ internal object CheckExplicitReceiverConsistency : ResolutionStage() {
|
||||
when (receiverKind) {
|
||||
NO_EXPLICIT_RECEIVER -> {
|
||||
if (explicitReceiver != null && explicitReceiver !is FirResolvedQualifier && !explicitReceiver.isSuperReferenceExpression()) {
|
||||
return sink.yieldApplicability(CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER)
|
||||
return sink.yieldDiagnostic(InapplicableWrongReceiver)
|
||||
}
|
||||
}
|
||||
EXTENSION_RECEIVER, DISPATCH_RECEIVER -> {
|
||||
if (explicitReceiver == null) {
|
||||
return sink.yieldApplicability(CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER)
|
||||
return sink.yieldDiagnostic(InapplicableWrongReceiver)
|
||||
}
|
||||
}
|
||||
BOTH_RECEIVERS -> {
|
||||
if (explicitReceiver == null) {
|
||||
return sink.yieldApplicability(CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER)
|
||||
return sink.yieldDiagnostic(InapplicableWrongReceiver)
|
||||
}
|
||||
// Here we should also check additional invoke receiver
|
||||
}
|
||||
@@ -152,20 +149,14 @@ private fun FirExpression.isSuperReferenceExpression(): Boolean {
|
||||
|
||||
internal object MapArguments : ResolutionStage() {
|
||||
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.reportDiagnostic(HiddenCandidate)
|
||||
val function = symbol.fir
|
||||
|
||||
val mapping = mapArguments(callInfo.arguments, function)
|
||||
candidate.argumentMapping = mapping.toArgumentToParameterMapping()
|
||||
|
||||
var applicability = CandidateApplicability.RESOLVED
|
||||
mapping.diagnostics.forEach {
|
||||
candidate.diagnostics += it
|
||||
applicability = min(applicability, it.applicability)
|
||||
}
|
||||
if (applicability < CandidateApplicability.RESOLVED) {
|
||||
return sink.yieldApplicability(applicability)
|
||||
}
|
||||
mapping.diagnostics.forEach(sink::reportDiagnostic)
|
||||
sink.yieldIfNeed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +173,7 @@ internal object CheckArguments : CheckerStage() {
|
||||
sink = sink
|
||||
)
|
||||
if (candidate.system.hasContradiction) {
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
sink.yieldDiagnostic(InapplicableCandidate)
|
||||
}
|
||||
sink.yieldIfNeed()
|
||||
}
|
||||
@@ -195,7 +186,7 @@ internal object EagerResolveOfCallableReferences : CheckerStage() {
|
||||
for (atom in candidate.postponedAtoms) {
|
||||
if (atom is ResolvedCallableReferenceAtom) {
|
||||
if (!candidate.bodyResolveComponents.callResolver.resolveCallableReference(candidate.csBuilder, atom)) {
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
sink.yieldDiagnostic(InapplicableCandidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,7 +255,7 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() {
|
||||
}
|
||||
|
||||
if (!isApplicable) {
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
sink.yieldDiagnostic(InapplicableCandidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,7 +357,7 @@ private fun FirSession.createAdaptedKFunctionType(
|
||||
internal object DiscriminateSynthetics : CheckerStage() {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
if (candidate.symbol is SyntheticSymbol) {
|
||||
sink.reportApplicability(CandidateApplicability.RESOLVED_LOW_PRIORITY)
|
||||
sink.reportDiagnostic(ResolvedWithLowPriority)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,7 +380,7 @@ internal object CheckVisibility : CheckerStage() {
|
||||
|
||||
if (classSymbol is FirRegularClassSymbol) {
|
||||
if (classSymbol.fir.classKind.isSingleton) {
|
||||
sink.yieldApplicability(CandidateApplicability.HIDDEN)
|
||||
sink.yieldDiagnostic(HiddenCandidate)
|
||||
}
|
||||
checkVisibility(classSymbol.fir, classSymbol, sink, candidate, visibilityChecker)
|
||||
}
|
||||
@@ -404,7 +395,7 @@ internal object CheckVisibility : CheckerStage() {
|
||||
visibilityChecker: FirVisibilityChecker
|
||||
): Boolean {
|
||||
if (!visibilityChecker.isVisible(declaration, symbol, candidate)) {
|
||||
sink.yieldApplicability(CandidateApplicability.HIDDEN)
|
||||
sink.yieldDiagnostic(HiddenCandidate)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -428,7 +419,7 @@ internal object CheckLowPriorityInOverloadResolution : CheckerStage() {
|
||||
}
|
||||
|
||||
if (hasLowPriorityAnnotation) {
|
||||
sink.reportApplicability(CandidateApplicability.RESOLVED_LOW_PRIORITY)
|
||||
sink.reportDiagnostic(ResolvedWithLowPriority)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.resolve.calls
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirTypePlaceholderProjection
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
|
||||
sealed class TypeArgumentMapping {
|
||||
abstract operator fun get(typeParameterIndex: Int): FirTypeProjection
|
||||
@@ -38,7 +37,7 @@ internal object MapTypeArguments : ResolutionStage() {
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments)
|
||||
} else {
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(emptyList())
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
sink.yieldDiagnostic(InapplicableCandidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +45,7 @@ internal object MapTypeArguments : ResolutionStage() {
|
||||
internal object NoTypeArguments : ResolutionStage() {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
if (callInfo.typeArguments.isNotEmpty()) {
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
sink.yieldDiagnostic(InapplicableCandidate)
|
||||
}
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.NoExplicitArguments
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user