[FIR] KT-54980 Fix resolvability of too few/too many type arguments

- If too few or too many type arguments were provided, they were all
  thrown away in `TypeArgumentMapping`,
  `FirCallCompletionResultsWriterTransformer`, and `KtFirCallResolver`.
  The fix handles type arguments of the wrong arity more gracefully.
  - Note for `TypeArgumentMapping`: Excess type arguments are not needed
    for candidate resolution. Excess type arguments are still resolved
    due to the handling in `FirCallCompletionResultsWriterTransformer`.
- Post-processing in `AllCandidatesResolver`: When all candidates are
  resolved in `AllCandidatesResolver.getAllCandidates`, the function
  builds a FIR file. During that resolution, the
  `generic<String, String>` call (in example
  `functionCallWithTooFewTypeArguments.kt`) is correctly marked as
  inapplicable, but the missing type argument is inferred as an error
  type. `firFile` then contains a function call
  `generic<String, String, ERROR>` instead of `generic<String, String>`.
  This call is still marked as inapplicable. Despite that, the
  *subsequent* resolution by
  `bodyResolveComponents.callResolve.collectAllCandidates` disregards
  the call's inapplicability and resolves successfully into an
  applicable candidate. This is because `CandidateFactory` doesn't make
  any guarantees for already inapplicable calls. The fix adds
  post-processing to `AllCandidatesResolver` to preserve candidate
  inapplicability.
- Most tests that this commit changes had slightly different results due
  to type arguments becoming resolvable.
- `wrongNumberOfTypeArguments.kt` and
  `wrongNumberOfArgumentsInTypeAliasConstructor.kt`:
  `ConeDiagnostic.toFirDiagnostics` prefers specific errors. Because
  `ARGUMENT_TYPE_MISMATCH` is specific and `INAPPLICABLE_CANDIDATE` is
  not, only the former is reported. I see no reason to pass an illegally
  typed argument in either test, so the change reduces the errors to
  `INAPPLICABLE_CANDIDATE`.
- `typeAliasSamAdapterConstructors2.fir.kt`: See KT-55007.
- Disable `mismatchTypeParameters` JS backend test due to its handling
  of excess type arguments. See KT-55250.

^KT-54980 fixed
This commit is contained in:
Marco Pennekamp
2022-11-21 19:15:50 +01:00
committed by teamcity
parent d6a9235d05
commit 5f554d0065
56 changed files with 721 additions and 37 deletions
@@ -11,11 +11,15 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbol
import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.calls.InapplicableCandidate
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext
import org.jetbrains.kotlin.fir.resolve.calls.tower.FirTowerResolver
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirExpressionsResolveTransformer
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
@@ -25,6 +29,7 @@ import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
class AllCandidatesResolver(private val firSession: FirSession) {
private val scopeSession = ScopeSession()
@@ -66,6 +71,7 @@ class AllCandidatesResolver(private val firSession: FirSession) {
return bodyResolveComponents.context.withFile(firFile, bodyResolveComponents) {
bodyResolveComponents.callResolver
.collectAllCandidates(functionCall, calleeName, bodyResolveComponents.context.containers, resolutionContext)
.apply { postProcessCandidates() }
}
}
@@ -84,6 +90,7 @@ class AllCandidatesResolver(private val firSession: FirSession) {
.resolveDelegatingConstructorCall(delegatedConstructorCall, constructedType, derivedClassLookupTag)
bodyResolveComponents.collector.allCandidates
.map { OverloadCandidate(it, isInBestCandidates = it in bodyResolveComponents.collector.bestCandidates()) }
.apply { postProcessCandidates() }
}
}
@@ -96,4 +103,28 @@ class AllCandidatesResolver(private val firSession: FirSession) {
element.parentsOfType<KtDeclaration>().map { it.resolveToFirSymbol(firResolveSession).fir }.toList().asReversed()
bodyResolveComponents.context.containers.addAll(containingDeclarations)
}
private fun List<OverloadCandidate>.postProcessCandidates() {
forEach { it.preserveCalleeInapplicability() }
}
/**
* Post-processes a candidate to carry the callee's inapplicability over into the candidate. Without this post-processing, an issue may
* arise where [getAllCandidates] produces "applicable" candidates with inapplicable callee references.
*
* For example, a function call `generic<String, String>` of function `fun <A, B, C> generic() { }` is correctly marked as inapplicable
* by the compiler (due to the missing type argument), but the `firFile` built during [getAllCandidates] will contain an inapplicable
* function call `generic<String, String, ERROR>` (with the missing type argument inferred as an error type). The *subsequent*
* resolution by `bodyResolveComponents.callResolver.collectAllCandidates` feeds this call to
* [org.jetbrains.kotlin.fir.resolve.calls.CandidateFactory], which doesn't make any guarantees for inapplicable calls. Hence, the
* resulting candidate is *not* marked as inapplicable and needs to be post-processed.
*/
private fun OverloadCandidate.preserveCalleeInapplicability() {
val callSite = candidate.callInfo.callSite as? FirQualifiedAccess ?: return
val calleeReference = callSite.calleeReference as? FirDiagnosticHolder ?: return
val diagnostic = calleeReference.diagnostic as? ConeInapplicableCandidateError ?: return
if (diagnostic.applicability != CandidateApplicability.INAPPLICABLE) return
candidate.addDiagnostic(InapplicableCandidate)
}
}