[FIR, IR] 1/2 Minimize usages of ExpectActualCompatibility, MismatchOrIncompatible and MatchedOrCompatible

- Migrate ExpectActualCompatibility -> ExpectActualCheckingCompatibility
  where the "checker" is expect
- Migrate ExpectActualCompatibility -> ExpectActualMatchingCompatibility
  where the "matching" is expect

KT-62590 in progress. A lot of tests start to fail now. I will fix them
in next commits

Review: https://jetbrains.team/p/kt/reviews/12750/timeline
This commit is contained in:
Nikita Bobko
2023-10-25 22:15:51 +02:00
committed by teamcity
parent 664b9cc3ba
commit eb0c8c00c3
16 changed files with 181 additions and 170 deletions
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.expectForActual
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.resolve.multiplatform.isCompatibleOrWeaklyIncompatible
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
internal class KtFirMultiplatformInfoProvider(
override val analysisSession: KtFirAnalysisSession,
@@ -31,10 +31,7 @@ internal class KtFirMultiplatformInfoProvider(
}
if (status?.isActual != true) return emptyList()
return firSymbol.expectForActual.orEmpty().asSequence()
.filter { it.key.isCompatibleOrWeaklyIncompatible }
.flatMap { it.value }
.map { analysisSession.firSymbolBuilder.buildSymbol(it) as KtDeclarationSymbol }
.toList()
return firSymbol.expectForActual?.get(ExpectActualMatchingCompatibility.MatchedSuccessfully)
?.map { analysisSession.firSymbolBuilder.buildSymbol(it) as KtDeclarationSymbol }.orEmpty()
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.areCompatibleExpectActualTypes
import org.jetbrains.kotlin.fir.types.createExpectActualTypeParameterSubstitutor
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import org.jetbrains.kotlin.utils.zipIfSizesAreEqual
object FirActualCallableDeclarationChecker : FirCallableDeclarationChecker() {
@@ -60,7 +61,7 @@ object FirActualCallableDeclarationChecker : FirCallableDeclarationChecker() {
callableDeclaration.source,
FirErrors.ACTUAL_WITHOUT_EXPECT,
actualFunctionSymbol,
actualFunctionSymbol.expectForActual as Map<ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>,
actualFunctionSymbol.expectForActual as Map<ExpectActualMatchingCompatibility, Collection<FirBasedSymbol<*>>>,
context
)
}
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker
import org.jetbrains.kotlin.resolve.multiplatform.compatible
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
internal object FirDefaultArgumentsInExpectActualizedByFakeOverrideChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -77,7 +77,8 @@ internal object FirDefaultArgumentsInExpectActualizedByFakeOverrideChecker : Fir
expectSymbol, actualSymbol, actualMember,
checkClassScopesCompatibility = false
)
val expectMember: DeclarationSymbolMarker = potentialExpects.entries.singleOrNull { it.value.compatible }?.key
val expectMember: DeclarationSymbolMarker = potentialExpects.entries
.singleOrNull { it.value == ExpectActualMatchingCompatibility.MatchedSuccessfully }?.key
?: potentialExpects.keys.singleOrNull()
?: return null
return expectMember as FirNamedFunctionSymbol
@@ -9,8 +9,7 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getModifierList
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
@@ -19,22 +18,22 @@ import org.jetbrains.kotlin.fir.declarations.utils.isActual
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isExternal
import org.jetbrains.kotlin.fir.declarations.utils.isTailRec
import org.jetbrains.kotlin.fir.expectActualMatchingContextFactory
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.mpp.RegularClassSymbolMarker
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualChecker
import org.jetbrains.kotlin.resolve.checkers.OptInNames
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCheckingCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.MismatchOrIncompatible
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.isCompatibleOrWeaklyIncompatible
@Suppress("DuplicatedCode")
object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
@@ -120,20 +119,35 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
declaration: FirMemberDeclaration,
context: CheckerContext,
reporter: DiagnosticReporter,
checkActual: Boolean = true
checkActual: Boolean = true,
) {
val symbol = declaration.symbol
val compatibilityToMembersMap = symbol.expectForActual ?: return
val matchingCompatibilityToMembersMap = symbol.expectForActual ?: return
val expectedSingleCandidate =
matchingCompatibilityToMembersMap[ExpectActualMatchingCompatibility.MatchedSuccessfully]?.singleOrNull()
val checkingCompatibility = if (expectedSingleCandidate != null) {
val expectActualMatchingContext = context.session.expectActualMatchingContextFactory.create(
context.session, context.scopeSession,
allowedWritingMemberExpectForActualMapping = true,
)
val actualContainingClass = context.containingDeclarations.lastOrNull()?.symbol as? FirRegularClassSymbol
val expectContainingClass = actualContainingClass?.getSingleExpectForActualOrNull() as? FirRegularClassSymbol
getCheckingCompatibility(
symbol,
expectedSingleCandidate,
actualContainingClass,
expectContainingClass,
expectActualMatchingContext,
)
} else null
checkAmbiguousExpects(symbol, compatibilityToMembersMap, symbol, context, reporter)
checkAmbiguousExpects(symbol, matchingCompatibilityToMembersMap, symbol, context, reporter)
val source = declaration.source
if (!declaration.isActual) {
if (compatibilityToMembersMap.allMismatches()) return
if (matchingCompatibilityToMembersMap.allMismatches()) return
if (ExpectActualCheckingCompatibility.Compatible in compatibilityToMembersMap ||
ExpectActualMatchingCompatibility.MatchedSuccessfully in compatibilityToMembersMap
) {
if (ExpectActualMatchingCompatibility.MatchedSuccessfully in matchingCompatibilityToMembersMap) {
if (checkActual) {
reporter.reportOn(source, FirErrors.ACTUAL_MISSING, context)
}
@@ -141,9 +155,8 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
}
}
val singleIncompatibility = compatibilityToMembersMap.keys.singleOrNull()
when {
singleIncompatibility is ExpectActualCheckingCompatibility.ClassScopes -> {
checkingCompatibility is ExpectActualCheckingCompatibility.ClassScopes -> {
require(symbol is FirRegularClassSymbol || symbol is FirTypeAliasSymbol) {
"Incompatible.ClassScopes is only possible for a class or a typealias: $declaration"
}
@@ -153,7 +166,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
// 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 MismatchOrIncompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>
expectedWithIncompatibility: Pair<FirBasedSymbol<*>, Map<out ExpectActualCompatibility.MismatchOrIncompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>,
): Boolean {
val (expectedMember, incompatibility) = expectedWithIncompatibility
val actualMember = incompatibility.values.singleOrNull()?.singleOrNull()
@@ -163,8 +176,8 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
actualMember.fir.expectForActual?.values?.singleOrNull()?.singleOrNull() == expectedMember
}
val nonTrivialIncompatibleMembers = singleIncompatibility.incompatibleMembers.filterNot(::hasSingleActualSuspect)
val nonTrivialMismatchedMembers = singleIncompatibility.mismatchedMembers.filterNot(::hasSingleActualSuspect)
val nonTrivialIncompatibleMembers = checkingCompatibility.incompatibleMembers.filterNot(::hasSingleActualSuspect)
val nonTrivialMismatchedMembers = checkingCompatibility.mismatchedMembers.filterNot(::hasSingleActualSuspect)
if (nonTrivialIncompatibleMembers.isNotEmpty()) {
reporter.reportOn(source, FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, symbol, nonTrivialIncompatibleMembers, context)
@@ -173,17 +186,28 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
}
}
ExpectActualCheckingCompatibility.Compatible !in compatibilityToMembersMap &&
ExpectActualMatchingCompatibility.MatchedSuccessfully !in compatibilityToMembersMap -> {
ExpectActualMatchingCompatibility.MatchedSuccessfully !in matchingCompatibilityToMembersMap &&
requireActualModifier(declaration.symbol, context.session) -> {
reporter.reportOn(
source,
FirErrors.ACTUAL_WITHOUT_EXPECT,
symbol,
matchingCompatibilityToMembersMap,
context
)
}
checkingCompatibility != null && checkingCompatibility != ExpectActualCheckingCompatibility.Compatible -> {
check(expectedSingleCandidate != null) // It can't be null, because checkingCompatibility is not null
// A nicer diagnostic for functions with default params
if (declaration is FirFunction && compatibilityToMembersMap.keys.any { it is ExpectActualCheckingCompatibility.ActualFunctionWithDefaultParameters }) {
if (declaration is FirFunction && checkingCompatibility == ExpectActualCheckingCompatibility.ActualFunctionWithDefaultParameters) {
reporter.reportOn(declaration.source, FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS, context)
} else if (requireActualModifier(declaration.symbol, context.session)) {
reporter.reportOn(
source,
FirErrors.ACTUAL_WITHOUT_EXPECT,
symbol,
compatibilityToMembersMap,
mapOf(checkingCompatibility to listOf(expectedSingleCandidate)),
context
)
}
@@ -191,27 +215,49 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
else -> {}
}
// We want to report errors even if a candidate is incompatible, but it's single
val expectedSingleCandidate = symbol.getSingleExpectForActualOrNull()
if (expectedSingleCandidate != null) {
checkOptInAnnotation(declaration, expectedSingleCandidate, context, reporter)
checkAnnotationsMatch(expectedSingleCandidate, symbol, context, reporter)
}
}
private fun getCheckingCompatibility(
actualSymbol: FirBasedSymbol<*>,
expectSymbol: FirBasedSymbol<*>,
actualContainingClass: FirRegularClassSymbol?,
expectContainingClass: FirRegularClassSymbol?,
context: FirExpectActualMatchingContext,
): ExpectActualCompatibility<FirBasedSymbol<*>> =
when {
actualSymbol is FirCallableSymbol<*> && expectSymbol is FirCallableSymbol<*> -> {
AbstractExpectActualChecker.getCallablesCompatibility(
expectSymbol,
actualSymbol,
expectContainingClass,
actualContainingClass,
context,
)
}
actualSymbol is FirClassLikeSymbol<*> && expectSymbol is RegularClassSymbolMarker -> {
AbstractExpectActualChecker.getClassifiersCompatibility(
expectSymbol,
actualSymbol,
checkClassScopesCompatibility = true,
context,
)
}
else -> error("These expect/actual shouldn't have been matched by FirExpectActualResolver")
}
private fun checkAmbiguousExpects(
actualDeclaration: FirBasedSymbol<*>,
compatibility: Map<ExpectActualCompatibility<FirBasedSymbol<*>>, List<FirBasedSymbol<*>>>,
compatibility: Map<ExpectActualMatchingCompatibility, List<FirBasedSymbol<*>>>,
symbol: FirBasedSymbol<*>,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val filesWithAtLeastWeaklyCompatibleExpects = compatibility.asSequence()
.filter { (compatibility, _) ->
compatibility.isCompatibleOrWeaklyIncompatible
}
.map { (_, members) -> members }
.flatten()
val filesWithAtLeastWeaklyCompatibleExpects = compatibility[ExpectActualMatchingCompatibility.MatchedSuccessfully]
.orEmpty()
.map { it.moduleData }
.sortedBy { it.name.asString() }
.toList()
@@ -451,7 +451,7 @@ class FirExpectActualMatchingContextImpl private constructor(
return symbol.source == null && symbol.origin !is FirDeclarationOrigin.Plugin
}
override fun onMatchedOrCompatibleMembers(
override fun onMatchedMembers(
expectSymbol: DeclarationSymbolMarker,
actualSymbol: DeclarationSymbolMarker,
containingExpectClassSymbol: RegularClassSymbolMarker?,
@@ -469,7 +469,7 @@ class FirExpectActualMatchingContextImpl private constructor(
override fun onMismatchedOrIncompatibleMembersFromClassScope(
expectSymbol: DeclarationSymbolMarker,
actualSymbolsByIncompatibility: Map<out ExpectActualCompatibility.MismatchOrIncompatible<*>, List<DeclarationSymbolMarker>>,
actualSymbolsByIncompatibility: Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker>>,
containingExpectClassSymbol: RegularClassSymbolMarker?,
containingActualClassSymbol: RegularClassSymbolMarker?
) {
@@ -489,7 +489,7 @@ class FirExpectActualMatchingContextImpl private constructor(
private fun FirRegularClassSymbol.addMemberExpectForActualMapping(
expectMember: FirBasedSymbol<*>, actualMember: FirBasedSymbol<*>,
expectClassSymbol: FirRegularClassSymbol, compatibility: ExpectActualCompatibility<*>,
expectClassSymbol: FirRegularClassSymbol, compatibility: ExpectActualMatchingCompatibility,
) {
check(allowedWritingMemberExpectForActualMapping) { "Writing memberExpectForActual is not allowed in this context" }
val fir = fir
@@ -524,7 +524,7 @@ class FirExpectActualMatchingContextImpl private constructor(
actualClass: RegularClassSymbolMarker,
actualMember: DeclarationSymbolMarker,
checkClassScopesCompatibility: Boolean,
): Map<FirBasedSymbol<*>, ExpectActualCompatibility<*>> {
): Map<FirBasedSymbol<*>, ExpectActualMatchingCompatibility> {
val mapping = actualClass.asSymbol().fir.memberExpectForActual
return mapping?.get(actualMember to expectClass) ?: emptyMap()
}
@@ -7,19 +7,20 @@ package org.jetbrains.kotlin.fir.resolve.transformers.mpp
import org.jetbrains.kotlin.fir.FirExpectActualMatchingContext
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.declarations.ExpectForActualMatchingData
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.dependenciesSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.mpp.CallableSymbolMarker
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualChecker
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualMatcher
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.getMatchedAndChecked
object FirExpectActualResolver {
fun findExpectForActual(
@@ -27,9 +28,9 @@ object FirExpectActualResolver {
useSiteSession: FirSession,
scopeSession: ScopeSession,
context: FirExpectActualMatchingContext,
): ExpectForActualData {
): ExpectForActualMatchingData {
with(context) {
val result = when (actualSymbol) {
val result: Map<ExpectActualMatchingCompatibility, List<FirBasedSymbol<*>>> = when (actualSymbol) {
is FirCallableSymbol<*> -> {
val callableId = actualSymbol.callableId
val classId = callableId.classId
@@ -60,7 +61,7 @@ object FirExpectActualResolver {
candidates.filter { expectSymbol ->
actualSymbol != expectSymbol && expectSymbol.isExpect
}.groupBy { expectDeclaration ->
AbstractExpectActualChecker.getCallablesCompatibility(
AbstractExpectActualMatcher.getCallablesMatchingCompatibility(
expectDeclaration,
actualSymbol as CallableSymbolMarker,
expectContainingClass,
@@ -69,21 +70,16 @@ object FirExpectActualResolver {
)
}.let {
// If there is a compatible entry, return a map only containing it
when (val compatibleSymbols = it.getMatchedAndChecked()) {
when (val compatibleSymbols = it[ExpectActualMatchingCompatibility.MatchedSuccessfully]) {
null -> it
else -> mapOf<ExpectActualCompatibility<FirBasedSymbol<*>>, _>(ExpectActualMatchingCompatibility.MatchedSuccessfully to compatibleSymbols)
else -> mapOf(ExpectActualMatchingCompatibility.MatchedSuccessfully to compatibleSymbols)
}
}
}
is FirClassLikeSymbol<*> -> {
val expectClassSymbol = useSiteSession.dependenciesSymbolProvider
.getClassLikeSymbolByClassId(actualSymbol.classId) as? FirRegularClassSymbol ?: return emptyMap()
val compatibility = AbstractExpectActualChecker.getClassifiersCompatibility(
expectClassSymbol,
actualSymbol,
checkClassScopesCompatibility = true,
context
)
val compatibility = AbstractExpectActualMatcher.matchClassifiers(expectClassSymbol, actualSymbol, context)
mapOf(compatibility to listOf(expectClassSymbol))
}
else -> emptyMap()
@@ -10,12 +10,11 @@ import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.isCompatibleOrWeaklyIncompatible
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
private object ExpectForActualAttributeKey : FirDeclarationDataKey()
typealias ExpectForActualData = Map<ExpectActualCompatibility<FirBasedSymbol<*>>, List<FirBasedSymbol<*>>>
typealias ExpectForActualMatchingData = Map<ExpectActualMatchingCompatibility, List<FirBasedSymbol<*>>>
/**
* Actual declaration -> (many) expect declaration mapping. For top-level declarations.
@@ -27,7 +26,7 @@ typealias ExpectForActualData = Map<ExpectActualCompatibility<FirBasedSymbol<*>>
* See `/docs/fir/k2_kmp.md`
*/
@SymbolInternals
var FirDeclaration.expectForActual: ExpectForActualData? by FirDeclarationDataRegistry.data(ExpectForActualAttributeKey)
var FirDeclaration.expectForActual: ExpectForActualMatchingData? by FirDeclarationDataRegistry.data(ExpectForActualAttributeKey)
/**
* @see expectForActual
@@ -38,17 +37,13 @@ fun FirFunctionSymbol<*>.getSingleExpectForActualOrNull(): FirFunctionSymbol<*>?
/**
* @see expectForActual
*/
fun FirBasedSymbol<*>.getSingleExpectForActualOrNull(): FirBasedSymbol<*>? {
val expectForActual = expectForActual ?: return null
val compatibleOrWeakCompatible: List<FirBasedSymbol<*>> =
expectForActual.entries.singleOrNull { it.key.isCompatibleOrWeaklyIncompatible }?.value ?: return null
return compatibleOrWeakCompatible.singleOrNull()
}
fun FirBasedSymbol<*>.getSingleExpectForActualOrNull(): FirBasedSymbol<*>? =
expectForActual?.get(ExpectActualMatchingCompatibility.MatchedSuccessfully)?.singleOrNull()
/**
* @see expectForActual
*/
val FirBasedSymbol<*>.expectForActual: ExpectForActualData?
val FirBasedSymbol<*>.expectForActual: ExpectForActualMatchingData?
get() {
lazyResolveToPhase(FirResolvePhase.EXPECT_ACTUAL_MATCHING)
return fir.expectForActual
@@ -61,7 +56,7 @@ private object MemberExpectForActualAttributeKey : FirDeclarationDataKey()
// in case when two `actual typealias` point to the same class.
typealias MemberExpectForActualData =
Map<Pair</* actual member */ FirBasedSymbol<*>, /* expect class */ FirRegularClassSymbol>,
Map</* expect member */ FirBasedSymbol<*>, ExpectActualCompatibility<*>>>
Map</* expect member */ FirBasedSymbol<*>, ExpectActualMatchingCompatibility>>
/**
* Actual class + expect class + actual member declaration -> (many) expect member declaration mapping.
@@ -10,7 +10,9 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.PsiIrFileEntry
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeAliasSymbol
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.callableId
@@ -20,8 +22,8 @@ import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker
import org.jetbrains.kotlin.mpp.RegularClassSymbolMarker
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualChecker
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualMatcher
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import java.io.File
/**
@@ -219,11 +221,10 @@ private class ExpectActualLinkCollector : IrElementVisitor<Unit, ExpectActualLin
actualSymbols: List<IrSymbol>,
context: MatchingContext
) {
AbstractExpectActualChecker.checkSingleExpectTopLevelDeclarationAgainstPotentialActuals(
AbstractExpectActualMatcher.matchSingleExpectTopLevelDeclarationAgainstPotentialActuals(
expectSymbol,
actualSymbols,
context,
checkClassScopesCompatibility = true
)
}
@@ -260,7 +261,7 @@ private class ExpectActualLinkCollector : IrElementVisitor<Unit, ExpectActualLin
override fun onMismatchedOrIncompatibleMembersFromClassScope(
expectSymbol: DeclarationSymbolMarker,
actualSymbolsByIncompatibility: Map<out ExpectActualCompatibility.MismatchOrIncompatible<*>, List<DeclarationSymbolMarker>>,
actualSymbolsByIncompatibility: Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker>>,
containingExpectClassSymbol: RegularClassSymbolMarker?,
containingActualClassSymbol: RegularClassSymbolMarker?,
) {
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualChecker
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualMatcher
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
@@ -45,11 +45,10 @@ internal fun collectActualCallablesMatchingToSpecificExpect(
matchingActuals += actualSymbol
}
}
AbstractExpectActualChecker.checkSingleExpectTopLevelDeclarationAgainstPotentialActuals(
AbstractExpectActualMatcher.matchSingleExpectTopLevelDeclarationAgainstPotentialActuals(
expectSymbol,
actualSymbols,
context,
checkClassScopesCompatibility = false
)
return matchingActuals
}
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualCollectionArgumentsCom
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
import org.jetbrains.kotlin.resolve.checkers.OptInNames
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.TypeCheckerState
import org.jetbrains.kotlin.types.Variance
@@ -480,7 +480,7 @@ internal abstract class IrExpectActualMatchingContext(
}
}
override fun onMatchedOrCompatibleMembers(
override fun onMatchedMembers(
expectSymbol: DeclarationSymbolMarker,
actualSymbol: DeclarationSymbolMarker,
containingExpectClassSymbol: RegularClassSymbolMarker?,
@@ -558,7 +558,7 @@ internal abstract class IrExpectActualMatchingContext(
actualClass: RegularClassSymbolMarker,
actualMember: DeclarationSymbolMarker,
checkClassScopesCompatibility: Boolean,
): Map<out DeclarationSymbolMarker, ExpectActualCompatibility<*>> = error("Should not be called")
): Map<out DeclarationSymbolMarker, ExpectActualMatchingCompatibility> = error("Should not be called")
// It's a stub, because not needed anywhere
private object IrSourceElementStub : SourceElementMarker
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.resolve.checkers.OptInNames
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.utils.zipIfSizesAreEqual
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType as IncompatibilityType
object AbstractExpectActualAnnotationMatchChecker {
@@ -316,7 +317,7 @@ object AbstractExpectActualAnnotationMatchChecker {
checkClassScopesCompatibility = false,
)
val expectMember = expectToCompatibilityMap
.filter { it.value is ExpectActualCompatibility.MatchedOrCompatible }.keys.singleOrNull()
.filter { it.value == ExpectActualMatchingCompatibility.MatchedSuccessfully }.keys.singleOrNull()
// Check also incompatible members if only one is found
?: expectToCompatibilityMap.keys.singleOrNull()
?: continue
@@ -13,8 +13,6 @@ import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCheckingCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.MismatchOrIncompatible
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
@@ -37,12 +35,17 @@ object AbstractExpectActualChecker {
actualClassLikeSymbol: ClassLikeSymbolMarker,
checkClassScopesCompatibility: Boolean,
context: ExpectActualMatchingContext<T>,
): ExpectActualCompatibility<T> {
): ExpectActualCheckingCompatibility<T> {
val result = with(context) {
getClassifiersCompatibility(expectClassSymbol, actualClassLikeSymbol, parentSubstitutor = null, checkClassScopesCompatibility)
getClassifiersCompatibility(
expectClassSymbol,
actualClassLikeSymbol,
parentSubstitutor = null,
checkClassScopesCompatibility,
)
}
@Suppress("UNCHECKED_CAST")
return result as ExpectActualCompatibility<T>
return result as ExpectActualCheckingCompatibility<T>
}
fun <T : DeclarationSymbolMarker> getCallablesCompatibility(
@@ -51,7 +54,7 @@ object AbstractExpectActualChecker {
expectContainingClass: RegularClassSymbolMarker?,
actualContainingClass: RegularClassSymbolMarker?,
context: ExpectActualMatchingContext<T>,
): ExpectActualCompatibility<T> = with (context) {
): ExpectActualCheckingCompatibility<T> = with (context) {
val expectTypeParameters = expectContainingClass?.typeParameters.orEmpty()
val actualTypeParameters = actualContainingClass?.typeParameters.orEmpty()
val parentSubstitutor = (expectTypeParameters zipIfSizesAreEqual actualTypeParameters)
@@ -61,10 +64,10 @@ object AbstractExpectActualChecker {
actualDeclaration,
parentSubstitutor,
expectContainingClass,
actualContainingClass
actualContainingClass,
)
@Suppress("UNCHECKED_CAST")
result as ExpectActualCompatibility<T>
result as ExpectActualCheckingCompatibility<T>
}
fun <T : DeclarationSymbolMarker> checkSingleExpectTopLevelDeclarationAgainstPotentialActuals(
@@ -93,7 +96,12 @@ object AbstractExpectActualChecker {
actualClassLikeSymbol: ClassLikeSymbolMarker,
parentSubstitutor: TypeSubstitutorMarker?,
checkClassScopes: Boolean,
): ExpectActualCheckingCompatibility<*> = getClassifiersIncompatibility(expectClassSymbol, actualClassLikeSymbol, parentSubstitutor, checkClassScopes)
): ExpectActualCheckingCompatibility<*> = getClassifiersIncompatibility(
expectClassSymbol,
actualClassLikeSymbol,
parentSubstitutor,
checkClassScopes,
)
?: ExpectActualCheckingCompatibility.Compatible
context(ExpectActualMatchingContext<*>)
@@ -301,27 +309,17 @@ object AbstractExpectActualChecker {
}
}
val mismatchedOrIncompatibleMap = mutableMapOf<MismatchOrIncompatible<*>, MutableList<DeclarationSymbolMarker>>()
val incompatibilityMap = mutableMapOf<ExpectActualCheckingCompatibility.Incompatible<*>, MutableList<DeclarationSymbolMarker>>()
for ((actualMember, compatibility) in mapping) {
when (compatibility) {
is ExpectActualCompatibility.MatchedOrCompatible<*> -> {
onMatchedOrCompatibleMembers(expectMember, actualMember, expectClassSymbol, actualClassSymbol)
return
}
is MismatchOrIncompatible<*> -> mismatchedOrIncompatibleMap.getOrPut(compatibility) { SmartList() }.add(actualMember)
ExpectActualCheckingCompatibility.Compatible -> return
is ExpectActualCheckingCompatibility.Incompatible<*> -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(actualMember)
}
}
// todo it's temporary code. KT-62590 in progress
val incompatibilities = mismatchedOrIncompatibleMap
.mapNotNull { (key, value) ->
(key as? ExpectActualCheckingCompatibility.Incompatible)?.let { it to value }
}
.toMap()
incompatibleMembers?.add(expectMember to incompatibilities)
onMismatchedOrIncompatibleMembersFromClassScope(expectMember, mismatchedOrIncompatibleMap, expectClassSymbol, actualClassSymbol)
incompatibleMembers?.add(expectMember to incompatibilityMap)
// Temporarily comment out reporting checking incompatibilities to backend. KT-62590 is in progress
//onMismatchedOrIncompatibleMembersFromClassScope(expectMember, incompatibilityMap, expectClassSymbol, actualClassSymbol)
}
context(ExpectActualMatchingContext<*>)
@@ -331,7 +329,7 @@ object AbstractExpectActualChecker {
parentSubstitutor: TypeSubstitutorMarker?,
expectContainingClass: RegularClassSymbolMarker?,
actualContainingClass: RegularClassSymbolMarker?,
): ExpectActualCompatibility<*> {
): ExpectActualCheckingCompatibility<*> {
require(
(expectDeclaration is ConstructorSymbolMarker && actualDeclaration is ConstructorSymbolMarker) ||
expectDeclaration.callableId.callableName == actualDeclaration.callableId.callableName
@@ -352,18 +350,15 @@ object AbstractExpectActualChecker {
return ExpectActualCheckingCompatibility.Compatible
}
// We must prioritize to return STRONG incompatible over WEAK incompatible (because STRONG incompatibility allows to search for overloads)
val annotationMode = expectContainingClass?.classKind == ClassKind.ANNOTATION_CLASS
return getCallablesStrongIncompatibility(expectDeclaration, actualDeclaration, annotationMode, parentSubstitutor)
?: getCallablesWeakIncompatibility(
expectDeclaration,
actualDeclaration,
annotationMode,
parentSubstitutor,
expectContainingClass,
actualContainingClass
)
?: ExpectActualCheckingCompatibility.Compatible
return getCallablesCheckingIncompatibility(
expectDeclaration,
actualDeclaration,
annotationMode,
parentSubstitutor,
expectContainingClass,
actualContainingClass,
) ?: ExpectActualCheckingCompatibility.Compatible
}
context(ExpectActualMatchingContext<*>)
@@ -423,14 +418,14 @@ object AbstractExpectActualChecker {
}
context(ExpectActualMatchingContext<*>)
private fun getCallablesWeakIncompatibility(
private fun getCallablesCheckingIncompatibility(
expectDeclaration: CallableSymbolMarker,
actualDeclaration: CallableSymbolMarker,
insideAnnotationClass: Boolean,
parentSubstitutor: TypeSubstitutorMarker?,
expectContainingClass: RegularClassSymbolMarker?,
actualContainingClass: RegularClassSymbolMarker?,
): ExpectActualCheckingCompatibility<*>? {
): ExpectActualCheckingCompatibility.Incompatible<*>? {
val expectedTypeParameters = expectDeclaration.typeParameters
val actualTypeParameters = actualDeclaration.typeParameters
val expectedValueParameters = expectDeclaration.valueParameters
@@ -679,7 +674,7 @@ object AbstractExpectActualChecker {
private fun getFunctionsIncompatibility(
expectFunction: CallableSymbolMarker,
actualFunction: CallableSymbolMarker,
): ExpectActualCheckingCompatibility<*>? {
): ExpectActualCheckingCompatibility.Incompatible<*>? {
if (!equalBy(expectFunction, actualFunction) { f -> f.isSuspend }) {
return ExpectActualCheckingCompatibility.FunctionModifiersDifferent
}
@@ -699,12 +694,13 @@ object AbstractExpectActualChecker {
private fun getPropertiesIncompatibility(
expected: PropertySymbolMarker,
actual: PropertySymbolMarker,
): ExpectActualCheckingCompatibility<*>? {
): ExpectActualCheckingCompatibility.Incompatible<*>? {
return when {
!equalBy(expected, actual) { p -> p.isVar } -> ExpectActualCheckingCompatibility.PropertyKind
!equalBy(expected, actual) { p -> p.isLateinit } -> ExpectActualCheckingCompatibility.PropertyLateinitModifier
expected.isConst && !actual.isConst -> ExpectActualCheckingCompatibility.PropertyConstModifier
!arePropertySettersWithCompatibleVisibilities(expected, actual) -> ExpectActualCheckingCompatibility.PropertySetterVisibility
!arePropertySettersWithCompatibleVisibilities(expected, actual) ->
ExpectActualCheckingCompatibility.PropertySetterVisibility
else -> null
}
}
@@ -716,7 +712,11 @@ object AbstractExpectActualChecker {
): Boolean {
val expectedSetter = expected.setter ?: return true
val actualSetter = actual.setter ?: return true
return areCompatibleCallableVisibilities(expectedSetter.visibility, expectedSetter.modality, actualSetter.visibility)
return areCompatibleCallableVisibilities(
expectedSetter.visibility,
expectedSetter.modality,
actualSetter.visibility,
)
}
// ---------------------------------------- Utils ----------------------------------------
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
@@ -27,26 +26,24 @@ import org.jetbrains.kotlin.utils.zipIfSizesAreEqual
* See `/docs/fir/k2_kmp.md` for details
*/
object AbstractExpectActualMatcher {
fun <T : DeclarationSymbolMarker> getCallablesCompatibility(
fun getCallablesMatchingCompatibility(
expectDeclaration: CallableSymbolMarker,
actualDeclaration: CallableSymbolMarker,
expectContainingClass: RegularClassSymbolMarker?,
actualContainingClass: RegularClassSymbolMarker?,
context: ExpectActualMatchingContext<T>,
): ExpectActualCompatibility<T> = with (context) {
context: ExpectActualMatchingContext<*>,
): ExpectActualMatchingCompatibility = with (context) {
val expectTypeParameters = expectContainingClass?.typeParameters.orEmpty()
val actualTypeParameters = actualContainingClass?.typeParameters.orEmpty()
val parentSubstitutor = (expectTypeParameters zipIfSizesAreEqual actualTypeParameters)
?.let { createExpectActualTypeParameterSubstitutor(it, parentSubstitutor = null) }
val result = getCallablesCompatibility(
getCallablesCompatibility(
expectDeclaration,
actualDeclaration,
parentSubstitutor,
expectContainingClass,
actualContainingClass
)
@Suppress("UNCHECKED_CAST")
result as ExpectActualCompatibility<T>
}
fun <T : DeclarationSymbolMarker> matchSingleExpectTopLevelDeclarationAgainstPotentialActuals(
@@ -147,7 +144,7 @@ object AbstractExpectActualMatcher {
for ((actualMember, compatibility) in mapping) {
when (compatibility) {
ExpectActualMatchingCompatibility.MatchedSuccessfully -> {
onMatchedOrCompatibleMembers(expectMember, actualMember, expectClassSymbol, actualClassSymbol)
onMatchedMembers(expectMember, actualMember, expectClassSymbol, actualClassSymbol)
return actualMember
}
@@ -189,12 +186,12 @@ object AbstractExpectActualMatcher {
}
val annotationMode = expectContainingClass?.classKind == ClassKind.ANNOTATION_CLASS
return getCallablesStrongIncompatibility(expectDeclaration, actualDeclaration, annotationMode, parentSubstitutor)
return getCallablesMatchingIncompatibility(expectDeclaration, actualDeclaration, annotationMode, parentSubstitutor)
?: ExpectActualMatchingCompatibility.MatchedSuccessfully
}
context(ExpectActualMatchingContext<*>)
private fun getCallablesStrongIncompatibility(
private fun getCallablesMatchingIncompatibility(
expectDeclaration: CallableSymbolMarker,
actualDeclaration: CallableSymbolMarker,
insideAnnotationClass: Boolean,
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
@@ -165,7 +165,7 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
val CallableSymbolMarker.hasStableParameterNames: Boolean
fun onMatchedOrCompatibleMembers(
fun onMatchedMembers(
expectSymbol: DeclarationSymbolMarker,
actualSymbol: DeclarationSymbolMarker,
containingExpectClassSymbol: RegularClassSymbolMarker?,
@@ -174,7 +174,7 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
fun onMismatchedOrIncompatibleMembersFromClassScope(
expectSymbol: DeclarationSymbolMarker,
actualSymbolsByIncompatibility: Map<out ExpectActualCompatibility.MismatchOrIncompatible<*>, List<DeclarationSymbolMarker>>,
actualSymbolsByIncompatibility: Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker>>,
containingExpectClassSymbol: RegularClassSymbolMarker?,
containingActualClassSymbol: RegularClassSymbolMarker?,
) {}
@@ -217,7 +217,7 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
actualClass: RegularClassSymbolMarker,
actualMember: DeclarationSymbolMarker,
checkClassScopesCompatibility: Boolean,
): Map<out DeclarationSymbolMarker, ExpectActualCompatibility<*>>
): Map<out DeclarationSymbolMarker, ExpectActualMatchingCompatibility>
fun DeclarationSymbolMarker.getSourceElement(): SourceElementMarker
@@ -20,9 +20,6 @@ sealed interface ExpectActualCompatibility<out D> {
sealed interface MismatchOrIncompatible<out D> : ExpectActualCompatibility<D> {
val reason: String?
}
// It's temporary class. KT-62590 is in progress
sealed interface MatchedOrCompatible<out D> : ExpectActualCompatibility<D>
}
/**
@@ -41,7 +38,7 @@ sealed class ExpectActualMatchingCompatibility : ExpectActualCompatibility<Nothi
object FunctionTypeParameterCount : Mismatch(TYPE_PARAMETER_COUNT)
object ParameterTypes : Mismatch("parameter types are different")
object FunctionTypeParameterUpperBounds : Mismatch("upper bounds of type parameters are different")
object MatchedSuccessfully : ExpectActualMatchingCompatibility(), ExpectActualCompatibility.MatchedOrCompatible<Nothing>
object MatchedSuccessfully : ExpectActualMatchingCompatibility()
}
/**
@@ -96,16 +93,5 @@ sealed class ExpectActualCheckingCompatibility<out D> : ExpectActualCompatibilit
object ClassTypeParameterUpperBounds : Incompatible<Nothing>(ExpectActualMatchingCompatibility.FunctionTypeParameterUpperBounds.reason)
object TypeParameterVariance : Incompatible<Nothing>("declaration-site variances of type parameters are different")
object TypeParameterReified : Incompatible<Nothing>("some type parameter is reified in one declaration and non-reified in the other")
object Compatible : ExpectActualCheckingCompatibility<Nothing>(), ExpectActualCompatibility.MatchedOrCompatible<Nothing>
object Compatible : ExpectActualCheckingCompatibility<Nothing>()
}
val ExpectActualCompatibility<*>.isCompatibleOrWeaklyIncompatible: Boolean
get() = this is ExpectActualCompatibility.MatchedOrCompatible || this is ExpectActualCheckingCompatibility
val ExpectActualCompatibility<*>.compatible: Boolean
get() = this is ExpectActualCompatibility.MatchedOrCompatible
// It's temporary function. KT-62590 is in progress
fun <T, R> Map<ExpectActualCompatibility<R>, List<T>>.getMatchedAndChecked(): List<T>? =
(get(ExpectActualMatchingCompatibility.MatchedSuccessfully).orEmpty() + get(ExpectActualCheckingCompatibility.Compatible).orEmpty())
.takeIf { it.isNotEmpty() }
@@ -56,16 +56,7 @@ data class ExpectActualMemberDiff<out M, out C>(val kind: Kind, val actualMember
}
}
fun ExpectActualCompatibility.MismatchOrIncompatible<*>.toMemberDiffKind(): ExpectActualMemberDiff.Kind? = when (this) {
ExpectActualMatchingCompatibility.CallableKind,
ExpectActualMatchingCompatibility.ParameterCount,
ExpectActualMatchingCompatibility.ParameterShape,
ExpectActualMatchingCompatibility.ParameterTypes,
ExpectActualMatchingCompatibility.FunctionTypeParameterCount,
ExpectActualMatchingCompatibility.FunctionTypeParameterUpperBounds,
// It's an awful API. It will be fixed in KT-62752
-> error("It's not allowed to call this function with receiver: $this")
fun ExpectActualCheckingCompatibility.Incompatible<*>.toMemberDiffKind(): ExpectActualMemberDiff.Kind? = when (this) {
ExpectActualCheckingCompatibility.ReturnType -> ExpectActualMemberDiff.Kind.ReturnTypeChangedInOverride
ExpectActualCheckingCompatibility.ClassTypeParameterCount -> error("Not applicable because ExpectActualMemberDiff is about members")
ExpectActualCheckingCompatibility.ClassTypeParameterUpperBounds -> error("Not applicable because ExpectActualMemberDiff is about members")