Analysis API: Add API functions to get all the candidates (with argument
mapping and substitutor) for a function call.
This commit is contained in:
committed by
Ilya Kirillov
parent
322b10f1bb
commit
4a09abc418
+3
@@ -146,6 +146,9 @@ internal class KtFe10CallResolver(
|
|||||||
} ?: handleResolveErrors(this, psi)
|
} ?: handleResolveErrors(this, psi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: See Call.resolveCandidates() in plugins/kotlin/core/src/org/jetbrains/kotlin/idea/core/Utils.kt
|
||||||
|
override fun resolveCandidates(psi: KtElement): List<KtCallInfo> = TODO()
|
||||||
|
|
||||||
private fun handleAsCompoundAssignment(context: BindingContext, binaryExpression: KtBinaryExpression): KtCallInfo? {
|
private fun handleAsCompoundAssignment(context: BindingContext, binaryExpression: KtBinaryExpression): KtCallInfo? {
|
||||||
val left = binaryExpression.left ?: return null
|
val left = binaryExpression.left ?: return null
|
||||||
val right = binaryExpression.right
|
val right = binaryExpression.right
|
||||||
|
|||||||
+110
-3
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.api.fir.components
|
|||||||
import org.jetbrains.kotlin.analysis.api.calls.*
|
import org.jetbrains.kotlin.analysis.api.calls.*
|
||||||
import org.jetbrains.kotlin.analysis.api.diagnostics.KtNonBoundToPsiErrorDiagnostic
|
import org.jetbrains.kotlin.analysis.api.diagnostics.KtNonBoundToPsiErrorDiagnostic
|
||||||
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
|
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
|
||||||
|
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
|
||||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirArrayOfSymbolProvider.arrayOf
|
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirArrayOfSymbolProvider.arrayOf
|
||||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirArrayOfSymbolProvider.arrayOfSymbol
|
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirArrayOfSymbolProvider.arrayOfSymbol
|
||||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirArrayOfSymbolProvider.arrayTypeToArrayOfCall
|
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirArrayOfSymbolProvider.arrayTypeToArrayOfCall
|
||||||
@@ -18,24 +19,32 @@ import org.jetbrains.kotlin.analysis.api.symbols.*
|
|||||||
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
|
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
|
||||||
import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
|
import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
|
||||||
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
|
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
|
||||||
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.psi
|
|
||||||
import org.jetbrains.kotlin.fir.realPsi
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.AbstractCandidate
|
import org.jetbrains.kotlin.fir.resolve.calls.AbstractCandidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.createConeDiagnosticForCandidateWithError
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnosticWithCandidates
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnosticWithCandidates
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeHiddenCandidateError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeHiddenCandidateError
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
|
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
|
||||||
@@ -628,6 +637,104 @@ internal class KtFirCallResolver(
|
|||||||
private fun FirValueParameterSymbol.toKtSymbol(): KtValueParameterSymbol =
|
private fun FirValueParameterSymbol.toKtSymbol(): KtValueParameterSymbol =
|
||||||
firSymbolBuilder.variableLikeBuilder.buildValueParameterSymbol(this)
|
firSymbolBuilder.variableLikeBuilder.buildValueParameterSymbol(this)
|
||||||
|
|
||||||
|
override fun resolveCandidates(psi: KtElement): List<KtCallInfo> = withValidityAssertion {
|
||||||
|
val firCall = when (val fir = psi.getOrBuildFir(firResolveState)) {
|
||||||
|
is FirFunctionCall -> fir
|
||||||
|
is FirSafeCallExpression -> fir.regularQualifiedAccess.safeAs<FirFunctionCall>()
|
||||||
|
// TODO: FirDelegatedConstructorColl, FirAnnotationCall, FirArrayOfCall, FirConstructor
|
||||||
|
else -> null
|
||||||
|
} ?: return@withValidityAssertion emptyList()
|
||||||
|
val firFile = psi.containingKtFile.getOrBuildFirFile(firResolveState)
|
||||||
|
AllCandidatesResolver(analysisSession.rootModuleSession, firFile).getAllCandidates(firCall, psi)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class AllCandidatesResolver(private val firSession: FirSession, private val firFile: FirFile) {
|
||||||
|
private val scopeSession = ScopeSession()
|
||||||
|
|
||||||
|
// TODO: This transformer is not intended for actual transformations and created here only to simplify access to call resolver
|
||||||
|
private val stubBodyResolveTransformer = FirBodyResolveTransformer(
|
||||||
|
session = firSession,
|
||||||
|
phase = FirResolvePhase.BODY_RESOLVE,
|
||||||
|
implicitTypeOnly = false,
|
||||||
|
scopeSession = scopeSession,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val bodyResolveComponents =
|
||||||
|
FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents(
|
||||||
|
firSession,
|
||||||
|
scopeSession,
|
||||||
|
stubBodyResolveTransformer,
|
||||||
|
stubBodyResolveTransformer.context,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val resolutionContext = ResolutionContext(firSession, bodyResolveComponents, stubBodyResolveTransformer.context)
|
||||||
|
|
||||||
|
@OptIn(PrivateForInline::class)
|
||||||
|
fun getAllCandidates(functionCall: FirFunctionCall, element: KtElement): List<KtCallInfo> {
|
||||||
|
val towerContext = firResolveState.getTowerContextProvider().getClosestAvailableParentContext(element)
|
||||||
|
towerContext?.let { bodyResolveComponents.context.replaceTowerDataContext(it) }
|
||||||
|
// Note: All candidate symbols should have the same name
|
||||||
|
val name =
|
||||||
|
functionCall.calleeReference.getCandidateSymbols().firstOrNull()?.safeAs<FirFunctionSymbol<*>>()?.name ?: return emptyList()
|
||||||
|
return bodyResolveComponents.context.withFile(firFile, bodyResolveComponents) {
|
||||||
|
val candidates = bodyResolveComponents.callResolver.collectAllCandidates(
|
||||||
|
functionCall,
|
||||||
|
name,
|
||||||
|
element.getContainingDeclarations(),
|
||||||
|
resolutionContext
|
||||||
|
)
|
||||||
|
candidates.mapNotNull { convertToKtCallInfo(functionCall, element, it.candidate, it.isInBestCandidates) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtElement.getContainingDeclarations(): List<FirDeclaration> {
|
||||||
|
fun KtElement.getContainingKtDeclaration(): KtDeclaration? =
|
||||||
|
when (val container = this.parentOfType<KtDeclaration>()) {
|
||||||
|
is KtDestructuringDeclaration -> container.parentOfType()
|
||||||
|
else -> container
|
||||||
|
}
|
||||||
|
|
||||||
|
val containingDeclarations = mutableListOf<FirDeclaration>()
|
||||||
|
var current = getContainingKtDeclaration()
|
||||||
|
while (current != null) {
|
||||||
|
val firElement = current.getOrBuildFir(firResolveState)
|
||||||
|
val firDeclaration = when (firElement) {
|
||||||
|
is FirAnonymousObjectExpression -> firElement.anonymousObject
|
||||||
|
is FirAnonymousFunctionExpression -> firElement.anonymousFunction
|
||||||
|
is FirDeclaration -> firElement
|
||||||
|
else -> error(
|
||||||
|
"Expected a FirDeclaration for KtDeclaration (type: ${current::class.simpleName}) " +
|
||||||
|
"but was ${firElement?.let { it::class.simpleName }}. KtDeclaration text:\n${current.text}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
containingDeclarations += firDeclaration
|
||||||
|
current = current.getContainingKtDeclaration()
|
||||||
|
}
|
||||||
|
return containingDeclarations.asReversed()
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
|
private fun convertToKtCallInfo(
|
||||||
|
functionCall: FirFunctionCall,
|
||||||
|
element: KtElement,
|
||||||
|
candidate: Candidate,
|
||||||
|
isInBestCandidates: Boolean
|
||||||
|
): KtCallInfo? {
|
||||||
|
val call = createKtCall(element, functionCall, candidate, resolveFragmentOfCall = false) // TODO: resolveFragmentOfCall
|
||||||
|
?: error("expect `createKtCall` to succeed for candidate")
|
||||||
|
return if (candidate.isSuccessful && isInBestCandidates) {
|
||||||
|
KtSuccessCallInfo(call)
|
||||||
|
} else {
|
||||||
|
val diagnostic = createConeDiagnosticForCandidateWithError(candidate.currentApplicability, candidate)
|
||||||
|
if (diagnostic is ConeHiddenCandidateError) return null
|
||||||
|
val ktDiagnostic =
|
||||||
|
functionCall.source?.let { diagnostic.asKtDiagnostic(it, element.toKtPsiSourceElement(), diagnosticCache) }
|
||||||
|
?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token)
|
||||||
|
KtErrorCallInfo(listOf(call), ktDiagnostic, token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun FirArrayOfCall.toKtCallInfo(): KtCallInfo? {
|
private fun FirArrayOfCall.toKtCallInfo(): KtCallInfo? {
|
||||||
val arrayOfSymbol = with(analysisSession) {
|
val arrayOfSymbol = with(analysisSession) {
|
||||||
val type = typeRef.coneTypeSafe<ConeClassLikeType>()
|
val type = typeRef.coneTypeSafe<ConeClassLikeType>()
|
||||||
|
|||||||
+11
-1
@@ -6,10 +6,14 @@
|
|||||||
package org.jetbrains.kotlin.analysis.api.components
|
package org.jetbrains.kotlin.analysis.api.components
|
||||||
|
|
||||||
import org.jetbrains.kotlin.analysis.api.calls.KtCallInfo
|
import org.jetbrains.kotlin.analysis.api.calls.KtCallInfo
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtUnaryExpression
|
||||||
|
|
||||||
public abstract class KtCallResolver : KtAnalysisSessionComponent() {
|
public abstract class KtCallResolver : KtAnalysisSessionComponent() {
|
||||||
public abstract fun resolveCall(psi: KtElement): KtCallInfo?
|
public abstract fun resolveCall(psi: KtElement): KtCallInfo?
|
||||||
|
public abstract fun resolveCandidates(psi: KtElement): List<KtCallInfo>
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface KtCallResolverMixIn : KtAnalysisSessionMixIn {
|
public interface KtCallResolverMixIn : KtAnalysisSessionMixIn {
|
||||||
@@ -26,4 +30,10 @@ public interface KtCallResolverMixIn : KtAnalysisSessionMixIn {
|
|||||||
|
|
||||||
public fun KtArrayAccessExpression.resolveCall(): KtCallInfo =
|
public fun KtArrayAccessExpression.resolveCall(): KtCallInfo =
|
||||||
analysisSession.callResolver.resolveCall(this) ?: error("KtArrayAccessExpression should always resolve to a KtCallInfo")
|
analysisSession.callResolver.resolveCall(this) ?: error("KtArrayAccessExpression should always resolve to a KtCallInfo")
|
||||||
|
|
||||||
|
public fun KtCallElement.resolveCandidates(): List<KtCallInfo> =
|
||||||
|
analysisSession.callResolver.resolveCandidates(this)
|
||||||
|
|
||||||
|
public fun KtArrayAccessExpression.resolveCandidates(): List<KtCallInfo> =
|
||||||
|
analysisSession.callResolver.resolveCandidates(this)
|
||||||
}
|
}
|
||||||
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
|||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.tower.FirTowerResolver
|
import org.jetbrains.kotlin.fir.resolve.calls.tower.FirTowerResolver
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerGroup
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerResolveManager
|
import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerResolveManager
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.ResolvedCallableReferenceAtom
|
import org.jetbrains.kotlin.fir.resolve.inference.ResolvedCallableReferenceAtom
|
||||||
@@ -159,11 +160,43 @@ class FirCallResolver(
|
|||||||
val info: CallInfo, val applicability: CandidateApplicability, val candidates: Collection<Candidate>,
|
val info: CallInfo, val applicability: CandidateApplicability, val candidates: Collection<Candidate>,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/** WARNING: This function is public for the analysis API and should only be used there. */
|
||||||
|
fun <T : FirQualifiedAccess> collectAllCandidates(
|
||||||
|
qualifiedAccess: T,
|
||||||
|
name: Name,
|
||||||
|
containingDeclarations: List<FirDeclaration> = transformer.components.containingDeclarations,
|
||||||
|
resolutionContext: ResolutionContext = transformer.resolutionContext
|
||||||
|
): List<OverloadCandidate> {
|
||||||
|
class AllCandidatesCollector(
|
||||||
|
components: BodyResolveComponents,
|
||||||
|
resolutionStageRunner: ResolutionStageRunner
|
||||||
|
) : CandidateCollector(components, resolutionStageRunner) {
|
||||||
|
private val allCandidatesSet = mutableSetOf<Candidate>()
|
||||||
|
|
||||||
|
override fun consumeCandidate(group: TowerGroup, candidate: Candidate, context: ResolutionContext): CandidateApplicability {
|
||||||
|
allCandidatesSet += candidate
|
||||||
|
return super.consumeCandidate(group, candidate, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
val allCandidates: List<Candidate>
|
||||||
|
get() = allCandidatesSet.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
val collector = AllCandidatesCollector(components, components.resolutionStageRunner)
|
||||||
|
val origin = (qualifiedAccess as? FirFunctionCall)?.origin ?: FirFunctionCallOrigin.Regular
|
||||||
|
val result =
|
||||||
|
collectCandidates(qualifiedAccess, name, forceCallKind = null, origin, containingDeclarations, resolutionContext, collector)
|
||||||
|
return collector.allCandidates.map { OverloadCandidate(it, isInBestCandidates = it in result.candidates) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun <T : FirQualifiedAccess> collectCandidates(
|
private fun <T : FirQualifiedAccess> collectCandidates(
|
||||||
qualifiedAccess: T,
|
qualifiedAccess: T,
|
||||||
name: Name,
|
name: Name,
|
||||||
forceCallKind: CallKind? = null,
|
forceCallKind: CallKind? = null,
|
||||||
origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Regular
|
origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Regular,
|
||||||
|
containingDeclarations: List<FirDeclaration> = transformer.components.containingDeclarations,
|
||||||
|
resolutionContext: ResolutionContext = transformer.resolutionContext,
|
||||||
|
collector: CandidateCollector? = null
|
||||||
): ResolutionResult {
|
): ResolutionResult {
|
||||||
val explicitReceiver = qualifiedAccess.explicitReceiver
|
val explicitReceiver = qualifiedAccess.explicitReceiver
|
||||||
val argumentList = (qualifiedAccess as? FirFunctionCall)?.argumentList ?: FirEmptyArgumentList
|
val argumentList = (qualifiedAccess as? FirFunctionCall)?.argumentList ?: FirEmptyArgumentList
|
||||||
@@ -179,11 +212,15 @@ class FirCallResolver(
|
|||||||
typeArguments,
|
typeArguments,
|
||||||
session,
|
session,
|
||||||
components.file,
|
components.file,
|
||||||
transformer.components.containingDeclarations,
|
containingDeclarations,
|
||||||
origin = origin
|
origin = origin
|
||||||
)
|
)
|
||||||
towerResolver.reset()
|
towerResolver.reset()
|
||||||
val result = towerResolver.runResolver(info, transformer.resolutionContext)
|
val result = if (collector != null) {
|
||||||
|
towerResolver.runResolver(info, resolutionContext, collector)
|
||||||
|
} else {
|
||||||
|
towerResolver.runResolver(info, resolutionContext)
|
||||||
|
}
|
||||||
val bestCandidates = result.bestCandidates()
|
val bestCandidates = result.bestCandidates()
|
||||||
|
|
||||||
fun chooseMostSpecific(): Set<Candidate> {
|
fun chooseMostSpecific(): Set<Candidate> {
|
||||||
@@ -773,19 +810,6 @@ class FirCallResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createConeDiagnosticForCandidateWithError(
|
|
||||||
applicability: CandidateApplicability,
|
|
||||||
candidate: Candidate
|
|
||||||
): ConeDiagnostic {
|
|
||||||
return when (applicability) {
|
|
||||||
CandidateApplicability.HIDDEN -> ConeHiddenCandidateError(candidate)
|
|
||||||
CandidateApplicability.VISIBILITY_ERROR -> ConeVisibilityError(candidate.symbol)
|
|
||||||
CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER -> ConeInapplicableWrongReceiver(listOf(candidate))
|
|
||||||
CandidateApplicability.NO_COMPANION_OBJECT -> ConeNoCompanionObject(candidate)
|
|
||||||
else -> ConeInapplicableCandidateError(applicability, candidate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildErrorReference(
|
private fun buildErrorReference(
|
||||||
callInfo: CallInfo,
|
callInfo: CallInfo,
|
||||||
diagnostic: ConeDiagnostic,
|
diagnostic: ConeDiagnostic,
|
||||||
@@ -800,3 +824,6 @@ class FirCallResolver(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A candidate in the overload candidate set. */
|
||||||
|
data class OverloadCandidate(val candidate: Candidate, val isInBestCandidates: Boolean)
|
||||||
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
|||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirPropertyWithExplicitBackingFieldResolvedNamedReference
|
import org.jetbrains.kotlin.fir.resolve.calls.FirPropertyWithExplicitBackingFieldResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
||||||
import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability
|
import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
|
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
|
||||||
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||||
import org.jetbrains.kotlin.types.SmartcastStability
|
import org.jetbrains.kotlin.types.SmartcastStability
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
@@ -509,3 +510,16 @@ fun FirExpression?.isIntegerLiteralOrOperatorCall(): Boolean {
|
|||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createConeDiagnosticForCandidateWithError(
|
||||||
|
applicability: CandidateApplicability,
|
||||||
|
candidate: Candidate
|
||||||
|
): ConeDiagnostic {
|
||||||
|
return when (applicability) {
|
||||||
|
CandidateApplicability.HIDDEN -> ConeHiddenCandidateError(candidate)
|
||||||
|
CandidateApplicability.VISIBILITY_ERROR -> ConeVisibilityError(candidate.symbol)
|
||||||
|
CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER -> ConeInapplicableWrongReceiver(listOf(candidate))
|
||||||
|
CandidateApplicability.NO_COMPANION_OBJECT -> ConeNoCompanionObject(candidate)
|
||||||
|
else -> ConeInapplicableCandidateError(applicability, candidate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+29
-13
@@ -133,20 +133,19 @@ private class FirCallArgumentsProcessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun processNonLambdaArguments(arguments: List<FirExpression>) {
|
fun processNonLambdaArguments(arguments: List<FirExpression>) {
|
||||||
for (argument in arguments) {
|
for ((argumentIndex, argument) in arguments.withIndex()) {
|
||||||
// process position argument
|
if (argument is FirVarargArgumentsExpression) {
|
||||||
if (argument !is FirNamedArgumentExpression) {
|
// If the argument list was already resolved, any arguments for a vararg parameter will be in a FirVarargArgumentsExpression.
|
||||||
if (processPositionArgument(argument, isLastArgument = argument === arguments.last())) {
|
// This can happen when getting all the candidates for an already resolved function call.
|
||||||
state = State.VARARG_POSITION
|
val varargArguments = argument.arguments
|
||||||
|
for ((varargArgumentIndex, varargArgument) in varargArguments.withIndex()) {
|
||||||
|
processNonLambdaArgument(
|
||||||
|
varargArgument,
|
||||||
|
isLastArgument = argumentIndex == arguments.lastIndex && varargArgumentIndex == varargArguments.lastIndex
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
// process named argument
|
processNonLambdaArgument(argument, isLastArgument = argumentIndex == arguments.lastIndex)
|
||||||
else {
|
|
||||||
if (state == State.VARARG_POSITION) {
|
|
||||||
completeVarargPositionArguments()
|
|
||||||
}
|
|
||||||
|
|
||||||
processNamedArgument(argument)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state == State.VARARG_POSITION) {
|
if (state == State.VARARG_POSITION) {
|
||||||
@@ -154,6 +153,23 @@ private class FirCallArgumentsProcessor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun processNonLambdaArgument(argument: FirExpression, isLastArgument: Boolean) {
|
||||||
|
// process position argument
|
||||||
|
if (argument !is FirNamedArgumentExpression) {
|
||||||
|
if (processPositionArgument(argument, isLastArgument)) {
|
||||||
|
state = State.VARARG_POSITION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// process named argument
|
||||||
|
else {
|
||||||
|
if (state == State.VARARG_POSITION) {
|
||||||
|
completeVarargPositionArguments()
|
||||||
|
}
|
||||||
|
|
||||||
|
processNamedArgument(argument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// return true, if it was mapped to vararg parameter
|
// return true, if it was mapped to vararg parameter
|
||||||
private fun processPositionArgument(argument: FirExpression, isLastArgument: Boolean): Boolean {
|
private fun processPositionArgument(argument: FirExpression, isLastArgument: Boolean): Boolean {
|
||||||
if (state == State.NAMED_ONLY_ARGUMENTS) {
|
if (state == State.NAMED_ONLY_ARGUMENTS) {
|
||||||
|
|||||||
+10
-2
@@ -27,8 +27,16 @@ class FirTowerResolver(
|
|||||||
fun runResolver(
|
fun runResolver(
|
||||||
info: CallInfo,
|
info: CallInfo,
|
||||||
context: ResolutionContext,
|
context: ResolutionContext,
|
||||||
collector: CandidateCollector = this.collector,
|
externalCollector: CandidateCollector? = null
|
||||||
manager: TowerResolveManager = this.manager
|
): CandidateCollector {
|
||||||
|
return runResolver(info, context, externalCollector ?: collector, manager)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runResolver(
|
||||||
|
info: CallInfo,
|
||||||
|
context: ResolutionContext,
|
||||||
|
collector: CandidateCollector,
|
||||||
|
manager: TowerResolveManager
|
||||||
): CandidateCollector {
|
): CandidateCollector {
|
||||||
val candidateFactoriesAndCollectors = buildCandidateFactoriesAndCollectors(info, collector, context)
|
val candidateFactoriesAndCollectors = buildCandidateFactoriesAndCollectors(info, collector, context)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user