[FIR] When call candidates resolve to errors, select the least bad ones

This fixes a scenario when INVISIBLE_REFERENCE is suppressed, but we
resolved to the wrong overload because when none of the candidates were
applicable, more or less the first one was chosen.

Because we call `fullyProcessCandidate` on the candidates, their
applicability can change which can lead to a situation where the
applicability of a ConeAmbiguityError is different to all its
candidates. The changes in coneDiagnosticToFirDiagnostic.kt account for
that, otherwise code like candidates.first { it.applicability ==
CandidateApplicability.UNSAFE_CALL } can throw NoSuchElementException.

#KT-57776 Fixed
This commit is contained in:
Kirill Rakhman
2023-04-05 17:21:24 +02:00
committed by Space Team
parent 09ea0ef757
commit 592baee852
24 changed files with 345 additions and 52 deletions
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.EmptyIntersectionTypeKind
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.runIf
private fun ConeDiagnostic.toKtDiagnostic(
@@ -68,14 +68,12 @@ private fun ConeDiagnostic.toKtDiagnostic(
is ConeAmbiguityError -> when {
applicability.isSuccess -> FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY.createOn(source, this.candidates.map { it.symbol })
applicability == CandidateApplicability.UNSAFE_CALL -> {
val candidate = candidates.first { it.applicability == CandidateApplicability.UNSAFE_CALL }
val unsafeCall = candidate.diagnostics.firstIsInstance<UnsafeCall>()
val (unsafeCall, candidate) = candidates.firstNotNullOf { it.diagnostics.firstIsInstanceOrNull<UnsafeCall>()?.to(it) }
mapUnsafeCallError(candidate, unsafeCall, source, qualifiedAccessSource)
}
applicability == CandidateApplicability.UNSTABLE_SMARTCAST -> {
val unstableSmartcast =
this.candidates.first { it.applicability == CandidateApplicability.UNSTABLE_SMARTCAST }.diagnostics.firstIsInstance<UnstableSmartCast>()
val unstableSmartcast = this.candidates.firstNotNullOf { it.diagnostics.firstIsInstanceOrNull<UnstableSmartCast>() }
FirErrors.SMARTCAST_IMPOSSIBLE.createOn(
unstableSmartcast.argument.source,
unstableSmartcast.targetType,