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> {
|
val USELESS_IS_CHECK by warning<KtElement> {
|
||||||
parameter<Boolean>("compileTimeCheckResult")
|
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") {
|
val WHEN_EXPRESSIONS by object : DiagnosticGroup("When expressions") {
|
||||||
|
|||||||
@@ -509,6 +509,8 @@ object FirErrors {
|
|||||||
// Casts and is-checks
|
// Casts and is-checks
|
||||||
val USELESS_CAST by warning0<KtBinaryExpressionWithTypeRHS>(SourceElementPositioningStrategies.AS_TYPE)
|
val USELESS_CAST by warning0<KtBinaryExpressionWithTypeRHS>(SourceElementPositioningStrategies.AS_TYPE)
|
||||||
val USELESS_IS_CHECK by warning1<KtElement, Boolean>()
|
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
|
// When expressions
|
||||||
val EXPECTED_CONDITION by error0<KtWhenCondition>()
|
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.DESERIALIZATION_ERROR
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DYNAMIC_UPPER_BOUND
|
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.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
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPLICABLE_WARNING
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPLICABLE_WARNING
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_RESOLUTION
|
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_IF_AS_EXPRESSION
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER
|
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.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.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.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA
|
||||||
@@ -1276,6 +1278,8 @@ class FirDefaultErrorMessages {
|
|||||||
// Casts and is-checks
|
// Casts and is-checks
|
||||||
map.put(USELESS_CAST, "No cast needed")
|
map.put(USELESS_CAST, "No cast needed")
|
||||||
map.put(USELESS_IS_CHECK, "Check for instance is always ''{0}''", TO_STRING)
|
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
|
// When expressions
|
||||||
map.put(EXPECTED_CONDITION, "Expected condition of type Boolean")
|
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.RecursiveTypealiasExpansion -> FirErrors.RECURSIVE_TYPEALIAS_EXPANSION
|
||||||
DiagnosticKind.LoopInSupertype -> FirErrors.CYCLIC_INHERITANCE_HIERARCHY
|
DiagnosticKind.LoopInSupertype -> FirErrors.CYCLIC_INHERITANCE_HIERARCHY
|
||||||
DiagnosticKind.IllegalSelector -> FirErrors.ILLEGAL_SELECTOR
|
DiagnosticKind.IllegalSelector -> FirErrors.ILLEGAL_SELECTOR
|
||||||
|
DiagnosticKind.IsEnumEntry -> FirErrors.IS_ENUM_ENTRY
|
||||||
|
DiagnosticKind.EnumEntryAsType -> FirErrors.ENUM_ENTRY_AS_TYPE
|
||||||
DiagnosticKind.UnresolvedSupertype,
|
DiagnosticKind.UnresolvedSupertype,
|
||||||
DiagnosticKind.UnresolvedExpandedType,
|
DiagnosticKind.UnresolvedExpandedType,
|
||||||
DiagnosticKind.Other -> FirErrors.OTHER_ERROR
|
DiagnosticKind.Other -> FirErrors.OTHER_ERROR
|
||||||
|
|||||||
@@ -11,5 +11,5 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
|||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
|
||||||
abstract class FirTypeResolver : FirSessionComponent {
|
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
|
package org.jetbrains.kotlin.fir.resolve.providers.impl
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.StandardNames
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
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.impl.FirOuterClassTypeParameterRef
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.classId
|
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.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.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeOuterClassArgumentsRequired
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeOuterClassArgumentsRequired
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedQualifierError
|
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.resolve.transformers.ScopeClassDeclaration
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
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.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
@@ -49,7 +58,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
private fun resolveToSymbol(
|
private fun resolveToSymbol(
|
||||||
typeRef: FirTypeRef,
|
typeRef: FirTypeRef,
|
||||||
scope: FirScope,
|
scope: FirScope,
|
||||||
): Pair<FirClassifierSymbol<*>?, ConeSubstitutor?> {
|
): Pair<FirBasedSymbol<*>?, ConeSubstitutor?> {
|
||||||
return when (typeRef) {
|
return when (typeRef) {
|
||||||
is FirResolvedTypeRef -> {
|
is FirResolvedTypeRef -> {
|
||||||
val resultSymbol = typeRef.coneTypeSafe<ConeLookupTagBasedType>()?.lookupTag?.let(symbolProvider::getSymbolByLookupTag)
|
val resultSymbol = typeRef.coneTypeSafe<ConeLookupTagBasedType>()?.lookupTag?.let(symbolProvider::getSymbolByLookupTag)
|
||||||
@@ -58,7 +67,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
|
|
||||||
is FirUserTypeRef -> {
|
is FirUserTypeRef -> {
|
||||||
val qualifierResolver = session.qualifierResolver
|
val qualifierResolver = session.qualifierResolver
|
||||||
var resolvedSymbol: FirClassifierSymbol<*>? = null
|
var resolvedSymbol: FirBasedSymbol<*>? = null
|
||||||
var substitutor: ConeSubstitutor? = null
|
var substitutor: ConeSubstitutor? = null
|
||||||
scope.processClassifiersByNameWithSubstitution(typeRef.qualifier.first().name) { symbol, substitutorFromScope ->
|
scope.processClassifiersByNameWithSubstitution(typeRef.qualifier.first().name) { symbol, substitutorFromScope ->
|
||||||
if (resolvedSymbol != null) return@processClassifiersByNameWithSubstitution
|
if (resolvedSymbol != null) return@processClassifiersByNameWithSubstitution
|
||||||
@@ -68,6 +77,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
symbol
|
symbol
|
||||||
} else {
|
} else {
|
||||||
qualifierResolver.resolveSymbolWithPrefix(typeRef.qualifier, symbol.classId)
|
qualifierResolver.resolveSymbolWithPrefix(typeRef.qualifier, symbol.classId)
|
||||||
|
?: qualifierResolver.resolveEnumEntrySymbol(typeRef.qualifier, symbol.classId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FirTypeParameterSymbol -> {
|
is FirTypeParameterSymbol -> {
|
||||||
@@ -80,7 +90,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Imports
|
// TODO: Imports
|
||||||
val resultSymbol: FirClassifierSymbol<*>? = resolvedSymbol ?: qualifierResolver.resolveSymbol(typeRef.qualifier)
|
val resultSymbol: FirBasedSymbol<*>? = resolvedSymbol ?: qualifierResolver.resolveSymbol(typeRef.qualifier)
|
||||||
resultSymbol to substitutor
|
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(
|
private fun resolveUserType(
|
||||||
typeRef: FirUserTypeRef,
|
typeRef: FirUserTypeRef,
|
||||||
symbol: FirClassifierSymbol<*>?,
|
symbol: FirBasedSymbol<*>?,
|
||||||
substitutor: ConeSubstitutor?,
|
substitutor: ConeSubstitutor?,
|
||||||
areBareTypesAllowed: Boolean,
|
areBareTypesAllowed: Boolean,
|
||||||
topDeclaration: FirRegularClass?
|
topDeclaration: FirRegularClass?,
|
||||||
|
isOperandOfIsOperator: Boolean
|
||||||
): ConeKotlinType {
|
): ConeKotlinType {
|
||||||
if (symbol == null) {
|
if (symbol == null || symbol !is FirClassifierSymbol<*>) {
|
||||||
return ConeKotlinErrorType(ConeUnresolvedQualifierError(typeRef.render()))
|
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) {
|
if (symbol is FirTypeParameterSymbol) {
|
||||||
for (part in typeRef.qualifier) {
|
for (part in typeRef.qualifier) {
|
||||||
@@ -191,6 +226,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
private fun getClassesAlignedToQualifierParts(
|
private fun getClassesAlignedToQualifierParts(
|
||||||
symbol: FirRegularClassSymbol,
|
symbol: FirRegularClassSymbol,
|
||||||
qualifier: List<FirQualifierPart>,
|
qualifier: List<FirQualifierPart>,
|
||||||
@@ -243,6 +279,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
val index: Int
|
val index: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
private fun createDiagnosticsIfExists(
|
private fun createDiagnosticsIfExists(
|
||||||
parameterClass: FirRegularClass?,
|
parameterClass: FirRegularClass?,
|
||||||
qualifierPartIndex: Int,
|
qualifierPartIndex: Int,
|
||||||
@@ -314,13 +351,21 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
override fun resolveType(
|
override fun resolveType(
|
||||||
typeRef: FirTypeRef,
|
typeRef: FirTypeRef,
|
||||||
scopeClassDeclaration: ScopeClassDeclaration,
|
scopeClassDeclaration: ScopeClassDeclaration,
|
||||||
areBareTypesAllowed: Boolean
|
areBareTypesAllowed: Boolean,
|
||||||
|
isOperandOfIsOperator: Boolean
|
||||||
): ConeKotlinType {
|
): ConeKotlinType {
|
||||||
return when (typeRef) {
|
return when (typeRef) {
|
||||||
is FirResolvedTypeRef -> typeRef.type
|
is FirResolvedTypeRef -> typeRef.type
|
||||||
is FirUserTypeRef -> {
|
is FirUserTypeRef -> {
|
||||||
val (symbol, substitutor) = resolveToSymbol(typeRef, scopeClassDeclaration.scope)
|
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 FirFunctionTypeRef -> createFunctionalType(typeRef)
|
||||||
is FirDynamicTypeRef -> ConeKotlinErrorType(ConeUnsupportedDynamicType())
|
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
|
@PrivateForInline
|
||||||
@JvmField
|
@JvmField
|
||||||
var currentFile: FirFile? = null
|
var currentFile: FirFile? = null
|
||||||
@@ -55,7 +69,7 @@ class FirSpecificTypeResolverTransformer(
|
|||||||
override fun transformTypeRef(typeRef: FirTypeRef, data: ScopeClassDeclaration): FirResolvedTypeRef {
|
override fun transformTypeRef(typeRef: FirTypeRef, data: ScopeClassDeclaration): FirResolvedTypeRef {
|
||||||
session.lookupTracker?.recordTypeLookup(typeRef, data.scope.scopeOwnerLookupNames, currentFile?.source)
|
session.lookupTracker?.recordTypeLookup(typeRef, data.scope.scopeOwnerLookupNames, currentFile?.source)
|
||||||
typeRef.transformChildren(this, data)
|
typeRef.transformChildren(this, data)
|
||||||
return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed))
|
return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed, isOperandOfIsOperator))
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(PrivateForInline::class)
|
@OptIn(PrivateForInline::class)
|
||||||
@@ -65,7 +79,7 @@ class FirSpecificTypeResolverTransformer(
|
|||||||
): FirResolvedTypeRef {
|
): FirResolvedTypeRef {
|
||||||
functionTypeRef.transformChildren(this, data)
|
functionTypeRef.transformChildren(this, data)
|
||||||
session.lookupTracker?.recordTypeLookup(functionTypeRef, data.scope.scopeOwnerLookupNames, currentFile?.source)
|
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) {
|
return if (resolvedType != null && resolvedType !is ConeClassErrorType) {
|
||||||
buildResolvedTypeRef {
|
buildResolvedTypeRef {
|
||||||
source = functionTypeRef.source
|
source = functionTypeRef.source
|
||||||
|
|||||||
+7
-1
@@ -606,7 +606,13 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
data: ResolutionMode,
|
data: ResolutionMode,
|
||||||
): FirStatement {
|
): FirStatement {
|
||||||
val resolved = components.typeResolverTransformer.withAllowedBareTypes {
|
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()
|
}.transformTypeOperatorCallChildren()
|
||||||
|
|
||||||
val conversionTypeRef = resolved.conversionTypeRef.withTypeArgumentsForBareType(resolved.argument)
|
val conversionTypeRef = resolved.conversionTypeRef.withTypeArgumentsForBareType(resolved.argument)
|
||||||
|
|||||||
@@ -48,5 +48,8 @@ enum class DiagnosticKind {
|
|||||||
FloatLiteralOutOfRange,
|
FloatLiteralOutOfRange,
|
||||||
WrongLongSuffix,
|
WrongLongSuffix,
|
||||||
|
|
||||||
|
IsEnumEntry,
|
||||||
|
EnumEntryAsType,
|
||||||
|
|
||||||
Other,
|
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
|
var z: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> = Color.RED
|
||||||
set(arg: <!UNRESOLVED_REFERENCE!>Color.RED<!>) { z = arg }
|
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<!> {
|
fun bar(): <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> {
|
||||||
class Local : <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
class Local : <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>
|
||||||
fun local(arg: <!UNRESOLVED_REFERENCE!>Color.RED<!>): <!UNRESOLVED_REFERENCE!>Color.RED<!> = arg
|
fun local(arg: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>): <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> = arg
|
||||||
val temp: <!UNRESOLVED_REFERENCE!>Color.RED<!> = Color.RED
|
val temp: <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> = Color.RED
|
||||||
temp as? <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Color.RED<!>
|
temp as? <!ENUM_ENTRY_AS_TYPE, ENUM_ENTRY_AS_TYPE!>Color.RED<!>
|
||||||
if (temp is <!UNRESOLVED_REFERENCE!>Color.RED<!>) {
|
if (temp is <!IS_ENUM_ENTRY!>Color.RED<!>) {
|
||||||
return temp as <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
return temp as <!ENUM_ENTRY_AS_TYPE!>Color.RED<!>
|
||||||
}
|
}
|
||||||
val obj = object : <!UNRESOLVED_REFERENCE!>Color.RED<!> {}
|
val obj = object : <!ENUM_ENTRY_AS_TYPE!>Color.RED<!> {}
|
||||||
if (obj is <!UNRESOLVED_REFERENCE!>Color.RED<!>) {
|
if (obj is <!IS_ENUM_ENTRY!>Color.RED<!>) {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
return Color.RED
|
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>
|
typealias ArrayOfEnumEntryAlias = Array<RedAlias>
|
||||||
|
|
||||||
fun <T> bar(a: Any): T = a as T
|
fun <T> bar(a: Any): T = a as T
|
||||||
|
|
||||||
fun <T> foo() {
|
fun <T> foo() {
|
||||||
foo<<!UNRESOLVED_REFERENCE!>Color.RED<!>>()
|
foo<<!ENUM_ENTRY_AS_TYPE!>Color.RED<!>>()
|
||||||
foo<<!CANNOT_INFER_PARAMETER_TYPE!>RedAlias<!>>()
|
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
|
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
|
ENTRY
|
||||||
}
|
}
|
||||||
|
|
||||||
class A : <!UNRESOLVED_REFERENCE!>E.ENTRY<!>
|
class A : <!ENUM_ENTRY_AS_TYPE!>E.ENTRY<!>
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ enum class MyEnum {
|
|||||||
SECOND
|
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 {
|
fun foo(x: MyEnum): Int {
|
||||||
return <!NO_ELSE_IN_WHEN!>when<!> (x) {
|
return <!NO_ELSE_IN_WHEN!>when<!> (x) {
|
||||||
is <!UNRESOLVED_REFERENCE!>MyEnum.A<!> -> 1
|
is <!IS_ENUM_ENTRY!>MyEnum.A<!> -> 1
|
||||||
is <!UNRESOLVED_REFERENCE!>MyEnum.B<!> -> 2
|
is <!IS_ENUM_ENTRY!>MyEnum.B<!> -> 2
|
||||||
is <!UNRESOLVED_REFERENCE!>MyEnum.C<!> -> 3
|
is <!IS_ENUM_ENTRY!>MyEnum.C<!> -> 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ enum class MyEnum {
|
|||||||
fun foo(x: MyEnum): Int {
|
fun foo(x: MyEnum): Int {
|
||||||
return <!NO_ELSE_IN_WHEN!>when<!> (x) {
|
return <!NO_ELSE_IN_WHEN!>when<!> (x) {
|
||||||
MyEnum.A -> 1
|
MyEnum.A -> 1
|
||||||
is <!UNRESOLVED_REFERENCE!>MyEnum.B<!> -> 2
|
is <!IS_ENUM_ENTRY!>MyEnum.B<!> -> 2
|
||||||
is <!UNRESOLVED_REFERENCE!>MyEnum.C<!> -> 3
|
is <!IS_ENUM_ENTRY!>MyEnum.C<!> -> 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -2616,6 +2616,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
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 ->
|
add(FirErrors.EXPECTED_CONDITION) { firDiagnostic ->
|
||||||
ExpectedConditionImpl(
|
ExpectedConditionImpl(
|
||||||
firDiagnostic as FirPsiDiagnostic,
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
|||||||
+8
@@ -1834,6 +1834,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
abstract val compileTimeCheckResult: Boolean
|
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>() {
|
abstract class ExpectedCondition : KtFirDiagnostic<KtWhenCondition>() {
|
||||||
override val diagnosticClass get() = ExpectedCondition::class
|
override val diagnosticClass get() = ExpectedCondition::class
|
||||||
}
|
}
|
||||||
|
|||||||
+14
@@ -2954,6 +2954,20 @@ internal class UselessIsCheckImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
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(
|
internal class ExpectedConditionImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic,
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
|
|||||||
Reference in New Issue
Block a user