From 990da9fa1a2cca52ebf1300f38292f300d78f6d9 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 9 Jan 2024 15:12:05 +0200 Subject: [PATCH] [FIR] Part 5. Introduce paired common checkers for expect classes There are some cases when we want to run some platform checker not from platform session but from common session. All such cases appear when we check some `expect` class ```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 some platform checkers were split 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 ^KT-58881 Fixed ^KT-58881 Fixed ^KT-64187 Fixed --- .../js/checkers/JsDeclarationCheckers.kt | 15 +- .../FirJsExternalInheritorOnlyChecker.kt | 18 ++- .../FirJsInheritanceClassChecker.kt | 18 ++- .../FirJsInheritanceFunctionChecker.kt | 19 ++- .../FirJsMultipleInheritanceChecker.kt | 18 ++- .../FirJsNameClashClassMembersChecker.kt | 18 ++- .../jvm/checkers/JvmDeclarationCheckers.kt | 3 +- ...irOverrideJavaNullabilityWarningChecker.kt | 18 ++- .../FirNativeObjCNameCallableChecker.kt | 33 +++- .../FirNativeObjCNameOverridesChecker.kt | 16 +- .../FirNativeObjCRefinementChecker.kt | 11 +- ...FirNativeObjCRefinementOverridesChecker.kt | 148 ++++++++++-------- .../native/checkers/FirNativeThrowsChecker.kt | 39 +++-- .../checkers/NativeDeclarationCheckers.kt | 12 +- .../wasm/checkers/WasmDeclarationCheckers.kt | 9 +- .../FirWasmExternalInheritanceChecker.kt | 18 ++- compiler/fir/checkers/module.md | 27 ++++ .../checkers/CommonDeclarationCheckers.kt | 28 ++-- .../FirFunInterfaceDeclarationChecker.kt | 22 ++- .../FirImplementationMismatchChecker.kt | 16 +- ...MixedFunctionalTypesInSupertypesChecker.kt | 18 ++- ...eDefaultsInheritedFromSupertypesChecker.kt | 18 ++- .../FirNotImplementedOverrideChecker.kt | 16 +- ...plementedOverrideSimpleEnumEntryChecker.kt | 18 ++- .../declaration/FirOverrideChecker.kt | 22 ++- .../FirTypeParameterBoundsChecker.kt | 27 +++- .../FirValueClassDeclarationChecker.kt | 26 ++- 27 files changed, 495 insertions(+), 156 deletions(-) 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()) {