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.
This commit is contained in:
committed by
Mikhail Glukhikh
parent
6dc75c2e51
commit
c648356887
+2
@@ -966,6 +966,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val USELESS_IS_CHECK by warning<KtElement> {
|
||||
parameter<Boolean>("compileTimeCheckResult")
|
||||
}
|
||||
val IS_ENUM_ENTRY by error<KtTypeReference>()
|
||||
val ENUM_ENTRY_AS_TYPE by error<KtTypeReference>()
|
||||
}
|
||||
|
||||
val WHEN_EXPRESSIONS by object : DiagnosticGroup("When expressions") {
|
||||
|
||||
@@ -509,6 +509,8 @@ object FirErrors {
|
||||
// Casts and is-checks
|
||||
val USELESS_CAST by warning0<KtBinaryExpressionWithTypeRHS>(SourceElementPositioningStrategies.AS_TYPE)
|
||||
val USELESS_IS_CHECK by warning1<KtElement, Boolean>()
|
||||
val IS_ENUM_ENTRY by error0<KtTypeReference>()
|
||||
val ENUM_ENTRY_AS_TYPE by error0<KtTypeReference>()
|
||||
|
||||
// When expressions
|
||||
val EXPECTED_CONDITION by error0<KtWhenCondition>()
|
||||
|
||||
+4
@@ -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")
|
||||
|
||||
+2
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+56
-11
@@ -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<FirClassifierSymbol<*>?, ConeSubstitutor?> {
|
||||
): Pair<FirBasedSymbol<*>?, ConeSubstitutor?> {
|
||||
return when (typeRef) {
|
||||
is FirResolvedTypeRef -> {
|
||||
val resultSymbol = typeRef.coneTypeSafe<ConeLookupTagBasedType>()?.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<FirQualifierPart>,
|
||||
classId: ClassId
|
||||
): FirVariableSymbol<FirEnumEntry>? {
|
||||
// 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<FirQualifierPart>,
|
||||
@@ -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())
|
||||
|
||||
+16
-2
@@ -36,6 +36,20 @@ class FirSpecificTypeResolverTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
@set:PrivateForInline
|
||||
var isOperandOfIsOperator: Boolean = false
|
||||
|
||||
@OptIn(PrivateForInline::class)
|
||||
inline fun <R> 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
|
||||
|
||||
+7
-1
@@ -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)
|
||||
|
||||
@@ -48,5 +48,8 @@ enum class DiagnosticKind {
|
||||
FloatLiteralOutOfRange,
|
||||
WrongLongSuffix,
|
||||
|
||||
IsEnumEntry,
|
||||
EnumEntryAsType,
|
||||
|
||||
Other,
|
||||
}
|
||||
|
||||
+22
-22
@@ -6,49 +6,49 @@ enum class Color {
|
||||
}
|
||||
}
|
||||
|
||||
class MyColor(val x: <!UNRESOLVED_REFERENCE!>Color.RED<!>, y: <!UNRESOLVED_REFERENCE!>Color.RED<!>) : <!UNRESOLVED_REFERENCE!>Color.RED<!> {
|
||||
class MyColor(val x: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>, y: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>) : <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> {
|
||||
|
||||
var z: <!UNRESOLVED_REFERENCE!>Color.RED<!> = Color.RED
|
||||
set(arg: <!UNRESOLVED_REFERENCE!>Color.RED<!>) { z = arg }
|
||||
var z: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> = Color.RED
|
||||
set(arg: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>) { z = arg }
|
||||
|
||||
fun foo(arg: <!UNRESOLVED_REFERENCE!>Color.RED<!>): <!UNRESOLVED_REFERENCE!>Color.RED<!> = arg
|
||||
fun foo(arg: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>): <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> = arg
|
||||
|
||||
fun bar(): <!UNRESOLVED_REFERENCE!>Color.RED<!> {
|
||||
class Local : <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
||||
fun local(arg: <!UNRESOLVED_REFERENCE!>Color.RED<!>): <!UNRESOLVED_REFERENCE!>Color.RED<!> = arg
|
||||
val temp: <!UNRESOLVED_REFERENCE!>Color.RED<!> = Color.RED
|
||||
temp as? <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Color.RED<!>
|
||||
if (temp is <!UNRESOLVED_REFERENCE!>Color.RED<!>) {
|
||||
return temp as <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
||||
fun bar(): <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> {
|
||||
class Local : <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>
|
||||
fun local(arg: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>): <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> = arg
|
||||
val temp: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> = Color.RED
|
||||
temp as? <!ENUM_ENTRY_AS_TYPE, ENUM_ENTRY_AS_TYPE!>Color.RED<!>
|
||||
if (temp is <!IS_ENUM_ENTRY!>Color.RED<!>) {
|
||||
return temp as <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>
|
||||
}
|
||||
val obj = object : <!UNRESOLVED_REFERENCE!>Color.RED<!> {}
|
||||
if (obj is <!UNRESOLVED_REFERENCE!>Color.RED<!>) {
|
||||
val obj = object : <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> {}
|
||||
if (obj is <!IS_ENUM_ENTRY!>Color.RED<!>) {
|
||||
return obj
|
||||
}
|
||||
return Color.RED
|
||||
}
|
||||
}
|
||||
|
||||
fun create(): Array<<!UNRESOLVED_REFERENCE!>Color.RED<!>>? = null
|
||||
fun create(): Array<<!ENUM_ENTRY_AS_TYPE!>Color.RED<!>>? = null
|
||||
|
||||
interface Your<T : <!UNRESOLVED_REFERENCE!>Color.RED<!>>
|
||||
interface Your<T : <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>>
|
||||
|
||||
class His : Your<<!UNRESOLVED_REFERENCE!>Color.RED<!>>
|
||||
class His : Your<<!ENUM_ENTRY_AS_TYPE!>Color.RED<!>>
|
||||
|
||||
fun <T : <!UNRESOLVED_REFERENCE!>Color.RED<!>> otherCreate(): Array<T>? = null
|
||||
fun <T : <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>> otherCreate(): Array<T>? = null
|
||||
|
||||
typealias RedAlias = <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
||||
typealias RedAlias = <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>
|
||||
|
||||
typealias ArrayOfEnumEntry = Array<<!UNRESOLVED_REFERENCE!>Color.RED<!>>
|
||||
typealias ArrayOfEnumEntry = Array<<!ENUM_ENTRY_AS_TYPE!>Color.RED<!>>
|
||||
|
||||
typealias ArrayOfEnumEntryAlias = Array<RedAlias>
|
||||
|
||||
fun <T> bar(a: Any): T = a as T
|
||||
|
||||
fun <T> foo() {
|
||||
foo<<!UNRESOLVED_REFERENCE!>Color.RED<!>>()
|
||||
foo<<!ENUM_ENTRY_AS_TYPE!>Color.RED<!>>()
|
||||
foo<<!CANNOT_INFER_PARAMETER_TYPE!>RedAlias<!>>()
|
||||
bar<<!UNRESOLVED_REFERENCE!>Color.RED<!>>(<!ARGUMENT_TYPE_MISMATCH!>Color.RED<!>)
|
||||
bar<<!ENUM_ENTRY_AS_TYPE!>Color.RED<!>>(<!ARGUMENT_TYPE_MISMATCH!>Color.RED<!>)
|
||||
}
|
||||
|
||||
fun Array<<!UNRESOLVED_REFERENCE!>Color.RED<!>>.foo(entries: Array<<!UNRESOLVED_REFERENCE!>Color.RED<!>>): Array<<!UNRESOLVED_REFERENCE!>Color.RED<!>> = null!!
|
||||
fun Array<<!ENUM_ENTRY_AS_TYPE!>Color.RED<!>>.foo(entries: Array<<!ENUM_ENTRY_AS_TYPE!>Color.RED<!>>): Array<<!ENUM_ENTRY_AS_TYPE!>Color.RED<!>> = null!!
|
||||
|
||||
@@ -3,4 +3,4 @@ enum class MyEnum {
|
||||
SECOND
|
||||
}
|
||||
|
||||
fun foo(me: MyEnum): Boolean = if (me is <!UNRESOLVED_REFERENCE!>MyEnum.FIRST<!>) true else false
|
||||
fun foo(me: MyEnum): Boolean = if (me is <!IS_ENUM_ENTRY!>MyEnum.FIRST<!>) true else false
|
||||
|
||||
@@ -2,4 +2,4 @@ enum class E {
|
||||
ENTRY
|
||||
}
|
||||
|
||||
class A : <!UNRESOLVED_REFERENCE!>E.ENTRY<!>
|
||||
class A : <!ENUM_ENTRY_AS_TYPE!>E.ENTRY<!>
|
||||
|
||||
@@ -3,4 +3,4 @@ enum class MyEnum {
|
||||
SECOND
|
||||
}
|
||||
|
||||
fun foo(me: MyEnum): Boolean = me is <!UNRESOLVED_REFERENCE!>MyEnum.FIRST<!>
|
||||
fun foo(me: MyEnum): Boolean = me is <!IS_ENUM_ENTRY!>MyEnum.FIRST<!>
|
||||
|
||||
@@ -13,8 +13,8 @@ enum class MyEnum {
|
||||
|
||||
fun foo(x: MyEnum): Int {
|
||||
return <!NO_ELSE_IN_WHEN!>when<!> (x) {
|
||||
is <!UNRESOLVED_REFERENCE!>MyEnum.A<!> -> 1
|
||||
is <!UNRESOLVED_REFERENCE!>MyEnum.B<!> -> 2
|
||||
is <!UNRESOLVED_REFERENCE!>MyEnum.C<!> -> 3
|
||||
is <!IS_ENUM_ENTRY!>MyEnum.A<!> -> 1
|
||||
is <!IS_ENUM_ENTRY!>MyEnum.B<!> -> 2
|
||||
is <!IS_ENUM_ENTRY!>MyEnum.C<!> -> 3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ enum class MyEnum {
|
||||
fun foo(x: MyEnum): Int {
|
||||
return <!NO_ELSE_IN_WHEN!>when<!> (x) {
|
||||
MyEnum.A -> 1
|
||||
is <!UNRESOLVED_REFERENCE!>MyEnum.B<!> -> 2
|
||||
is <!UNRESOLVED_REFERENCE!>MyEnum.C<!> -> 3
|
||||
is <!IS_ENUM_ENTRY!>MyEnum.B<!> -> 2
|
||||
is <!IS_ENUM_ENTRY!>MyEnum.C<!> -> 3
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -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,
|
||||
|
||||
+8
@@ -1834,6 +1834,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val compileTimeCheckResult: Boolean
|
||||
}
|
||||
|
||||
abstract class IsEnumEntry : KtFirDiagnostic<KtTypeReference>() {
|
||||
override val diagnosticClass get() = IsEnumEntry::class
|
||||
}
|
||||
|
||||
abstract class EnumEntryAsType : KtFirDiagnostic<KtTypeReference>() {
|
||||
override val diagnosticClass get() = EnumEntryAsType::class
|
||||
}
|
||||
|
||||
abstract class ExpectedCondition : KtFirDiagnostic<KtWhenCondition>() {
|
||||
override val diagnosticClass get() = ExpectedCondition::class
|
||||
}
|
||||
|
||||
+14
@@ -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<KtTypeReference> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class EnumEntryAsTypeImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.EnumEntryAsType(), KtAbstractFirDiagnostic<KtTypeReference> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ExpectedConditionImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
|
||||
Reference in New Issue
Block a user