FIR: Use refined visibility/modality for intersection overrides

This commit is contained in:
Denis Zharkov
2020-09-23 14:26:18 +03:00
parent 20bf238c27
commit 9696fecab5
3 changed files with 68 additions and 20 deletions
@@ -5,11 +5,13 @@
package org.jetbrains.kotlin.fir.scopes.impl package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.* import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
@@ -316,14 +318,16 @@ class FirClassSubstitutionScope(
newParameterTypes: List<ConeKotlinType?>? = null, newParameterTypes: List<ConeKotlinType?>? = null,
newTypeParameters: List<FirTypeParameter>? = null, newTypeParameters: List<FirTypeParameter>? = null,
newReceiverType: ConeKotlinType? = null, newReceiverType: ConeKotlinType? = null,
newReturnType: ConeKotlinType? = null newReturnType: ConeKotlinType? = null,
newModality: Modality? = null,
newVisibility: Visibility? = null,
): FirSimpleFunction { ): FirSimpleFunction {
return buildSimpleFunction { return buildSimpleFunction {
source = baseFunction.source source = baseFunction.source
this.session = session this.session = session
this.origin = origin this.origin = origin
name = baseFunction.name name = baseFunction.name
status = baseFunction.status.withExpect(isExpect) status = baseFunction.status.updatedStatus(isExpect, newModality, newVisibility)
symbol = newSymbol symbol = newSymbol
resolvePhase = baseFunction.resolvePhase resolvePhase = baseFunction.resolvePhase
@@ -349,7 +353,7 @@ class FirClassSubstitutionScope(
this.session = session this.session = session
origin = FirDeclarationOrigin.FakeOverride origin = FirDeclarationOrigin.FakeOverride
receiverTypeRef = baseConstructor.receiverTypeRef?.withReplacedConeType(null) receiverTypeRef = baseConstructor.receiverTypeRef?.withReplacedConeType(null)
status = baseConstructor.status.withExpect(isExpect) status = baseConstructor.status.updatedStatus(isExpect)
symbol = fakeOverrideSymbol symbol = fakeOverrideSymbol
resolvePhase = baseConstructor.resolvePhase resolvePhase = baseConstructor.resolvePhase
@@ -452,6 +456,8 @@ class FirClassSubstitutionScope(
newTypeParameters: List<FirTypeParameter>? = null, newTypeParameters: List<FirTypeParameter>? = null,
newReceiverType: ConeKotlinType? = null, newReceiverType: ConeKotlinType? = null,
newReturnType: ConeKotlinType? = null, newReturnType: ConeKotlinType? = null,
newModality: Modality? = null,
newVisibility: Visibility? = null,
): FirProperty { ): FirProperty {
return buildProperty { return buildProperty {
source = baseProperty.source source = baseProperty.source
@@ -461,7 +467,8 @@ class FirClassSubstitutionScope(
isVar = baseProperty.isVar isVar = baseProperty.isVar
this.symbol = newSymbol this.symbol = newSymbol
isLocal = false isLocal = false
status = baseProperty.status.withExpect(isExpect) status = baseProperty.status.updatedStatus(isExpect, newModality, newVisibility)
resolvePhase = baseProperty.resolvePhase resolvePhase = baseProperty.resolvePhase
typeParameters += configureAnnotationsTypeParametersAndSignature( typeParameters += configureAnnotationsTypeParametersAndSignature(
baseProperty, baseProperty,
@@ -574,11 +581,16 @@ class FirClassSubstitutionScope(
}.symbol }.symbol
} }
private fun FirDeclarationStatus.withExpect(isExpect: Boolean): FirDeclarationStatus { private fun FirDeclarationStatus.updatedStatus(
return if (this.isExpect == isExpect) { isExpect: Boolean,
newModality: Modality? = null,
newVisibility: Visibility? = null,
): FirDeclarationStatus {
return if (this.isExpect == isExpect && newModality == null && newVisibility == null) {
this this
} else { } else {
FirResolvedDeclarationStatusImpl(visibility, modality!!).apply { require(this is FirDeclarationStatusImpl) { "Unexpected class ${this::class}" }
this.resolved(newVisibility ?: visibility, newModality ?: modality!!).apply {
this.isExpect = isExpect this.isExpect = isExpect
} }
} }
@@ -5,8 +5,10 @@
package org.jetbrains.kotlin.fir.scopes.impl package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
@@ -38,7 +40,8 @@ class FirTypeIntersectionScope private constructor(
private val typeContext = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = false, session) private val typeContext = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = false, session)
private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<out FirCallableSymbol<*>>>> = mutableMapOf() private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<out FirCallableSymbol<*>>>> =
mutableMapOf()
private val intersectionOverrides: MutableMap<FirCallableSymbol<*>, MemberWithBaseScope<out FirCallableSymbol<*>>> = mutableMapOf() private val intersectionOverrides: MutableMap<FirCallableSymbol<*>, MemberWithBaseScope<out FirCallableSymbol<*>>> = mutableMapOf()
@@ -97,21 +100,23 @@ class FirTypeIntersectionScope private constructor(
while (allMembersWithScope.isNotEmpty()) { while (allMembersWithScope.isNotEmpty()) {
val maxByVisibility = findMemberWithMaxVisibility(allMembersWithScope) val maxByVisibility = findMemberWithMaxVisibility(allMembersWithScope)
val extractedOverrides = extractBothWaysOverridable(maxByVisibility, allMembersWithScope) val extractBothWaysWithPrivate = extractBothWaysOverridable(maxByVisibility, allMembersWithScope)
val extractedOverrides = extractBothWaysWithPrivate.filterNot {
Visibilities.isPrivate((it.member.fir as FirMemberDeclaration).visibility)
}.takeIf { it.isNotEmpty() } ?: extractBothWaysWithPrivate
val (mostSpecific, scopeForMostSpecific) = selectMostSpecificMember(extractedOverrides) val (mostSpecific, scopeForMostSpecific) = selectMostSpecificMember(extractedOverrides)
if (extractedOverrides.size > 1) { if (extractedOverrides.size > 1) {
val intersectionOverride = intersectionOverrides.getOrPut(mostSpecific) { val intersectionOverride = intersectionOverrides.getOrPut(mostSpecific) {
val newModality = chooseIntersectionOverrideModality(extractedOverrides)
val newVisibility = chooseIntersectionVisibility(extractedOverrides)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
when (mostSpecific) { when (mostSpecific) {
is FirNamedFunctionSymbol -> { is FirNamedFunctionSymbol -> {
createIntersectionOverride( createIntersectionOverride(mostSpecific, newModality, newVisibility)
mostSpecific,
extractedOverrides as Collection<MemberWithBaseScope<FirNamedFunctionSymbol>>
)
} }
is FirPropertySymbol -> { is FirPropertySymbol -> {
createIntersectionOverride(mostSpecific) createIntersectionOverride(mostSpecific, newModality, newVisibility)
} }
else -> { else -> {
throw IllegalStateException("Should not be here") throw IllegalStateException("Should not be here")
@@ -130,9 +135,32 @@ class FirTypeIntersectionScope private constructor(
return true return true
} }
private fun <D : FirCallableSymbol<*>> chooseIntersectionOverrideModality(
extractedOverrides: Collection<MemberWithBaseScope<D>>
): Modality {
return extractedOverrides.minOf { (it.member.fir as FirMemberDeclaration).modality ?: Modality.ABSTRACT }
}
private fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
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
if (compare > 0) {
maxVisibility = visibility
}
}
return maxVisibility
}
private fun createIntersectionOverride( private fun createIntersectionOverride(
mostSpecific: FirNamedFunctionSymbol, mostSpecific: FirNamedFunctionSymbol,
extractedOverrides: Collection<MemberWithBaseScope<FirNamedFunctionSymbol>> newModality: Modality,
newVisibility: Visibility,
): FirNamedFunctionSymbol { ): FirNamedFunctionSymbol {
val newSymbol = val newSymbol =
FirNamedFunctionSymbol( FirNamedFunctionSymbol(
@@ -146,15 +174,23 @@ class FirTypeIntersectionScope private constructor(
newSymbol, newSymbol,
mostSpecificFunction, session, FirDeclarationOrigin.IntersectionOverride, mostSpecificFunction, session, FirDeclarationOrigin.IntersectionOverride,
mostSpecificFunction.isExpect, mostSpecificFunction.isExpect,
newModality = newModality,
newVisibility = newVisibility,
) )
return newSymbol return newSymbol
} }
private fun createIntersectionOverride(mostSpecific: FirPropertySymbol): FirPropertySymbol { private fun createIntersectionOverride(
mostSpecific: FirPropertySymbol,
newModality: Modality,
newVisibility: Visibility,
): FirPropertySymbol {
val newSymbol = FirPropertySymbol(mostSpecific.callableId, mostSpecific.isFakeOverride, mostSpecific, isIntersectionOverride = true) val newSymbol = FirPropertySymbol(mostSpecific.callableId, mostSpecific.isFakeOverride, mostSpecific, isIntersectionOverride = true)
val mostSpecificProperty = mostSpecific.fir val mostSpecificProperty = mostSpecific.fir
FirClassSubstitutionScope.createCopyForFirProperty( FirClassSubstitutionScope.createCopyForFirProperty(
newSymbol, mostSpecificProperty, mostSpecificProperty.session newSymbol, mostSpecificProperty, mostSpecificProperty.session,
newModality = newModality,
newVisibility = newVisibility,
) )
return newSymbol return newSymbol
} }
@@ -166,7 +166,7 @@ open class FirDeclarationStatusImpl(
return this return this
} }
fun resolved(visibility: Visibility, modality: Modality): FirDeclarationStatus { fun resolved(visibility: Visibility, modality: Modality): FirResolvedDeclarationStatusImpl {
return FirResolvedDeclarationStatusImpl(visibility, modality, flags) return FirResolvedDeclarationStatusImpl(visibility, modality, flags)
} }
} }