WIP! Thu 21 Sep 19:25:58 CEST 2023
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt index 2e877af..dbe1e83 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt
@@ -185,7 +185,8 @@ classTypeSubstitutor, expect, actual, - matchingContext + matchingContext, + context.languageVersionSettings ) } .takeIf { kinds -> kinds.all { it != ExpectActualCompatibility.Compatible } }
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt index 5294c02..25b6c27 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.mpp.CallableSymbolMarker -import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker +import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCallablesMatcher import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility import org.jetbrains.kotlin.utils.zipIfSizesAreEqual @@ -69,7 +69,7 @@ candidates.filter { expectSymbol -> actualSymbol != expectSymbol && expectSymbol.isExpect }.groupBy { expectDeclaration -> - AbstractExpectActualCompatibilityChecker.getCallablesCompatibility( + AbstractExpectActualCallablesMatcher.getCallablesCompatibility( expectDeclaration, actualSymbol as CallableSymbolMarker, parentSubstitutor, @@ -88,13 +88,7 @@ is FirClassLikeSymbol<*> -> { val expectClassSymbol = useSiteSession.dependenciesSymbolProvider .getClassLikeSymbolByClassId(actualSymbol.classId) as? FirRegularClassSymbol ?: return emptyMap() - val compatibility = AbstractExpectActualCompatibilityChecker.getClassifiersCompatibility( - expectClassSymbol, - actualSymbol, - checkClassScopesCompatibility = true, - context - ) - mapOf(compatibility to listOf(expectClassSymbol)) + mapOf((ExpectActualCompatibility.Compatible as ExpectActualCompatibility<FirBasedSymbol<*>>) to listOf(expectClassSymbol)) } else -> emptyMap() }
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt index fa67e2f..ea92dcd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt
@@ -6,6 +6,7 @@ package org.jetbrains.kotlin.resolve.checkers import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.incremental.components.NoLookupLocation @@ -70,7 +71,7 @@ declaration: KtClassLikeDeclaration, descriptor: ClassifierDescriptorWithTypeParameters, ) { - val scopeDiff = calculateExpectActualScopeDiff(expect, actual) + val scopeDiff = calculateExpectActualScopeDiff(expect, actual, context.languageVersionSettings) if (scopeDiff.isNotEmpty()) { context.trace.report( Errors.ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_MEMBERS_AS_NON_FINAL_EXPECT_CLASSIFIER_WARNING.on( @@ -139,6 +140,7 @@ private fun calculateExpectActualScopeDiff( expect: ClassDescriptor, actual: ClassDescriptor, + languageVersionSettings: LanguageVersionSettings, ): Set<ExpectActualMemberDiff<CallableMemberDescriptor, ClassDescriptor>> { val matchingContext = ClassicExpectActualMatchingContext(actual.module) val classTypeSubstitutor = (expect.declaredTypeParameters zipIfSizesAreEqual actual.declaredTypeParameters) @@ -164,7 +166,8 @@ classTypeSubstitutor, expect, actual, - matchingContext + matchingContext, + languageVersionSettings ) } .takeIf { kinds -> kinds.all { it != ExpectActualCompatibility.Compatible } }
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCallablesMatcher.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCallablesMatcher.kt index d68690d..e0f8249 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCallablesMatcher.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCallablesMatcher.kt
@@ -5,14 +5,40 @@ package org.jetbrains.kotlin.resolve.calls.mpp +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.mpp.* +import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker.name +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.zipIfSizesAreEqual object AbstractExpectActualCallablesMatcher { + fun <T : DeclarationSymbolMarker> getCallablesCompatibility( + expectDeclaration: CallableSymbolMarker, + actualDeclaration: CallableSymbolMarker, + parentSubstitutor: TypeSubstitutorMarker?, + expectContainingClass: RegularClassSymbolMarker?, + actualContainingClass: RegularClassSymbolMarker?, + context: ExpectActualMatchingContext<T>, + ): ExpectActualCompatibility<T> { + val result = with(context) { + getCallablesMatchingIncompatibility( + expectDeclaration, + actualDeclaration, + parentSubstitutor, + expectContainingClass, + actualContainingClass, + ) ?: ExpectActualCompatibility.Compatible + } + @Suppress("UNCHECKED_CAST") + return result as ExpectActualCompatibility<T> + } + context(ExpectActualMatchingContext<*>) internal fun getCallablesMatchingIncompatibility( expectDeclaration: CallableSymbolMarker, @@ -90,6 +116,118 @@ } context(ExpectActualMatchingContext<*>) + private fun getClassScopesIncompatibility( + expectClassSymbol: RegularClassSymbolMarker, + actualClassSymbol: RegularClassSymbolMarker, + substitutor: TypeSubstitutorMarker, + ): Incompatible.ExpectActualCheckingIncompatible<*>? { + val unfulfilled = arrayListOf<Pair<DeclarationSymbolMarker, Map<Incompatible<*>, List<DeclarationSymbolMarker?>>>>() + + val actualMembersByName = actualClassSymbol.collectAllMembers(isActualDeclaration = true).groupBy { it.name } + + outer@ for (expectMember in expectClassSymbol.collectAllMembers(isActualDeclaration = false)) { + if (expectMember is CallableSymbolMarker && expectMember.shouldSkipMatching(expectClassSymbol)) continue + + val actualMembers = actualMembersByName[expectMember.name]?.filter { actualMember -> + expectMember is CallableSymbolMarker && actualMember is CallableSymbolMarker || + expectMember is RegularClassSymbolMarker && actualMember is RegularClassSymbolMarker + }.orEmpty() + + matchSingleExpectAgainstPotentialActuals( + expectMember, + actualMembers, + substitutor, + expectClassSymbol, + actualClassSymbol, + unfulfilled, +// checkClassScopesCompatibility = true, + ) + } + + if (expectClassSymbol.classKind == ClassKind.ENUM_CLASS) { + val aEntries = expectClassSymbol.collectEnumEntryNames() + val bEntries = actualClassSymbol.collectEnumEntryNames() + + if (!bEntries.containsAll(aEntries)) return Incompatible.EnumEntries + } + + // TODO: check static scope? + + if (unfulfilled.isEmpty()) return null + + return Incompatible.ClassScopes(unfulfilled) + } + + fun <T : DeclarationSymbolMarker> matchSingleExpectTopLevelDeclarationAgainstPotentialActuals( + expectDeclaration: DeclarationSymbolMarker, + actualDeclarations: List<DeclarationSymbolMarker>, + context: ExpectActualMatchingContext<T>, + ) { + with(context) { + matchSingleExpectAgainstPotentialActuals( + expectDeclaration, + actualDeclarations, + substitutor = null, + expectClassSymbol = null, + actualClassSymbol = null, + unfulfilled = null, +// checkClassScopesCompatibility = true, + ) + } + } + + context(ExpectActualMatchingContext<*>) + private fun matchSingleExpectAgainstPotentialActuals( + expectMember: DeclarationSymbolMarker, + actualMembers: List<DeclarationSymbolMarker>, + substitutor: TypeSubstitutorMarker?, + expectClassSymbol: RegularClassSymbolMarker?, + actualClassSymbol: RegularClassSymbolMarker?, + unfulfilled: MutableList<Pair<DeclarationSymbolMarker, Map<Incompatible<*>, List<DeclarationSymbolMarker?>>>>?, +// checkClassScopesCompatibility: Boolean, + ) { + val mapping = actualMembers.keysToMap { actualMember -> + when (expectMember) { + is CallableSymbolMarker -> getCallablesMatchingIncompatibility( + expectMember, + actualMember as CallableSymbolMarker, + substitutor, + expectClassSymbol, + actualClassSymbol, + ) ?: ExpectActualCompatibility.Compatible + + is RegularClassSymbolMarker -> { +// val parentSubstitutor = substitutor?.takeIf { !innerClassesCapturesOuterTypeParameters } +// AbstractExpectActualCompatibilityChecker.getClassifiersCompatibility( +// expectMember, +// actualMember as ClassLikeSymbolMarker, +// languageVersionSettings, +// parentSubstitutor, +// checkClassScopesCompatibility, +// ) + ExpectActualCompatibility.Compatible + } + else -> error("Unsupported declaration: $expectMember ($actualMembers)") + } + } + + val incompatibilityMap = mutableMapOf<Incompatible<*>, MutableList<DeclarationSymbolMarker>>() + for ((actualMember, compatibility) in mapping) { + when (compatibility) { + ExpectActualCompatibility.Compatible -> { + onMatchedMembers(expectMember, actualMember, expectClassSymbol, actualClassSymbol) + return + } + + is Incompatible -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(actualMember) + } + } + + unfulfilled?.add(expectMember to incompatibilityMap) + onMismatchedMembersFromClassScope(expectMember, incompatibilityMap, expectClassSymbol, actualClassSymbol) + } + + context(ExpectActualMatchingContext<*>) private fun valueParametersCountCompatible( expectDeclaration: CallableSymbolMarker, actualDeclaration: CallableSymbolMarker,
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCompatibilityChecker.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCompatibilityChecker.kt index ab6477e..e6bedb4 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCompatibilityChecker.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCompatibilityChecker.kt
@@ -5,6 +5,7 @@ package org.jetbrains.kotlin.resolve.calls.mpp +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities @@ -28,9 +29,16 @@ actualClassLikeSymbol: ClassLikeSymbolMarker, checkClassScopesCompatibility: Boolean, context: ExpectActualMatchingContext<T>, + languageVersionSettings: LanguageVersionSettings, ): ExpectActualCompatibility<T> { val result = with(context) { - getClassifiersCompatibility(expectClassSymbol, actualClassLikeSymbol, parentSubstitutor = null, checkClassScopesCompatibility) + getClassifiersCompatibility( + expectClassSymbol, + actualClassLikeSymbol, + languageVersionSettings, + parentSubstitutor = null, + checkClassScopesCompatibility + ) } @Suppress("UNCHECKED_CAST") return result as ExpectActualCompatibility<T> @@ -43,40 +51,31 @@ expectContainingClass: RegularClassSymbolMarker?, actualContainingClass: RegularClassSymbolMarker?, context: ExpectActualMatchingContext<T>, + languageVersionSettings: LanguageVersionSettings, ): ExpectActualCompatibility<T> { val result = with(context) { - getCallablesCompatibility(expectDeclaration, actualDeclaration, parentSubstitutor, expectContainingClass, actualContainingClass) + getCallablesCompatibility( + expectDeclaration, + actualDeclaration, + parentSubstitutor, + expectContainingClass, + actualContainingClass, + languageVersionSettings + ) } @Suppress("UNCHECKED_CAST") return result as ExpectActualCompatibility<T> } - fun <T : DeclarationSymbolMarker> matchSingleExpectTopLevelDeclarationAgainstPotentialActuals( - expectDeclaration: DeclarationSymbolMarker, - actualDeclarations: List<DeclarationSymbolMarker>, - context: ExpectActualMatchingContext<T>, - ) { - with(context) { - matchSingleExpectAgainstPotentialActuals( - expectDeclaration, - actualDeclarations, - substitutor = null, - expectClassSymbol = null, - actualClassSymbol = null, - unfulfilled = null, - checkClassScopesCompatibility = true, - ) - } - } - context(ExpectActualMatchingContext<*>) @Suppress("warnings") private fun getClassifiersCompatibility( expectClassSymbol: RegularClassSymbolMarker, actualClassLikeSymbol: ClassLikeSymbolMarker, + languageVersionSettings: LanguageVersionSettings, parentSubstitutor: TypeSubstitutorMarker?, checkClassScopes: Boolean, - ): ExpectActualCompatibility<*> = getClassifiersIncompatibility(expectClassSymbol, actualClassLikeSymbol, parentSubstitutor, checkClassScopes) + ): ExpectActualCompatibility<*> = getClassifiersIncompatibility(expectClassSymbol, actualClassLikeSymbol, parentSubstitutor, checkClassScopes, languageVersionSettings) ?: ExpectActualCompatibility.Compatible context(ExpectActualMatchingContext<*>) @@ -86,6 +85,7 @@ actualClassLikeSymbol: ClassLikeSymbolMarker, parentSubstitutor: TypeSubstitutorMarker?, checkClassScopesCompatibility: Boolean, + languageVersionSettings: LanguageVersionSettings, ): ExpectActualCompatibility.Incompatible.ExpectActualCheckingIncompatible<*>? { // Can't check FQ names here because nested expected class may be implemented via actual typealias's expansion with the other FQ name require(expectClassSymbol.name == actualClassLikeSymbol.name) { @@ -141,7 +141,7 @@ } if (checkClassScopesCompatibility) { - getClassScopesIncompatibility(expectClassSymbol, actualClass, substitutor)?.let { return it } + getClassScopesIncompatibility(expectClassSymbol, actualClass, substitutor, languageVersionSettings)?.let { return it } } return null @@ -194,104 +194,13 @@ } context(ExpectActualMatchingContext<*>) - private fun getClassScopesIncompatibility( - expectClassSymbol: RegularClassSymbolMarker, - actualClassSymbol: RegularClassSymbolMarker, - substitutor: TypeSubstitutorMarker, - ): Incompatible.ExpectActualCheckingIncompatible<*>? { - val unfulfilled = arrayListOf<Pair<DeclarationSymbolMarker, Map<Incompatible<*>, List<DeclarationSymbolMarker?>>>>() - - val actualMembersByName = actualClassSymbol.collectAllMembers(isActualDeclaration = true).groupBy { it.name } - - outer@ for (expectMember in expectClassSymbol.collectAllMembers(isActualDeclaration = false)) { - if (expectMember is CallableSymbolMarker && expectMember.shouldSkipMatching(expectClassSymbol)) continue - - val actualMembers = actualMembersByName[expectMember.name]?.filter { actualMember -> - expectMember is CallableSymbolMarker && actualMember is CallableSymbolMarker || - expectMember is RegularClassSymbolMarker && actualMember is RegularClassSymbolMarker - }.orEmpty() - - matchSingleExpectAgainstPotentialActuals( - expectMember, - actualMembers, - substitutor, - expectClassSymbol, - actualClassSymbol, - unfulfilled, - checkClassScopesCompatibility = true, - ) - } - - if (expectClassSymbol.classKind == ClassKind.ENUM_CLASS) { - val aEntries = expectClassSymbol.collectEnumEntryNames() - val bEntries = actualClassSymbol.collectEnumEntryNames() - - if (!bEntries.containsAll(aEntries)) return Incompatible.EnumEntries - } - - // TODO: check static scope? - - if (unfulfilled.isEmpty()) return null - - return Incompatible.ClassScopes(unfulfilled) - } - - context(ExpectActualMatchingContext<*>) - private fun matchSingleExpectAgainstPotentialActuals( - expectMember: DeclarationSymbolMarker, - actualMembers: List<DeclarationSymbolMarker>, - substitutor: TypeSubstitutorMarker?, - expectClassSymbol: RegularClassSymbolMarker?, - actualClassSymbol: RegularClassSymbolMarker?, - unfulfilled: MutableList<Pair<DeclarationSymbolMarker, Map<Incompatible<*>, List<DeclarationSymbolMarker?>>>>?, - checkClassScopesCompatibility: Boolean, - ) { - val mapping = actualMembers.keysToMap { actualMember -> - when (expectMember) { - is CallableSymbolMarker -> getCallablesCompatibility( - expectMember, - actualMember as CallableSymbolMarker, - substitutor, - expectClassSymbol, - actualClassSymbol - ) - - is RegularClassSymbolMarker -> { - val parentSubstitutor = substitutor?.takeIf { !innerClassesCapturesOuterTypeParameters } - getClassifiersCompatibility( - expectMember, - actualMember as ClassLikeSymbolMarker, - parentSubstitutor, - checkClassScopesCompatibility, - ) - } - else -> error("Unsupported declaration: $expectMember ($actualMembers)") - } - } - - val incompatibilityMap = mutableMapOf<Incompatible<*>, MutableList<DeclarationSymbolMarker>>() - for ((actualMember, compatibility) in mapping) { - when (compatibility) { - ExpectActualCompatibility.Compatible -> { - onMatchedMembers(expectMember, actualMember, expectClassSymbol, actualClassSymbol) - return - } - - is Incompatible -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(actualMember) - } - } - - unfulfilled?.add(expectMember to incompatibilityMap) - onMismatchedMembersFromClassScope(expectMember, incompatibilityMap, expectClassSymbol, actualClassSymbol) - } - - context(ExpectActualMatchingContext<*>) private fun getCallablesCompatibility( expectDeclaration: CallableSymbolMarker, actualDeclaration: CallableSymbolMarker, parentSubstitutor: TypeSubstitutorMarker?, expectContainingClass: RegularClassSymbolMarker?, actualContainingClass: RegularClassSymbolMarker?, + languageVersionSettings: LanguageVersionSettings, ): ExpectActualCompatibility<*> { require( (expectDeclaration is ConstructorSymbolMarker && actualDeclaration is ConstructorSymbolMarker) || @@ -326,7 +235,8 @@ actualDeclaration, parentSubstitutor, expectContainingClass, - actualContainingClass + actualContainingClass, + languageVersionSettings, ) ?: ExpectActualCompatibility.Compatible } @@ -338,6 +248,7 @@ parentSubstitutor: TypeSubstitutorMarker?, expectContainingClass: RegularClassSymbolMarker?, actualContainingClass: RegularClassSymbolMarker?, + languageVersionSettings: LanguageVersionSettings, ): Incompatible.ExpectActualCheckingIncompatible<*>? { val expectedTypeParameters = expectDeclaration.typeParameters val actualTypeParameters = actualDeclaration.typeParameters @@ -377,7 +288,7 @@ return Incompatible.Modality } - if (!areCompatibleCallableVisibilities(expectDeclaration.visibility, expectModality, actualDeclaration.visibility)) { + if (!areCompatibleCallableVisibilities(expectDeclaration.visibility, expectModality, actualDeclaration.visibility, languageVersionSettings)) { return Incompatible.Visibility } @@ -418,7 +329,7 @@ getFunctionsIncompatibility(expectDeclaration, actualDeclaration)?.let { return it } expectDeclaration is PropertySymbolMarker && actualDeclaration is PropertySymbolMarker -> - getPropertiesIncompatibility(expectDeclaration, actualDeclaration)?.let { return it } + getPropertiesIncompatibility(expectDeclaration, actualDeclaration, languageVersionSettings)?.let { return it } expectDeclaration is EnumEntrySymbolMarker && actualDeclaration is EnumEntrySymbolMarker -> { // do nothing, entries are matched only by name @@ -480,6 +391,7 @@ expectVisibility: Visibility, expectModality: Modality?, actualVisibility: Visibility, + languageVersionSettings: LanguageVersionSettings, ): Boolean { val compare = Visibilities.compare(expectVisibility, actualVisibility) return if (expectModality != Modality.FINAL) { @@ -549,12 +461,14 @@ private fun getPropertiesIncompatibility( expected: PropertySymbolMarker, actual: PropertySymbolMarker, + languageVersionSettings: LanguageVersionSettings, ): Incompatible.ExpectActualCheckingIncompatible<*>? { return when { !equalBy(expected, actual) { p -> p.isVar } -> Incompatible.PropertyKind !equalBy(expected, actual) { p -> p.isLateinit } -> Incompatible.PropertyLateinitModifier expected.isConst && !actual.isConst -> Incompatible.PropertyConstModifier - !arePropertySettersWithCompatibleVisibilities(expected, actual) -> Incompatible.PropertySetterVisibility + !arePropertySettersWithCompatibleVisibilities(expected, actual, languageVersionSettings) -> + Incompatible.PropertySetterVisibility else -> null } } @@ -563,10 +477,16 @@ private fun arePropertySettersWithCompatibleVisibilities( expected: PropertySymbolMarker, actual: PropertySymbolMarker, + languageVersionSettings: LanguageVersionSettings ): 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, + languageVersionSettings + ) } // ---------------------------------------- Utils ----------------------------------------
diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt index 26e3e9c..40befb3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt
@@ -5,7 +5,9 @@ package org.jetbrains.kotlin.resolve.multiplatform +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCallablesMatcher import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.module @@ -29,7 +31,7 @@ // TODO: support non-source definitions (e.g. from Java) actual.couldHaveASource }.groupBy { actual -> - AbstractExpectActualCompatibilityChecker.getCallablesCompatibility( + AbstractExpectActualCallablesMatcher.getCallablesCompatibility( expected, actual, parentSubstitutor = null, @@ -40,16 +42,9 @@ } } is ClassDescriptor -> { - context.findClassifiersFromModule(expected.classId, platformModule, moduleVisibilityFilter).filter { actual -> - expected != actual && !actual.isExpect && actual.couldHaveASource - }.groupBy { actual -> - AbstractExpectActualCompatibilityChecker.getClassifiersCompatibility( - expected, - actual, - checkClassScopesCompatibility = true, - context - ) - } + context.findClassifiersFromModule(expected.classId, platformModule, moduleVisibilityFilter) + .singleOrNull { actual -> expected != actual && !actual.isExpect && actual.couldHaveASource } + ?.let { mapOf(Compatible to listOf(it)) } } else -> null } @@ -71,7 +66,7 @@ actual, candidates.filterIsInstance<CallableMemberDescriptor>(), actualClass, - context + context, ) } is ClassDescriptor -> { @@ -79,7 +74,7 @@ actual, candidates.filterIsInstance<ClassifierDescriptorWithTypeParameters>(), checkClassScopesCompatibility, - context + context, ) } else -> emptyMap() @@ -99,8 +94,11 @@ is ClassifierDescriptorWithTypeParameters -> { // TODO: replace with 'singleOrNull' as soon as multi-module diagnostic tests are refactored val expectedClass = - findExpectedForActual(container, moduleFilter, shouldCheckAbsenceOfDefaultParamsInActual)?.values - ?.firstOrNull()?.firstOrNull() as? ClassDescriptor + findExpectedForActual( + container, + moduleFilter, + shouldCheckAbsenceOfDefaultParamsInActual + )?.values?.firstOrNull()?.firstOrNull() as? ClassDescriptor with(context) { expectedClass?.getMembersForExpectClass(actual.name)?.filterIsInstance<CallableMemberDescriptor>().orEmpty() } @@ -113,7 +111,12 @@ } is ClassifierDescriptorWithTypeParameters -> { val candidates = context.findClassifiersFromModule(actual.classId, actual.module, moduleFilter) - matchActualClassAgainstPotentialExpects(actual, candidates, checkClassScopesCompatibility = true, context) + matchActualClassAgainstPotentialExpects( + actual, + candidates, + checkClassScopesCompatibility = true, + context, + ) } else -> null } @@ -147,13 +150,13 @@ } else -> null } - AbstractExpectActualCompatibilityChecker.getCallablesCompatibility( + AbstractExpectActualCallablesMatcher.getCallablesCompatibility( expectDeclaration = declaration, actualDeclaration = actual, parentSubstitutor = substitutor, expectContainingClass = expectedClass, actualContainingClass = actualClass, - context + context, ) } } @@ -164,16 +167,9 @@ checkClassScopesCompatibility: Boolean, context: ClassicExpectActualMatchingContext, ): Map<ExpectActualCompatibility<MemberDescriptor>, List<ClassifierDescriptorWithTypeParameters>> { - return candidates.filter { declaration -> - actual != declaration && declaration is ClassDescriptor && declaration.isExpect - }.groupBy { expected -> - AbstractExpectActualCompatibilityChecker.getClassifiersCompatibility( - expected as ClassDescriptor, - actual, - checkClassScopesCompatibility, - context - ) - } + return candidates.singleOrNull { declaration -> actual != declaration && declaration is ClassDescriptor && declaration.isExpect } + ?.let { mapOf((Compatible as ExpectActualCompatibility<MemberDescriptor>) to listOf(it)) } + .orEmpty() } private fun CallableMemberDescriptor.findNamesakesFromModule(