From 4272f2e15620c9985be9cbfe6963e544a39dd4df Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 6 Dec 2023 15:40:00 +0200 Subject: [PATCH] [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 --- .../singleIntersectionOverride.overrides.txt | 11 +++++++--- .../specialFunctionInJava_1.overrides.txt | 1 + .../specialFunctionInJava_2.overrides.txt | 12 +++++++---- .../impl/AbstractFirUseSiteMemberScope.kt | 21 ++++++------------- .../kotlin/fir/scopes/FirTypeScope.kt | 4 ++-- ...ropertyWithMultipleOverriddens_generics.kt | 2 -- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/scopes/singleIntersectionOverride.overrides.txt b/compiler/fir/analysis-tests/testData/resolve/scopes/singleIntersectionOverride.overrides.txt index 3dbaa09f8a7..916f0866883 100644 --- a/compiler/fir/analysis-tests/testData/resolve/scopes/singleIntersectionOverride.overrides.txt +++ b/compiler/fir/analysis-tests/testData/resolve/scopes/singleIntersectionOverride.overrides.txt @@ -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 [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 [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 [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 [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 [id: 5] + [Source]: public abstract fun foo(): R|E1| from Use site scope of /A [id: 3] diff --git a/compiler/fir/analysis-tests/testData/resolve/scopes/specialFunctionInJava_1.overrides.txt b/compiler/fir/analysis-tests/testData/resolve/scopes/specialFunctionInJava_1.overrides.txt index f8cf0b7d515..421195e9e46 100644 --- a/compiler/fir/analysis-tests/testData/resolve/scopes/specialFunctionInJava_1.overrides.txt +++ b/compiler/fir/analysis-tests/testData/resolve/scopes/specialFunctionInJava_1.overrides.txt @@ -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] diff --git a/compiler/fir/analysis-tests/testData/resolve/scopes/specialFunctionInJava_2.overrides.txt b/compiler/fir/analysis-tests/testData/resolve/scopes/specialFunctionInJava_2.overrides.txt index 54d7bd4be56..134ec0d4d88 100644 --- a/compiler/fir/analysis-tests/testData/resolve/scopes/specialFunctionInJava_2.overrides.txt +++ b/compiler/fir/analysis-tests/testData/resolve/scopes/specialFunctionInJava_2.overrides.txt @@ -2,7 +2,8 @@ SomeMap: [Enhancement]: public abstract fun containsKey(key: R|ft|): R|kotlin/Boolean| from Java enhancement scope for /SomeMap [id: 0] [SubstitutionOverride(DeclarationSite)]: public abstract fun containsKey(key: R|ft|): R|kotlin/Boolean| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type SomeMap [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 [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 [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 [id: 6] @@ -10,20 +11,23 @@ SomeMap: [IntersectionOverride]: public abstract fun containsValue(value: R|ft|): R|kotlin/Boolean| from Java enhancement scope for /SomeMap [id: 0] [SubstitutionOverride(DeclarationSite)]: public abstract fun containsValue(value: R|ft|): R|kotlin/Boolean| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type SomeMap [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 [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 [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|): R|V3?| from Java enhancement scope for /SomeMap [id: 0] [SubstitutionOverride(DeclarationSite)]: public abstract operator fun get(key: R|ft|): R|V3?| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type SomeMap [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 [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|): R|ft| from Substitution scope for [Java enhancement scope for /MyMap] for type SomeMap [id: 4] [Enhancement]: public abstract operator fun get(key: R|ft|): R|ft| from Java enhancement scope for /MyMap [id: 5] [Enhancement]: public abstract fun remove(key: R|ft|): R|V3?| from Java enhancement scope for /SomeMap [id: 0] [SubstitutionOverride(DeclarationSite)]: public abstract fun remove(key: R|ft|): R|V3?| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type SomeMap [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|, value: R|ft|): 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|, value: R|ft|): R|kotlin/Boolean| from Substitution scope for [Use site scope of kotlin/collections/MutableMap] for type 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] MyMap: [Enhancement]: public abstract fun containsKey(key: R|kotlin/Any!|): R|kotlin/Boolean| from Java enhancement scope for /MyMap [id: 0] diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt index 3c0d98be8b2..8227cd1acd4 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt @@ -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>>, callablesFromSupertypes: Map>>, 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) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirTypeScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirTypeScope.kt index 0494e8acf5f..e0fba8ece47 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirTypeScope.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirTypeScope.kt @@ -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 diff --git a/compiler/testData/codegen/box/functions/delegatedPropertyWithMultipleOverriddens_generics.kt b/compiler/testData/codegen/box/functions/delegatedPropertyWithMultipleOverriddens_generics.kt index 28263c3adaa..d91f3278bcb 100644 --- a/compiler/testData/codegen/box/functions/delegatedPropertyWithMultipleOverriddens_generics.kt +++ b/compiler/testData/codegen/box/functions/delegatedPropertyWithMultipleOverriddens_generics.kt @@ -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.