[FIR] Process all overridden members from intersection scopes

Previously, there was a contract that each callable symbol in the chain
  of `processDirectOverriddenWithBaseScope` will be unique. And if some
  symbol is accessible from multiple scopes, then only last of them will
  be returned as a component of `MemberWithScope`

But after the change from previous commit, we don't have this contract anymore.
  Which means that we may meet the same symbol during processing hierarchy
  of overridden functions (but with different base scopes)

So if some code utilizes `process...Overridden...WithBaseScope` functions
  it should consider that the same symbol may be obtained several times

^KT-63738 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-12-06 15:40:00 +02:00
committed by Space Team
parent c34511af37
commit 4272f2e156
6 changed files with 25 additions and 26 deletions
@@ -1,6 +1,11 @@
D:
[SubstitutionOverride(DeclarationSite)]: public abstract override fun foo(): R|E4| from Use site scope of /D [id: 0]
[Source]: public abstract override fun foo(): R|E2| from Use site scope of /B [id: 1]
[SubstitutionOverride(DeclarationSite)]: public abstract fun foo(): R|E2| from Substitution scope for [Use site scope of /A] for type B<E2> [id: 2]
[Source]: public abstract fun foo(): R|E1| from Use site scope of /A [id: 3]
[SubstitutionOverride(DeclarationSite)]: public abstract override fun foo(): R|E4| from Substitution scope for [Use site scope of /B] for type D<E4> [id: 0]
[Source]: public abstract override fun foo(): R|E2| from Use site scope of /B [id: 1]
[SubstitutionOverride(DeclarationSite)]: public abstract fun foo(): R|E2| from Substitution scope for [Use site scope of /A] for type B<E2> [id: 2]
[Source]: public abstract fun foo(): R|E1| from Use site scope of /A [id: 3]
[SubstitutionOverride(DeclarationSite)]: public abstract fun foo(): R|E4| from Substitution scope for [Use site scope of /C] for type D<E4> [id: 4]
[SubstitutionOverride(DeclarationSite)]: public abstract fun foo(): R|E3| from Use site scope of /C [id: 5]
[SubstitutionOverride(DeclarationSite)]: public abstract fun foo(): R|E3| from Substitution scope for [Use site scope of /A] for type C<E3> [id: 5]
[Source]: public abstract fun foo(): R|E1| from Use site scope of /A [id: 3]
@@ -11,6 +11,7 @@ Some:
[Library]: public abstract fun toInt(): R|kotlin/Int| from Use site scope of kotlin/Number [id: 1]
[RenamedForOverride]: public abstract fun toInt(): R|kotlin/Int| from Java enhancement scope for /MyNumber [id: 2]
[Library]: public abstract fun toLong(): R|kotlin/Long| from Java enhancement scope for /Some [id: 0]
[Library]: public abstract fun toLong(): R|kotlin/Long| from Use site scope of kotlin/Number [id: 0]
MyNumber:
[Enhancement]: public abstract fun byteValue(): R|kotlin/Byte| from Java enhancement scope for /MyNumber [id: 0]
@@ -2,7 +2,8 @@ SomeMap:
[Enhancement]: public abstract fun containsKey(key: R|ft<K3 & Any, K3?>|): R|kotlin/Boolean| from Java enhancement scope for /SomeMap [id: 0]
[SubstitutionOverride(DeclarationSite)]: public abstract fun containsKey(key: R|ft<K3 & Any, K3?>|): R|kotlin/Boolean| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type SomeMap<K3, V3> [id: 1]
[SubstitutionOverride(DeclarationSite)]: public abstract fun containsKey(key: R|K|): R|kotlin/Boolean| from Use site scope of kotlin/collections/MutableMap [id: 2]
[Library]: public abstract fun containsKey(key: R|K|): R|kotlin/Boolean| from Use site scope of kotlin/collections/Map [id: 3]
[SubstitutionOverride(DeclarationSite)]: public abstract fun containsKey(key: R|K|): R|kotlin/Boolean| from Substitution scope for [Use site scope of kotlin/collections/Map] for type kotlin/collections/MutableMap<K, V> [id: 2]
[Library]: public abstract fun containsKey(key: R|K|): R|kotlin/Boolean| from Use site scope of kotlin/collections/Map [id: 3]
[SubstitutionOverride(DeclarationSite)]: public abstract fun containsKey(key: R|kotlin/Any!|): R|kotlin/Boolean| from Substitution scope for [Java enhancement scope for /MyMap] for type SomeMap<K3, V3> [id: 4]
[Enhancement]: public abstract fun containsKey(key: R|kotlin/Any!|): R|kotlin/Boolean| from Java enhancement scope for /MyMap [id: 5]
[SubstitutionOverride(DeclarationSite)]: public abstract fun containsKey(key: R|kotlin/Any!|): R|kotlin/Boolean| from Substitution scope for [Java enhancement scope for /MyBaseMap] for type MyMap<K2, V2> [id: 6]
@@ -10,20 +11,23 @@ SomeMap:
[IntersectionOverride]: public abstract fun containsValue(value: R|ft<V3 & Any, V3?>|): R|kotlin/Boolean| from Java enhancement scope for /SomeMap [id: 0]
[SubstitutionOverride(DeclarationSite)]: public abstract fun containsValue(value: R|ft<V3 & Any, V3?>|): R|kotlin/Boolean| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type SomeMap<K3, V3> [id: 1]
[SubstitutionOverride(DeclarationSite)]: public abstract fun containsValue(value: R|V|): R|kotlin/Boolean| from Use site scope of kotlin/collections/MutableMap [id: 2]
[Library]: public abstract fun containsValue(value: R|V|): R|kotlin/Boolean| from Use site scope of kotlin/collections/Map [id: 3]
[SubstitutionOverride(DeclarationSite)]: public abstract fun containsValue(value: R|V|): R|kotlin/Boolean| from Substitution scope for [Use site scope of kotlin/collections/Map] for type kotlin/collections/MutableMap<K, V> [id: 2]
[Library]: public abstract fun containsValue(value: R|V|): R|kotlin/Boolean| from Use site scope of kotlin/collections/Map [id: 3]
[SubstitutionOverride(DeclarationSite)]: public abstract fun containsValue(key: R|kotlin/Any!|): R|kotlin/Boolean| from Substitution scope for [Java enhancement scope for /MyMap] for type SomeMap<K3, V3> [id: 4]
[Enhancement]: public abstract fun containsValue(key: R|kotlin/Any!|): R|kotlin/Boolean| from Java enhancement scope for /MyMap [id: 5]
[IntersectionOverride]: public abstract operator fun get(key: R|ft<K3 & Any, K3?>|): R|V3?| from Java enhancement scope for /SomeMap [id: 0]
[SubstitutionOverride(DeclarationSite)]: public abstract operator fun get(key: R|ft<K3 & Any, K3?>|): R|V3?| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type SomeMap<K3, V3> [id: 1]
[SubstitutionOverride(DeclarationSite)]: public abstract operator fun get(key: R|K|): R|V?| from Use site scope of kotlin/collections/MutableMap [id: 2]
[Library]: public abstract operator fun get(key: R|K|): R|V?| from Use site scope of kotlin/collections/Map [id: 3]
[SubstitutionOverride(DeclarationSite)]: public abstract operator fun get(key: R|K|): R|V?| from Substitution scope for [Use site scope of kotlin/collections/Map] for type kotlin/collections/MutableMap<K, V> [id: 2]
[Library]: public abstract operator fun get(key: R|K|): R|V?| from Use site scope of kotlin/collections/Map [id: 3]
[SubstitutionOverride(DeclarationSite)]: public abstract operator fun get(key: R|ft<K3 & Any, K3?>|): R|ft<V3 & Any, V3?>| from Substitution scope for [Java enhancement scope for /MyMap] for type SomeMap<K3, V3> [id: 4]
[Enhancement]: public abstract operator fun get(key: R|ft<K2 & Any, K2?>|): R|ft<V2 & Any, V2?>| from Java enhancement scope for /MyMap [id: 5]
[Enhancement]: public abstract fun remove(key: R|ft<K3 & Any, K3?>|): R|V3?| from Java enhancement scope for /SomeMap [id: 0]
[SubstitutionOverride(DeclarationSite)]: public abstract fun remove(key: R|ft<K3 & Any, K3?>|): R|V3?| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type SomeMap<K3, V3> [id: 1]
[Library]: public abstract fun remove(key: R|K|): R|V?| from Use site scope of kotlin/collections/MutableMap [id: 2]
[SubstitutionOverride(DeclarationSite)]: public open fun remove(key: R|ft<K3 & Any, K3?>|, value: R|ft<V3 & Any, V3?>|): R|kotlin/Boolean| from Java enhancement scope for /SomeMap [id: 0]
[Library]: public open fun remove(key: R|K|, value: R|V|): R|kotlin/Boolean| from Use site scope of kotlin/collections/MutableMap [id: 1]
[SubstitutionOverride(DeclarationSite)]: public open fun remove(key: R|ft<K3 & Any, K3?>|, value: R|ft<V3 & Any, V3?>|): R|kotlin/Boolean| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type SomeMap<K3, V3> [id: 0]
[Library]: public open fun remove(key: R|K|, value: R|V|): R|kotlin/Boolean| from Use site scope of kotlin/collections/MutableMap [id: 1]
MyMap:
[Enhancement]: public abstract fun containsKey(key: R|kotlin/Any!|): R|kotlin/Boolean| from Java enhancement scope for /MyMap [id: 0]
@@ -148,8 +148,7 @@ abstract class AbstractFirUseSiteMemberScope(
directOverriddenFunctions,
functionsFromSupertypes,
functionSymbol,
processor,
FirTypeScope::processDirectOverriddenFunctionsWithBaseScope
processor
)
}
@@ -161,8 +160,7 @@ abstract class AbstractFirUseSiteMemberScope(
directOverriddenProperties,
propertiesFromSupertypes,
propertySymbol,
processor,
FirTypeScope::processDirectOverriddenPropertiesWithBaseScope
processor
)
}
@@ -170,24 +168,17 @@ abstract class AbstractFirUseSiteMemberScope(
directOverriddenMap: Map<D, List<ResultOfIntersection<D>>>,
callablesFromSupertypes: Map<Name, List<ResultOfIntersection<D>>>,
callableSymbol: D,
processor: (D, FirTypeScope) -> ProcessorAction,
processDirectOverriddenCallables: FirTypeScope.(D, (D, FirTypeScope) -> ProcessorAction) -> ProcessorAction
processor: (D, FirTypeScope) -> ProcessorAction
): ProcessorAction {
when (val directOverridden = directOverriddenMap[callableSymbol]) {
null -> {
val resultOfIntersection = callablesFromSupertypes[callableSymbol.name]
?.firstOrNull { it.chosenSymbol == callableSymbol }
?: return ProcessorAction.NONE
if (resultOfIntersection.isIntersectionOverride()) {
for ((overridden, baseScope) in resultOfIntersection.overriddenMembers) {
if (!processor(overridden, baseScope)) return ProcessorAction.STOP
}
return ProcessorAction.NONE
} else {
return resultOfIntersection.containingScope
?.processDirectOverriddenCallables(callableSymbol, processor)
?: ProcessorAction.NONE
for ((overridden, baseScope) in resultOfIntersection.overriddenMembers) {
if (!processor(overridden, baseScope)) return ProcessorAction.STOP
}
return ProcessorAction.NONE
}
else -> {
for (resultOfIntersection in directOverridden) {
@@ -27,8 +27,8 @@ abstract class FirTypeScope : FirContainingNamesAwareScope() {
// Then, for B::foo from scope for B one may receive override A::foo and scope for A
//
// Currently, this function and its property brother both have very weak guarantees
// - It may silently do nothing on symbols originated from different scope instance
// - It may return the same overridden symbols more then once in case of substitution
// - It may return the same overridden symbols more than once in case of substitution or intersection
// (but with different base scope)
abstract fun processDirectOverriddenFunctionsWithBaseScope(
functionSymbol: FirNamedFunctionSymbol,
processor: (FirNamedFunctionSymbol, FirTypeScope) -> ProcessorAction
@@ -1,7 +1,5 @@
// ISSUE: KT-55828
// DUMP_IR
// IGNORE_BACKEND_K2: ANY
// Ignore reason: FIR scopes skip part of overridden hierarchy. It will fixed in next commits
// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: extra overridden symbols for declarations in MyMutableList.
// ^ This is most likely not a problem, and IR dump can be changed once IR fake override generation is enabled by default.