diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeCastChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeCastChecker.kt new file mode 100644 index 00000000000..d75ce43435e --- /dev/null +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeCastChecker.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.native.checkers + +import org.jetbrains.kotlin.fir.FirPlatformSpecificCastChecker +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.toRegularClassSymbol + +object FirNativeCastChecker : FirPlatformSpecificCastChecker() { + override fun shouldSuppressImpossibleCast(session: FirSession, fromType: ConeKotlinType, toType: ConeKotlinType): Boolean { + return isCastToAForwardDeclaration(session, toType) + } + + /** + * Here, we only check that we are casting to a forward declaration to suppress a CAST_NEVER_SUCCEEDS warning. + * The cast would be further checked with FirNativeForwardDeclarationTypeOperatorChecker and FirNativeForwardDeclarationGetClassCallChecker. + */ + private fun isCastToAForwardDeclaration(session: FirSession, forwardDeclarationType: ConeKotlinType): Boolean { + return forwardDeclarationType.toRegularClassSymbol(session)?.forwardDeclarationKindOrNull() != null + } +} \ No newline at end of file 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 5330ba89d6c..0378b9c8302 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 @@ -16,10 +16,9 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors 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.firPlatformSpecificCastChecker import org.jetbrains.kotlin.fir.resolve.fullyExpandedType -import org.jetbrains.kotlin.fir.types.ConeDynamicType -import org.jetbrains.kotlin.fir.types.coneType -import org.jetbrains.kotlin.fir.types.resolvedType +import org.jetbrains.kotlin.fir.types.* object FirCastOperatorsChecker : FirTypeOperatorCallChecker() { override fun check(expression: FirTypeOperatorCall, context: CheckerContext, reporter: DiagnosticReporter) { @@ -38,7 +37,9 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker() { 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 (!session.firPlatformSpecificCastChecker.shouldSuppressImpossibleCast(session, actualType, targetType)) { + reporter.reportOn(expression.source, FirErrors.CAST_NEVER_SUCCEEDS, context) + } } } else if (castType == CastingType.Always) { if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) { diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt index 21b2f4a8988..b4a508b27a1 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt @@ -95,6 +95,7 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion register(FirPrimaryConstructorSuperTypeCheckerPlatformComponent::class, FirPrimaryConstructorSuperTypeCheckerPlatformComponent.Default) register(FirGenericArrayClassLiteralSupport::class, FirGenericArrayClassLiteralSupport.Disabled) register(FirMissingDependencyStorage::class, FirMissingDependencyStorage(this)) + register(FirPlatformSpecificCastChecker::class, FirPlatformSpecificCastChecker.Default) } @OptIn(SessionConfiguration::class) diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirNativeSessionFactory.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirNativeSessionFactory.kt index 2020bd7a65c..6e3051bec8d 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirNativeSessionFactory.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirNativeSessionFactory.kt @@ -6,10 +6,8 @@ package org.jetbrains.kotlin.fir.session import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.fir.BinaryModuleData -import org.jetbrains.kotlin.fir.FirModuleData -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.SessionConfiguration +import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeCastChecker import org.jetbrains.kotlin.fir.backend.native.FirNativeClassMapper import org.jetbrains.kotlin.fir.checkers.registerNativeCheckers import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider @@ -44,6 +42,7 @@ object FirNativeSessionFactory : FirAbstractSessionFactory() { registerExtraComponents = { session -> session.registerDefaultComponents() session.register(FirPlatformClassMapper::class, FirNativeClassMapper()) + session.register(FirPlatformSpecificCastChecker::class, FirNativeCastChecker) registerExtraComponents(session) }, createKotlinScopeProvider = { FirKotlinScopeProvider() }, @@ -90,6 +89,7 @@ object FirNativeSessionFactory : FirAbstractSessionFactory() { registerExtraComponents = { it.registerDefaultComponents() it.register(FirPlatformClassMapper::class, FirNativeClassMapper()) + it.register(FirPlatformSpecificCastChecker::class, FirNativeCastChecker) registerExtraComponents(it) }, registerExtraCheckers = { it.registerNativeCheckers() }, diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactoryHelper.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactoryHelper.kt index 174af6020e8..1368618a1a4 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactoryHelper.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactoryHelper.kt @@ -140,5 +140,6 @@ object FirSessionFactoryHelper { register(FirPlatformClassMapper::class, FirPlatformClassMapper.Default) register(FirOverridesBackwardCompatibilityHelper::class, FirDefaultOverridesBackwardCompatibilityHelper) register(FirDelegatedMembersFilter::class, FirDelegatedMembersFilter.Default) + register(FirPlatformSpecificCastChecker::class, FirPlatformSpecificCastChecker.Default) } } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirPlatformSpecificCastChecker.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirPlatformSpecificCastChecker.kt new file mode 100644 index 00000000000..1826f06af11 --- /dev/null +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirPlatformSpecificCastChecker.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir + +import org.jetbrains.kotlin.fir.types.ConeKotlinType + +abstract class FirPlatformSpecificCastChecker : FirSessionComponent { + abstract fun shouldSuppressImpossibleCast(session: FirSession, fromType: ConeKotlinType, toType: ConeKotlinType): Boolean + + object Default : FirPlatformSpecificCastChecker() { + override fun shouldSuppressImpossibleCast(session: FirSession, fromType: ConeKotlinType, toType: ConeKotlinType): Boolean { + return false + } + } +} + +val FirSession.firPlatformSpecificCastChecker: FirPlatformSpecificCastChecker by FirSession.sessionComponentAccessor() diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/diagnostics/AbstractDiagnosticsNativeTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/diagnostics/AbstractDiagnosticsNativeTest.kt index 3dfb10bae2a..8c174910c1e 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/diagnostics/AbstractDiagnosticsNativeTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/diagnostics/AbstractDiagnosticsNativeTest.kt @@ -115,6 +115,10 @@ abstract class AbstractFirNativeDiagnosticsTestBase(val parser: FirParser) : Abs forTestsMatching("compiler/testData/diagnostics/*") { configurationForClassicAndFirTestsAlongside() } + + defaultDirectives { + LanguageSettingsDirectives.LANGUAGE + "+EnableDfaWarningsInK2" + } } } }