diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirTypeCompatibilityHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirTypeCompatibilityHelpers.kt index a3c8ef25398..984a9c749cd 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirTypeCompatibilityHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirTypeCompatibilityHelpers.kt @@ -115,3 +115,24 @@ internal fun FirExpression.toArgumentInfo(context: CheckerContext) = originalType = mostOriginalTypeIfSmartCast.fullyExpandedType(context.session).finalApproximationOrSelf(context), context.session, ) + +private fun TypeInfo.isSubtypeOf(other: TypeInfo, context: CheckerContext) = + notNullType.isSubtypeOf(other.notNullType, context.session) + +internal fun areUnrelated(a: TypeInfo, b: TypeInfo, context: CheckerContext): Boolean { + return !a.isSubtypeOf(b, context) && !b.isSubtypeOf(a, context) +} + +internal fun areRelated(a: TypeInfo, b: TypeInfo, context: CheckerContext): Boolean = !areUnrelated(a, b, context) + +/** + * See [KT-57779](https://youtrack.jetbrains.com/issue/KT-57779) for more information. + */ +internal fun shouldReportAsPerRules1(l: TypeInfo, r: TypeInfo, context: CheckerContext): Boolean { + val oneIsFinal = l.isFinal || r.isFinal + + return when { + oneIsFinal -> areUnrelated(l, r, context) + else -> false + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCastOperatorsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCastOperatorsChecker.kt index c24d0f6457f..c80ce771b46 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCastOperatorsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCastOperatorsChecker.kt @@ -53,7 +53,7 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker(MppCheckerKind.Commo || l.type.isNullableNothing && !r.type.isNullable return when { - l.type.isNothing && r.type.isNothingOrNullableNothing -> Applicability.APPLICABLE + l.type.isNothing -> Applicability.APPLICABLE r.type.isNothing -> Applicability.IMPOSSIBLE_CAST isNullableNothingWithNotNull -> when (expression.operation) { // (null as? WhatEver) == null @@ -71,23 +71,16 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker(MppCheckerKind.Commo useless: Applicability, context: CheckerContext, ): Applicability { - val oneIsFinal = l.isFinal || r.isFinal val oneIsNotNull = !l.type.isNullable || !r.type.isNullable return when { isRefinementUseless(context, l.directType.upperBoundIfFlexible(), r.directType, expression) -> useless - oneIsNotNull && oneIsFinal && areUnrelated(l, r, context) -> impossible + oneIsNotNull && shouldReportAsPerRules1(l, r, context) -> impossible isCastErased(l.directType, r.directType, context) -> Applicability.CAST_ERASED else -> Applicability.APPLICABLE } } - private fun areUnrelated(a: TypeInfo, b: TypeInfo, context: CheckerContext) = - !a.isSubtypeOf(b, context) && !b.isSubtypeOf(a, context) - - private fun TypeInfo.isSubtypeOf(other: TypeInfo, context: CheckerContext) = - notNullType.isSubtypeOf(other.notNullType, context.session) - /** * K1 reports different diagnostics for different * cases, and this enum helps to replicate the K1's diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt index 0222a4165d5..edb05a35b9e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt @@ -105,19 +105,6 @@ object FirEqualityCompatibilityChecker : FirEqualityOperatorCallChecker(MppCheck } } - private fun shouldReportAsPerRules1(l: TypeInfo, r: TypeInfo, context: CheckerContext): Boolean { - val oneIsFinal = l.isFinal || r.isFinal - - return when { - l.type.isNothingOrNullableNothing || r.type.isNothingOrNullableNothing -> false - oneIsFinal -> !l.isSubtypeOf(r, context) && !r.isSubtypeOf(l, context) - else -> false - } - } - - private fun TypeInfo.isSubtypeOf(other: TypeInfo, context: CheckerContext) = - notNullType.isSubtypeOf(other.notNullType, context.session) - /** * K1 reports different diagnostics for different * cases, and this enum helps to replicate the K1's @@ -155,7 +142,7 @@ object FirEqualityCompatibilityChecker : FirEqualityOperatorCallChecker(MppCheck val shouldProperlyReportError = context.languageVersionSettings.supportsFeature(LanguageFeature.ReportErrorsForComparisonOperators) // In this case K1 reports nothing - val shouldRelaxDiagnostic = (l.isPrimitive || r.isPrimitive) && (l.isSubtypeOf(r, context) || r.isSubtypeOf(l, context)) + val shouldRelaxDiagnostic = (l.isPrimitive || r.isPrimitive) && areRelated(l, r, context) && !shouldProperlyReportError return when {