[JS FIR] Support DYNAMIC_NOT_ALLOWED diagnostic

^KT-59384 Fixed
This commit is contained in:
Alexander Korepanov
2023-07-13 17:29:23 +02:00
committed by Space Team
parent 39fba56de9
commit 6034d32d7c
8 changed files with 53 additions and 22 deletions
@@ -3779,6 +3779,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.DYNAMIC_NOT_ALLOWED) { firDiagnostic ->
DynamicNotAllowedImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.ENUM_ENTRY_AS_TYPE) { firDiagnostic ->
EnumEntryAsTypeImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -2641,6 +2641,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = IsEnumEntry::class
}
interface DynamicNotAllowed : KtFirDiagnostic<KtTypeReference> {
override val diagnosticClass get() = DynamicNotAllowed::class
}
interface EnumEntryAsType : KtFirDiagnostic<KtTypeReference> {
override val diagnosticClass get() = EnumEntryAsType::class
}
@@ -3183,6 +3183,11 @@ internal class IsEnumEntryImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtTypeReference>(firDiagnostic, token), KtFirDiagnostic.IsEnumEntry
internal class DynamicNotAllowedImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtTypeReference>(firDiagnostic, token), KtFirDiagnostic.DynamicNotAllowed
internal class EnumEntryAsTypeImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
@@ -1307,6 +1307,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<Boolean>("compileTimeCheckResult")
}
val IS_ENUM_ENTRY by error<KtTypeReference>()
val DYNAMIC_NOT_ALLOWED by error<KtTypeReference>()
val ENUM_ENTRY_AS_TYPE by error<KtTypeReference>(PositioningStrategy.SELECTOR_BY_QUALIFIED)
}
@@ -678,6 +678,7 @@ object FirErrors {
val UNCHECKED_CAST by warning2<KtBinaryExpressionWithTypeRHS, ConeKotlinType, ConeKotlinType>(SourceElementPositioningStrategies.AS_TYPE)
val USELESS_IS_CHECK by warning1<KtElement, Boolean>()
val IS_ENUM_ENTRY by error0<KtTypeReference>()
val DYNAMIC_NOT_ALLOWED by error0<KtTypeReference>()
val ENUM_ENTRY_AS_TYPE by error0<KtTypeReference>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
// When expressions
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.expressions.FirOperation
import org.jetbrains.kotlin.fir.expressions.FirTypeOperatorCall
import org.jetbrains.kotlin.fir.expressions.unwrapSmartcastExpression
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.types.ConeDynamicType
import org.jetbrains.kotlin.fir.types.coneType
object FirCastOperatorsChecker : FirTypeOperatorCallChecker() {
@@ -29,22 +30,33 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker() {
val isSafeAs = expression.operation == FirOperation.SAFE_AS
if (expression.operation == FirOperation.AS || isSafeAs) {
val castType = checkCasting(actualType, targetType, isSafeAs, context)
if (castType == CastingType.Impossible) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) {
reporter.reportOn(expression.source, FirErrors.CAST_NEVER_SUCCEEDS, context)
if (targetType is ConeDynamicType) {
reporter.reportOn(conversionTypeRef.source, FirErrors.DYNAMIC_NOT_ALLOWED, context)
} else {
val castType = checkCasting(actualType, targetType, isSafeAs, context)
if (castType == CastingType.Impossible) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) {
reporter.reportOn(expression.source, FirErrors.CAST_NEVER_SUCCEEDS, context)
}
} else if (castType == CastingType.Always) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) {
reporter.reportOn(expression.source, FirErrors.USELESS_CAST, context)
}
} else if (isCastErased(actualType, targetType, context)) {
reporter.reportOn(expression.source, FirErrors.UNCHECKED_CAST, actualType, targetType, context)
}
} else if (castType == CastingType.Always) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) {
reporter.reportOn(expression.source, FirErrors.USELESS_CAST, context)
}
} else if (isCastErased(actualType, targetType, context)) {
reporter.reportOn(expression.source, FirErrors.UNCHECKED_CAST, actualType, targetType, context)
}
} else if (expression.operation == FirOperation.IS) {
if (targetType is ConeDynamicType) {
reporter.reportOn(conversionTypeRef.source, FirErrors.DYNAMIC_NOT_ALLOWED, context)
}
if (!context.isContractBody && isCastErased(actualType, targetType, context)) {
reporter.reportOn(conversionTypeRef.source, FirErrors.CANNOT_CHECK_FOR_ERASED, targetType, context)
}
} else if (expression.operation == FirOperation.NOT_IS) {
if (targetType is ConeDynamicType) {
reporter.reportOn(conversionTypeRef.source, FirErrors.DYNAMIC_NOT_ALLOWED, context)
}
}
}
}
@@ -229,6 +229,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FLOAT_LITERAL_OUT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_BINARY_MOD
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_PROPERTY_TYPE_IN_CONSTRUCTOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_IDENTITY_EQUALS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DYNAMIC_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_EXTERNAL_DECLARATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_TAILREC_FUNCTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECT_ACTUAL_OPT_IN_ANNOTATION
@@ -1966,6 +1967,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(USELESS_CAST, "No cast needed")
map.put(UNCHECKED_CAST, "Unchecked cast: ''{0}'' to ''{1}''", RENDER_TYPE, RENDER_TYPE)
map.put(USELESS_IS_CHECK, "Check for instance is always ''{0}''", TO_STRING)
map.put(DYNAMIC_NOT_ALLOWED, "Dynamic types are not allowed in this position");
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")
@@ -1,23 +1,23 @@
// !DIAGNOSTICS: -REDUNDANT_NULLABLE
fun test(d: Any, dl: Collection<dynamic>) {
d as dynamic
d as dynamic?
d as <!DYNAMIC_NOT_ALLOWED!>dynamic<!>
d as <!DYNAMIC_NOT_ALLOWED!>dynamic?<!>
d as? dynamic
d as? dynamic?
d as? <!DYNAMIC_NOT_ALLOWED!>dynamic<!>
d as? <!DYNAMIC_NOT_ALLOWED!>dynamic?<!>
d is dynamic
d is dynamic?
d is <!DYNAMIC_NOT_ALLOWED!>dynamic<!>
d is <!DYNAMIC_NOT_ALLOWED!>dynamic?<!>
d !is dynamic
d !is dynamic?
d !is <!DYNAMIC_NOT_ALLOWED!>dynamic<!>
d !is <!DYNAMIC_NOT_ALLOWED!>dynamic?<!>
when (d) {
is dynamic -> {}
is dynamic? -> {}
!is dynamic -> {}
!is dynamic? -> {}
is <!DYNAMIC_NOT_ALLOWED!>dynamic<!> -> {}
is <!DYNAMIC_NOT_ALLOWED!>dynamic?<!> -> {}
!is <!DYNAMIC_NOT_ALLOWED!>dynamic<!> -> {}
!is <!DYNAMIC_NOT_ALLOWED!>dynamic?<!> -> {}
}
dl as List<dynamic>