[FIR] Create FirResolvedErrorReference for error reference with single candidate

Note that this reference won't be created for hidden candidates,
  because they are designed to be truly invisible from the user side
This commit is contained in:
Dmitriy Novozhilov
2022-12-08 18:57:00 +02:00
committed by Space Team
parent 9e4e5eed68
commit dde64c10ea
25 changed files with 308 additions and 220 deletions
@@ -44,10 +44,7 @@ import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
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.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.resolve.calls.AbstractCandidate
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
import org.jetbrains.kotlin.fir.resolve.createConeDiagnosticForCandidateWithError
@@ -176,9 +173,29 @@ internal class KtFirCallResolver(
resolveFragmentOfCall = resolveFragmentOfCall
)
}
fun <T> transformErrorReference(call: FirResolvable, calleeReference: T): KtCallInfo where T : FirNamedReference, T : FirDiagnosticHolder {
val diagnostic = calleeReference.diagnostic
val ktDiagnostic = calleeReference.createKtDiagnostic(psi)
if (diagnostic is ConeHiddenCandidateError)
return KtErrorCallInfo(emptyList(), ktDiagnostic, token)
val candidateCalls = mutableListOf<KtCall>()
if (diagnostic is ConeDiagnosticWithCandidates) {
diagnostic.candidates.mapNotNullTo(candidateCalls) {
createKtCall(psi, call, it, resolveFragmentOfCall)
}
} else {
candidateCalls.addIfNotNull(createKtCall(psi, call, null, resolveFragmentOfCall))
}
return KtErrorCallInfo(candidateCalls, ktDiagnostic, token)
}
return when (this) {
is FirResolvable -> {
when (val calleeReference = calleeReference) {
is FirResolvedErrorReference -> transformErrorReference(this, calleeReference)
is FirResolvedNamedReference -> when (calleeReference.resolvedSymbol) {
// `calleeReference.resolvedSymbol` isn't guaranteed to be callable. For example, function type parameters used in
// expression positions (e.g. `T` in `println(T)`) are parsed as `KtSimpleNameExpression` and built into
@@ -194,23 +211,7 @@ internal class KtFirCallResolver(
}
else -> null
}
is FirErrorNamedReference -> {
val diagnostic = calleeReference.diagnostic
val ktDiagnostic = calleeReference.createKtDiagnostic(psi)
if (diagnostic is ConeHiddenCandidateError)
return KtErrorCallInfo(emptyList(), ktDiagnostic, token)
val candidateCalls = mutableListOf<KtCall>()
if (diagnostic is ConeDiagnosticWithCandidates) {
diagnostic.candidates.mapNotNullTo(candidateCalls) {
createKtCall(psi, this@toKtCallInfo, it, resolveFragmentOfCall)
}
} else {
candidateCalls.addIfNotNull(createKtCall(psi, this, null, resolveFragmentOfCall))
}
KtErrorCallInfo(candidateCalls, ktDiagnostic, token)
}
is FirErrorNamedReference -> transformErrorReference(this, calleeReference)
// Unresolved delegated constructor call is untransformed and end up as an `FirSuperReference`
is FirSuperReference -> {
val delegatedConstructorCall = this as? FirDelegatedConstructorCall ?: return null
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
@@ -142,8 +143,8 @@ object FirNativeThrowsChecker : FirBasicDeclarationChecker() {
}
if (this is FirResolvable) {
if (this.calleeReference is FirErrorNamedReference) {
return true
when (this.calleeReference) {
is FirErrorNamedReference, is FirResolvedErrorReference -> return true
}
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -29,7 +30,9 @@ internal fun checkConstantArguments(
expression: FirExpression,
session: FirSession,
): ConstantArgumentKind? {
val expressionSymbol = expression.toResolvedCallableSymbol()
val expressionSymbol = expression.toResolvedCallableReference()
?.takeUnless { it is FirResolvedErrorReference }
?.resolvedSymbol as? FirCallableSymbol<*>
val classKindOfParent = (expressionSymbol?.getReferencedClassSymbol(session) as? FirRegularClassSymbol)
?.classKind
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
@@ -95,7 +96,9 @@ object FirCommonConstructorDelegationIssuesChecker : FirRegularClassChecker() {
private fun FirConstructor.getDelegated(): FirConstructor? {
this.symbol.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE)
val delegatedConstructorSymbol = (delegatedConstructor?.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol
val delegatedConstructorSymbol = (delegatedConstructor?.calleeReference as? FirResolvedNamedReference)
.takeUnless { it is FirResolvedErrorReference }
?.resolvedSymbol
@OptIn(SymbolInternals::class)
return delegatedConstructorSymbol?.fir as? FirConstructor
}
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirImplicitInvokeCall
import org.jetbrains.kotlin.fir.expressions.arguments
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.types.*
@@ -63,15 +64,20 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
* @return true if any error was reported; false otherwise.
*/
private fun checkFunctionReferenceErrors(functionCall: FirFunctionCall): Boolean {
val errorNamedReference = functionCall.calleeReference as? FirErrorNamedReference ?: return false
if (errorNamedReference.source?.kind != KtFakeSourceElementKind.DelegatedPropertyAccessor) return false
val reference = functionCall.calleeReference
val diagnostic = when (reference) {
is FirErrorNamedReference -> reference.diagnostic
is FirResolvedErrorReference -> reference.diagnostic
else -> return false
}
if (reference.source?.kind != KtFakeSourceElementKind.DelegatedPropertyAccessor) return false
val expectedFunctionSignature =
(if (isGet) "getValue" else "setValue") + "(${functionCall.arguments.joinToString(", ") { it.typeRef.coneType.renderReadable() }})"
val delegateDescription = if (isGet) "delegate" else "delegate for var (read-write property)"
fun reportInapplicableDiagnostics(candidates: Collection<FirBasedSymbol<*>>) {
reporter.reportOn(
errorNamedReference.source,
reference.source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE,
expectedFunctionSignature,
candidates,
@@ -80,9 +86,9 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
}
var errorReported = true
when (val diagnostic = errorNamedReference.diagnostic) {
when (diagnostic) {
is ConeUnresolvedNameError -> reporter.reportOn(
errorNamedReference.source,
reference.source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_MISSING,
expectedFunctionSignature,
delegateType,
@@ -94,7 +100,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
if (diagnostic.applicability.isSuccess) {
// Match is successful but there are too many matches! So we report DELEGATE_SPECIAL_FUNCTION_AMBIGUITY.
reporter.reportOn(
errorNamedReference.source,
reference.source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_AMBIGUITY,
expectedFunctionSignature,
diagnostic.candidates.map { it.symbol },
@@ -106,7 +112,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
}
is ConeInapplicableWrongReceiver -> reporter.reportOn(
errorNamedReference.source,
reference.source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_MISSING,
expectedFunctionSignature,
delegateType,
@@ -15,10 +15,12 @@ import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.resolvedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
@@ -70,19 +72,24 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
else -> null
} ?: return
when (val reference = componentCall.calleeReference) {
is FirErrorNamedReference ->
checkComponentCall(
originalDestructuringDeclarationOrInitializerSource,
originalDestructuringDeclarationType,
reference,
declaration,
componentCall,
originalDestructuringDeclaration,
reporter,
context
)
val diagnostic = when (val reference = componentCall.calleeReference) {
is FirErrorNamedReference -> reference.diagnostic
is FirResolvedErrorReference -> reference.diagnostic
else -> null
}
if (diagnostic != null) {
checkComponentCall(
originalDestructuringDeclarationOrInitializerSource,
originalDestructuringDeclarationType,
diagnostic,
declaration,
componentCall,
originalDestructuringDeclaration,
reporter,
context
)
}
}
private fun checkInitializer(
@@ -105,14 +112,14 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
private fun checkComponentCall(
source: KtSourceElement,
destructuringDeclarationType: ConeKotlinType,
reference: FirErrorNamedReference,
diagnostic: ConeDiagnostic,
property: FirProperty,
componentCall: FirComponentCall,
destructuringDeclaration: FirVariable,
reporter: DiagnosticReporter,
context: CheckerContext
) {
when (val diagnostic = reference.diagnostic) {
when (diagnostic) {
is ConeUnresolvedNameError -> {
reporter.reportOn(
source,
@@ -26,10 +26,12 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_NONE_APPLICA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPERATOR_MODIFIER_REQUIRED
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.calls.UnsafeCall
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
@@ -104,8 +106,8 @@ object FirForLoopChecker : FirBlockChecker() {
unsafeCallFactory: KtDiagnosticFactory0? = null,
): Boolean {
when (val calleeReference = call.calleeReference) {
is FirErrorNamedReference -> {
when (val diagnostic = calleeReference.diagnostic) {
is FirErrorNamedReference, is FirResolvedErrorReference -> {
when (val diagnostic = (calleeReference as FirDiagnosticHolder).diagnostic) {
is ConeAmbiguityError -> if (diagnostic.applicability.isSuccess) {
reporter.reportOn(reportSource, ambiguityFactory, diagnostic.candidates.map { it.symbol }, context)
} else if (noneApplicableFactory != null) {
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -23,6 +24,7 @@ import org.jetbrains.kotlin.fir.types.coneType
object FirSealedClassConstructorCallChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val constructorSymbol = (expression.calleeReference as? FirResolvedNamedReference)
?.takeUnless { it is FirResolvedErrorReference }
?.resolvedSymbol as? FirConstructorSymbol
?: return
@@ -11,13 +11,12 @@ import org.jetbrains.kotlin.fir.analysis.checkers.checkUpperBoundViolated
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableWrongReceiver
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.isTypeAliasedConstructor
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
@@ -29,15 +28,15 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
// declarations with their declared bounds.
// it may be the called function declaration
// or the class declaration
val calleeReference = expression.calleeReference
var calleeSymbol: FirCallableSymbol<*>? = null
if (calleeReference is FirResolvedNamedReference) {
calleeSymbol = calleeReference.toResolvedCallableSymbol()
} else if (calleeReference is FirErrorNamedReference) {
if (calleeReference.diagnostic is ConeInapplicableWrongReceiver) {
return
val calleeSymbol = when (val calleeReference = expression.calleeReference) {
is FirResolvedErrorReference -> {
if (calleeReference.diagnostic is ConeInapplicableWrongReceiver) {
return
}
calleeReference.toResolvedCallableSymbol()
}
calleeSymbol = calleeReference.candidateSymbol as? FirCallableSymbol<*>
is FirResolvedNamedReference -> calleeReference.toResolvedCallableSymbol()
else -> null
}
val typeArguments: List<TypeArgumentWithSourceInfo>
@@ -26,11 +26,11 @@ object RedundantExplicitTypeChecker : FirPropertyChecker() {
if (!declaration.isLocal) return
val initializer = declaration.initializer ?: return
val typeReference = declaration.returnTypeRef
val typeReference = declaration.returnTypeRef.takeUnless { it is FirErrorTypeRef } ?: return
if (typeReference.source?.kind is KtFakeSourceElementKind) return
val type = declaration.returnTypeRef.coneType
val type = typeReference.coneType
if (type.toSymbol(context.session) is FirTypeAliasSymbol) return
if (typeReference.annotations.isNotEmpty()) return
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.types.ConeErrorType
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
@@ -52,20 +54,28 @@ class ErrorNodeDiagnosticCollectorComponent(
}
override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference, data: CheckerContext) {
val source = errorNamedReference.source ?: return
val qualifiedAccessOrAnnotationCall = data.qualifiedAccessOrAnnotationCalls.lastOrNull()?.takeIf {
processErrorReference(errorNamedReference, errorNamedReference.diagnostic, data)
}
override fun visitResolvedErrorReference(resolvedErrorReference: FirResolvedErrorReference, data: CheckerContext) {
processErrorReference(resolvedErrorReference, resolvedErrorReference.diagnostic, data)
}
private fun processErrorReference(reference: FirNamedReference, diagnostic: ConeDiagnostic, context: CheckerContext) {
val source = reference.source ?: return
val qualifiedAccessOrAnnotationCall = context.qualifiedAccessOrAnnotationCalls.lastOrNull()?.takeIf {
// Use the source of the enclosing FirQualifiedAccess if it is exactly the call to the erroneous callee.
when (it) {
is FirQualifiedAccess -> it.calleeReference == errorNamedReference
is FirAnnotationCall -> it.calleeReference == errorNamedReference
is FirQualifiedAccess -> it.calleeReference == reference
is FirAnnotationCall -> it.calleeReference == reference
else -> false
}
}
// Don't report duplicated unresolved reference on annotation entry (already reported on its type)
if (source.elementType == KtNodeTypes.ANNOTATION_ENTRY && errorNamedReference.diagnostic is ConeUnresolvedNameError) return
if (source.elementType == KtNodeTypes.ANNOTATION_ENTRY && diagnostic is ConeUnresolvedNameError) return
// Already reported in FirConventionFunctionCallChecker
if (source.kind == KtFakeSourceElementKind.ArrayAccessNameReference &&
errorNamedReference.diagnostic is ConeUnresolvedNameError
diagnostic is ConeUnresolvedNameError
) return
// If the receiver cannot be resolved, we skip reporting any further problems for this call.
@@ -76,7 +86,7 @@ class ErrorNodeDiagnosticCollectorComponent(
) return
}
reportFirDiagnostic(errorNamedReference.diagnostic, source, data, qualifiedAccessOrAnnotationCall?.source)
reportFirDiagnostic(diagnostic, source, context, qualifiedAccessOrAnnotationCall?.source)
}
private fun FirExpression?.cannotBeResolved(): Boolean {
@@ -1302,6 +1302,18 @@ class HtmlFirDump internal constructor(private var linkResolver: FirLinkResolver
simpleName(reference.name)
}
}
is FirResolvedErrorReference -> {
errorWithDiagnostic {
resolved {
symbolRef(reference.resolvedSymbol) {
simpleName(reference.name)
}
}
diagnosticHover {
generate(reference.diagnostic)
}
}
}
is FirResolvedNamedReference -> {
resolved {
symbolRef(reference.resolvedSymbol) {
@@ -197,15 +197,6 @@ fun FirReference.toSymbolForCall(
isReference
)
is FirErrorNamedReference ->
candidateSymbol?.toSymbolForCall(
dispatchReceiver,
preferGetter,
explicitReceiver,
isDelegate,
isReference
)
is FirThisReference -> {
when (val boundSymbol = boundSymbol) {
is FirClassSymbol<*> -> classifierStorage.getIrClassSymbol(boundSymbol).owner.thisReceiver?.symbol
@@ -1066,12 +1066,9 @@ class CallAndReferenceGenerator(
}
if (ownerFunction?.extensionReceiverParameter != null) {
extensionReceiver = qualifiedAccess.findIrExtensionReceiver(explicitReceiverExpression)?.let {
val symbol = when (val reference = qualifiedAccess.calleeReference) {
is FirResolvedNamedReference -> reference.resolvedSymbol
is FirErrorNamedReference -> reference.candidateSymbol
else -> null
} ?: error("Symbol for call ${qualifiedAccess.render()} not found")
(symbol.fir as? FirCallableDeclaration)?.receiverParameter?.typeRef?.let { receiverType ->
val symbol = qualifiedAccess.calleeReference.toResolvedCallableSymbol()
?: error("Symbol for call ${qualifiedAccess.render()} not found")
symbol.fir.receiverParameter?.typeRef?.let { receiverType ->
with(visitor.implicitCastInserter) {
it.cast(
qualifiedAccess.extensionReceiver,
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
@@ -18,6 +19,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
import org.jetbrains.kotlin.fir.isCatchParameter
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.renderer.FirRenderer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
@@ -82,12 +84,14 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
}
override fun visitQualifiedAccess(qualifiedAccess: FirQualifiedAccess, data: FirElement) {
val calleeReference = qualifiedAccess.calleeReference
if (calleeReference is FirErrorNamedReference) {
errorReferences++
println(calleeReference.diagnostic.reason)
} else {
normalReferences++
when (val calleeReference = qualifiedAccess.calleeReference) {
is FirErrorNamedReference, is FirResolvedErrorReference -> {
errorReferences++
println((calleeReference as FirDiagnosticHolder).diagnostic.reason)
}
else -> {
normalReferences++
}
}
visitStatement(qualifiedAccess, data)
}
@@ -285,6 +285,7 @@ class FirCallResolver(
val diagnostic = when (nameReference) {
is FirErrorReferenceWithCandidate -> nameReference.diagnostic
is FirResolvedErrorReference -> nameReference.diagnostic
is FirErrorNamedReference -> nameReference.diagnostic
else -> null
}
@@ -371,7 +372,7 @@ class FirCallResolver(
when {
noSuccessfulCandidates -> {
val errorReference = buildErrorReference(
val errorReference = buildReferenceWithErrorCandidate(
info,
if (applicability == CandidateApplicability.K2_UNSUPPORTED) {
val unsupportedResolutionDiagnostic = reducedCandidates.firstOrNull()?.diagnostics?.firstOrNull() as? Unsupported
@@ -386,7 +387,7 @@ class FirCallResolver(
}
reducedCandidates.size > 1 -> {
if (resolvedCallableReferenceAtom.hasBeenPostponed) {
val errorReference = buildErrorReference(
val errorReference = buildReferenceWithErrorCandidate(
info,
ConeAmbiguityError(info.name, applicability, reducedCandidates),
callableReferenceAccess.source
@@ -530,7 +531,7 @@ class FirCallResolver(
explicitReceiver = null
)
} else {
buildErrorReference(
buildReferenceWithErrorCandidate(
callInfo,
if (annotationClassSymbol != null) ConeIllegalAnnotationError(reference.name)
//calleeReference and annotationTypeRef are both error nodes so we need to avoid doubling of the diagnostic report
@@ -635,133 +636,132 @@ class FirCallResolver(
expectedCandidates: Collection<Candidate>? = null
): FirNamedReference {
val source = reference.source
return when {
val diagnostic = when {
expectedCallKind != null -> {
fun isValueParametersNotEmpty(candidate: Candidate): Boolean {
return (candidate.symbol.fir as? FirFunction)?.valueParameters?.size?.let { it > 0 } ?: false
}
val candidate = candidates.singleOrNull()
when (expectedCallKind) {
CallKind.Function -> ConeFunctionCallExpectedError(name, candidates.any { isValueParametersNotEmpty(it) }, candidates)
else -> {
val singleExpectedCandidate = expectedCandidates?.singleOrNull()
val diagnostic = if (expectedCallKind == CallKind.Function) {
ConeFunctionCallExpectedError(name, candidates.any { isValueParametersNotEmpty(it) }, candidates)
} else {
val singleExpectedCandidate = expectedCandidates?.singleOrNull()
var fir = singleExpectedCandidate?.symbol?.fir
if (fir is FirTypeAlias) {
fir = (fir.expandedTypeRef.coneType.fullyExpandedType(session).toSymbol(session) as? FirRegularClassSymbol)?.fir
}
var fir = singleExpectedCandidate?.symbol?.fir
if (fir is FirTypeAlias) {
fir = (fir.expandedTypeRef.coneType.fullyExpandedType(session).toSymbol(session) as? FirRegularClassSymbol)?.fir
}
if (fir is FirRegularClass) {
ConeResolutionToClassifierError(singleExpectedCandidate!!, fir.symbol)
} else {
val coneType = explicitReceiver?.typeRef?.coneType
when {
coneType != null && !coneType.isUnit -> {
ConeFunctionExpectedError(
name.asString(),
(fir as? FirCallableDeclaration)?.returnTypeRef?.coneType ?: coneType
)
when (fir) {
is FirRegularClass -> {
ConeResolutionToClassifierError(singleExpectedCandidate!!, fir.symbol)
}
singleExpectedCandidate != null && !singleExpectedCandidate.currentApplicability.isSuccess -> {
createConeDiagnosticForCandidateWithError(
singleExpectedCandidate.currentApplicability,
singleExpectedCandidate
)
else -> {
val coneType = explicitReceiver?.typeRef?.coneType
when {
coneType != null && !coneType.isUnit -> {
ConeFunctionExpectedError(
name.asString(),
(fir as? FirCallableDeclaration)?.returnTypeRef?.coneType ?: coneType
)
}
singleExpectedCandidate != null && !singleExpectedCandidate.currentApplicability.isSuccess -> {
createConeDiagnosticForCandidateWithError(
singleExpectedCandidate.currentApplicability,
singleExpectedCandidate
)
}
else -> ConeUnresolvedNameError(name)
}
}
else -> ConeUnresolvedNameError(name)
}
}
}
if (candidate != null) {
createErrorReferenceWithExistingCandidate(
candidate,
diagnostic,
source,
transformer.resolutionContext,
components.resolutionStageRunner
)
} else {
buildErrorReference(callInfo, diagnostic, source)
}
}
candidates.isEmpty() -> {
val diagnostic = if (name.asString() == "invoke" && explicitReceiver is FirConstExpression<*>) {
if (name.asString() == "invoke" && explicitReceiver is FirConstExpression<*>) {
ConeFunctionExpectedError(explicitReceiver.value?.toString() ?: "", explicitReceiver.typeRef.coneType)
} else {
ConeUnresolvedNameError(name)
}
buildErrorReference(
callInfo,
diagnostic,
source
)
}
candidates.size > 1 -> buildErrorReference(
callInfo,
ConeAmbiguityError(name, applicability, candidates),
source
)
candidates.size > 1 -> ConeAmbiguityError(name, applicability, candidates)
!applicability.isSuccess -> {
val candidate = candidates.single()
val diagnostic = createConeDiagnosticForCandidateWithError(applicability, candidate)
createErrorReferenceWithExistingCandidate(
candidate,
diagnostic,
source,
transformer.resolutionContext,
components.resolutionStageRunner
)
createConeDiagnosticForCandidateWithError(applicability, candidate)
}
else -> {
val candidate = candidates.single()
val coneSymbol = candidate.symbol
if (coneSymbol is FirBackingFieldSymbol) {
coneSymbol.fir.propertySymbol.fir.isReferredViaField = true
return buildBackingFieldReference {
this.source = source
resolvedSymbol = coneSymbol
}
}
if ((coneSymbol as? FirPropertySymbol)?.hasExplicitBackingField == true) {
return FirPropertyWithExplicitBackingFieldResolvedNamedReference(
source, name, candidate.symbol, candidate.hasVisibleBackingField
)
}
/*
* This `if` is an optimization for local variables and properties without type parameters
* Since they have no type variables, so we can don't run completion on them at all and create
* resolved reference immediately
*
* But for callable reference resolution we should keep candidate, because it was resolved
* with special resolution stages, which saved in candidate additional reference info,
* like `resultingTypeForCallableReference`
*/
if (
createResolvedReferenceWithoutCandidateForLocalVariables &&
explicitReceiver?.typeRef?.coneTypeSafe<ConeIntegerLiteralType>() == null &&
coneSymbol is FirVariableSymbol &&
(coneSymbol !is FirPropertySymbol || (coneSymbol.fir as FirMemberDeclaration).typeParameters.isEmpty())
) {
return buildResolvedNamedReference {
this.source = source
this.name = name
resolvedSymbol = coneSymbol
}
}
FirNamedReferenceWithCandidate(source, name, candidate)
else -> null
}
if (diagnostic != null) {
return createErrorReferenceForSingleCandidate(candidates.singleOrNull(), diagnostic, callInfo, source)
}
// successful candidate
val candidate = candidates.single()
val coneSymbol = candidate.symbol
if (coneSymbol is FirBackingFieldSymbol) {
coneSymbol.fir.propertySymbol.fir.isReferredViaField = true
return buildBackingFieldReference {
this.source = source
resolvedSymbol = coneSymbol
}
}
if ((coneSymbol as? FirPropertySymbol)?.hasExplicitBackingField == true) {
return FirPropertyWithExplicitBackingFieldResolvedNamedReference(
source, name, candidate.symbol, candidate.hasVisibleBackingField
)
}
/*
* This `if` is an optimization for local variables and properties without type parameters
* Since they have no type variables, so we can don't run completion on them at all and create
* resolved reference immediately
*
* But for callable reference resolution we should keep candidate, because it was resolved
* with special resolution stages, which saved in candidate additional reference info,
* like `resultingTypeForCallableReference`
*/
if (
createResolvedReferenceWithoutCandidateForLocalVariables &&
explicitReceiver?.typeRef?.coneTypeSafe<ConeIntegerLiteralType>() == null &&
coneSymbol is FirVariableSymbol &&
(coneSymbol !is FirPropertySymbol || (coneSymbol.fir as FirMemberDeclaration).typeParameters.isEmpty())
) {
return buildResolvedNamedReference {
this.source = source
this.name = name
resolvedSymbol = coneSymbol
}
}
return FirNamedReferenceWithCandidate(source, name, candidate)
}
private fun createErrorReferenceForSingleCandidate(
candidate: Candidate?,
diagnostic: ConeDiagnostic,
callInfo: CallInfo,
source: KtSourceElement?
): FirNamedReference {
if (candidate == null) return buildReferenceWithErrorCandidate(callInfo, diagnostic, source)
return when (diagnostic) {
is ConeUnresolvedError, is ConeHiddenCandidateError -> buildReferenceWithErrorCandidate(callInfo, diagnostic, source)
else -> createErrorReferenceWithExistingCandidate(
candidate,
diagnostic,
source,
transformer.resolutionContext,
components.resolutionStageRunner
)
}
}
private fun buildErrorReference(
private fun buildReferenceWithErrorCandidate(
callInfo: CallInfo,
diagnostic: ConeDiagnostic,
source: KtSourceElement?
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameterCopy
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.*
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirPropertyAccessExpressionImpl
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedCallableReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedErrorReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
@@ -37,9 +39,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.ConvertibleIntegerOperators.binaryOp
import org.jetbrains.kotlin.fir.scopes.impl.isWrappedIntegerOperator
import org.jetbrains.kotlin.fir.scopes.impl.isWrappedIntegerOperatorForUnsignedType
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
@@ -379,11 +379,7 @@ class FirCallCompletionResultsWriterTransformer(
session.lookupTracker?.recordTypeResolveAsLookup(resultType, typeRef.source ?: callableReferenceAccess.source, context.file.source)
val resolvedReference = when (calleeReference) {
is FirErrorReferenceWithCandidate -> buildErrorNamedReference {
source = calleeReference.source
diagnostic = calleeReference.diagnostic
candidateSymbol = calleeReference.candidateSymbol
}
is FirErrorReferenceWithCandidate -> calleeReference.toErrorReference(calleeReference.diagnostic)
else -> buildResolvedCallableReference {
source = calleeReference.source
name = calleeReference.name
@@ -400,6 +396,23 @@ class FirCallCompletionResultsWriterTransformer(
.transformExtensionReceiver(StoreReceiver, subCandidate.chosenExtensionReceiverExpression())
}
private fun FirNamedReferenceWithCandidate.toErrorReference(diagnostic: ConeDiagnostic): FirNamedReference {
val calleeReference = this
return when (calleeReference.candidateSymbol) {
is FirErrorPropertySymbol, is FirErrorFunctionSymbol -> buildErrorNamedReference {
source = calleeReference.source
candidateSymbol = calleeReference.candidateSymbol
this.diagnostic = diagnostic
}
else -> buildResolvedErrorReference {
source = calleeReference.source
name = calleeReference.name
resolvedSymbol = calleeReference.candidateSymbol
this.diagnostic = diagnostic
}
}
}
override fun transformVariableAssignment(
variableAssignment: FirVariableAssignment,
data: ExpectedArgumentType?,
@@ -866,18 +879,14 @@ class FirCallCompletionResultsWriterTransformer(
else -> null
}
return if (errorDiagnostic != null) {
buildErrorNamedReference {
source = this@toResolvedReference.source
diagnostic = errorDiagnostic
candidateSymbol = this@toResolvedReference.candidateSymbol
}
} else {
buildResolvedNamedReference {
return when (errorDiagnostic) {
null -> buildResolvedNamedReference {
source = this@toResolvedReference.source
name = this@toResolvedReference.name
resolvedSymbol = this@toResolvedReference.candidateSymbol
}
else -> toErrorReference(errorDiagnostic)
}
}
}
@@ -14,13 +14,13 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirIntegerLiteralOperatorCall
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedErrorReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.resolvedSymbol
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
import org.jetbrains.kotlin.fir.scopes.getFunctions
@@ -90,13 +90,21 @@ class IntegerLiteralAndOperatorApproximationTransformer(
val wrappedFunctionSymbol = calleeReference.resolvedSymbol as FirNamedFunctionSymbol
val originalFunctionSymbol = wrappedFunctionSymbol.fir.originalForWrappedIntegerOperator!!
call.replaceCalleeReference(
buildResolvedNamedReference {
val newCalleeReference = when (calleeReference) {
is FirResolvedErrorReference -> buildResolvedErrorReference {
name = calleeReference.name
source = calleeReference.source
resolvedSymbol = originalFunctionSymbol
diagnostic = calleeReference.diagnostic
}
else -> buildResolvedNamedReference {
name = calleeReference.name
source = calleeReference.source
resolvedSymbol = originalFunctionSymbol
}
)
}
call.replaceCalleeReference(newCalleeReference)
}
if (approximatedType.isInt || approximatedType.isUInt) return call
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList
import org.jetbrains.kotlin.fir.expressions.builder.buildArrayOfCall
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -79,6 +80,7 @@ internal class FirArrayOfCallTransformer : FirDefaultTransformer<Nothing?>() {
private fun FirFunctionCall.getOriginalFunction(): FirCallableDeclaration? {
val symbol: FirBasedSymbol<*>? = when (val reference = calleeReference) {
is FirResolvedErrorReference -> null
is FirResolvedNamedReference -> reference.resolvedSymbol
is FirNamedReferenceWithCandidate -> reference.candidateSymbol
else -> null
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildReturnExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildUnitExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirLazyBlock
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
@@ -362,7 +363,8 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
return provideDelegateCall
}
if (provideDelegateCall.calleeReference is FirResolvedNamedReference) {
val provideDelegateReference = provideDelegateCall.calleeReference
if (provideDelegateReference is FirResolvedNamedReference && provideDelegateReference !is FirResolvedErrorReference) {
return provideDelegateCall
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedErrorReference
import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.*
@@ -891,9 +892,10 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
else -> {
val altererNames = alteredAssignments.map { it.second::class.qualifiedName }
val errorReference = buildErrorNamedReference {
val errorReference = buildResolvedErrorReference {
source = resolvedReference.source
candidateSymbol = resolvedReference.resolvedSymbol
name = resolvedReference.name
resolvedSymbol = resolvedReference.resolvedSymbol
diagnostic = ConeAmbiguousAlteredAssign(altererNames)
}
completeAssignment.replaceCalleeReference(errorReference)
@@ -839,9 +839,16 @@ class FirRenderer(
}
print(">")
}
if (resolvedNamedReference is FirResolvedErrorReference) {
print("<${resolvedNamedReference.diagnostic.reason}>#")
}
print("|")
}
override fun visitResolvedErrorReference(resolvedErrorReference: FirResolvedErrorReference) {
visitResolvedNamedReference(resolvedErrorReference)
}
private fun FirBasedSymbol<*>.unwrapIntersectionOverrides(): FirBasedSymbol<*> {
(this as? FirCallableSymbol<*>)?.baseForIntersectionOverride?.let { return it.unwrapIntersectionOverrides() }
return this
@@ -11,11 +11,13 @@ import org.jetbrains.kotlin.KtIoFileSourceFile
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.resolve.transformers.FirGlobalResolveProcessor
@@ -281,8 +283,8 @@ class FirResolveBench(val withProgress: Boolean, val listener: BenchListener? =
if (type is ConeErrorType) {
errorFunctionCallTypes++
val psi = callee.psi
if (callee is FirErrorNamedReference && psi != null) {
reportProblem(callee.diagnostic.reason, psi)
if ((callee is FirErrorNamedReference || callee is FirResolvedErrorReference) && psi != null) {
reportProblem((callee as FirDiagnosticHolder).diagnostic.reason, psi)
}
}
}
@@ -298,8 +300,8 @@ class FirResolveBench(val withProgress: Boolean, val listener: BenchListener? =
if (type is ConeErrorType) {
errorQualifiedAccessTypes++
val psi = callee.psi
if (callee is FirErrorNamedReference && psi != null) {
reportProblem(callee.diagnostic.reason, psi)
if ((callee is FirErrorNamedReference || callee is FirResolvedErrorReference) && psi != null) {
reportProblem((callee as FirDiagnosticHolder).diagnostic.reason, psi)
}
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.references.*
@@ -675,12 +676,16 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
override fun visitNamedReference(namedReference: FirNamedReference, data: StringBuilder) {
if (namedReference is FirErrorNamedReference) {
data.append("[ERROR : ${namedReference.diagnostic.reason}]")
data.append(namedReference.diagnostic.dump())
return
}
visitElement(namedReference, data)
}
private fun ConeDiagnostic.dump(): String {
return "[ERROR : ${reason}]"
}
override fun visitResolvedNamedReference(resolvedNamedReference: FirResolvedNamedReference, data: StringBuilder) {
val symbol = resolvedNamedReference.resolvedSymbol
renderImplicitReceiver(symbol, resolvedNamedReference.source.psi)
@@ -698,6 +703,11 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
}
}
override fun visitResolvedErrorReference(resolvedErrorReference: FirResolvedErrorReference, data: StringBuilder) {
visitResolvedNamedReference(resolvedErrorReference, data)
data.append(resolvedErrorReference.diagnostic.dump())
}
override fun visitResolvedCallableReference(resolvedCallableReference: FirResolvedCallableReference, data: StringBuilder) {
when (val symbol = resolvedCallableReference.resolvedSymbol) {
is FirPropertySymbol -> renderPropertySymbol(symbol, data)
@@ -772,8 +782,11 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
is FirConstructorSymbol -> visitConstructor(callee.resolvedSymbol.fir as FirConstructor, data)
else -> renderFunctionSymbol(callee.resolvedSymbol as FirNamedFunctionSymbol, data, functionCall)
}
if (callee is FirResolvedErrorReference) {
data.append(callee.diagnostic.dump())
}
}
is FirErrorNamedReference -> data.append("[ERROR : ${callee.diagnostic.reason}]")
is FirErrorNamedReference -> data.append(callee.diagnostic.dump())
}
}
@@ -16,10 +16,12 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.arguments
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnosticWithSingleCandidate
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
@@ -42,10 +44,13 @@ object FirAssignmentPluginFunctionCallChecker : FirFunctionCallChecker() {
private fun FirFunctionCall.isOverloadAssignCallCandidate() =
arguments.size == 1 && source?.kind == KtFakeSourceElementKind.DesugaredCompoundAssignment
private fun FirFunctionCall.isFunctionResolveError() = calleeReference is FirErrorNamedReference
private fun FirFunctionCall.isFunctionResolveError() = when(calleeReference){
is FirErrorNamedReference, is FirResolvedErrorReference -> true
else -> false
}
private fun FirFunctionCall.isOverloadedAssignCallError(session: FirSession): Boolean {
val functionName = when (val diagnostic = (calleeReference as? FirErrorNamedReference)?.diagnostic) {
val functionName = when (val diagnostic = (calleeReference as? FirDiagnosticHolder)?.diagnostic) {
is ConeAmbiguityError -> diagnostic.name
is ConeDiagnosticWithSingleCandidate -> diagnostic.candidate.callInfo.name
is ConeUnresolvedNameError -> diagnostic.name