[FIR] Cleanup: extract reportClassScopesIncompatibility into its own function

Review: https://jetbrains.team/p/kt/reviews/13094/timeline
This commit is contained in:
Nikita Bobko
2023-11-17 10:49:09 +01:00
committed by teamcity
parent 7166adb179
commit 6f17022449
@@ -155,57 +155,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
when {
checkingCompatibility is ExpectActualCheckingCompatibility.ClassScopes -> {
require((symbol is FirRegularClassSymbol || symbol is FirTypeAliasSymbol) && expectedSingleCandidate is FirRegularClassSymbol) {
"Incompatible.ClassScopes is only possible for a class or a typealias: $declaration"
}
// Do not report "expected members have no actual ones" for those expected members, for which there's a clear
// (albeit maybe incompatible) single actual suspect, declared in the actual class.
// This is needed only to reduce the number of errors. Incompatibility errors for those members will be reported
// later when this checker is called for them
fun hasSingleActualSuspect(
expectedWithIncompatibility: Pair<FirBasedSymbol<*>, Map<out ExpectActualCheckingCompatibility.Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>,
): Boolean {
val (expectedMember, incompatibility) = expectedWithIncompatibility
val actualMember = incompatibility.values.singleOrNull()?.singleOrNull()
@OptIn(SymbolInternals::class)
return actualMember != null &&
actualMember.fir.expectForActual?.values?.singleOrNull()?.singleOrNull() == expectedMember
}
val nonTrivialIncompatibleMembers = checkingCompatibility.incompatibleMembers.filterNot(::hasSingleActualSuspect)
if (nonTrivialIncompatibleMembers.isNotEmpty()) {
val (defaultArgsIncompatibleMembers, otherIncompatibleMembers) =
nonTrivialIncompatibleMembers.partition { it.second.contains(ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride) }
if (defaultArgsIncompatibleMembers.isNotEmpty()) { // report a nicer diagnostic for DefaultArgumentsInExpectActualizedByFakeOverride
val problematicExpectMembers = defaultArgsIncompatibleMembers
.map {
it.first as? FirNamedFunctionSymbol
?: error("${ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride} can be reported only for ${FirNamedFunctionSymbol::class}")
}
reporter.reportOn(
source,
FirErrors.DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE,
expectedSingleCandidate,
problematicExpectMembers,
context
)
}
if (otherIncompatibleMembers.isNotEmpty()) {
reporter.reportOn(source, FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, symbol, otherIncompatibleMembers, context)
}
}
if (checkingCompatibility.mismatchedMembers.isNotEmpty()) {
reporter.reportOn(
source,
FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS,
symbol,
checkingCompatibility.mismatchedMembers,
context
)
}
reportClassScopesIncompatibility(symbol, expectedSingleCandidate, declaration, checkingCompatibility, reporter, source, context)
}
ExpectActualMatchingCompatibility.MatchedSuccessfully !in matchingCompatibilityToMembersMap &&
@@ -242,6 +192,68 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
}
}
private fun reportClassScopesIncompatibility(
symbol: FirBasedSymbol<out FirDeclaration>,
expectedSingleCandidate: FirBasedSymbol<*>?,
declaration: FirMemberDeclaration,
checkingCompatibility: ExpectActualCheckingCompatibility.ClassScopes<FirBasedSymbol<*>>,
reporter: DiagnosticReporter,
source: KtSourceElement?,
context: CheckerContext,
) {
require((symbol is FirRegularClassSymbol || symbol is FirTypeAliasSymbol) && expectedSingleCandidate is FirRegularClassSymbol) {
"Incompatible.ClassScopes is only possible for a class or a typealias: $declaration"
}
// Do not report "expected members have no actual ones" for those expected members, for which there's a clear
// (albeit maybe incompatible) single actual suspect, declared in the actual class.
// This is needed only to reduce the number of errors. Incompatibility errors for those members will be reported
// later when this checker is called for them
fun hasSingleActualSuspect(
expectedWithIncompatibility: Pair<FirBasedSymbol<*>, Map<out ExpectActualCheckingCompatibility.Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>,
): Boolean {
val (expectedMember, incompatibility) = expectedWithIncompatibility
val actualMember = incompatibility.values.singleOrNull()?.singleOrNull()
@OptIn(SymbolInternals::class)
return actualMember != null &&
actualMember.fir.expectForActual?.values?.singleOrNull()?.singleOrNull() == expectedMember
}
val nonTrivialIncompatibleMembers = checkingCompatibility.incompatibleMembers.filterNot(::hasSingleActualSuspect)
if (nonTrivialIncompatibleMembers.isNotEmpty()) {
val (defaultArgsIncompatibleMembers, otherIncompatibleMembers) =
nonTrivialIncompatibleMembers.partition { it.second.contains(ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride) }
if (defaultArgsIncompatibleMembers.isNotEmpty()) { // report a nicer diagnostic for DefaultArgumentsInExpectActualizedByFakeOverride
val problematicExpectMembers = defaultArgsIncompatibleMembers
.map {
it.first as? FirNamedFunctionSymbol
?: error("${ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride} can be reported only for ${FirNamedFunctionSymbol::class}")
}
reporter.reportOn(
source,
FirErrors.DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE,
expectedSingleCandidate,
problematicExpectMembers,
context
)
}
if (otherIncompatibleMembers.isNotEmpty()) {
reporter.reportOn(source, FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, symbol, otherIncompatibleMembers, context)
}
}
if (checkingCompatibility.mismatchedMembers.isNotEmpty()) {
reporter.reportOn(
source,
FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS,
symbol,
checkingCompatibility.mismatchedMembers,
context
)
}
}
private fun getCheckingCompatibility(
actualSymbol: FirBasedSymbol<*>,
expectSymbol: FirBasedSymbol<*>,