From c648356887a2d13ce19abceebccbee18813dcecf Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Tue, 8 Jun 2021 15:14:41 -0700 Subject: [PATCH] FIR: report ENUM_ENTRY_AS_TYPE and IS_ENUM_TYPE These two diagnostics are similar: both are reported on type references to enum entries. But `IS_ENUM_TYPE` is reported if the type ref is an operand of `is` operator. To pass along this contextual information, a boolean is added to FirSpecificTypeResolverTransformer. --- .../diagnostics/FirDiagnosticsList.kt | 2 + .../fir/analysis/diagnostics/FirErrors.kt | 2 + .../diagnostics/FirDefaultErrorMessages.kt | 4 ++ .../coneDiagnosticToFirDiagnostic.kt | 2 + .../kotlin/fir/resolve/FirTypeResolver.kt | 2 +- .../providers/impl/FirTypeResolverImpl.kt | 67 ++++++++++++++++--- .../FirSpecificTypeResolverTransformer.kt | 18 ++++- .../FirExpressionsResolveTransformer.kt | 8 ++- .../fir/diagnostics/ConeSimpleDiagnostic.kt | 3 + .../diagnostics/tests/EnumEntryAsType.fir.kt | 44 ++++++------ .../diagnostics/tests/enum/ifEnumEntry.fir.kt | 2 +- .../tests/enum/inheritFromEnumEntry.fir.kt | 2 +- .../diagnostics/tests/enum/isEnumEntry.fir.kt | 2 +- .../tests/when/ExhaustiveEnumIs.fir.kt | 6 +- .../tests/when/ExhaustiveEnumMixed.fir.kt | 4 +- .../diagnostics/KtFirDataClassConverters.kt | 12 ++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 8 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 14 ++++ 18 files changed, 157 insertions(+), 45 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 ec238c9b18d..9a852cb09c1 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 @@ -966,6 +966,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val USELESS_IS_CHECK by warning { parameter("compileTimeCheckResult") } + val IS_ENUM_ENTRY by error() + val ENUM_ENTRY_AS_TYPE by error() } val WHEN_EXPRESSIONS by object : DiagnosticGroup("When expressions") { 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 555436140d7..bd290c11ff4 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 @@ -509,6 +509,8 @@ object FirErrors { // Casts and is-checks val USELESS_CAST by warning0(SourceElementPositioningStrategies.AS_TYPE) val USELESS_IS_CHECK by warning1() + val IS_ENUM_ENTRY by error0() + val ENUM_ENTRY_AS_TYPE by error0() // When expressions val EXPECTED_CONDITION by error0() 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 9b061350621..64aa4902e2f 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 @@ -131,6 +131,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATION_ERROR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DESERIALIZATION_ERROR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DYNAMIC_UPPER_BOUND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EMPTY_RANGE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ENUM_ENTRY_AS_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPLICABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPLICABLE_WARNING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_RESOLUTION @@ -223,6 +224,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_WITH_SU import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_IF_AS_EXPRESSION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_REFERENCE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IS_ENUM_ENTRY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_AMBIGUITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA @@ -1276,6 +1278,8 @@ class FirDefaultErrorMessages { // Casts and is-checks map.put(USELESS_CAST, "No cast needed") map.put(USELESS_IS_CHECK, "Check for instance is always ''{0}''", TO_STRING) + map.put(IS_ENUM_ENTRY, "'is' over enum entry is not allowed, use comparison instead") + map.put(ENUM_ENTRY_AS_TYPE, "Use of enum entry names as types is not allowed, use enum type instead") // When expressions map.put(EXPECTED_CONDITION, "Expected condition of type Boolean") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index d93c6c78f06..39be7eeddfa 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -359,6 +359,8 @@ private fun ConeSimpleDiagnostic.getFactory(source: FirSourceElement): FirDiagno DiagnosticKind.RecursiveTypealiasExpansion -> FirErrors.RECURSIVE_TYPEALIAS_EXPANSION DiagnosticKind.LoopInSupertype -> FirErrors.CYCLIC_INHERITANCE_HIERARCHY DiagnosticKind.IllegalSelector -> FirErrors.ILLEGAL_SELECTOR + DiagnosticKind.IsEnumEntry -> FirErrors.IS_ENUM_ENTRY + DiagnosticKind.EnumEntryAsType -> FirErrors.ENUM_ENTRY_AS_TYPE DiagnosticKind.UnresolvedSupertype, DiagnosticKind.UnresolvedExpandedType, DiagnosticKind.Other -> FirErrors.OTHER_ERROR diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt index 0ee7432c7e4..2591295dc25 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt @@ -11,5 +11,5 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirTypeRef abstract class FirTypeResolver : FirSessionComponent { - abstract fun resolveType(typeRef: FirTypeRef, scopeClassDeclaration: ScopeClassDeclaration, areBareTypesAllowed: Boolean): ConeKotlinType + abstract fun resolveType(typeRef: FirTypeRef, scopeClassDeclaration: ScopeClassDeclaration, areBareTypesAllowed: Boolean, isOperandOfIsOperator: Boolean): ConeKotlinType } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt index 82561a26e0a..d5e715c2f34 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt @@ -6,11 +6,18 @@ package org.jetbrains.kotlin.fir.resolve.providers.impl import org.jetbrains.kotlin.builtins.StandardNames -import org.jetbrains.kotlin.fir.* -import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.FirSourceElement +import org.jetbrains.kotlin.fir.ThreadSafeMutableState +import org.jetbrains.kotlin.fir.declarations.FirEnumEntry +import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef import org.jetbrains.kotlin.fir.declarations.utils.classId +import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass +import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeUnexpectedTypeArgumentsError +import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind +import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeOuterClassArgumentsRequired import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedQualifierError @@ -20,6 +27,8 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.transformers.ScopeClassDeclaration import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl @@ -49,7 +58,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { private fun resolveToSymbol( typeRef: FirTypeRef, scope: FirScope, - ): Pair?, ConeSubstitutor?> { + ): Pair?, ConeSubstitutor?> { return when (typeRef) { is FirResolvedTypeRef -> { val resultSymbol = typeRef.coneTypeSafe()?.lookupTag?.let(symbolProvider::getSymbolByLookupTag) @@ -58,7 +67,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { is FirUserTypeRef -> { val qualifierResolver = session.qualifierResolver - var resolvedSymbol: FirClassifierSymbol<*>? = null + var resolvedSymbol: FirBasedSymbol<*>? = null var substitutor: ConeSubstitutor? = null scope.processClassifiersByNameWithSubstitution(typeRef.qualifier.first().name) { symbol, substitutorFromScope -> if (resolvedSymbol != null) return@processClassifiersByNameWithSubstitution @@ -68,6 +77,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { symbol } else { qualifierResolver.resolveSymbolWithPrefix(typeRef.qualifier, symbol.classId) + ?: qualifierResolver.resolveEnumEntrySymbol(typeRef.qualifier, symbol.classId) } } is FirTypeParameterSymbol -> { @@ -80,7 +90,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { } // TODO: Imports - val resultSymbol: FirClassifierSymbol<*>? = resolvedSymbol ?: qualifierResolver.resolveSymbol(typeRef.qualifier) + val resultSymbol: FirBasedSymbol<*>? = resolvedSymbol ?: qualifierResolver.resolveSymbol(typeRef.qualifier) resultSymbol to substitutor } @@ -92,15 +102,40 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { } } + @OptIn(SymbolInternals::class) + private fun FirQualifierResolver.resolveEnumEntrySymbol( + qualifier: List, + classId: ClassId + ): FirVariableSymbol? { + // Assuming the current qualifier refers to an enum entry, we drop the last part so we get a reference to the enum class. + val enumClassSymbol = resolveSymbolWithPrefix(qualifier.dropLast(1), classId) ?: return null + val enumClassFir = enumClassSymbol.fir as? FirRegularClass ?: return null + if (!enumClassFir.isEnumClass) return null + val enumEntryMatchingLastQualifier = enumClassFir.declarations + .firstOrNull { it is FirEnumEntry && it.name == qualifier.last().name } as? FirEnumEntry + return enumEntryMatchingLastQualifier?.symbol + } + + @OptIn(SymbolInternals::class) private fun resolveUserType( typeRef: FirUserTypeRef, - symbol: FirClassifierSymbol<*>?, + symbol: FirBasedSymbol<*>?, substitutor: ConeSubstitutor?, areBareTypesAllowed: Boolean, - topDeclaration: FirRegularClass? + topDeclaration: FirRegularClass?, + isOperandOfIsOperator: Boolean ): ConeKotlinType { - if (symbol == null) { - return ConeKotlinErrorType(ConeUnresolvedQualifierError(typeRef.render())) + if (symbol == null || symbol !is FirClassifierSymbol<*>) { + val diagnostic = if (symbol?.fir is FirEnumEntry) { + if (isOperandOfIsOperator) { + ConeSimpleDiagnostic("'is' operator can not be applied to an enum entry.", DiagnosticKind.IsEnumEntry) + } else { + ConeSimpleDiagnostic("An enum entry should not be used as a type.", DiagnosticKind.EnumEntryAsType) + } + } else { + ConeUnresolvedQualifierError(typeRef.render()) + } + return ConeKotlinErrorType(diagnostic) } if (symbol is FirTypeParameterSymbol) { for (part in typeRef.qualifier) { @@ -191,6 +226,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { } } + @OptIn(SymbolInternals::class) private fun getClassesAlignedToQualifierParts( symbol: FirRegularClassSymbol, qualifier: List, @@ -243,6 +279,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { val index: Int ) + @OptIn(SymbolInternals::class) private fun createDiagnosticsIfExists( parameterClass: FirRegularClass?, qualifierPartIndex: Int, @@ -314,13 +351,21 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { override fun resolveType( typeRef: FirTypeRef, scopeClassDeclaration: ScopeClassDeclaration, - areBareTypesAllowed: Boolean + areBareTypesAllowed: Boolean, + isOperandOfIsOperator: Boolean ): ConeKotlinType { return when (typeRef) { is FirResolvedTypeRef -> typeRef.type is FirUserTypeRef -> { val (symbol, substitutor) = resolveToSymbol(typeRef, scopeClassDeclaration.scope) - resolveUserType(typeRef, symbol, substitutor, areBareTypesAllowed, scopeClassDeclaration.topDeclaration) + resolveUserType( + typeRef, + symbol, + substitutor, + areBareTypesAllowed, + scopeClassDeclaration.topDeclaration, + isOperandOfIsOperator + ) } is FirFunctionTypeRef -> createFunctionalType(typeRef) is FirDynamicTypeRef -> ConeKotlinErrorType(ConeUnsupportedDynamicType()) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt index 80a20de6481..f4d7446faf0 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt @@ -36,6 +36,20 @@ class FirSpecificTypeResolverTransformer( } } + @set:PrivateForInline + var isOperandOfIsOperator: Boolean = false + + @OptIn(PrivateForInline::class) + inline fun withIsOperandOfIsOperator(block: () -> R): R { + val oldValue = isOperandOfIsOperator + isOperandOfIsOperator = true + return try { + block() + } finally { + isOperandOfIsOperator = oldValue + } + } + @PrivateForInline @JvmField var currentFile: FirFile? = null @@ -55,7 +69,7 @@ class FirSpecificTypeResolverTransformer( override fun transformTypeRef(typeRef: FirTypeRef, data: ScopeClassDeclaration): FirResolvedTypeRef { session.lookupTracker?.recordTypeLookup(typeRef, data.scope.scopeOwnerLookupNames, currentFile?.source) typeRef.transformChildren(this, data) - return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed)) + return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed, isOperandOfIsOperator)) } @OptIn(PrivateForInline::class) @@ -65,7 +79,7 @@ class FirSpecificTypeResolverTransformer( ): FirResolvedTypeRef { functionTypeRef.transformChildren(this, data) session.lookupTracker?.recordTypeLookup(functionTypeRef, data.scope.scopeOwnerLookupNames, currentFile?.source) - val resolvedType = typeResolver.resolveType(functionTypeRef, data, areBareTypesAllowed).takeIfAcceptable() + val resolvedType = typeResolver.resolveType(functionTypeRef, data, areBareTypesAllowed, isOperandOfIsOperator).takeIfAcceptable() return if (resolvedType != null && resolvedType !is ConeClassErrorType) { buildResolvedTypeRef { source = functionTypeRef.source diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 826d43eb920..d9d8ea483b3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -606,7 +606,13 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform data: ResolutionMode, ): FirStatement { val resolved = components.typeResolverTransformer.withAllowedBareTypes { - typeOperatorCall.transformConversionTypeRef(transformer, ResolutionMode.ContextIndependent) + if (typeOperatorCall.operation == FirOperation.IS || typeOperatorCall.operation == FirOperation.NOT_IS) { + components.typeResolverTransformer.withIsOperandOfIsOperator { + typeOperatorCall.transformConversionTypeRef(transformer, ResolutionMode.ContextIndependent) + } + } else { + typeOperatorCall.transformConversionTypeRef(transformer, ResolutionMode.ContextIndependent) + } }.transformTypeOperatorCallChildren() val conversionTypeRef = resolved.conversionTypeRef.withTypeArgumentsForBareType(resolved.argument) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt index 47fc5db73c3..080e59f1866 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt @@ -48,5 +48,8 @@ enum class DiagnosticKind { FloatLiteralOutOfRange, WrongLongSuffix, + IsEnumEntry, + EnumEntryAsType, + Other, } diff --git a/compiler/testData/diagnostics/tests/EnumEntryAsType.fir.kt b/compiler/testData/diagnostics/tests/EnumEntryAsType.fir.kt index cdcb8f3dce9..f5d3ac33d74 100644 --- a/compiler/testData/diagnostics/tests/EnumEntryAsType.fir.kt +++ b/compiler/testData/diagnostics/tests/EnumEntryAsType.fir.kt @@ -6,49 +6,49 @@ enum class Color { } } -class MyColor(val x: Color.RED, y: Color.RED) : Color.RED { +class MyColor(val x: Color.RED, y: Color.RED) : Color.RED { - var z: Color.RED = Color.RED - set(arg: Color.RED) { z = arg } + var z: Color.RED = Color.RED + set(arg: Color.RED) { z = arg } - fun foo(arg: Color.RED): Color.RED = arg + fun foo(arg: Color.RED): Color.RED = arg - fun bar(): Color.RED { - class Local : Color.RED - fun local(arg: Color.RED): Color.RED = arg - val temp: Color.RED = Color.RED - temp as? Color.RED - if (temp is Color.RED) { - return temp as Color.RED + fun bar(): Color.RED { + class Local : Color.RED + fun local(arg: Color.RED): Color.RED = arg + val temp: Color.RED = Color.RED + temp as? Color.RED + if (temp is Color.RED) { + return temp as Color.RED } - val obj = object : Color.RED {} - if (obj is Color.RED) { + val obj = object : Color.RED {} + if (obj is Color.RED) { return obj } return Color.RED } } -fun create(): Array<Color.RED>? = null +fun create(): Array<Color.RED>? = null -interface YourColor.RED> +interface YourColor.RED> -class His : Your<Color.RED> +class His : Your<Color.RED> -fun Color.RED> otherCreate(): Array? = null +fun Color.RED> otherCreate(): Array? = null -typealias RedAlias = Color.RED +typealias RedAlias = Color.RED -typealias ArrayOfEnumEntry = Array<Color.RED> +typealias ArrayOfEnumEntry = Array<Color.RED> typealias ArrayOfEnumEntryAlias = Array fun bar(a: Any): T = a as T fun foo() { - foo<Color.RED>() + foo<Color.RED>() foo<RedAlias>() - bar<Color.RED>(Color.RED) + bar<Color.RED>(Color.RED) } -fun Array<Color.RED>.foo(entries: Array<Color.RED>): Array<Color.RED> = null!! +fun Array<Color.RED>.foo(entries: Array<Color.RED>): Array<Color.RED> = null!! diff --git a/compiler/testData/diagnostics/tests/enum/ifEnumEntry.fir.kt b/compiler/testData/diagnostics/tests/enum/ifEnumEntry.fir.kt index 9da746b15a6..11c88c24595 100644 --- a/compiler/testData/diagnostics/tests/enum/ifEnumEntry.fir.kt +++ b/compiler/testData/diagnostics/tests/enum/ifEnumEntry.fir.kt @@ -3,4 +3,4 @@ enum class MyEnum { SECOND } -fun foo(me: MyEnum): Boolean = if (me is MyEnum.FIRST) true else false \ No newline at end of file +fun foo(me: MyEnum): Boolean = if (me is MyEnum.FIRST) true else false diff --git a/compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.fir.kt b/compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.fir.kt index 0e35087a78f..f5634e0fe77 100644 --- a/compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.fir.kt +++ b/compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.fir.kt @@ -2,4 +2,4 @@ enum class E { ENTRY } -class A : E.ENTRY +class A : E.ENTRY diff --git a/compiler/testData/diagnostics/tests/enum/isEnumEntry.fir.kt b/compiler/testData/diagnostics/tests/enum/isEnumEntry.fir.kt index c7c7fc3e4cc..fd43def1054 100644 --- a/compiler/testData/diagnostics/tests/enum/isEnumEntry.fir.kt +++ b/compiler/testData/diagnostics/tests/enum/isEnumEntry.fir.kt @@ -3,4 +3,4 @@ enum class MyEnum { SECOND } -fun foo(me: MyEnum): Boolean = me is MyEnum.FIRST \ No newline at end of file +fun foo(me: MyEnum): Boolean = me is MyEnum.FIRST diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveEnumIs.fir.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveEnumIs.fir.kt index 398609150ba..3b9bd445bb6 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveEnumIs.fir.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveEnumIs.fir.kt @@ -13,8 +13,8 @@ enum class MyEnum { fun foo(x: MyEnum): Int { return when (x) { - is MyEnum.A -> 1 - is MyEnum.B -> 2 - is MyEnum.C -> 3 + is MyEnum.A -> 1 + is MyEnum.B -> 2 + is MyEnum.C -> 3 } } diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveEnumMixed.fir.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveEnumMixed.fir.kt index aaea91337b6..73104e1b758 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveEnumMixed.fir.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveEnumMixed.fir.kt @@ -15,7 +15,7 @@ enum class MyEnum { fun foo(x: MyEnum): Int { return when (x) { MyEnum.A -> 1 - is MyEnum.B -> 2 - is MyEnum.C -> 3 + is MyEnum.B -> 2 + is MyEnum.C -> 3 } } 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 7f6b0eca5c3..057f335888d 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 @@ -2616,6 +2616,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.IS_ENUM_ENTRY) { firDiagnostic -> + IsEnumEntryImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.ENUM_ENTRY_AS_TYPE) { firDiagnostic -> + EnumEntryAsTypeImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.EXPECTED_CONDITION) { firDiagnostic -> ExpectedConditionImpl( 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 2b566977971..76ecec8d595 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 @@ -1834,6 +1834,14 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val compileTimeCheckResult: Boolean } + abstract class IsEnumEntry : KtFirDiagnostic() { + override val diagnosticClass get() = IsEnumEntry::class + } + + abstract class EnumEntryAsType : KtFirDiagnostic() { + override val diagnosticClass get() = EnumEntryAsType::class + } + abstract class ExpectedCondition : KtFirDiagnostic() { override val diagnosticClass get() = ExpectedCondition::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 19909812e85..67338879666 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 @@ -2954,6 +2954,20 @@ internal class UselessIsCheckImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class IsEnumEntryImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.IsEnumEntry(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class EnumEntryAsTypeImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.EnumEntryAsType(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class ExpectedConditionImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,