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