[FIR] Properly calculate visibilities

`testIntersectionOfPrimitiveBasedFunctions`
is fine, because we deprecate this
already in ^KT-63243.

`CANNOT_INFER_VISIBILITY` is
positioned as `DECLARATION_NAME`,
just in case we decide for
some reason that we do want to
report it along with
`MANY_*_NOT_IMPLEMENTED`. In that
case, we'd get a problem that
their bounds overlap, but not
completely contain one another.

^KT-63741 Fixed
^KT-59400 Fixed
This commit is contained in:
Nikolay Lunyak
2024-01-19 12:44:09 +02:00
committed by Space Team
parent 7056ad5325
commit 8f8c7fe7cf
31 changed files with 203 additions and 139 deletions
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@@ -321,17 +322,52 @@ class FirTypeIntersectionScopeContext(
private fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>
): Visibility {
): Visibility = chooseIntersectionVisibilityOrNull(extractedOverrides) ?: Visibilities.Unknown
private fun <D : FirCallableSymbol<*>> chooseIntersectionVisibilityOrNull(
extractedOverrides: Collection<MemberWithBaseScope<D>>
): Visibility? {
val overridesWithoutIntersections = extractedOverrides.flatMap { it.flattenIntersectionsRecursively() }
val nonSubsumed = overridesWithoutIntersections.nonSubsumed().filterOutDuplicates()
val nonAbstract = nonSubsumed.filter {
require(it.member.rawStatus is FirResolvedDeclarationStatus) {
"We expect that to be true already, but we can't yet call resolvedStatus"
}
// Kotlin's Cloneable interface contains phantom `protected open fun clone()`.
it.member.rawStatus.modality != Modality.ABSTRACT && it.member.callableId != StandardClassIds.Callables.clone
}
val allAreAbstract = nonAbstract.isEmpty()
if (allAreAbstract) {
return findMaxVisibilityOrNull(nonSubsumed)
}
if (nonAbstract.size >= 2) {
return null
}
return nonAbstract.single().member.rawStatus.visibility
}
private fun <D : FirCallableSymbol<*>> List<MemberWithBaseScope<D>>.filterOutDuplicates(): List<MemberWithBaseScope<D>> {
val uniqueSymbols = mutableSetOf<FirCallableSymbol<*>>()
return filter { uniqueSymbols.add(it.member.fir.unwrapSubstitutionOverrides().symbol) }
}
private fun <D : FirCallableSymbol<*>> findMaxVisibilityOrNull(
extractedOverrides: Collection<MemberWithBaseScope<D>>
): Visibility? {
var maxVisibility: Visibility = Visibilities.Private
for ((override) in extractedOverrides) {
val visibility = (override.fir as FirMemberDeclaration).visibility
// TODO: There is more complex logic at org.jetbrains.kotlin.resolve.OverridingUtil.resolveUnknownVisibilityForMember
// TODO: and org.jetbrains.kotlin.resolve.OverridingUtil.findMaxVisibility
val compare = Visibilities.compare(visibility, maxVisibility) ?: return Visibilities.DEFAULT_VISIBILITY
val compare = Visibilities.compare(visibility, maxVisibility) ?: return null
if (compare > 0) {
maxVisibility = visibility
}
}
return maxVisibility
}