[FIR] Implement FUNCTION_CALL_EXPECTED
This commit is contained in:
+4
@@ -102,6 +102,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
|
||||
val CALL_RESOLUTION by object : DiagnosticGroup("Call resolution") {
|
||||
val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error<KtExpression>()
|
||||
val FUNCTION_CALL_EXPECTED by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
||||
parameter<String>("functionName")
|
||||
parameter<Boolean>("hasValueParameters")
|
||||
}
|
||||
}
|
||||
|
||||
val SUPER by object : DiagnosticGroup("Super") {
|
||||
|
||||
@@ -119,6 +119,7 @@ object FirErrors {
|
||||
|
||||
// Call resolution
|
||||
val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error0<KtExpression>()
|
||||
val FUNCTION_CALL_EXPECTED by error2<PsiElement, String, Boolean>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
|
||||
// Super
|
||||
val SUPER_IS_NOT_AN_EXPRESSION by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
|
||||
+3
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.AMBI
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.DECLARATION_NAME
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FIR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FQ_NAMES_IN_TYPES
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FUNCTION_PARAMETERS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NAME
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NOT_RENDERED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NULLABLE_STRING
|
||||
@@ -149,6 +150,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FINAL_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FINAL_UPPER_BOUND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FORBIDDEN_VARARG_PARAMETER_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_CALL_EXPECTED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS
|
||||
@@ -443,6 +445,7 @@ class FirDefaultErrorMessages {
|
||||
TO_STRING
|
||||
)
|
||||
map.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class")
|
||||
map.put(FUNCTION_CALL_EXPECTED, "Function invocation ''{0}({1})'' expected", TO_STRING, FUNCTION_PARAMETERS)
|
||||
|
||||
// Supertypes
|
||||
map.put(ENUM_AS_SUPERTYPE, "Enum as supertype")
|
||||
|
||||
+2
@@ -119,4 +119,6 @@ object FirDiagnosticRenderers {
|
||||
val NOT_RENDERED = Renderer<Any?> {
|
||||
""
|
||||
}
|
||||
|
||||
val FUNCTION_PARAMETERS = Renderer { hasValueParameters: Boolean -> if (hasValueParameters) "..." else "" }
|
||||
}
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ private fun ConeDiagnostic.toFirDiagnostic(
|
||||
is ConeUnresolvedSymbolError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.classId.asString())
|
||||
is ConeUnresolvedNameError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.name.asString())
|
||||
is ConeUnresolvedQualifierError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.qualifier)
|
||||
is ConeFunctionCallExpectedError -> FirErrors.FUNCTION_CALL_EXPECTED.createOn(source, this.name.asString(), this.hasValueParameters)
|
||||
is ConeHiddenCandidateError -> FirErrors.INVISIBLE_REFERENCE.createOn(source, this.candidateSymbol)
|
||||
is ConeAmbiguityError -> when {
|
||||
applicability.isSuccess -> FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY.createOn(source, this.candidates.map { it.symbol })
|
||||
|
||||
@@ -136,14 +136,18 @@ class FirCallResolver(
|
||||
val info: CallInfo, val applicability: CandidateApplicability, val candidates: Collection<Candidate>,
|
||||
)
|
||||
|
||||
private fun <T : FirQualifiedAccess> collectCandidates(qualifiedAccess: T, name: Name): ResolutionResult {
|
||||
private fun <T : FirQualifiedAccess> collectCandidates(
|
||||
qualifiedAccess: T,
|
||||
name: Name,
|
||||
forceCallKind: CallKind? = null
|
||||
): ResolutionResult {
|
||||
val explicitReceiver = qualifiedAccess.explicitReceiver
|
||||
val argumentList = (qualifiedAccess as? FirFunctionCall)?.argumentList ?: FirEmptyArgumentList
|
||||
val typeArguments = (qualifiedAccess as? FirFunctionCall)?.typeArguments.orEmpty()
|
||||
|
||||
val info = CallInfo(
|
||||
qualifiedAccess,
|
||||
if (qualifiedAccess is FirFunctionCall) CallKind.Function else CallKind.VariableAccess,
|
||||
if (qualifiedAccess is FirFunctionCall || forceCallKind == CallKind.Function) CallKind.Function else CallKind.VariableAccess,
|
||||
name,
|
||||
explicitReceiver,
|
||||
argumentList,
|
||||
@@ -195,16 +199,7 @@ class FirCallResolver(
|
||||
return resolvedQualifierPart
|
||||
}
|
||||
|
||||
val result = collectCandidates(qualifiedAccess, callee.name)
|
||||
val reducedCandidates = result.candidates
|
||||
val nameReference = createResolvedNamedReference(
|
||||
callee,
|
||||
callee.name,
|
||||
result.info,
|
||||
reducedCandidates,
|
||||
result.applicability,
|
||||
qualifiedAccess.explicitReceiver,
|
||||
)
|
||||
var result = collectCandidates(qualifiedAccess, callee.name)
|
||||
|
||||
if (qualifiedAccess.explicitReceiver == null) {
|
||||
if (!result.applicability.isSuccess) {
|
||||
@@ -217,6 +212,26 @@ class FirCallResolver(
|
||||
qualifiedResolver.reset()
|
||||
}
|
||||
|
||||
var functionCallExpected = false
|
||||
if (result.candidates.isEmpty() && qualifiedAccess !is FirFunctionCall) {
|
||||
val newResult = collectCandidates(qualifiedAccess, callee.name, CallKind.Function)
|
||||
if (newResult.candidates.isNotEmpty()) {
|
||||
result = newResult
|
||||
functionCallExpected = true
|
||||
}
|
||||
}
|
||||
|
||||
val reducedCandidates = result.candidates
|
||||
val nameReference = createResolvedNamedReference(
|
||||
callee,
|
||||
callee.name,
|
||||
result.info,
|
||||
reducedCandidates,
|
||||
result.applicability,
|
||||
qualifiedAccess.explicitReceiver,
|
||||
functionCallExpected = functionCallExpected
|
||||
)
|
||||
|
||||
val referencedSymbol = when (nameReference) {
|
||||
is FirResolvedNamedReference -> nameReference.resolvedSymbol
|
||||
is FirNamedReferenceWithCandidate -> nameReference.candidateSymbol
|
||||
@@ -544,10 +559,34 @@ class FirCallResolver(
|
||||
candidates: Collection<Candidate>,
|
||||
applicability: CandidateApplicability,
|
||||
explicitReceiver: FirExpression? = null,
|
||||
createResolvedReferenceWithoutCandidateForLocalVariables: Boolean = true
|
||||
createResolvedReferenceWithoutCandidateForLocalVariables: Boolean = true,
|
||||
functionCallExpected: Boolean = false
|
||||
): FirNamedReference {
|
||||
val source = reference.source
|
||||
return when {
|
||||
functionCallExpected -> {
|
||||
fun isValueParametersNotEmpty(candidate: Candidate): Boolean {
|
||||
return (candidate.symbol.fir as? FirFunction)?.valueParameters?.size?.let { it > 0 } ?: false
|
||||
}
|
||||
|
||||
val candidate = candidates.singleOrNull()
|
||||
if (candidate != null) {
|
||||
createErrorReferenceWithExistingCandidate(
|
||||
candidate,
|
||||
ConeFunctionCallExpectedError(name, isValueParametersNotEmpty(candidate)),
|
||||
source,
|
||||
transformer.resolutionContext,
|
||||
components.resolutionStageRunner
|
||||
)
|
||||
} else {
|
||||
buildErrorReference(
|
||||
callInfo,
|
||||
ConeFunctionCallExpectedError(name, candidates.any { isValueParametersNotEmpty(it) }),
|
||||
source
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
candidates.isEmpty() -> buildErrorReference(
|
||||
callInfo,
|
||||
ConeUnresolvedNameError(name),
|
||||
|
||||
+4
@@ -44,6 +44,10 @@ class ConeUnresolvedNameError(val name: Name) : ConeUnresolvedError() {
|
||||
override val reason: String get() = "Unresolved name: $name"
|
||||
}
|
||||
|
||||
class ConeFunctionCallExpectedError(val name: Name, val hasValueParameters: Boolean) : ConeDiagnostic() {
|
||||
override val reason: String get() = "Function call expected: $name(${if (hasValueParameters) "..." else ""})"
|
||||
}
|
||||
|
||||
class ConeHiddenCandidateError(
|
||||
val candidateSymbol: FirBasedSymbol<*>
|
||||
) : ConeDiagnostic() {
|
||||
|
||||
Reference in New Issue
Block a user