FIR IDE: pass candidate super types for AMBIGUOUS_SUPER

This way the IDE quickfix do not need to do resolution again to figure
out what super type to offer in the quickfix.
This commit is contained in:
Tianyu Geng
2021-10-12 16:21:48 -07:00
committed by Ilya Kirillov
parent 7c3706dd3f
commit bdc71a3281
11 changed files with 33 additions and 18 deletions
@@ -569,6 +569,9 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
}
add(FirErrors.AMBIGUOUS_SUPER) { firDiagnostic ->
AmbiguousSuperImpl(
firDiagnostic.a.map { coneKotlinType ->
firSymbolBuilder.typeBuilder.buildKtType(coneKotlinType)
},
firDiagnostic as FirPsiDiagnostic,
token,
)
@@ -425,6 +425,7 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract class AmbiguousSuper : KtFirDiagnostic<KtSuperExpression>() {
override val diagnosticClass get() = AmbiguousSuper::class
abstract val candidates: List<KtType>
}
abstract class ConstructorInObject : KtFirDiagnostic<KtDeclaration>() {
@@ -500,6 +500,7 @@ internal class InconsistentTypeParameterBoundsImpl(
) : KtFirDiagnostic.InconsistentTypeParameterBounds(), KtAbstractFirDiagnostic<PsiElement>
internal class AmbiguousSuperImpl(
override val candidates: List<KtType>,
override val firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.AmbiguousSuper(), KtAbstractFirDiagnostic<KtSuperExpression>
@@ -192,7 +192,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirRegularClassSymbol>("type")
parameter<Collection<ConeKotlinType>>("bounds")
}
val AMBIGUOUS_SUPER by error<KtSuperExpression>()
val AMBIGUOUS_SUPER by error<KtSuperExpression> {
parameter<List<ConeKotlinType>>("candidates")
}
}
val CONSTRUCTOR_PROBLEMS by object : DiagnosticGroup("Constructor problems") {
@@ -183,7 +183,7 @@ object FirErrors {
val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
val INCONSISTENT_TYPE_PARAMETER_VALUES by error3<KtClass, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>(SourceElementPositioningStrategies.SUPERTYPES_LIST)
val INCONSISTENT_TYPE_PARAMETER_BOUNDS by error3<PsiElement, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>()
val AMBIGUOUS_SUPER by error0<KtSuperExpression>()
val AMBIGUOUS_SUPER by error1<KtSuperExpression, List<ConeKotlinType>>()
// Constructor problems
val CONSTRUCTOR_IN_OBJECT by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.toFirDiagnostics
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.FirErrorImport
import org.jetbrains.kotlin.fir.diagnostics.ConeAmbiguousSuper
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
@@ -75,11 +76,10 @@ class ErrorNodeDiagnosticCollectorComponent(
private fun FirExpression?.cannotBeResolved(): Boolean {
return when (val diagnostic = (this?.typeRef as? FirErrorTypeRef)?.diagnostic) {
is ConeUnresolvedNameError, is ConeInstanceAccessBeforeSuperCall -> true
is ConeUnresolvedNameError, is ConeInstanceAccessBeforeSuperCall, is ConeAmbiguousSuper -> true
is ConeSimpleDiagnostic -> diagnostic.kind == DiagnosticKind.NotASupertype ||
diagnostic.kind == DiagnosticKind.SuperNotAvailable ||
diagnostic.kind == DiagnosticKind.UnresolvedLabel ||
diagnostic.kind == DiagnosticKind.AmbiguousSuper
diagnostic.kind == DiagnosticKind.UnresolvedLabel
else -> false
}
}
@@ -636,7 +636,7 @@ class FirDefaultErrorMessages {
SYMBOL,
RENDER_COLLECTION_OF_TYPES
)
map.put(AMBIGUOUS_SUPER, "Many supertypes available, please specify the one you mean in angle brackets, e.g. 'super<Foo>'")
map.put(AMBIGUOUS_SUPER, "Many supertypes available, please specify the one you mean in angle brackets, e.g. 'super<Foo>'", NOT_RENDERED)
// Constructor problems
map.put(CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects")
@@ -111,6 +111,7 @@ private fun ConeDiagnostic.toFirDiagnostic(
runIf(variable.isLocalMember) { FirErrors.VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.createOn(source) }
is ConeUnderscoreIsReserved -> FirErrors.UNDERSCORE_IS_RESERVED.createOn(this.source)
is ConeUnderscoreUsageWithoutBackticks -> FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.createOn(this.source)
is ConeAmbiguousSuper -> FirErrors.AMBIGUOUS_SUPER.createOn(source, this.candidateTypes)
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
}
@@ -407,7 +408,6 @@ private fun ConeSimpleDiagnostic.getFactory(source: FirSourceElement): FirDiagno
DiagnosticKind.EnumEntryAsType -> FirErrors.ENUM_ENTRY_AS_TYPE
DiagnosticKind.NotASupertype -> FirErrors.NOT_A_SUPERTYPE
DiagnosticKind.SuperNotAvailable -> FirErrors.SUPER_NOT_AVAILABLE
DiagnosticKind.AmbiguousSuper -> FirErrors.AMBIGUOUS_SUPER
DiagnosticKind.UnresolvedSupertype,
DiagnosticKind.UnresolvedExpandedType,
DiagnosticKind.Other -> FirErrors.OTHER_ERROR
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.utils.addIfNotNull
fun BodyResolveComponents.findTypesForSuperCandidates(
superTypeRefs: List<FirTypeRef>,
containingCall: FirQualifiedAccess,
): Collection<ConeKotlinType> {
): List<ConeKotlinType> {
val supertypes = superTypeRefs.map { (it as FirResolvedTypeRef).type }
val isMethodOfAny = containingCall is FirFunctionCall && isCallingMethodOfAny(containingCall)
if (supertypes.size <= 1 && !isMethodOfAny) return supertypes
@@ -61,7 +61,7 @@ private fun isCallingMethodOfAny(callExpression: FirFunctionCall): Boolean =
private fun BodyResolveComponents.resolveSupertypesForMethodOfAny(
supertypes: Collection<ConeKotlinType>,
calleeName: Name
): Collection<ConeKotlinType> {
): List<ConeKotlinType> {
val typesWithConcreteOverride = resolveSupertypesByMembers(supertypes, false) {
getFunctionMembers(it, calleeName)
}
@@ -71,13 +71,19 @@ private fun BodyResolveComponents.resolveSupertypesForMethodOfAny(
listOf(session.builtinTypes.anyType.type)
}
private fun BodyResolveComponents.resolveSupertypesByCalleeName(supertypes: Collection<ConeKotlinType>, calleeName: Name): Collection<ConeKotlinType> =
private fun BodyResolveComponents.resolveSupertypesByCalleeName(
supertypes: Collection<ConeKotlinType>,
calleeName: Name
): List<ConeKotlinType> =
resolveSupertypesByMembers(supertypes, true) {
getFunctionMembers(it, calleeName) +
getPropertyMembers(it, calleeName)
}
private fun BodyResolveComponents.resolveSupertypesByPropertyName(supertypes: Collection<ConeKotlinType>, propertyName: Name): Collection<ConeKotlinType> =
private fun BodyResolveComponents.resolveSupertypesByPropertyName(
supertypes: Collection<ConeKotlinType>,
propertyName: Name
): List<ConeKotlinType> =
resolveSupertypesByMembers(supertypes, true) {
getPropertyMembers(it, propertyName)
}
@@ -86,7 +92,7 @@ private inline fun BodyResolveComponents.resolveSupertypesByMembers(
supertypes: Collection<ConeKotlinType>,
allowNonConcreteMembers: Boolean,
getMembers: (ConeKotlinType) -> Collection<FirCallableDeclaration>
): Collection<ConeKotlinType> {
): List<ConeKotlinType> {
val typesWithConcreteMembers = SmartList<ConeKotlinType>()
val typesWithNonConcreteMembers = SmartList<ConeKotlinType>()
@@ -8,10 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.diagnostics.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall
@@ -266,7 +263,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
}
else -> buildErrorTypeRef {
source = superReferenceContainer.source
diagnostic = ConeSimpleDiagnostic("Ambiguous supertype", DiagnosticKind.AmbiguousSuper)
diagnostic = ConeAmbiguousSuper(types)
}
}
superReferenceContainer.resultType =
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.diagnostics
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.types.ConeKotlinType
class ConeSimpleDiagnostic(override val reason: String, val kind: DiagnosticKind = DiagnosticKind.Other) : ConeDiagnostic
@@ -23,6 +24,11 @@ class ConeUnderscoreUsageWithoutBackticks(source: FirSourceElement) : ConeDiagno
override val reason: String get() = "Names _, __, ___, ... can be used only in back-ticks (`_`, `__`, `___`, ...)"
}
class ConeAmbiguousSuper(val candidateTypes: List<ConeKotlinType>) : ConeDiagnostic {
override val reason: String
get() = "Ambiguous supertype"
}
enum class DiagnosticKind {
Syntax,
ExpressionExpected,
@@ -49,7 +55,6 @@ enum class DiagnosticKind {
MissingStdlibClass,
NotASupertype,
SuperNotAvailable,
AmbiguousSuper,
LoopInSupertype,
RecursiveTypealiasExpansion,