From e29b40b07f2e6057e72e5ecc4f6ef104cf0e2b39 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Thu, 4 Mar 2021 23:48:47 -0800 Subject: [PATCH] FIR checker: report TYPE_PARAMETER_AS_REIFIED --- .../generator/diagnostics/FirDiagnosticsList.kt | 7 +++++-- .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../expression/FirGetClassCallChecker.kt | 17 +++++++++++++++-- .../diagnostics/FirDefaultErrorMessages.kt | 3 +++ .../diagnostics/FirDiagnosticRenderers.kt | 2 ++ .../tests/classLiteral/nonClassesOnLHS.fir.kt | 2 +- .../tpAsReified/ClassDereference.fir.kt | 2 +- .../fir/diagnostics/KtFirDataClassConverters.kt | 7 +++++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 5 +++++ .../api/fir/diagnostics/KtFirDiagnosticsImpl.kt | 8 ++++++++ 10 files changed, 48 insertions(+), 6 deletions(-) diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 65a866d5d9b..3222510871e 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -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() val GENERIC_THROWABLE_SUBCLASS by error() val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error(PositioningStrategy.DECLARATION_NAME) + + val TYPE_PARAMETER_AS_REIFIED by error { + parameter("typeParameter") + } } val REFLECTION by object : DiagnosticGroup("Reflection") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index a1b0a6ca2f9..155106e13f4 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -193,6 +193,7 @@ object FirErrors { val TYPE_PARAMETER_IN_CATCH_CLAUSE by error0() val GENERIC_THROWABLE_SUBCLASS by error0() val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error0(SourceElementPositioningStrategies.DECLARATION_NAME) + val TYPE_PARAMETER_AS_REIFIED by error1() // Reflection val CALLABLE_REFERENCE_LHS_NOT_A_CLASS by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirGetClassCallChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirGetClassCallChecker.kt index 1520463a7e4..942f29bc384 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirGetClassCallChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirGetClassCallChecker.kt @@ -53,6 +53,13 @@ object FirGetClassCallChecker : FirBasicExpressionChecker() { return } + argument.safeAsTypeParameterSymbol?.let { + if (!it.fir.isReified) { + // E.g., fun 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 = diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 4d68c77f69b..11402f0ce34 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -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") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt index 744030776be..858c77573bb 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt @@ -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 -> "???" } } diff --git a/compiler/testData/diagnostics/tests/classLiteral/nonClassesOnLHS.fir.kt b/compiler/testData/diagnostics/tests/classLiteral/nonClassesOnLHS.fir.kt index f3f2fa1aed4..ac672488338 100644 --- a/compiler/testData/diagnostics/tests/classLiteral/nonClassesOnLHS.fir.kt +++ b/compiler/testData/diagnostics/tests/classLiteral/nonClassesOnLHS.fir.kt @@ -9,7 +9,7 @@ val l1 = List?::class val l2 = List?::class fun foo() { - val t1 = T::class + val t1 = T::class val t2 = T?::class } diff --git a/compiler/testData/diagnostics/tests/generics/tpAsReified/ClassDereference.fir.kt b/compiler/testData/diagnostics/tests/generics/tpAsReified/ClassDereference.fir.kt index 758753b3116..64ad9a91d37 100644 --- a/compiler/testData/diagnostics/tests/generics/tpAsReified/ClassDereference.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/tpAsReified/ClassDereference.fir.kt @@ -1,3 +1,3 @@ fun dereferenceClass(): Any = - T::class + T::class diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 1df7c00ddb1..5a02d7cf4c0 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -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<*>, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index e781743719d..2bc4ba84cdb 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -564,6 +564,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = InnerClassOfGenericThrowableSubclass::class } + abstract class TypeParameterAsReified : KtFirDiagnostic() { + override val diagnosticClass get() = TypeParameterAsReified::class + abstract val typeParameter: KtTypeParameterSymbol + } + abstract class CallableReferenceLhsNotAClass : KtFirDiagnostic() { override val diagnosticClass get() = CallableReferenceLhsNotAClass::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 22c9f401f10..89b750c0d8d 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -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 { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class CallableReferenceLhsNotAClassImpl( firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken,