FIR checker: report TYPE_PARAMETER_AS_REIFIED

This commit is contained in:
Jinseong Jeon
2021-03-04 23:48:47 -08:00
committed by Mikhail Glukhikh
parent 5ba5b63dee
commit e29b40b07f
10 changed files with 48 additions and 6 deletions
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.checkers.generator.diagnostics
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiTypeElement
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
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.FirClass
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.symbols.AbstractFirBasedSymbol
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.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.types.KotlinType
@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 GENERIC_THROWABLE_SUBCLASS by error<FirSourceElement, KtTypeParameterList>()
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") {
@@ -193,6 +193,7 @@ object FirErrors {
val TYPE_PARAMETER_IN_CATCH_CLAUSE by error0<FirSourceElement, PsiElement>()
val GENERIC_THROWABLE_SUBCLASS by error0<FirSourceElement, KtTypeParameterList>()
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
val CALLABLE_REFERENCE_LHS_NOT_A_CLASS by error0<FirSourceElement, KtExpression>()
@@ -53,6 +53,13 @@ object FirGetClassCallChecker : FirBasicExpressionChecker() {
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
// TODO: differentiate RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS
if (argument.typeArguments.isNotEmpty() && !argument.typeRef.coneType.isAllowedInClassLiteral(context)) {
@@ -71,8 +78,14 @@ object FirGetClassCallChecker : FirBasicExpressionChecker() {
get() {
return this is FirResolvedQualifier ||
this is FirResolvedReifiedParameterReference ||
((this is FirQualifiedAccessExpression) &&
(this.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol is FirTypeParameterSymbol)
safeAsTypeParameterSymbol != null
}
private val FirExpression.safeAsTypeParameterSymbol: FirTypeParameterSymbol?
get() {
return ((this as? FirQualifiedAccessExpression)
?.calleeReference as? FirResolvedNamedReference)
?.resolvedSymbol as? FirTypeParameterSymbol
}
private fun ConeKotlinType.isAllowedInClassLiteral(context: CheckerContext): Boolean =
@@ -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_PARAMETERS_IN_ENUM
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_IN_CATCH_CLAUSE
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(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
map.put(CALLABLE_REFERENCE_LHS_NOT_A_CLASS, "Left-hand side of a callable reference cannot be a type parameter")
@@ -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.FirClassLikeSymbol
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.render
@@ -27,6 +28,7 @@ object FirDiagnosticRenderers {
when (symbol) {
is FirClassLikeSymbol<*> -> symbol.classId.asString()
is FirCallableSymbol<*> -> symbol.callableId.toString()
is FirTypeParameterSymbol -> symbol.name.asString()
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<!>
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<!>
}
@@ -1,3 +1,3 @@
fun <T: Any> dereferenceClass(): Any =
<!OTHER_ERROR!>T<!>::class
<!TYPE_PARAMETER_AS_REIFIED!><!TYPE_PARAMETER_IS_NOT_AN_EXPRESSION!>T<!>::class<!>
@@ -797,6 +797,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
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 ->
CallableReferenceLhsNotAClassImpl(
firDiagnostic as FirPsiDiagnostic<*>,
@@ -564,6 +564,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
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>() {
override val diagnosticClass get() = CallableReferenceLhsNotAClass::class
}
@@ -913,6 +913,14 @@ internal class InnerClassOfGenericThrowableSubclassImpl(
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(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,