[FIR] Don't remove subsumed members from intersection overrides's overriddens
This fixes a bunch of missing overridden symbols in IR. This is also required for fixing KT-59921 in the following commit where we need to keep all overridden symbols of intersection overrides so that we can enhance them properly. #KT-57300 Fixed #KT-57299 Fixed #KT-59921 #KT-57300 #KT-62788 #KT-64271 #KT-64382
This commit is contained in:
committed by
Space Team
parent
d80dee6e1c
commit
3b841dcb98
@@ -9,7 +9,10 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.util.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInline
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectOrStaticData
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -19,6 +22,7 @@ import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.fir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.fir.types.toSymbol
|
||||
import org.jetbrains.kotlin.fir.unwrapSubstitutionOverrides
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
fun FirClass.constructors(session: FirSession): List<FirConstructorSymbol> {
|
||||
@@ -126,3 +130,72 @@ fun FirSimpleFunction.isEquals(session: FirSession): Boolean {
|
||||
val parameter = valueParameters.first()
|
||||
return parameter.returnTypeRef.coneType.fullyExpandedType(session).isNullableAny
|
||||
}
|
||||
|
||||
/**
|
||||
* An intersection override is trivial if one of the overridden symbols subsumes all others.
|
||||
*
|
||||
* @see org.jetbrains.kotlin.fir.scopes.impl.FirTypeIntersectionScopeContext.convertGroupedCallablesToIntersectionResults
|
||||
*/
|
||||
fun MemberWithBaseScope<FirCallableSymbol<*>>.isTrivialIntersection(): Boolean {
|
||||
return baseScope
|
||||
.getDirectOverriddenMembersWithBaseScope(member)
|
||||
.nonSubsumed()
|
||||
.mapTo(mutableSetOf()) { it.member.unwrapSubstitutionOverrides() }.size == 1
|
||||
}
|
||||
|
||||
fun FirIntersectionCallableSymbol.getNonSubsumedOverriddenSymbols(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
): List<FirCallableSymbol<*>> {
|
||||
require(this is FirCallableSymbol<*>)
|
||||
|
||||
val dispatchReceiverScope = dispatchReceiverScope(session, scopeSession)
|
||||
return MemberWithBaseScope(this, dispatchReceiverScope).getNonSubsumedOverriddenSymbols()
|
||||
}
|
||||
|
||||
fun MemberWithBaseScope<FirCallableSymbol<*>>.getNonSubsumedOverriddenSymbols(): List<FirCallableSymbol<*>> {
|
||||
return flattenIntersectionsRecursively()
|
||||
.nonSubsumed()
|
||||
.distinctBy { it.member.unwrapSubstitutionOverrides<FirCallableSymbol<*>>() }
|
||||
.map { it.member }
|
||||
}
|
||||
|
||||
fun FirCallableSymbol<*>.dispatchReceiverScope(session: FirSession, scopeSession: ScopeSession): FirTypeScope {
|
||||
val dispatchReceiverType = requireNotNull(dispatchReceiverType)
|
||||
return dispatchReceiverType.scope(
|
||||
session,
|
||||
scopeSession,
|
||||
CallableCopyTypeCalculator.DoNothing,
|
||||
FirResolvePhase.STATUS
|
||||
) ?: FirTypeScope.Empty
|
||||
}
|
||||
|
||||
fun MemberWithBaseScope<FirCallableSymbol<*>>.flattenIntersectionsRecursively(): List<MemberWithBaseScope<FirCallableSymbol<*>>> {
|
||||
if (member.origin != FirDeclarationOrigin.IntersectionOverride) return listOf(this)
|
||||
|
||||
return baseScope.getDirectOverriddenMembersWithBaseScope(member).flatMap { it.flattenIntersectionsRecursively() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable declaration D [subsumes](https://kotlinlang.org/spec/inheritance.html#matching-and-subsumption-of-declarations)
|
||||
* a callable declaration B if D overrides B.
|
||||
*/
|
||||
fun Collection<MemberWithBaseScope<FirCallableSymbol<*>>>.nonSubsumed(): List<MemberWithBaseScope<FirCallableSymbol<*>>> {
|
||||
val baseMembers = mutableSetOf<FirCallableSymbol<*>>()
|
||||
for ((member, scope) in this) {
|
||||
val unwrapped = member.unwrapSubstitutionOverrides<FirCallableSymbol<*>>()
|
||||
val addIfDifferent = { it: FirCallableSymbol<*> ->
|
||||
val symbol = it.unwrapSubstitutionOverrides()
|
||||
if (symbol != unwrapped) {
|
||||
baseMembers += symbol
|
||||
}
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
if (member is FirNamedFunctionSymbol) {
|
||||
scope.processOverriddenFunctions(member, addIfDifferent)
|
||||
} else if (member is FirPropertySymbol) {
|
||||
scope.processOverriddenProperties(member, addIfDifferent)
|
||||
}
|
||||
}
|
||||
return filter { (member, _) -> member.unwrapSubstitutionOverrides<FirCallableSymbol<*>>() !in baseMembers }
|
||||
}
|
||||
+6
-33
@@ -10,9 +10,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.caches.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
@@ -159,8 +157,7 @@ class FirTypeIntersectionScopeContext(
|
||||
val groupWithInvisible =
|
||||
overrideService.extractBothWaysOverridable(allMembersWithScope.maxByVisibility(), allMembersWithScope, overrideChecker)
|
||||
val group = groupWithInvisible.filter { it.isVisible() }.ifEmpty { groupWithInvisible }
|
||||
val nonSubsumed = if (forClassUseSiteScope) group.nonSubsumed() else group
|
||||
val mostSpecific = overrideService.selectMostSpecificMembers(nonSubsumed, ReturnTypeCalculatorForFullBodyResolve.Default)
|
||||
val mostSpecific = overrideService.selectMostSpecificMembers(group, ReturnTypeCalculatorForFullBodyResolve.Default)
|
||||
val nonTrivial = if (forClassUseSiteScope) {
|
||||
// Create a non-trivial intersection override when the base methods come from different scopes,
|
||||
// even if one of them is more specific than the others, i.e. when there is more than one method that is not subsumed.
|
||||
@@ -169,15 +166,15 @@ class FirTypeIntersectionScopeContext(
|
||||
// It is also possible to have the opposite case (> 1 most specific member, but all members are from
|
||||
// the same base scope), but this means there are different instantiations of the same base class,
|
||||
// which should generally result in INCONSISTENT_TYPE_PARAMETER_VALUES errors.
|
||||
nonSubsumed.size > 1 &&
|
||||
nonSubsumed.mapTo(mutableSetOf()) { it.member.fir.unwrapSubstitutionOverrides().symbol }.size > 1
|
||||
group.size > 1 &&
|
||||
group.mapTo(mutableSetOf()) { it.member.fir.unwrapSubstitutionOverrides().symbol }.size > 1
|
||||
} else {
|
||||
// Create a non-trivial intersection override when return types should be intersected.
|
||||
mostSpecific.size > 1
|
||||
}
|
||||
if (nonTrivial) {
|
||||
// Only add non-subsumed members to list of overridden in intersection override.
|
||||
result += ResultOfIntersection.NonTrivial(this, mostSpecific, overriddenMembers = nonSubsumed, containingScope = null)
|
||||
result += ResultOfIntersection.NonTrivial(this, mostSpecific, overriddenMembers = group, containingScope = null)
|
||||
} else {
|
||||
val (member, containingScope) = mostSpecific.first()
|
||||
result += ResultOfIntersection.SingleMember(member, group, containingScope)
|
||||
@@ -207,7 +204,7 @@ class FirTypeIntersectionScopeContext(
|
||||
mostSpecific: List<MemberWithBaseScope<D>>,
|
||||
extractedOverrides: List<MemberWithBaseScope<D>>,
|
||||
): MemberWithBaseScope<FirCallableSymbol<*>> {
|
||||
val newModality = chooseIntersectionOverrideModality(extractedOverrides)
|
||||
val newModality = chooseIntersectionOverrideModality(extractedOverrides.flatMap { it.flattenIntersectionsRecursively() }.nonSubsumed())
|
||||
val newVisibility = chooseIntersectionVisibility(extractedOverrides)
|
||||
val mostSpecificSymbols = mostSpecific.map { it.member }
|
||||
val extractedOverridesSymbols = extractedOverrides.map { it.member }
|
||||
@@ -228,30 +225,6 @@ class FirTypeIntersectionScopeContext(
|
||||
}.withScope(key.baseScope)
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable declaration D [subsumes](https://kotlinlang.org/spec/inheritance.html#matching-and-subsumption-of-declarations)
|
||||
* a callable declaration B if D overrides B.
|
||||
*/
|
||||
private fun <S : FirCallableSymbol<*>> List<MemberWithBaseScope<S>>.nonSubsumed(): List<MemberWithBaseScope<S>> {
|
||||
val baseMembers = mutableSetOf<FirCallableSymbol<*>>()
|
||||
for ((member, scope) in this) {
|
||||
val unwrapped = member.unwrapSubstitutionOverrides<FirCallableSymbol<*>>()
|
||||
val addIfDifferent = { it: FirCallableSymbol<*> ->
|
||||
val symbol = it.unwrapSubstitutionOverrides()
|
||||
if (symbol != unwrapped) {
|
||||
baseMembers += symbol
|
||||
}
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
if (member is FirNamedFunctionSymbol) {
|
||||
scope.processOverriddenFunctions(member, addIfDifferent)
|
||||
} else if (member is FirPropertySymbol) {
|
||||
scope.processOverriddenProperties(member, addIfDifferent)
|
||||
}
|
||||
}
|
||||
return filter { it.member.unwrapSubstitutionOverrides<FirCallableSymbol<*>>() !in baseMembers }
|
||||
}
|
||||
|
||||
private fun <S : FirCallableSymbol<*>> Collection<MemberWithBaseScope<S>>.maxByVisibility(): MemberWithBaseScope<S> {
|
||||
var member: MemberWithBaseScope<S>? = null
|
||||
for (candidate in this) {
|
||||
|
||||
Reference in New Issue
Block a user