FIR checker: report AMBIGUOUS_SUPER

This commit is contained in:
Tianyu Geng
2021-07-19 15:13:39 -07:00
committed by Ivan Kochurkin
parent 5b9ce7e823
commit 06ee84f809
20 changed files with 59 additions and 27 deletions
@@ -15,7 +15,7 @@ open class B {
override fun foo() { override fun foo() {
super.foo() super.foo()
super.<!UNRESOLVED_REFERENCE!>bar<!>() // should be ambiguity (NB: really we should have overridden bar in C) <!AMBIGUOUS_SUPER!>super<!>.bar() // should be ambiguity (NB: really we should have overridden bar in C)
super.baz() // Ok super.baz() // Ok
baz() // Ok baz() // Ok
@@ -178,6 +178,7 @@ 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 CONSTRUCTOR_PROBLEMS by object : DiagnosticGroup("Constructor problems") { val CONSTRUCTOR_PROBLEMS by object : DiagnosticGroup("Constructor problems") {
@@ -71,6 +71,7 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtReturnExpression import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.psi.KtTypeAlias import org.jetbrains.kotlin.psi.KtTypeAlias
import org.jetbrains.kotlin.psi.KtTypeParameter import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeProjection import org.jetbrains.kotlin.psi.KtTypeProjection
@@ -172,6 +173,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>()
// Constructor problems // Constructor problems
val CONSTRUCTOR_IN_OBJECT by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val CONSTRUCTOR_IN_OBJECT by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -79,7 +79,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 -> true
is ConeSimpleDiagnostic -> diagnostic.kind == DiagnosticKind.NotASupertype || diagnostic.kind == DiagnosticKind.SuperNotAvailable || diagnostic.kind == DiagnosticKind.UnresolvedLabel is ConeSimpleDiagnostic -> diagnostic.kind == DiagnosticKind.NotASupertype ||
diagnostic.kind == DiagnosticKind.SuperNotAvailable ||
diagnostic.kind == DiagnosticKind.UnresolvedLabel ||
diagnostic.kind == DiagnosticKind.AmbiguousSuper
else -> false else -> false
} }
} }
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_WITHOUT_EXPECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_WITHOUT_EXPECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ACTUALS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ACTUALS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_EXPECTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_EXPECTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_SUPER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_CONSTRUCTOR_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_CONSTRUCTOR_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_MEMBER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_MEMBER
@@ -582,6 +583,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>'")
// 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")
@@ -372,6 +372,7 @@ 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
@@ -236,17 +236,19 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
} }
else -> { else -> {
val types = components.findTypesForSuperCandidates(superTypeRefs, containingCall) val types = components.findTypesForSuperCandidates(superTypeRefs, containingCall)
val resultType = if (types.size == 1) { val resultType = when (types.size) {
// NB: NOT_A_SUPERTYPE is reported by a separate checker 0 -> buildErrorTypeRef {
buildResolvedTypeRef { source = superReferenceContainer.source
// Report stub error so that it won't surface up. Instead, errors on the callee would be reported.
diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("Unresolved super method", DiagnosticKind.Other))
}
1 -> buildResolvedTypeRef {
source = superReferenceContainer.source?.fakeElement(FirFakeSourceElementKind.SuperCallImplicitType) source = superReferenceContainer.source?.fakeElement(FirFakeSourceElementKind.SuperCallImplicitType)
type = types.single() type = types.single()
} }
} else { else -> buildErrorTypeRef {
buildErrorTypeRef {
source = superReferenceContainer.source source = superReferenceContainer.source
// NB: NOT_A_SUPERTYPE is reported by a separate checker diagnostic = ConeSimpleDiagnostic("Ambiguous supertype", DiagnosticKind.AmbiguousSuper)
diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("Ambiguous supertype", DiagnosticKind.Other))
} }
} }
superReferenceContainer.resultType = superReferenceContainer.resultType =
@@ -48,6 +48,7 @@ enum class DiagnosticKind {
MissingStdlibClass, MissingStdlibClass,
NotASupertype, NotASupertype,
SuperNotAvailable, SuperNotAvailable,
AmbiguousSuper,
LoopInSupertype, LoopInSupertype,
RecursiveTypealiasExpansion, RecursiveTypealiasExpansion,
@@ -1,6 +1,6 @@
enum class E : Cloneable { enum class E : Cloneable {
A; A;
<!OVERRIDING_FINAL_MEMBER!>override<!> fun clone(): Any { <!OVERRIDING_FINAL_MEMBER!>override<!> fun clone(): Any {
return super.<!UNRESOLVED_REFERENCE!>clone<!>() return <!AMBIGUOUS_SUPER!>super<!>.clone()
} }
} }
@@ -13,7 +13,7 @@ class GenericDerivedClass<T> : GenericBaseClass<T>(), GenericBaseInterface<T> {
override fun bar(x: T): T = super.bar(x) override fun bar(x: T): T = super.bar(x)
override fun ambiguous(x: T): T = override fun ambiguous(x: T): T =
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x) <!AMBIGUOUS_SUPER!>super<!>.ambiguous(x)
} }
class SpecializedDerivedClass : GenericBaseClass<Int>(), GenericBaseInterface<String> { class SpecializedDerivedClass : GenericBaseClass<Int>(), GenericBaseInterface<String> {
@@ -21,9 +21,9 @@ class SpecializedDerivedClass : GenericBaseClass<Int>(), GenericBaseInterface<St
override fun bar(x: String): String = super.bar(x) override fun bar(x: String): String = super.bar(x)
override fun ambiguous(x: String): String = override fun ambiguous(x: String): String =
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x) <!AMBIGUOUS_SUPER!>super<!>.ambiguous(x)
override fun ambiguous(x: Int): Int = override fun ambiguous(x: Int): Int =
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x) <!AMBIGUOUS_SUPER!>super<!>.ambiguous(x)
} }
class MixedDerivedClass<T> : GenericBaseClass<Int>(), GenericBaseInterface<T> { class MixedDerivedClass<T> : GenericBaseClass<Int>(), GenericBaseInterface<T> {
@@ -31,7 +31,7 @@ class MixedDerivedClass<T> : GenericBaseClass<Int>(), GenericBaseInterface<T> {
override fun bar(x: T): T = super.bar(x) override fun bar(x: T): T = super.bar(x)
override fun ambiguous(x: Int): Int = override fun ambiguous(x: Int): Int =
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x) <!AMBIGUOUS_SUPER!>super<!>.ambiguous(x)
override fun ambiguous(x: T): T = override fun ambiguous(x: T): T =
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x) <!AMBIGUOUS_SUPER!>super<!>.ambiguous(x)
} }
@@ -45,13 +45,13 @@ class Derived : Base(), Interface {
super.prop super.prop
fun getAmbiguousSuperProp(): Int = fun getAmbiguousSuperProp(): Int =
super.<!UNRESOLVED_REFERENCE!>ambiguousProp<!> <!AMBIGUOUS_SUPER!>super<!>.ambiguousProp
fun callsFunFromSuperInterface() { fun callsFunFromSuperInterface() {
super.bar() super.bar()
} }
fun callsAmbiguousSuperFun() { fun callsAmbiguousSuperFun() {
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>() <!AMBIGUOUS_SUPER!>super<!>.ambiguous()
} }
} }
@@ -34,6 +34,6 @@ class B : A(), I {
} }
override fun qux() { override fun qux() {
super.<!UNRESOLVED_REFERENCE!>qux<!>() <!AMBIGUOUS_SUPER!>super<!>.qux()
} }
} }
@@ -13,7 +13,7 @@ interface InterfaceWithFun {
class DerivedUsingFun : BaseWithCallableProp(), InterfaceWithFun { class DerivedUsingFun : BaseWithCallableProp(), InterfaceWithFun {
fun foo(): String = fun foo(): String =
super.<!UNRESOLVED_REFERENCE!>fn<!>() <!AMBIGUOUS_SUPER!>super<!>.fn()
override fun bar(): String = override fun bar(): String =
super.bar() super.bar()
@@ -31,4 +31,4 @@ class C : A(), B {
super@D.qux() super@D.qux()
} }
} }
} }
@@ -20,9 +20,9 @@ interface AnotherInterface {
interface DerivedInterface: Interface, AnotherInterface { interface DerivedInterface: Interface, AnotherInterface {
override fun foo() { super.foo() } override fun foo() { super.foo() }
override fun ambiguous() { override fun ambiguous() {
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>() <!AMBIGUOUS_SUPER!>super<!>.ambiguous()
} }
override val ambiguousProp: Int override val ambiguousProp: Int
get() = super.<!UNRESOLVED_REFERENCE!>ambiguousProp<!> get() = <!AMBIGUOUS_SUPER!>super<!>.ambiguousProp
} }
@@ -41,13 +41,13 @@ class ClassDerivedFromUnresolved : Base(), Interface, <!UNRESOLVED_REFERENCE!>Un
super.prop super.prop
fun getAmbiguousSuperProp(): Int = fun getAmbiguousSuperProp(): Int =
super.<!UNRESOLVED_REFERENCE!>ambiguousProp<!> <!AMBIGUOUS_SUPER!>super<!>.ambiguousProp
fun callsFunFromSuperInterface() { fun callsFunFromSuperInterface() {
super.bar() super.bar()
} }
fun callsAmbiguousSuperFun() { fun callsAmbiguousSuperFun() {
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>() <!AMBIGUOUS_SUPER!>super<!>.ambiguous()
} }
} }
@@ -41,7 +41,7 @@ class ManySupers: Foo2(), B {
fun foo() { fun foo() {
super<Foo2>.test() super<Foo2>.test()
super<<!QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE!>B<!>>.test() super<<!QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE!>B<!>>.test()
super.<!UNRESOLVED_REFERENCE!>test<!>() <!AMBIGUOUS_SUPER!>super<!>.test()
} }
} }
@@ -49,7 +49,7 @@ class ManySupers2: Foo2(), C {
fun foo() { fun foo() {
super<Foo2>.test() super<Foo2>.test()
super<C>.test() super<C>.test()
super.<!UNRESOLVED_REFERENCE!>test<!>() <!AMBIGUOUS_SUPER!>super<!>.test()
} }
} }
@@ -57,6 +57,6 @@ class ManySupers2: Foo2(), C {
fun foo() { fun foo() {
super<Bar2>.test() super<Bar2>.test()
super<C>.test() super<C>.test()
super.<!UNRESOLVED_REFERENCE!>test<!>() <!AMBIGUOUS_SUPER!>super<!>.test()
} }
} }
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtReturnExpression import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.psi.KtTypeAlias import org.jetbrains.kotlin.psi.KtTypeAlias
import org.jetbrains.kotlin.psi.KtTypeParameter import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeProjection import org.jetbrains.kotlin.psi.KtTypeProjection
@@ -515,6 +516,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.AMBIGUOUS_SUPER) { firDiagnostic ->
AmbiguousSuperImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.CONSTRUCTOR_IN_OBJECT) { firDiagnostic -> add(FirErrors.CONSTRUCTOR_IN_OBJECT) { firDiagnostic ->
ConstructorInObjectImpl( ConstructorInObjectImpl(
firDiagnostic as FirPsiDiagnostic, firDiagnostic as FirPsiDiagnostic,
@@ -59,6 +59,7 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtReturnExpression import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.psi.KtTypeAlias import org.jetbrains.kotlin.psi.KtTypeAlias
import org.jetbrains.kotlin.psi.KtTypeParameter import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeProjection import org.jetbrains.kotlin.psi.KtTypeProjection
@@ -384,6 +385,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val bounds: List<KtType> abstract val bounds: List<KtType>
} }
abstract class AmbiguousSuper : KtFirDiagnostic<KtSuperExpression>() {
override val diagnosticClass get() = AmbiguousSuper::class
}
abstract class ConstructorInObject : KtFirDiagnostic<KtDeclaration>() { abstract class ConstructorInObject : KtFirDiagnostic<KtDeclaration>() {
override val diagnosticClass get() = ConstructorInObject::class override val diagnosticClass get() = ConstructorInObject::class
} }
@@ -61,6 +61,7 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtReturnExpression import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.psi.KtTypeAlias import org.jetbrains.kotlin.psi.KtTypeAlias
import org.jetbrains.kotlin.psi.KtTypeParameter import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeProjection import org.jetbrains.kotlin.psi.KtTypeProjection
@@ -592,6 +593,13 @@ internal class InconsistentTypeParameterBoundsImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
} }
internal class AmbiguousSuperImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.AmbiguousSuper(), KtAbstractFirDiagnostic<KtSuperExpression> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ConstructorInObjectImpl( internal class ConstructorInObjectImpl(
firDiagnostic: FirPsiDiagnostic, firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken, override val token: ValidityToken,