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