FIR: report NO_TYPE_ARGUMENTS_ON_RHS properly

This commit is contained in:
Mikhail Glukhikh
2021-03-29 15:25:23 +03:00
parent 5617d83c6b
commit f453649d0b
20 changed files with 63 additions and 27 deletions
@@ -250,6 +250,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
parameter<Int>("expectedCount") parameter<Int>("expectedCount")
parameter<FirClassLikeSymbol<*>>("classifier") parameter<FirClassLikeSymbol<*>>("classifier")
} }
val NO_TYPE_ARGUMENTS_ON_RHS by error<FirSourceElement, PsiElement> {
parameter<Int>("expectedCount")
parameter<FirClassLikeSymbol<*>>("classifier")
}
val TYPE_PARAMETERS_IN_OBJECT by error<FirSourceElement, PsiElement>() val TYPE_PARAMETERS_IN_OBJECT by error<FirSourceElement, PsiElement>()
val ILLEGAL_PROJECTION_USAGE by error<FirSourceElement, PsiElement>() val ILLEGAL_PROJECTION_USAGE by error<FirSourceElement, PsiElement>()
val TYPE_PARAMETERS_IN_ENUM by error<FirSourceElement, PsiElement>() val TYPE_PARAMETERS_IN_ENUM by error<FirSourceElement, PsiElement>()
@@ -192,6 +192,7 @@ object FirErrors {
val UPPER_BOUND_VIOLATED by error2<FirSourceElement, PsiElement, FirTypeParameterSymbol, ConeKotlinType>() val UPPER_BOUND_VIOLATED by error2<FirSourceElement, PsiElement, FirTypeParameterSymbol, ConeKotlinType>()
val TYPE_ARGUMENTS_NOT_ALLOWED by error0<FirSourceElement, PsiElement>() val TYPE_ARGUMENTS_NOT_ALLOWED by error0<FirSourceElement, PsiElement>()
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<FirSourceElement, PsiElement, Int, FirClassLikeSymbol<*>>() val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<FirSourceElement, PsiElement, Int, FirClassLikeSymbol<*>>()
val NO_TYPE_ARGUMENTS_ON_RHS by error2<FirSourceElement, PsiElement, Int, FirClassLikeSymbol<*>>()
val TYPE_PARAMETERS_IN_OBJECT by error0<FirSourceElement, PsiElement>() val TYPE_PARAMETERS_IN_OBJECT by error0<FirSourceElement, PsiElement>()
val ILLEGAL_PROJECTION_USAGE by error0<FirSourceElement, PsiElement>() val ILLEGAL_PROJECTION_USAGE by error0<FirSourceElement, PsiElement>()
val TYPE_PARAMETERS_IN_ENUM by error0<FirSourceElement, PsiElement>() val TYPE_PARAMETERS_IN_ENUM by error0<FirSourceElement, PsiElement>()
@@ -44,6 +44,8 @@ private fun ConeDiagnostic.toFirDiagnostic(
is ConeIllegalAnnotationError -> FirErrors.NOT_AN_ANNOTATION_CLASS.on(source, this.name.asString()) is ConeIllegalAnnotationError -> FirErrors.NOT_AN_ANNOTATION_CLASS.on(source, this.name.asString())
is ConeWrongNumberOfTypeArgumentsError -> is ConeWrongNumberOfTypeArgumentsError ->
FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(qualifiedAccessSource ?: source, this.desiredCount, this.type) FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(qualifiedAccessSource ?: source, this.desiredCount, this.type)
is ConeNoTypeArgumentsOnRhsError ->
FirErrors.NO_TYPE_ARGUMENTS_ON_RHS.on(qualifiedAccessSource ?: source, this.desiredCount, this.type)
is ConeSimpleDiagnostic -> when { is ConeSimpleDiagnostic -> when {
source.kind is FirFakeSourceElementKind -> null source.kind is FirFakeSourceElementKind -> null
else -> this.getFactory().on(qualifiedAccessSource ?: source) else -> this.getFactory().on(qualifiedAccessSource ?: source)
@@ -70,10 +70,22 @@ class ConeIllegalAnnotationError(val name: Name) : ConeDiagnostic() {
override val reason: String get() = "Not a legal annotation: $name" override val reason: String get() = "Not a legal annotation: $name"
} }
class ConeWrongNumberOfTypeArgumentsError(val desiredCount: Int, val type: FirClassLikeSymbol<*>) : ConeDiagnostic() { abstract class ConeUnmatchedTypeArgumentsError(val desiredCount: Int, val type: FirClassLikeSymbol<*>) : ConeDiagnostic()
class ConeWrongNumberOfTypeArgumentsError(
desiredCount: Int,
type: FirClassLikeSymbol<*>
) : ConeUnmatchedTypeArgumentsError(desiredCount, type) {
override val reason: String get() = "Wrong number of type arguments" override val reason: String get() = "Wrong number of type arguments"
} }
class ConeNoTypeArgumentsOnRhsError(
desiredCount: Int,
type: FirClassLikeSymbol<*>
) : ConeUnmatchedTypeArgumentsError(desiredCount, type) {
override val reason: String get() = "No type arguments on RHS"
}
class ConeInstanceAccessBeforeSuperCall(val target: String) : ConeDiagnostic() { class ConeInstanceAccessBeforeSuperCall(val target: String) : ConeDiagnostic() {
override val reason: String get() = "Cannot access ''${target}'' before superclass constructor has been called" override val reason: String get() = "Cannot access ''${target}'' before superclass constructor has been called"
} }
@@ -502,7 +502,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
val originalType = argument.typeRef.coneTypeSafe<ConeKotlinType>() ?: return this val originalType = argument.typeRef.coneTypeSafe<ConeKotlinType>() ?: return this
val newType = computeRepresentativeTypeForBareType(type, originalType) ?: return buildErrorTypeRef { val newType = computeRepresentativeTypeForBareType(type, originalType) ?: return buildErrorTypeRef {
source = this@withTypeArgumentsForBareType.source source = this@withTypeArgumentsForBareType.source
diagnostic = ConeWrongNumberOfTypeArgumentsError(firClass.typeParameters.size, firClass.symbol) diagnostic = ConeNoTypeArgumentsOnRhsError(firClass.typeParameters.size, firClass.symbol)
} }
return if (newType.typeArguments.isEmpty()) this else withReplacedConeType(newType) return if (newType.typeArguments.isEmpty()) this else withReplacedConeType(newType)
} }
@@ -4,7 +4,7 @@ interface Tr
interface G<T> interface G<T>
fun test(tr: Tr) { fun test(tr: Tr) {
val v = tr as <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G?<!> val v = tr as <!NO_TYPE_ARGUMENTS_ON_RHS!>G?<!>
// If v is not nullable, there will be a warning on this line: // If v is not nullable, there will be a warning on this line:
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><G<*>>(v!!) <!INAPPLICABLE_CANDIDATE!>checkSubtype<!><G<*>>(v!!)
} }
@@ -4,6 +4,6 @@ interface Tr
interface G<T> interface G<T>
fun test(tr: Tr?) { fun test(tr: Tr?) {
val v = tr as <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G<!> val v = tr as <!NO_TYPE_ARGUMENTS_ON_RHS!>G<!>
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><G<*>>(v) <!INAPPLICABLE_CANDIDATE!>checkSubtype<!><G<*>>(v)
} }
@@ -4,6 +4,6 @@ interface Tr
interface G<T> interface G<T>
fun test(tr: Tr?) { fun test(tr: Tr?) {
val v = tr as <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G?<!> val v = tr as <!NO_TYPE_ARGUMENTS_ON_RHS!>G?<!>
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><G<*>>(v!!) <!INAPPLICABLE_CANDIDATE!>checkSubtype<!><G<*>>(v!!)
} }
@@ -4,6 +4,6 @@ interface Tr
interface G<T> interface G<T>
fun test(tr: Tr) { fun test(tr: Tr) {
val v = tr as <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G<!> val v = tr as <!NO_TYPE_ARGUMENTS_ON_RHS!>G<!>
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><G<*>>(v) <!INAPPLICABLE_CANDIDATE!>checkSubtype<!><G<*>>(v)
} }
@@ -1,4 +0,0 @@
interface Tr
interface G<T>
fun test(tr: Tr) = tr is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G<!>
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
interface Tr interface Tr
interface G<T> interface G<T>
@@ -2,13 +2,13 @@ package p
public fun foo(a: Any) { public fun foo(a: Any) {
a is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<Int><!> a is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<Int><!>
a is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<!> a is <!NO_TYPE_ARGUMENTS_ON_RHS!>Map<!>
a is Map<out Any?, Any?> a is Map<out Any?, Any?>
a is Map<*, *> a is Map<*, *>
a is Map<<!SYNTAX!><!>> a is Map<<!SYNTAX!><!>>
a is List<Map> a is List<Map>
a is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>List<!> a is <!NO_TYPE_ARGUMENTS_ON_RHS!>List<!>
a is Int a is Int
(a as <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<!>) is Int (a as <!NO_TYPE_ARGUMENTS_ON_RHS!>Map<!>) is Int
} }
@@ -1,12 +1,12 @@
public fun foo(a: Any, b: <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<!>) { public fun foo(a: Any, b: <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<!>) {
when (a) { when (a) {
is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<Int><!> -> {} is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<Int><!> -> {}
is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Map<!> -> {} is <!NO_TYPE_ARGUMENTS_ON_RHS!>Map<!> -> {}
is Map<out Any?, Any?> -> {} is Map<out Any?, Any?> -> {}
is Map<*, *> -> {} is Map<*, *> -> {}
is Map<<!SYNTAX!><!>> -> {} is Map<<!SYNTAX!><!>> -> {}
is List<Map> -> {} is List<Map> -> {}
is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>List<!> -> {} is <!NO_TYPE_ARGUMENTS_ON_RHS!>List<!> -> {}
is Int -> {} is Int -> {}
else -> {} else -> {}
} }
@@ -8,7 +8,7 @@ class DerivedOuter<G> : SuperOuter<G>() {
fun bare(x: SuperOuter<*>.SuperInner<*>, y: Any?) { fun bare(x: SuperOuter<*>.SuperInner<*>, y: Any?) {
if (x is SuperOuter.SuperInner) return if (x is SuperOuter.SuperInner) return
if (y is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>SuperOuter.SuperInner<!>) { if (y is <!NO_TYPE_ARGUMENTS_ON_RHS!>SuperOuter.SuperInner<!>) {
return return
} }
} }
@@ -12,7 +12,7 @@ class Outer<E> {
x.prop.checkType { _<E>() } x.prop.checkType { _<E>() }
} }
if (y is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Inner<!>) return if (y is <!NO_TYPE_ARGUMENTS_ON_RHS!>Inner<!>) return
if (z is Inner) { if (z is Inner) {
z.prop.checkType { _<Any?>() } z.prop.checkType { _<Any?>() }
@@ -26,7 +26,7 @@ class Outer<E> {
fun bar(x: InnerBase<String>, y: Any?, z: Outer<*>.InnerBase<String>) { fun bar(x: InnerBase<String>, y: Any?, z: Outer<*>.InnerBase<String>) {
x as Inner x as Inner
y as <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Inner<!> y as <!NO_TYPE_ARGUMENTS_ON_RHS!>Inner<!>
z as Inner z as Inner
} }
} }
@@ -14,8 +14,8 @@ fun testNL1(x: Collection<Int>?): Boolean = x is NL
fun testNL2(x: Collection<Int>?): List<Int>? = x as NL fun testNL2(x: Collection<Int>?): List<Int>? = x as NL
fun testNL3(x: Collection<Int>?): List<Int>? = x as NL? fun testNL3(x: Collection<Int>?): List<Int>? = x as NL?
fun testLStar(x: Collection<Int>): List<Int> = x as <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>LStar<!> fun testLStar(x: Collection<Int>): List<Int> = x as <!NO_TYPE_ARGUMENTS_ON_RHS!>LStar<!>
fun testMyList(x: Collection<Int>): List<Int> = x as <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>MyList<!> fun testMyList(x: Collection<Int>): List<Int> = x as <!NO_TYPE_ARGUMENTS_ON_RHS!>MyList<!>
typealias MMTT<T> = MutableMap<T, T> typealias MMTT<T> = MutableMap<T, T>
typealias Dictionary<T> = MutableMap<String, T> typealias Dictionary<T> = MutableMap<String, T>
@@ -24,8 +24,8 @@ typealias ReadableList<T> = MutableList<out T>
fun testWrong1(x: Map<Any, Any>) = x is MMTT fun testWrong1(x: Map<Any, Any>) = x is MMTT
fun testWrong2(x: Map<Any, Any>) = x is Dictionary fun testWrong2(x: Map<Any, Any>) = x is Dictionary
fun testWrong3(x: Map<Any, Any>) = x is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>WriteableMap<!> fun testWrong3(x: Map<Any, Any>) = x is <!NO_TYPE_ARGUMENTS_ON_RHS!>WriteableMap<!>
fun testWrong4(x: List<Any>) = x is <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>ReadableList<!> fun testWrong4(x: List<Any>) = x is <!NO_TYPE_ARGUMENTS_ON_RHS!>ReadableList<!>
fun <T> testLocal(x: Any) { fun <T> testLocal(x: Any) {
class C class C
@@ -763,6 +763,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.NO_TYPE_ARGUMENTS_ON_RHS) { firDiagnostic ->
NoTypeArgumentsOnRhsImpl(
firDiagnostic.a,
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.b.fir as FirClass<*>),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.TYPE_PARAMETERS_IN_OBJECT) { firDiagnostic -> add(FirErrors.TYPE_PARAMETERS_IN_OBJECT) { firDiagnostic ->
TypeParametersInObjectImpl( TypeParametersInObjectImpl(
firDiagnostic as FirPsiDiagnostic<*>, firDiagnostic as FirPsiDiagnostic<*>,
@@ -546,6 +546,12 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val classifier: KtClassLikeSymbol abstract val classifier: KtClassLikeSymbol
} }
abstract class NoTypeArgumentsOnRhs : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = NoTypeArgumentsOnRhs::class
abstract val expectedCount: Int
abstract val classifier: KtClassLikeSymbol
}
abstract class TypeParametersInObject : KtFirDiagnostic<PsiElement>() { abstract class TypeParametersInObject : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = TypeParametersInObject::class override val diagnosticClass get() = TypeParametersInObject::class
} }
@@ -874,6 +874,15 @@ internal class WrongNumberOfTypeArgumentsImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
} }
internal class NoTypeArgumentsOnRhsImpl(
override val expectedCount: Int,
override val classifier: KtClassLikeSymbol,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.NoTypeArgumentsOnRhs(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class TypeParametersInObjectImpl( internal class TypeParametersInObjectImpl(
firDiagnostic: FirPsiDiagnostic<*>, firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken, override val token: ValidityToken,
@@ -15,10 +15,7 @@ import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertySymbol import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeOperatorAmbiguityError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeWrongNumberOfTypeArgumentsError
import org.jetbrains.kotlin.fir.resolve.symbolProvider import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
@@ -51,7 +48,7 @@ internal object FirReferenceResolveHelper {
val symbol = resolvedSymbol ?: run { val symbol = resolvedSymbol ?: run {
val diagnostic = (this as? FirErrorTypeRef)?.diagnostic val diagnostic = (this as? FirErrorTypeRef)?.diagnostic
(diagnostic as? ConeWrongNumberOfTypeArgumentsError)?.type (diagnostic as? ConeUnmatchedTypeArgumentsError)?.type
} }
return symbol?.fir?.buildSymbol(symbolBuilder) return symbol?.fir?.buildSymbol(symbolBuilder)