diff --git a/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/FirNativeOverrideChecker.kt b/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/FirNativeOverrideChecker.kt index bf5a8a6e094..b80848d3a21 100644 --- a/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/FirNativeOverrideChecker.kt +++ b/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/FirNativeOverrideChecker.kt @@ -5,16 +5,20 @@ package org.jetbrains.kotlin.fir.backend.native +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.backend.native.interop.decodeObjCMethodAnnotation -import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration -import org.jetbrains.kotlin.fir.declarations.FirProperty -import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.backend.native.interop.isObjCClass +import org.jetbrains.kotlin.fir.containingClassLookupTag +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker import org.jetbrains.kotlin.fir.scopes.MemberWithBaseScope -import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker +import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol /** @@ -37,7 +41,14 @@ class FirNativeOverrideChecker(private val session: FirSession) : FirOverrideChe override fun > chooseIntersectionVisibility( extractedOverrides: Collection>, dispatchClassSymbol: FirRegularClassSymbol?, - ): Visibility = standardOverrideChecker.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol) + ): Visibility { + val nonSubsumed = extractedOverrides.getNonSubsumedNonPhantomOverriddenSymbols() + return chooseIntersectionVisibilityOrNull(nonSubsumed) { it.isAbstract || it.member.isObjCClassProperty(session) } + ?: Visibilities.Unknown + } + + private fun FirCallableSymbol<*>.isObjCClassProperty(session: FirSession) = + this is FirPropertySymbol && (containingClassLookupTag()?.toSymbol(session) as? FirClassSymbol<*>)?.isObjCClass(session) ?: false /** * mimics ObjCOverridabilityCondition.isOverridable diff --git a/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/interop/FirObjCInterop.kt b/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/interop/FirObjCInterop.kt index 5872c028ec0..37403dc2a3d 100644 --- a/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/interop/FirObjCInterop.kt +++ b/compiler/fir/native/src/org/jetbrains/kotlin/fir/backend/native/interop/FirObjCInterop.kt @@ -109,7 +109,7 @@ internal fun FirConstructorSymbol.isObjCConstructor(session: FirSession) = /** * mimics IrClass.isObjCClass() */ -private fun FirClassSymbol<*>.isObjCClass(session: FirSession) = classId.packageFqName != NativeStandardInteropNames.cInteropPackage && +fun FirClassSymbol<*>.isObjCClass(session: FirSession) = classId.packageFqName != NativeStandardInteropNames.cInteropPackage && selfOrAnySuperClass(session) { it.classId == NativeStandardInteropNames.objCObjectClassId } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt index 222a5afe9f4..dfa0b1e8211 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt @@ -160,9 +160,15 @@ fun MemberWithBaseScope>.getNonSubsumedOverriddenSymbols(): .map { it.member } } -fun List>>.getNonSubsumedNonPhantomOverriddenSymbols(): List>> { +fun Collection>>.getNonSubsumedNonPhantomOverriddenSymbols(): List>> { + // It's crucial that we only unwrap phantom intersection overrides. + // See comments in the following tests for explanation: + // - intersectionWithMultipleDefaultsInJavaOverriddenByIntersectionInKotlin.kt + // - intersectionOverridesIntersection.kt return flatMap { it.flattenPhantomIntersectionsRecursively() } .nonSubsumed() + // To learn why `distinctBy` is needed, see: + // - intersectionWithMultipleDefaultsInJavaWithAdditionalSymbolsAfterNonSubsumed.kt .distinctBy { it.member.unwrapSubstitutionOverrides>() } } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirOverrideUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirOverrideUtils.kt index 774b9cc801f..fbda9bf6fc7 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirOverrideUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirOverrideUtils.kt @@ -64,12 +64,13 @@ fun > overrides( return result } -fun chooseIntersectionVisibilityOrNull( +inline fun chooseIntersectionVisibilityOrNull( nonSubsumedOverrides: List>>, + isAbstract: (MemberWithBaseScope>) -> Boolean = MemberWithBaseScope>::isAbstract, ): Visibility? { val nonAbstract = nonSubsumedOverrides.filter { // Kotlin's Cloneable interface contains phantom `protected open fun clone()`. - !it.isAbstract && it.member.callableId != StandardClassIds.Callables.clone + !isAbstract(it) && it.member.callableId != StandardClassIds.Callables.clone } val allAreAbstract = nonAbstract.isEmpty()