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 -> add(FirErrors.AMBIGUOUS_SUPER) { firDiagnostic ->
AmbiguousSuperImpl( AmbiguousSuperImpl(
firDiagnostic.a.map { coneKotlinType ->
firSymbolBuilder.typeBuilder.buildKtType(coneKotlinType)
},
firDiagnostic as FirPsiDiagnostic, firDiagnostic as FirPsiDiagnostic,
token, token,
) )
@@ -425,6 +425,7 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract class AmbiguousSuper : KtFirDiagnostic<KtSuperExpression>() { abstract class AmbiguousSuper : KtFirDiagnostic<KtSuperExpression>() {
override val diagnosticClass get() = AmbiguousSuper::class override val diagnosticClass get() = AmbiguousSuper::class
abstract val candidates: List<KtType>
} }
abstract class ConstructorInObject : KtFirDiagnostic<KtDeclaration>() { abstract class ConstructorInObject : KtFirDiagnostic<KtDeclaration>() {
@@ -500,6 +500,7 @@ internal class InconsistentTypeParameterBoundsImpl(
) : KtFirDiagnostic.InconsistentTypeParameterBounds(), KtAbstractFirDiagnostic<PsiElement> ) : KtFirDiagnostic.InconsistentTypeParameterBounds(), KtAbstractFirDiagnostic<PsiElement>
internal class AmbiguousSuperImpl( internal class AmbiguousSuperImpl(
override val candidates: List<KtType>,
override val firDiagnostic: FirPsiDiagnostic, override val firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.AmbiguousSuper(), KtAbstractFirDiagnostic<KtSuperExpression> ) : KtFirDiagnostic.AmbiguousSuper(), KtAbstractFirDiagnostic<KtSuperExpression>
@@ -192,7 +192,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirRegularClassSymbol>("type") parameter<FirRegularClassSymbol>("type")
parameter<Collection<ConeKotlinType>>("bounds") 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") { 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 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_VALUES by error3<KtClass, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>(SourceElementPositioningStrategies.SUPERTYPES_LIST)
val INCONSISTENT_TYPE_PARAMETER_BOUNDS by error3<PsiElement, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>() 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 // Constructor problems
val CONSTRUCTOR_IN_OBJECT by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) 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.analysis.diagnostics.toFirDiagnostics
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.FirErrorImport 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.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
@@ -75,11 +76,10 @@ class ErrorNodeDiagnosticCollectorComponent(
private fun FirExpression?.cannotBeResolved(): Boolean { private fun FirExpression?.cannotBeResolved(): Boolean {
return when (val diagnostic = (this?.typeRef as? FirErrorTypeRef)?.diagnostic) { 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 || is ConeSimpleDiagnostic -> diagnostic.kind == DiagnosticKind.NotASupertype ||
diagnostic.kind == DiagnosticKind.SuperNotAvailable || diagnostic.kind == DiagnosticKind.SuperNotAvailable ||
diagnostic.kind == DiagnosticKind.UnresolvedLabel || diagnostic.kind == DiagnosticKind.UnresolvedLabel
diagnostic.kind == DiagnosticKind.AmbiguousSuper
else -> false else -> false
} }
} }
@@ -636,7 +636,7 @@ class FirDefaultErrorMessages {
SYMBOL, SYMBOL,
RENDER_COLLECTION_OF_TYPES 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 // Constructor problems
map.put(CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects") 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) } runIf(variable.isLocalMember) { FirErrors.VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.createOn(source) }
is ConeUnderscoreIsReserved -> FirErrors.UNDERSCORE_IS_RESERVED.createOn(this.source) is ConeUnderscoreIsReserved -> FirErrors.UNDERSCORE_IS_RESERVED.createOn(this.source)
is ConeUnderscoreUsageWithoutBackticks -> FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.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}") 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.EnumEntryAsType -> FirErrors.ENUM_ENTRY_AS_TYPE
DiagnosticKind.NotASupertype -> FirErrors.NOT_A_SUPERTYPE DiagnosticKind.NotASupertype -> FirErrors.NOT_A_SUPERTYPE
DiagnosticKind.SuperNotAvailable -> FirErrors.SUPER_NOT_AVAILABLE DiagnosticKind.SuperNotAvailable -> FirErrors.SUPER_NOT_AVAILABLE
DiagnosticKind.AmbiguousSuper -> FirErrors.AMBIGUOUS_SUPER
DiagnosticKind.UnresolvedSupertype, DiagnosticKind.UnresolvedSupertype,
DiagnosticKind.UnresolvedExpandedType, DiagnosticKind.UnresolvedExpandedType,
DiagnosticKind.Other -> FirErrors.OTHER_ERROR DiagnosticKind.Other -> FirErrors.OTHER_ERROR
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.utils.addIfNotNull
fun BodyResolveComponents.findTypesForSuperCandidates( fun BodyResolveComponents.findTypesForSuperCandidates(
superTypeRefs: List<FirTypeRef>, superTypeRefs: List<FirTypeRef>,
containingCall: FirQualifiedAccess, containingCall: FirQualifiedAccess,
): Collection<ConeKotlinType> { ): List<ConeKotlinType> {
val supertypes = superTypeRefs.map { (it as FirResolvedTypeRef).type } val supertypes = superTypeRefs.map { (it as FirResolvedTypeRef).type }
val isMethodOfAny = containingCall is FirFunctionCall && isCallingMethodOfAny(containingCall) val isMethodOfAny = containingCall is FirFunctionCall && isCallingMethodOfAny(containingCall)
if (supertypes.size <= 1 && !isMethodOfAny) return supertypes if (supertypes.size <= 1 && !isMethodOfAny) return supertypes
@@ -61,7 +61,7 @@ private fun isCallingMethodOfAny(callExpression: FirFunctionCall): Boolean =
private fun BodyResolveComponents.resolveSupertypesForMethodOfAny( private fun BodyResolveComponents.resolveSupertypesForMethodOfAny(
supertypes: Collection<ConeKotlinType>, supertypes: Collection<ConeKotlinType>,
calleeName: Name calleeName: Name
): Collection<ConeKotlinType> { ): List<ConeKotlinType> {
val typesWithConcreteOverride = resolveSupertypesByMembers(supertypes, false) { val typesWithConcreteOverride = resolveSupertypesByMembers(supertypes, false) {
getFunctionMembers(it, calleeName) getFunctionMembers(it, calleeName)
} }
@@ -71,13 +71,19 @@ private fun BodyResolveComponents.resolveSupertypesForMethodOfAny(
listOf(session.builtinTypes.anyType.type) 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) { resolveSupertypesByMembers(supertypes, true) {
getFunctionMembers(it, calleeName) + getFunctionMembers(it, calleeName) +
getPropertyMembers(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) { resolveSupertypesByMembers(supertypes, true) {
getPropertyMembers(it, propertyName) getPropertyMembers(it, propertyName)
} }
@@ -86,7 +92,7 @@ private inline fun BodyResolveComponents.resolveSupertypesByMembers(
supertypes: Collection<ConeKotlinType>, supertypes: Collection<ConeKotlinType>,
allowNonConcreteMembers: Boolean, allowNonConcreteMembers: Boolean,
getMembers: (ConeKotlinType) -> Collection<FirCallableDeclaration> getMembers: (ConeKotlinType) -> Collection<FirCallableDeclaration>
): Collection<ConeKotlinType> { ): List<ConeKotlinType> {
val typesWithConcreteMembers = SmartList<ConeKotlinType>() val typesWithConcreteMembers = SmartList<ConeKotlinType>()
val typesWithNonConcreteMembers = 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.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.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.diagnostics.*
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.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall
@@ -266,7 +263,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
} }
else -> buildErrorTypeRef { else -> buildErrorTypeRef {
source = superReferenceContainer.source source = superReferenceContainer.source
diagnostic = ConeSimpleDiagnostic("Ambiguous supertype", DiagnosticKind.AmbiguousSuper) diagnostic = ConeAmbiguousSuper(types)
} }
} }
superReferenceContainer.resultType = superReferenceContainer.resultType =
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.diagnostics package org.jetbrains.kotlin.fir.diagnostics
import org.jetbrains.kotlin.fir.FirSourceElement 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 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 (`_`, `__`, `___`, ...)" 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 { enum class DiagnosticKind {
Syntax, Syntax,
ExpressionExpected, ExpressionExpected,
@@ -49,7 +55,6 @@ enum class DiagnosticKind {
MissingStdlibClass, MissingStdlibClass,
NotASupertype, NotASupertype,
SuperNotAvailable, SuperNotAvailable,
AmbiguousSuper,
LoopInSupertype, LoopInSupertype,
RecursiveTypealiasExpansion, RecursiveTypealiasExpansion,