FIR checker: report TYPE_PARAMETER_AS_REIFIED
This commit is contained in:
committed by
Mikhail Glukhikh
parent
5ba5b63dee
commit
e29b40b07f
+5
-2
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.checkers.generator.diagnostics
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiTypeElement
|
import com.intellij.psi.PsiTypeElement
|
||||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||||
@@ -18,6 +17,7 @@ import org.jetbrains.kotlin.fir.PrivateForInline
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
|||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
|
|
||||||
|
|
||||||
@Suppress("UNUSED_VARIABLE", "LocalVariableName", "ClassName", "unused")
|
@Suppress("UNUSED_VARIABLE", "LocalVariableName", "ClassName", "unused")
|
||||||
@@ -247,6 +246,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
|||||||
val TYPE_PARAMETER_IN_CATCH_CLAUSE by error<FirSourceElement, PsiElement>()
|
val TYPE_PARAMETER_IN_CATCH_CLAUSE by error<FirSourceElement, PsiElement>()
|
||||||
val GENERIC_THROWABLE_SUBCLASS by error<FirSourceElement, KtTypeParameterList>()
|
val GENERIC_THROWABLE_SUBCLASS by error<FirSourceElement, KtTypeParameterList>()
|
||||||
val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error<FirSourceElement, KtClassOrObject>(PositioningStrategy.DECLARATION_NAME)
|
val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error<FirSourceElement, KtClassOrObject>(PositioningStrategy.DECLARATION_NAME)
|
||||||
|
|
||||||
|
val TYPE_PARAMETER_AS_REIFIED by error<FirSourceElement, PsiElement> {
|
||||||
|
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ object FirErrors {
|
|||||||
val TYPE_PARAMETER_IN_CATCH_CLAUSE by error0<FirSourceElement, PsiElement>()
|
val TYPE_PARAMETER_IN_CATCH_CLAUSE by error0<FirSourceElement, PsiElement>()
|
||||||
val GENERIC_THROWABLE_SUBCLASS by error0<FirSourceElement, KtTypeParameterList>()
|
val GENERIC_THROWABLE_SUBCLASS by error0<FirSourceElement, KtTypeParameterList>()
|
||||||
val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error0<FirSourceElement, KtClassOrObject>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error0<FirSourceElement, KtClassOrObject>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||||
|
val TYPE_PARAMETER_AS_REIFIED by error1<FirSourceElement, PsiElement, FirTypeParameterSymbol>()
|
||||||
|
|
||||||
// Reflection
|
// Reflection
|
||||||
val CALLABLE_REFERENCE_LHS_NOT_A_CLASS by error0<FirSourceElement, KtExpression>()
|
val CALLABLE_REFERENCE_LHS_NOT_A_CLASS by error0<FirSourceElement, KtExpression>()
|
||||||
|
|||||||
+15
-2
@@ -53,6 +53,13 @@ object FirGetClassCallChecker : FirBasicExpressionChecker() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
argument.safeAsTypeParameterSymbol?.let {
|
||||||
|
if (!it.fir.isReified) {
|
||||||
|
// E.g., fun <T: Any> foo(): Any = T::class
|
||||||
|
reporter.reportOn(source, FirErrors.TYPE_PARAMETER_AS_REIFIED, it, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (argument !is FirResolvedQualifier) return
|
if (argument !is FirResolvedQualifier) return
|
||||||
// TODO: differentiate RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS
|
// TODO: differentiate RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS
|
||||||
if (argument.typeArguments.isNotEmpty() && !argument.typeRef.coneType.isAllowedInClassLiteral(context)) {
|
if (argument.typeArguments.isNotEmpty() && !argument.typeRef.coneType.isAllowedInClassLiteral(context)) {
|
||||||
@@ -71,8 +78,14 @@ object FirGetClassCallChecker : FirBasicExpressionChecker() {
|
|||||||
get() {
|
get() {
|
||||||
return this is FirResolvedQualifier ||
|
return this is FirResolvedQualifier ||
|
||||||
this is FirResolvedReifiedParameterReference ||
|
this is FirResolvedReifiedParameterReference ||
|
||||||
((this is FirQualifiedAccessExpression) &&
|
safeAsTypeParameterSymbol != null
|
||||||
(this.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol is FirTypeParameterSymbol)
|
}
|
||||||
|
|
||||||
|
private val FirExpression.safeAsTypeParameterSymbol: FirTypeParameterSymbol?
|
||||||
|
get() {
|
||||||
|
return ((this as? FirQualifiedAccessExpression)
|
||||||
|
?.calleeReference as? FirResolvedNamedReference)
|
||||||
|
?.resolvedSymbol as? FirTypeParameterSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ConeKotlinType.isAllowedInClassLiteral(context: CheckerContext): Boolean =
|
private fun ConeKotlinType.isAllowedInClassLiteral(context: CheckerContext): Boolean =
|
||||||
|
|||||||
+3
@@ -185,6 +185,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_NO
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_MISMATCH
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_MISMATCH
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_ENUM
|
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_IN_OBJECT
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_REIFIED
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_SUPERTYPE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_SUPERTYPE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION
|
||||||
@@ -394,6 +395,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
|||||||
map.put(REIFIED_TYPE_IN_CATCH_CLAUSE, "Reified type is forbidden for catch parameter")
|
map.put(REIFIED_TYPE_IN_CATCH_CLAUSE, "Reified type is forbidden for catch parameter")
|
||||||
map.put(TYPE_PARAMETER_IN_CATCH_CLAUSE, "Type parameter is forbidden for catch parameter")
|
map.put(TYPE_PARAMETER_IN_CATCH_CLAUSE, "Type parameter is forbidden for catch parameter")
|
||||||
|
|
||||||
|
map.put(TYPE_PARAMETER_AS_REIFIED, "Cannot use ''{0}'' as reified type parameter. Use a class instead", SYMBOL)
|
||||||
|
|
||||||
// Reflection
|
// Reflection
|
||||||
map.put(CALLABLE_REFERENCE_LHS_NOT_A_CLASS, "Left-hand side of a callable reference cannot be a type parameter")
|
map.put(CALLABLE_REFERENCE_LHS_NOT_A_CLASS, "Left-hand side of a callable reference cannot be a type parameter")
|
||||||
|
|
||||||
|
|||||||
+2
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.render
|
import org.jetbrains.kotlin.fir.types.render
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ object FirDiagnosticRenderers {
|
|||||||
when (symbol) {
|
when (symbol) {
|
||||||
is FirClassLikeSymbol<*> -> symbol.classId.asString()
|
is FirClassLikeSymbol<*> -> symbol.classId.asString()
|
||||||
is FirCallableSymbol<*> -> symbol.callableId.toString()
|
is FirCallableSymbol<*> -> symbol.callableId.toString()
|
||||||
|
is FirTypeParameterSymbol -> symbol.name.asString()
|
||||||
else -> "???"
|
else -> "???"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ val l1 = <!NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>List<String>?::class<!>
|
|||||||
val l2 = <!NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>List?::class<!>
|
val l2 = <!NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>List?::class<!>
|
||||||
|
|
||||||
fun <T : Any> foo() {
|
fun <T : Any> foo() {
|
||||||
val t1 = <!TYPE_PARAMETER_IS_NOT_AN_EXPRESSION!>T<!>::class
|
val t1 = <!TYPE_PARAMETER_AS_REIFIED!><!TYPE_PARAMETER_IS_NOT_AN_EXPRESSION!>T<!>::class<!>
|
||||||
val t2 = <!NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!><!TYPE_PARAMETER_IS_NOT_AN_EXPRESSION!>T<!>?::class<!>
|
val t2 = <!NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!><!TYPE_PARAMETER_IS_NOT_AN_EXPRESSION!>T<!>?::class<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
|
|
||||||
fun <T: Any> dereferenceClass(): Any =
|
fun <T: Any> dereferenceClass(): Any =
|
||||||
<!OTHER_ERROR!>T<!>::class
|
<!TYPE_PARAMETER_AS_REIFIED!><!TYPE_PARAMETER_IS_NOT_AN_EXPRESSION!>T<!>::class<!>
|
||||||
|
|||||||
+7
@@ -797,6 +797,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.TYPE_PARAMETER_AS_REIFIED) { firDiagnostic ->
|
||||||
|
TypeParameterAsReifiedImpl(
|
||||||
|
firSymbolBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir as FirTypeParameter),
|
||||||
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.CALLABLE_REFERENCE_LHS_NOT_A_CLASS) { firDiagnostic ->
|
add(FirErrors.CALLABLE_REFERENCE_LHS_NOT_A_CLASS) { firDiagnostic ->
|
||||||
CallableReferenceLhsNotAClassImpl(
|
CallableReferenceLhsNotAClassImpl(
|
||||||
firDiagnostic as FirPsiDiagnostic<*>,
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
|||||||
+5
@@ -564,6 +564,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = InnerClassOfGenericThrowableSubclass::class
|
override val diagnosticClass get() = InnerClassOfGenericThrowableSubclass::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class TypeParameterAsReified : KtFirDiagnostic<PsiElement>() {
|
||||||
|
override val diagnosticClass get() = TypeParameterAsReified::class
|
||||||
|
abstract val typeParameter: KtTypeParameterSymbol
|
||||||
|
}
|
||||||
|
|
||||||
abstract class CallableReferenceLhsNotAClass : KtFirDiagnostic<KtExpression>() {
|
abstract class CallableReferenceLhsNotAClass : KtFirDiagnostic<KtExpression>() {
|
||||||
override val diagnosticClass get() = CallableReferenceLhsNotAClass::class
|
override val diagnosticClass get() = CallableReferenceLhsNotAClass::class
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -913,6 +913,14 @@ internal class InnerClassOfGenericThrowableSubclassImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class TypeParameterAsReifiedImpl(
|
||||||
|
override val typeParameter: KtTypeParameterSymbol,
|
||||||
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.TypeParameterAsReified(), KtAbstractFirDiagnostic<PsiElement> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class CallableReferenceLhsNotAClassImpl(
|
internal class CallableReferenceLhsNotAClassImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
|
|||||||
Reference in New Issue
Block a user