[FIR] Report ResolutionDiagnostics instead of applicability in resolve

This commit is contained in:
Dmitriy Novozhilov
2020-09-08 12:33:40 +03:00
parent a148db9d81
commit edb1273355
7 changed files with 44 additions and 41 deletions
@@ -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
}
@@ -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
}
@@ -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)
@@ -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
}
}
@@ -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)
}
}
}
@@ -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
}