FIR checker: report type parameters on anonymous objects

This commit is contained in:
Tianyu Geng
2021-07-22 16:54:25 -07:00
committed by TeamCityServer
parent 4d9102f749
commit a18daa5d62
10 changed files with 58 additions and 19 deletions
@@ -500,6 +500,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirRegularClassSymbol>("outer")
}
val TYPE_PARAMETERS_IN_OBJECT by error<PsiElement>(PositioningStrategy.TYPE_PARAMETERS_LIST)
val TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT by error<PsiElement>(PositioningStrategy.TYPE_PARAMETERS_LIST)
val ILLEGAL_PROJECTION_USAGE by error<PsiElement>()
val TYPE_PARAMETERS_IN_ENUM by error<PsiElement>()
val CONFLICTING_PROJECTION by error<KtTypeProjection>(PositioningStrategy.VARIANCE_MODIFIER) {
@@ -333,6 +333,7 @@ object FirErrors {
val NO_TYPE_ARGUMENTS_ON_RHS by error2<PsiElement, Int, FirClassLikeSymbol<*>>()
val OUTER_CLASS_ARGUMENTS_REQUIRED by error1<PsiElement, FirRegularClassSymbol>()
val TYPE_PARAMETERS_IN_OBJECT by error0<PsiElement>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT by error0<PsiElement>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val ILLEGAL_PROJECTION_USAGE by error0<PsiElement>()
val TYPE_PARAMETERS_IN_ENUM by error0<PsiElement>()
val CONFLICTING_PROJECTION by error1<KtTypeProjection, ConeKotlinType>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
@@ -72,6 +72,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirMemberFunctionsChecker,
FirMemberPropertiesChecker,
FirImplementationMismatchChecker,
FirTypeParametersInObjectChecker,
)
override val regularClassCheckers: Set<FirRegularClassChecker>
@@ -89,7 +90,6 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirMethodOfAnyImplementedInInterfaceChecker,
FirDataClassPrimaryConstructorChecker,
FirPrimaryConstructorSuperTypeChecker,
FirTypeParametersInObjectChecker,
FirFunInterfaceDeclarationChecker,
FirNestedClassChecker,
FirInlineClassDeclarationChecker,
@@ -5,21 +5,38 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.languageVersionSettings
object FirTypeParametersInObjectChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
object FirTypeParametersInObjectChecker : FirClassChecker() {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.classKind != ClassKind.OBJECT) {
return
}
if (declaration.typeParameters.isNotEmpty()) {
reporter.reportOn(declaration.source, FirErrors.TYPE_PARAMETERS_IN_OBJECT, context)
when (declaration) {
is FirRegularClass -> if (declaration.typeParameters.isNotEmpty()) {
reporter.reportOn(declaration.source, FirErrors.TYPE_PARAMETERS_IN_OBJECT, context)
}
is FirAnonymousObject -> if (declaration.source?.getChild(KtNodeTypes.TYPE_PARAMETER_LIST, depth = 1) != null) {
val diagnosticFactory =
if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitTypeParametersInAnonymousObjects)) {
FirErrors.TYPE_PARAMETERS_IN_OBJECT
} else {
FirErrors.TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT
}
reporter.reportOn(declaration.source, diagnosticFactory, context)
}
}
}
}
@@ -406,6 +406,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_NO
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_CANT_BE_USED_FOR_CONST_VAL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_ENUM
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_NOT_ALLOWED
@@ -825,6 +826,8 @@ class FirDefaultErrorMessages {
RENDER_CLASS_OR_OBJECT_NAME
)
map.put(TYPE_PARAMETERS_IN_OBJECT, "Type parameters are not allowed for objects")
map.put(TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT, "Type parameters for anonymous objects are deprecated")
// map.put(ILLEGAL_PROJECTION_USAGE, ...) // &
map.put(TYPE_PARAMETERS_IN_ENUM, "Enum class cannot have type parameters")
map.put(
@@ -3,23 +3,23 @@
// ISSUE: KT-28999
fun case_1() {
val x = object<T> { } // type of x is <anonymous object><T>
val x = object<!TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT!><T><!> { } // type of x is <anonymous object><T>
}
fun case_2() {
val x = object<T : Number, K: Comparable<K>> { }
val x = object<!TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT!><T : Number, K: Comparable<K>><!> { }
}
fun case_3() {
val x = object<T> <!SYNTAX!>where T : Comparable<T><!> { } // ERROR: Where clause is not allowed for objects
val x = object<!TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT!><T><!> <!SYNTAX!>where T : Comparable<T><!> { } // ERROR: Where clause is not allowed for objects
}
val x = object<T, K: Comparable<K>> {
val x = object<!TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT!><T, K: Comparable<K>><!> {
fun test() = 10 as <!UNRESOLVED_REFERENCE!>T<!> // OK
}
fun case_4() {
val x = object<T> {
val x = object<!TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT!><T><!> {
fun test() = 10 as <!UNRESOLVED_REFERENCE!>T<!>
}
@@ -27,7 +27,7 @@ fun case_4() {
}
inline fun <reified T> case_5() {
val x = object<T> {
val x = object<!TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT!><T><!> {
fun test() = 10 as T
}
@@ -38,7 +38,7 @@ inline fun <reified T> case_5() {
<!UNRESOLVED_REFERENCE!>println<!>(z)
}
val a = object<A> {
val a = object<!TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT!><A><!> {
fun test() = 42 as <!UNRESOLVED_REFERENCE!>A<!>
}
@@ -3,23 +3,23 @@
// ISSUE: KT-28999
fun case_1() {
val x = object<T> { } // type of x is <anonymous object><T>
val x = object<!TYPE_PARAMETERS_IN_OBJECT!><T><!> { } // type of x is <anonymous object><T>
}
fun case_2() {
val x = object<T : Number, K: Comparable<K>> { }
val x = object<!TYPE_PARAMETERS_IN_OBJECT!><T : Number, K: Comparable<K>><!> { }
}
fun case_3() {
val x = object<T> <!SYNTAX!>where T : Comparable<T><!> { } // ERROR: Where clause is not allowed for objects
val x = object<!TYPE_PARAMETERS_IN_OBJECT!><T><!> <!SYNTAX!>where T : Comparable<T><!> { } // ERROR: Where clause is not allowed for objects
}
val x = object<T, K: Comparable<K>> {
val x = object<!TYPE_PARAMETERS_IN_OBJECT!><T, K: Comparable<K>><!> {
fun test() = 10 as <!UNRESOLVED_REFERENCE!>T<!> // OK
}
fun case_4() {
val x = object<T> {
val x = object<!TYPE_PARAMETERS_IN_OBJECT!><T><!> {
fun test() = 10 as <!UNRESOLVED_REFERENCE!>T<!>
}
@@ -27,7 +27,7 @@ fun case_4() {
}
inline fun <reified T> case_5() {
val x = object<T> {
val x = object<!TYPE_PARAMETERS_IN_OBJECT!><T><!> {
fun test() = 10 as T
}
@@ -38,7 +38,7 @@ inline fun <reified T> case_5() {
<!UNRESOLVED_REFERENCE!>println<!>(z)
}
val a = object<A> {
val a = object<!TYPE_PARAMETERS_IN_OBJECT!><A><!> {
fun test() = 42 as <!UNRESOLVED_REFERENCE!>A<!>
}
@@ -1486,6 +1486,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT) { firDiagnostic ->
TypeParametersInAnonymousObjectImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.ILLEGAL_PROJECTION_USAGE) { firDiagnostic ->
IllegalProjectionUsageImpl(
firDiagnostic as FirPsiDiagnostic,
@@ -1057,6 +1057,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = TypeParametersInObject::class
}
abstract class TypeParametersInAnonymousObject : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = TypeParametersInAnonymousObject::class
}
abstract class IllegalProjectionUsage : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = IllegalProjectionUsage::class
}
@@ -1691,6 +1691,13 @@ internal class TypeParametersInObjectImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class TypeParametersInAnonymousObjectImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.TypeParametersInAnonymousObject(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class IllegalProjectionUsageImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,