diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/JsDeclarationCheckers.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/JsDeclarationCheckers.kt index 4bfc72739ec..ef9d44dfdbc 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/JsDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/JsDeclarationCheckers.kt @@ -12,7 +12,8 @@ import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirJsEx object JsDeclarationCheckers : DeclarationCheckers() { override val functionCheckers: Set get() = setOf( - FirJsInheritanceFunctionChecker, + FirJsInheritanceFunctionChecker.Regular, + FirJsInheritanceFunctionChecker.ForExpectClass, ) override val basicDeclarationCheckers: Set @@ -30,11 +31,15 @@ object JsDeclarationCheckers : DeclarationCheckers() { override val classCheckers: Set get() = setOf( - FirJsMultipleInheritanceChecker, + FirJsMultipleInheritanceChecker.Regular, + FirJsMultipleInheritanceChecker.ForExpectClass, FirJsDynamicDeclarationChecker, - FirJsInheritanceClassChecker, - FirJsExternalInheritorOnlyChecker, - FirJsNameClashClassMembersChecker + FirJsInheritanceClassChecker.Regular, + FirJsInheritanceClassChecker.ForExpectClass, + FirJsExternalInheritorOnlyChecker.Regular, + FirJsExternalInheritorOnlyChecker.ForExpectClass, + FirJsNameClashClassMembersChecker.Regular, + FirJsNameClashClassMembersChecker.ForExpectClass, ) override val simpleFunctionCheckers: Set diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsExternalInheritorOnlyChecker.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsExternalInheritorOnlyChecker.kt index 68b53d63c82..3597041aa23 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsExternalInheritorOnlyChecker.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsExternalInheritorOnlyChecker.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.hasAnnotation +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType @@ -21,8 +22,21 @@ import org.jetbrains.kotlin.fir.types.toRegularClassSymbol import org.jetbrains.kotlin.name.JsStandardClassIds.Annotations.JsExternalInheritorsOnly import org.jetbrains.kotlin.utils.addToStdlib.popLast -// TODO: extract common checker for expect interfaces -object FirJsExternalInheritorOnlyChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirJsExternalInheritorOnlyChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirJsExternalInheritorOnlyChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirJsExternalInheritorOnlyChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + private fun FirClass.forEachParents(context: CheckerContext, f: (FirRegularClassSymbol) -> Unit) { val todo = superConeTypes.toMutableList() val done = hashSetOf() diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceClassChecker.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceClassChecker.kt index 74220179caf..fb897410e7d 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceClassChecker.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceClassChecker.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal import org.jetbrains.kotlin.fir.analysis.js.checkers.isOverridingExternalWithOptionalParams import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.scopes.collectAllFunctions import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverrideFunctionSymbol @@ -26,8 +27,21 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.isSuspendOrKSuspendFunctionType import org.jetbrains.kotlin.fir.types.typeContext -// TODO: extract common checker for expect interfaces -object FirJsInheritanceClassChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirJsInheritanceClassChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirJsInheritanceClassChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirJsInheritanceClassChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { if (!declaration.symbol.isEffectivelyExternal(context)) { val fakeOverriddenMethod = declaration.findFakeMethodOverridingExternalWithOptionalParams(context) diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceFunctionChecker.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceFunctionChecker.kt index 6d1c40215cd..dbc5409bfac 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceFunctionChecker.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceFunctionChecker.kt @@ -13,11 +13,26 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFunctionChecker import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal import org.jetbrains.kotlin.fir.analysis.js.checkers.isOverridingExternalWithOptionalParams +import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFunction +import org.jetbrains.kotlin.fir.declarations.utils.isExpect + +sealed class FirJsInheritanceFunctionChecker(mppKind: MppCheckerKind) : FirFunctionChecker(mppKind) { + object Regular : FirJsInheritanceFunctionChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) { + if ((context.containingDeclarations.last() as? FirClass)?.isExpect == true) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirJsInheritanceFunctionChecker(MppCheckerKind.Common) { + override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) { + if ((context.containingDeclarations.last() as? FirClass)?.isExpect != true) return + super.check(declaration, context, reporter) + } + } -// TODO: extract common checker for expect interfaces -object FirJsInheritanceFunctionChecker : FirFunctionChecker(MppCheckerKind.Platform) { override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) { if (declaration.isNotEffectivelyExternalFunctionButOverridesExternal(context)) { reporter.reportOn(declaration.source, FirJsErrors.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS, context) diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsMultipleInheritanceChecker.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsMultipleInheritanceChecker.kt index b8be64c7068..e34a523a07c 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsMultipleInheritanceChecker.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsMultipleInheritanceChecker.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.overriddenFunctions import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.scopes.getFunctions import org.jetbrains.kotlin.fir.types.ConeKotlinType @@ -23,8 +24,21 @@ import org.jetbrains.kotlin.fir.types.isSubtypeOf import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.OperatorNameConventions -// TODO: extract common checker for expect interfaces -object FirJsMultipleInheritanceChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirJsMultipleInheritanceChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirJsMultipleInheritanceChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirJsMultipleInheritanceChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { declaration.checkFunctionIfSubtypeOf( functionToCheck = OperatorNameConventions.GET, diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsNameClashClassMembersChecker.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsNameClashClassMembersChecker.kt index 7a3e6813a35..f1767462593 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsNameClashClassMembersChecker.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsNameClashClassMembersChecker.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.constructors +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.isFinal import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol @@ -31,8 +32,21 @@ import org.jetbrains.kotlin.fir.unwrapFakeOverridesOrDelegated import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.popLast -// TODO: extract common checker for expect interfaces -object FirJsNameClashClassMembersChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirJsNameClashClassMembersChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirJsNameClashClassMembersChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirJsNameClashClassMembersChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + private class StableNamesCollector { val jsStableNames = mutableSetOf() val overrideIntersections = hashMapOf, HashSet>>() diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt index af62209650e..bf5a9c30569 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt @@ -24,7 +24,8 @@ object JvmDeclarationCheckers : DeclarationCheckers() { override val classCheckers: Set get() = setOf( FirStrictfpApplicabilityChecker, - FirOverrideJavaNullabilityWarningChecker, + FirOverrideJavaNullabilityWarningChecker.Regular, + FirOverrideJavaNullabilityWarningChecker.ForExpectClass, ) override val regularClassCheckers: Set diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirOverrideJavaNullabilityWarningChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirOverrideJavaNullabilityWarningChecker.kt index a84c449f737..559d20efda5 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirOverrideJavaNullabilityWarningChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirOverrideJavaNullabilityWarningChecker.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirAbstractOverrid import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.java.enhancement.EnhancedForWarningConeSubstitutor import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator @@ -24,8 +25,21 @@ import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.typeContext import org.jetbrains.kotlin.utils.addToStdlib.runIf -// TODO: extract common checker for expect interfaces -object FirOverrideJavaNullabilityWarningChecker : FirAbstractOverrideChecker(MppCheckerKind.Platform) { +sealed class FirOverrideJavaNullabilityWarningChecker(mppKind: MppCheckerKind) : FirAbstractOverrideChecker(mppKind) { + object Regular : FirOverrideJavaNullabilityWarningChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirOverrideJavaNullabilityWarningChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { val substitutor = EnhancedForWarningConeSubstitutor(context.session.typeContext) val scope = declaration.unsubstitutedScope(context) diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameCallableChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameCallableChecker.kt index e8e7f48a2f9..d1cc47ca209 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameCallableChecker.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameCallableChecker.kt @@ -14,14 +14,33 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.utils.isExpect -object FirNativeObjCNameCallableChecker : FirCallableDeclarationChecker(MppCheckerKind.Common) { - override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { - if (declaration !is FirSimpleFunction && declaration !is FirProperty) return - val containingClass = context.containingDeclarations.lastOrNull() as? FirClass - if (containingClass != null) { - val firTypeScope = containingClass.unsubstitutedScope(context) - FirNativeObjCNameUtilities.checkCallableMember(firTypeScope, declaration.symbol, declaration, context, reporter) +sealed class FirNativeObjCNameCallableChecker(mppKind: MppCheckerKind) : FirCallableDeclarationChecker(mppKind) { + object Regular : FirNativeObjCNameCallableChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + val containingClass = context.containingDeclarations.lastOrNull() as? FirClass ?: return + if (containingClass.isExpect) return + check(declaration, containingClass, context, reporter) } } + + object ForExpectClass : FirNativeObjCNameCallableChecker(MppCheckerKind.Common) { + override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + val containingClass = context.containingDeclarations.lastOrNull() as? FirClass ?: return + if (!containingClass.isExpect) return + check(declaration, containingClass, context, reporter) + } + } + + protected fun check( + declaration: FirCallableDeclaration, + containingClass: FirClass, + context: CheckerContext, + reporter: DiagnosticReporter, + ) { + if (declaration !is FirSimpleFunction && declaration !is FirProperty) return + val firTypeScope = containingClass.unsubstitutedScope(context) + FirNativeObjCNameUtilities.checkCallableMember(firTypeScope, declaration.symbol, declaration, context, reporter) + } } diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameOverridesChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameOverridesChecker.kt index 1cc7248478c..152439f32b6 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameOverridesChecker.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameOverridesChecker.kt @@ -12,11 +12,25 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCNameUtilities.checkCallableMember import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.isIntersectionOverride import org.jetbrains.kotlin.fir.scopes.processAllFunctions import org.jetbrains.kotlin.fir.scopes.processAllProperties -object FirNativeObjCNameOverridesChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirNativeObjCNameOverridesChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirNativeObjCNameOverridesChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirNativeObjCNameOverridesChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { // We just need to check intersection overrides, all other declarations are checked by FirNativeObjCNameChecker diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementChecker.kt index 41f32f766fe..fd823a2d9cc 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementChecker.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementChecker.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirCallableDeclarationChecker import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT -import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCRefinementOverridesChecker.check import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.name.ClassId @@ -35,7 +34,15 @@ object FirNativeObjCRefinementChecker : FirCallableDeclarationChecker(MppChecker val containingClass = context.containingDeclarations.lastOrNull() as? FirClass if (containingClass != null) { val firTypeScope = containingClass.unsubstitutedScope(context) - check(firTypeScope, declaration.symbol, declaration, context, reporter, objCAnnotations, swiftAnnotations) + FirNativeObjCRefinementOverridesChecker.check( + firTypeScope, + declaration.symbol, + declaration, + context, + reporter, + objCAnnotations, + swiftAnnotations + ) } } diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementOverridesChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementOverridesChecker.kt index b68704cbf18..822a683553e 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementOverridesChecker.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementOverridesChecker.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId import org.jetbrains.kotlin.fir.declarations.toAnnotationClassLikeSymbol +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.isIntersectionOverride import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol @@ -29,8 +30,20 @@ import org.jetbrains.kotlin.fir.scopes.processAllFunctions import org.jetbrains.kotlin.fir.scopes.processAllProperties import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -// TODO: extract common checker for expect interfaces -object FirNativeObjCRefinementOverridesChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirNativeObjCRefinementOverridesChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirNativeObjCRefinementOverridesChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirNativeObjCRefinementOverridesChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { // We just need to check intersection overrides, all other declarations are checked by FirNativeObjCRefinementChecker @@ -45,80 +58,83 @@ object FirNativeObjCRefinementOverridesChecker : FirClassChecker(MppCheckerKind. } } - fun check( - baseScope: FirTypeScope, - memberSymbol: FirCallableSymbol<*>, - declarationToReport: FirDeclaration, - context: CheckerContext, - reporter: DiagnosticReporter, - objCAnnotations: List, - swiftAnnotations: List - ) { - val overriddenMemberSymbols = baseScope.getDirectOverriddenMembersWithBaseScope(memberSymbol) - if (overriddenMemberSymbols.isEmpty()) return - var isHiddenFromObjC = objCAnnotations.isNotEmpty() - var isRefinedInSwift = swiftAnnotations.isNotEmpty() - val supersNotHiddenFromObjC = mutableListOf>() - val supersNotRefinedInSwift = mutableListOf>() - for ((symbol, scope) in overriddenMemberSymbols) { - val (superIsHiddenFromObjC, superIsRefinedInSwift) = symbol.inheritsRefinedAnnotations(context.session, scope) - if (superIsHiddenFromObjC) isHiddenFromObjC = true else supersNotHiddenFromObjC.add(symbol) - if (superIsRefinedInSwift) isRefinedInSwift = true else supersNotRefinedInSwift.add(symbol) + companion object { + fun check( + baseScope: FirTypeScope, + memberSymbol: FirCallableSymbol<*>, + declarationToReport: FirDeclaration, + context: CheckerContext, + reporter: DiagnosticReporter, + objCAnnotations: List, + swiftAnnotations: List + ) { + val overriddenMemberSymbols = baseScope.getDirectOverriddenMembersWithBaseScope(memberSymbol) + if (overriddenMemberSymbols.isEmpty()) return + var isHiddenFromObjC = objCAnnotations.isNotEmpty() + var isRefinedInSwift = swiftAnnotations.isNotEmpty() + val supersNotHiddenFromObjC = mutableListOf>() + val supersNotRefinedInSwift = mutableListOf>() + for ((symbol, scope) in overriddenMemberSymbols) { + val (superIsHiddenFromObjC, superIsRefinedInSwift) = symbol.inheritsRefinedAnnotations(context.session, scope) + if (superIsHiddenFromObjC) isHiddenFromObjC = true else supersNotHiddenFromObjC.add(symbol) + if (superIsRefinedInSwift) isRefinedInSwift = true else supersNotRefinedInSwift.add(symbol) + } + if (isHiddenFromObjC && supersNotHiddenFromObjC.isNotEmpty()) { + reporter.reportIncompatibleOverride(declarationToReport, objCAnnotations, supersNotHiddenFromObjC, context) + } + if (isRefinedInSwift && supersNotRefinedInSwift.isNotEmpty()) { + reporter.reportIncompatibleOverride(declarationToReport, swiftAnnotations, supersNotRefinedInSwift, context) + } } - if (isHiddenFromObjC && supersNotHiddenFromObjC.isNotEmpty()) { - reporter.reportIncompatibleOverride(declarationToReport, objCAnnotations, supersNotHiddenFromObjC, context) + + private fun FirCallableSymbol<*>.inheritsRefinedAnnotations(session: FirSession, baseScope: FirTypeScope): Pair { + val (hasObjC, hasSwift) = hasRefinedAnnotations(session) + if (hasObjC && hasSwift) return true to true + // Note: `checkMember` requires all overridden symbols to be either refined or not refined. + val (overriddenMemberSymbol, scope) = baseScope.getDirectOverriddenMembersWithBaseScope(this).firstOrNull() + ?: return hasObjC to hasSwift + val (inheritsObjC, inheritsSwift) = overriddenMemberSymbol.inheritsRefinedAnnotations(session, scope) + return (hasObjC || inheritsObjC) to (hasSwift || inheritsSwift) } - if (isRefinedInSwift && supersNotRefinedInSwift.isNotEmpty()) { - reporter.reportIncompatibleOverride(declarationToReport, swiftAnnotations, supersNotRefinedInSwift, context) - } - } - private fun FirCallableSymbol<*>.inheritsRefinedAnnotations(session: FirSession, baseScope: FirTypeScope): Pair { - val (hasObjC, hasSwift) = hasRefinedAnnotations(session) - if (hasObjC && hasSwift) return true to true - // Note: `checkMember` requires all overridden symbols to be either refined or not refined. - val (overriddenMemberSymbol, scope) = baseScope.getDirectOverriddenMembersWithBaseScope(this).firstOrNull() - ?: return hasObjC to hasSwift - val (inheritsObjC, inheritsSwift) = overriddenMemberSymbol.inheritsRefinedAnnotations(session, scope) - return (hasObjC || inheritsObjC) to (hasSwift || inheritsSwift) - } + private fun FirCallableSymbol<*>.hasRefinedAnnotations(session: FirSession): Pair { + var hasObjC = false + var hasSwift = false + for (annotation in resolvedAnnotationsWithClassIds) { + val metaAnnotations = annotation.toAnnotationClassLikeSymbol(session)?.resolvedAnnotationsWithClassIds.orEmpty() + for (metaAnnotation in metaAnnotations) { + when (metaAnnotation.toAnnotationClassId(session)) { + hidesFromObjCClassId -> { + hasObjC = true + break + } - private fun FirCallableSymbol<*>.hasRefinedAnnotations(session: FirSession): Pair { - var hasObjC = false - var hasSwift = false - for (annotation in resolvedAnnotationsWithClassIds) { - val metaAnnotations = annotation.toAnnotationClassLikeSymbol(session)?.resolvedAnnotationsWithClassIds.orEmpty() - for (metaAnnotation in metaAnnotations) { - when (metaAnnotation.toAnnotationClassId(session)) { - hidesFromObjCClassId -> { - hasObjC = true - break - } - - refinesInSwiftClassId -> { - hasSwift = true - break + refinesInSwiftClassId -> { + hasSwift = true + break + } } } + if (hasObjC && hasSwift) return true to true } - if (hasObjC && hasSwift) return true to true + return hasObjC to hasSwift } - return hasObjC to hasSwift - } - private fun DiagnosticReporter.reportIncompatibleOverride( - declaration: FirDeclaration, - annotations: List, - notRefinedSupers: List>, - context: CheckerContext - ) { - val containingDeclarations = notRefinedSupers.mapNotNull { it.containingClassLookupTag()?.toFirRegularClassSymbol(context.session) } - if (annotations.isEmpty()) { - reportOn(declaration.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context) - } else { - for (annotation in annotations) { - reportOn(annotation.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context) + private fun DiagnosticReporter.reportIncompatibleOverride( + declaration: FirDeclaration, + annotations: List, + notRefinedSupers: List>, + context: CheckerContext + ) { + val containingDeclarations = notRefinedSupers.mapNotNull { it.containingClassLookupTag()?.toFirRegularClassSymbol(context.session) } + if (annotations.isEmpty()) { + reportOn(declaration.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context) + } else { + for (annotation in annotations) { + reportOn(annotation.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context) + } } } + } } diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeThrowsChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeThrowsChecker.kt index 9743429cf32..52437a47cae 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeThrowsChecker.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeThrowsChecker.kt @@ -18,8 +18,10 @@ import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride import org.jetbrains.kotlin.fir.references.isError @@ -34,19 +36,34 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.annotations.KOTLIN_THROWS_ANNOTATION_FQ_NAME -// TODO: extract common checker for expect interfaces -object FirNativeThrowsChecker : FirBasicDeclarationChecker(MppCheckerKind.Platform) { - private val throwsClassId = ClassId.topLevel(KOTLIN_THROWS_ANNOTATION_FQ_NAME) +sealed class FirNativeThrowsChecker(mppKind: MppCheckerKind) : FirBasicDeclarationChecker(mppKind) { + object Regular : FirNativeThrowsChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if ((declaration as? FirMemberDeclaration)?.isExpect == true) return + super.check(declaration, context, reporter) + } + } - private val cancellationExceptionFqName = FqName("kotlin.coroutines.cancellation.CancellationException") + object ForExpectClass : FirNativeThrowsChecker(MppCheckerKind.Common) { + override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if ((declaration as? FirMemberDeclaration)?.isExpect != true) return + super.check(declaration, context, reporter) + } + } - private val cancellationExceptionAndSupersClassIds = setOf( - ClassId.topLevel(StandardNames.FqNames.throwable), - ClassId.topLevel(FqName("kotlin.Exception")), - ClassId.topLevel(FqName("kotlin.RuntimeException")), - ClassId.topLevel(FqName("kotlin.IllegalStateException")), - ClassId.topLevel(cancellationExceptionFqName) - ) + companion object { + private val throwsClassId = ClassId.topLevel(KOTLIN_THROWS_ANNOTATION_FQ_NAME) + + private val cancellationExceptionFqName = FqName("kotlin.coroutines.cancellation.CancellationException") + + private val cancellationExceptionAndSupersClassIds = setOf( + ClassId.topLevel(StandardNames.FqNames.throwable), + ClassId.topLevel(FqName("kotlin.Exception")), + ClassId.topLevel(FqName("kotlin.RuntimeException")), + ClassId.topLevel(FqName("kotlin.IllegalStateException")), + ClassId.topLevel(cancellationExceptionFqName) + ) + } override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { val throwsAnnotation = declaration.getAnnotationByClassId(throwsClassId, context.session) as? FirAnnotationCall diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt index 0dab38ac8b9..18a4f9dece9 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt @@ -10,7 +10,8 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.* object NativeDeclarationCheckers : DeclarationCheckers() { override val basicDeclarationCheckers: Set get() = setOf( - FirNativeThrowsChecker, + FirNativeThrowsChecker.Regular, + FirNativeThrowsChecker.ForExpectClass, FirNativeSharedImmutableChecker, FirNativeThreadLocalChecker, FirNativeIdentifierChecker, @@ -20,13 +21,16 @@ object NativeDeclarationCheckers : DeclarationCheckers() { override val callableDeclarationCheckers: Set get() = setOf( FirNativeObjCRefinementChecker, - FirNativeObjCNameCallableChecker, + FirNativeObjCNameCallableChecker.Regular, + FirNativeObjCNameCallableChecker.ForExpectClass, ) override val classCheckers: Set get() = setOf( - FirNativeObjCRefinementOverridesChecker, - FirNativeObjCNameOverridesChecker, + FirNativeObjCRefinementOverridesChecker.Regular, + FirNativeObjCRefinementOverridesChecker.ForExpectClass, + FirNativeObjCNameOverridesChecker.Regular, + FirNativeObjCNameOverridesChecker.ForExpectClass, FirNativeObjCOutletChecker, FirNativeObjCActionChecker, FirNativeObjCOverrideInitChecker, diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt index e056a220c64..dc279539b70 100644 --- a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt @@ -5,14 +5,17 @@ package org.jetbrains.kotlin.fir.analysis.wasm.checkers -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.* +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker import org.jetbrains.kotlin.fir.analysis.wasm.checkers.declaration.* import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirJsExportAnnotationChecker object WasmBaseDeclarationCheckers : DeclarationCheckers() { override val classCheckers: Set get() = setOf( - FirWasmExternalInheritanceChecker, + FirWasmExternalInheritanceChecker.Regular, + FirWasmExternalInheritanceChecker.ForExpectClass, ) override val basicDeclarationCheckers: Set @@ -39,4 +42,4 @@ object WasmWasiDeclarationCheckers : DeclarationCheckers() { get() = setOf( FirWasmWasiExternalDeclarationChecker, ) -} \ No newline at end of file +} diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmExternalInheritanceChecker.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmExternalInheritanceChecker.kt index 56f69a054e6..cb88f9d1a24 100644 --- a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmExternalInheritanceChecker.kt +++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmExternalInheritanceChecker.kt @@ -15,11 +15,25 @@ import org.jetbrains.kotlin.fir.analysis.checkers.toClassLikeSymbol import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.utils.isEffectivelyExternal +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.name.StandardClassIds -// TODO: extract common checker for expect interfaces -object FirWasmExternalInheritanceChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirWasmExternalInheritanceChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirWasmExternalInheritanceChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirWasmExternalInheritanceChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { val session = context.session val isCurrentClassExternal = declaration.symbol.isEffectivelyExternal(session) diff --git a/compiler/fir/checkers/module.md b/compiler/fir/checkers/module.md index 398bb7f16c9..dab185e1e95 100644 --- a/compiler/fir/checkers/module.md +++ b/compiler/fir/checkers/module.md @@ -143,3 +143,30 @@ So the author of each new checker should decide in which session this checker sh it most likely should be `Common` - if the checker is interested in the scope of some type, it should be carefully considered how the actualization of the scope may affect the checker + +#### Checkers for expect classes + +```kotlin +// MODULE: common +expect interface A +expect class B : A + +class C : A + +// MODULE: platform()()(common) +actual interface A { + fun foo() +} + +actual class B : A { + override fun foo() {} +} +``` + +In this example we want to report "abstract foo not implemented" on class `C`, but we don't want to report it on `expect class B` (as its supertype is always `expect A`, never `actual A`) + +So to cover such cases, it's worth splitting the platform checker into two parts: +- `Regular`, which is platform checkers and runs for everything except `expect` declaration +- `ForExpectClass`, which is common checkers and runs only for `expect` declarations + +As an example, check the implementation of [FirImplementationMismatchChecker](compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImplementationMismatchChecker.kt) checker diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 14441a18983..5639a0a5a44 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.fir.analysis.cfa.FirPropertyInitializationAnalyzer import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.* import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnonymousFunctionParametersChecker -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFiniteBoundRestrictionChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirInlinedLambdaNonSourceAnnotationsChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirMissingDependencySupertypeChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirSuspendAnonymousFunctionChecker @@ -103,15 +102,19 @@ object CommonDeclarationCheckers : DeclarationCheckers() { override val classCheckers: Set get() = setOf( - FirOverrideChecker, - FirNotImplementedOverrideChecker, - FirNotImplementedOverrideSimpleEnumEntryChecker, + FirOverrideChecker.Regular, + FirOverrideChecker.ForExpectClass, + FirNotImplementedOverrideChecker.Regular, + FirNotImplementedOverrideChecker.ForExpectClass, + FirNotImplementedOverrideSimpleEnumEntryChecker.Regular, + FirNotImplementedOverrideSimpleEnumEntryChecker.ForExpectClass, FirThrowableSubclassChecker, FirOpenMemberChecker, FirClassVarianceChecker, FirSealedSupertypeChecker, FirMemberPropertiesChecker, - FirImplementationMismatchChecker, + FirImplementationMismatchChecker.Regular, + FirImplementationMismatchChecker.ForExpectClass, FirTypeParametersInObjectChecker, FirSupertypesChecker, FirPrimaryConstructorSuperTypeChecker, @@ -119,7 +122,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirEnumCompanionInEnumConstructorCallChecker, FirBadInheritedJavaSignaturesChecker, FirSealedInterfaceAllowedChecker, - FirMixedFunctionalTypesInSupertypesChecker, + FirMixedFunctionalTypesInSupertypesChecker.Regular, + FirMixedFunctionalTypesInSupertypesChecker.ForExpectClass, ) override val regularClassCheckers: Set @@ -135,13 +139,16 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirManyCompanionObjectsChecker, FirMethodOfAnyImplementedInInterfaceChecker, FirDataClassPrimaryConstructorChecker, - FirFunInterfaceDeclarationChecker, + FirFunInterfaceDeclarationChecker.Regular, + FirFunInterfaceDeclarationChecker.ForExpectClass, FirNestedClassChecker, - FirValueClassDeclarationChecker, + FirValueClassDeclarationChecker.Regular, + FirValueClassDeclarationChecker.ForExpectClass, FirOuterClassArgumentsRequiredChecker, FirPropertyInitializationChecker, FirDelegateFieldTypeMismatchChecker, - FirMultipleDefaultsInheritedFromSupertypesChecker, + FirMultipleDefaultsInheritedFromSupertypesChecker.Regular, + FirMultipleDefaultsInheritedFromSupertypesChecker.ForExpectClass, FirFiniteBoundRestrictionChecker, FirNonExpansiveInheritanceRestrictionChecker, ) @@ -176,7 +183,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() { override val typeParameterCheckers: Set get() = setOf( - FirTypeParameterBoundsChecker, + FirTypeParameterBoundsChecker.Regular, + FirTypeParameterBoundsChecker.ForExpectClass, FirTypeParameterVarianceChecker, FirReifiedTypeParameterChecker, FirTypeParameterSyntaxChecker, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunInterfaceDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunInterfaceDeclarationChecker.kt index 328a42453f6..11eabcb4896 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunInterfaceDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunInterfaceDeclarationChecker.kt @@ -18,18 +18,28 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CAN import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WITH_SUSPEND_FUNCTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS import org.jetbrains.kotlin.fir.declarations.FirRegularClass -import org.jetbrains.kotlin.fir.declarations.utils.isAbstract -import org.jetbrains.kotlin.fir.declarations.utils.isFun -import org.jetbrains.kotlin.fir.declarations.utils.isInterface -import org.jetbrains.kotlin.fir.declarations.utils.isSuspend +import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.scopes.getFunctions import org.jetbrains.kotlin.fir.scopes.getProperties import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol -// TODO: extract common checker for expect interfaces -object FirFunInterfaceDeclarationChecker : FirRegularClassChecker(MppCheckerKind.Platform) { + +sealed class FirFunInterfaceDeclarationChecker(mppKind: MppCheckerKind) : FirRegularClassChecker(mppKind) { + object Regular : FirFunInterfaceDeclarationChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirFunInterfaceDeclarationChecker(MppCheckerKind.Common) { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { if (!declaration.isInterface || !declaration.isFun) return diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImplementationMismatchChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImplementationMismatchChecker.kt index 52f7b1258fb..c34161999db 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImplementationMismatchChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImplementationMismatchChecker.kt @@ -40,8 +40,20 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.TypeCheckerState import org.jetbrains.kotlin.utils.addIfNotNull -// TODO: extract common checker for expect interfaces -object FirImplementationMismatchChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirImplementationMismatchChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirImplementationMismatchChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirImplementationMismatchChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { val source = declaration.source ?: return diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMixedFunctionalTypesInSupertypesChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMixedFunctionalTypesInSupertypesChecker.kt index 935577a89d8..f0b2f5ced47 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMixedFunctionalTypesInSupertypesChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMixedFunctionalTypesInSupertypesChecker.kt @@ -13,11 +13,25 @@ import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes import org.jetbrains.kotlin.fir.types.functionTypeKind -// TODO: extract common checker for expect interfaces -object FirMixedFunctionalTypesInSupertypesChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirMixedFunctionalTypesInSupertypesChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirMixedFunctionalTypesInSupertypesChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirMixedFunctionalTypesInSupertypesChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { val superKinds = lookupSuperTypes(declaration.symbol, lookupInterfaces = true, deep = true, context.session) .mapNotNullTo(mutableSetOf()) { it.functionTypeKind(context.session)?.nonReflectKind() } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMultipleDefaultsInheritedFromSupertypesChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMultipleDefaultsInheritedFromSupertypesChecker.kt index c5b8ce2b41f..96e04382da8 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMultipleDefaultsInheritedFromSupertypesChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMultipleDefaultsInheritedFromSupertypesChecker.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.isSubstitutionOverride import org.jetbrains.kotlin.fir.scopes.processAllFunctions @@ -24,8 +25,21 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol import org.jetbrains.kotlin.fir.unwrapSubstitutionOverrides import org.jetbrains.kotlin.name.Name -// TODO: extract common checker for expect interfaces -object FirMultipleDefaultsInheritedFromSupertypesChecker : FirRegularClassChecker(MppCheckerKind.Platform) { +sealed class FirMultipleDefaultsInheritedFromSupertypesChecker(mppKind: MppCheckerKind) : FirRegularClassChecker(mppKind) { + object Regular : FirMultipleDefaultsInheritedFromSupertypesChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirMultipleDefaultsInheritedFromSupertypesChecker(MppCheckerKind.Common) { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { declaration.unsubstitutedScope(context).processAllFunctions { val originalIfSubstitutionOverride = it.unwrapSubstitutionOverrides() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt index 0c68037a8e2..b82dd3df42c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt @@ -41,8 +41,20 @@ import org.jetbrains.kotlin.util.ImplementationStatus import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract -// TODO: extract common checker for expect interfaces -object FirNotImplementedOverrideChecker : FirClassChecker(MppCheckerKind.Platform) { +sealed class FirNotImplementedOverrideChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirNotImplementedOverrideChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirNotImplementedOverrideChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { val source = declaration.source ?: return diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideSimpleEnumEntryChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideSimpleEnumEntryChecker.kt index 649502263f4..fa1cd14c0dd 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideSimpleEnumEntryChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideSimpleEnumEntryChecker.kt @@ -15,11 +15,25 @@ import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirEnumEntry import org.jetbrains.kotlin.fir.declarations.utils.isAbstract import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.scopes.processAllCallables import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -// TODO: extract common checker for expect interfaces -object FirNotImplementedOverrideSimpleEnumEntryChecker : FirClassChecker(MppCheckerKind.Common) { +sealed class FirNotImplementedOverrideSimpleEnumEntryChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) { + object Regular : FirNotImplementedOverrideSimpleEnumEntryChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirNotImplementedOverrideSimpleEnumEntryChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { if (!declaration.isEnumClass) return diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOverrideChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOverrideChecker.kt index 54e2cb1ffe1..72aab34e9fe 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOverrideChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOverrideChecker.kt @@ -23,10 +23,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.overridesBackwardCompatibilityHelper import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.utils.isFinal -import org.jetbrains.kotlin.fir.declarations.utils.isOverride -import org.jetbrains.kotlin.fir.declarations.utils.modality -import org.jetbrains.kotlin.fir.declarations.utils.visibility +import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.originalOrSelf import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap @@ -107,8 +104,21 @@ abstract class FirAbstractOverrideChecker(mppKind: MppCheckerKind) : FirClassChe } } -// TODO: extract common checker for expect interfaces -object FirOverrideChecker : FirAbstractOverrideChecker(MppCheckerKind.Platform) { +sealed class FirOverrideChecker(mppKind: MppCheckerKind) : FirAbstractOverrideChecker(mppKind) { + object Regular : FirOverrideChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + object ForExpectClass : FirOverrideChecker(MppCheckerKind.Common) { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { val typeCheckerState = context.session.typeContext.newTypeCheckerState( errorTypesEqualToAnything = false, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeParameterBoundsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeParameterBoundsChecker.kt index 9de8a295f1d..a86b8f95dc3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeParameterBoundsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeParameterBoundsChecker.kt @@ -13,14 +13,29 @@ import org.jetbrains.kotlin.fir.analysis.checkers.* import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.isOverride import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.TypeCheckerProviderContext -// TODO: extract common checker for expect interfaces -object FirTypeParameterBoundsChecker : FirTypeParameterChecker(MppCheckerKind.Platform) { +sealed class FirTypeParameterBoundsChecker(mppKind: MppCheckerKind) : FirTypeParameterChecker(mppKind) { + object Regular : FirTypeParameterBoundsChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) { + val containingDeclaration = context.containingDeclarations.lastOrNull() ?: return + if ((containingDeclaration as? FirMemberDeclaration)?.isExpect == true) return + check(declaration, containingDeclaration, context, reporter) + } + } + + object ForExpectClass : FirTypeParameterBoundsChecker(MppCheckerKind.Common) { + override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) { + val containingDeclaration = context.containingDeclarations.lastOrNull() ?: return + if ((containingDeclaration as? FirMemberDeclaration)?.isExpect != true) return + check(declaration, containingDeclaration, context, reporter) + } + } private val classKinds = setOf( ClassKind.CLASS, @@ -28,8 +43,12 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker(MppCheckerKind.Pl ClassKind.OBJECT ) - override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) { - val containingDeclaration = context.containingDeclarations.lastOrNull() ?: return + protected fun check( + declaration: FirTypeParameter, + containingDeclaration: FirDeclaration, + context: CheckerContext, + reporter: DiagnosticReporter, + ) { if (containingDeclaration is FirConstructor) return checkFinalUpperBounds(declaration, containingDeclaration, context, reporter) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirValueClassDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirValueClassDeclarationChecker.kt index b96b127803d..2a8189cb048 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirValueClassDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirValueClassDeclarationChecker.kt @@ -33,13 +33,27 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.StandardClassIds -// TODO: extract common checker for expect interfaces -object FirValueClassDeclarationChecker : FirRegularClassChecker(MppCheckerKind.Platform) { +sealed class FirValueClassDeclarationChecker(mppKind: MppCheckerKind) : FirRegularClassChecker(mppKind) { + object Regular : FirValueClassDeclarationChecker(MppCheckerKind.Platform) { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.isExpect) return + super.check(declaration, context, reporter) + } + } - private val boxAndUnboxNames = setOf("box", "unbox") - private val equalsAndHashCodeNames = setOf("equals", "hashCode") - private val javaLangFqName = FqName("java.lang") - private val cloneableFqName = FqName("Cloneable") + object ForExpectClass : FirValueClassDeclarationChecker(MppCheckerKind.Common) { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isExpect) return + super.check(declaration, context, reporter) + } + } + + companion object { + private val boxAndUnboxNames = setOf("box", "unbox") + private val equalsAndHashCodeNames = setOf("equals", "hashCode") + private val javaLangFqName = FqName("java.lang") + private val cloneableFqName = FqName("Cloneable") + } override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { if (!declaration.symbol.isInlineOrValueClass()) {