From ff4b6a0bf9ae1a2aa7a18b699cf33dfb28d18123 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 29 Sep 2020 20:08:37 +0300 Subject: [PATCH] FIR: Fix modality computation for corner cases in FirTypeIntersectionScope See org.jetbrains.kotlin.resolve.OverridingUtil#determineModalityForFakeOverride --- .../scopes/impl/FirTypeIntersectionScope.kt | 113 ++++++++++++++++-- .../kotlin/fir/scopes/FirTypeScope.kt | 25 ++-- 2 files changed, 123 insertions(+), 15 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt index 25833e88aac..b004feb5175 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt @@ -11,11 +11,9 @@ import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor -import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker -import org.jetbrains.kotlin.fir.scopes.FirScope -import org.jetbrains.kotlin.fir.scopes.FirTypeScope -import org.jetbrains.kotlin.fir.scopes.ProcessorAction +import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.symbols.CallableId +import org.jetbrains.kotlin.fir.symbols.PossiblyFirFakeOverrideSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.ConeFlexibleType import org.jetbrains.kotlin.fir.types.ConeKotlinType @@ -136,9 +134,110 @@ class FirTypeIntersectionScope private constructor( } private fun > chooseIntersectionOverrideModality( - extractedOverrides: Collection> + extractedOverridden: Collection> ): Modality { - return extractedOverrides.minOf { (it.member.fir as FirMemberDeclaration).modality ?: Modality.ABSTRACT } + var hasOpen = false + var hasAbstract = false + + for ((member) in extractedOverridden) { + when ((member.fir as FirMemberDeclaration).modality) { + Modality.FINAL -> return Modality.FINAL + Modality.SEALED -> error("Members should not be sealed: $member") + Modality.OPEN -> { + hasOpen = true + } + Modality.ABSTRACT -> { + hasAbstract = true + } + null -> { + } + } + } + + if (hasAbstract && !hasOpen) return Modality.ABSTRACT + if (!hasAbstract && hasOpen) return Modality.OPEN + + @Suppress("UNCHECKED_CAST") + val processDirectOverridden: ProcessOverriddenWithBaseScope = when (extractedOverridden.first().member) { + is FirNamedFunctionSymbol -> FirTypeScope::processDirectOverriddenFunctionsWithBaseScope as ProcessOverriddenWithBaseScope + is FirPropertySymbol -> FirTypeScope::processDirectOverriddenPropertiesWithBaseScope as ProcessOverriddenWithBaseScope + else -> error("Unexpected callable kind: ${extractedOverridden.first().member}") + } + + val realOverridden = extractedOverridden.flatMap { realOverridden(it.member, it.baseScope, processDirectOverridden) } + val filteredOverridden = filterOutOverridden(realOverridden, processDirectOverridden) + + return filteredOverridden.minOf { (it.member.fir as FirMemberDeclaration).modality ?: Modality.ABSTRACT } + } + + private fun > realOverridden( + symbol: D, + scope: FirTypeScope, + processDirectOverridden: ProcessOverriddenWithBaseScope, + ): Collection> { + val result = mutableSetOf>() + + collectRealOverridden(symbol, scope, result, mutableSetOf(), processDirectOverridden) + + return result + } + + private fun > collectRealOverridden( + symbol: D, + scope: FirTypeScope, + result: MutableCollection>, + visited: MutableSet, + processDirectOverridden: FirTypeScope.(D, (D, FirTypeScope) -> ProcessorAction) -> ProcessorAction, + ) { + if (!visited.add(symbol)) return + if (!symbol.isIntersectionOverride && !(symbol as PossiblyFirFakeOverrideSymbol<*, *>).isFakeOverride) { + result.add(MemberWithBaseScope(symbol, scope)) + return + } + + scope.processDirectOverridden(symbol) { overridden, baseScope -> + collectRealOverridden(overridden, baseScope, result, visited, processDirectOverridden) + ProcessorAction.NEXT + } + } + + + private fun > filterOutOverridden( + extractedOverridden: Collection>, + processAllOverridden: ProcessOverriddenWithBaseScope, + ): Collection> { + return extractedOverridden.filter { overridden1 -> + extractedOverridden.none { overridden2 -> + overridden1 !== overridden2 && overrides( + overridden2, + overridden1, + processAllOverridden + ) + } + } + } + + // Whether f overrides g + private fun > overrides( + f: MemberWithBaseScope, + g: MemberWithBaseScope, + processAllOverridden: ProcessOverriddenWithBaseScope, + ): Boolean { + val (fMember, fScope) = f + val (gMember) = g + + var result = false + + fScope.processAllOverridden(fMember) { overridden, _ -> + if (overridden == gMember) { + result = true + ProcessorAction.STOP + } else { + ProcessorAction.NEXT + } + } + + return result } private fun > chooseIntersectionVisibility( @@ -395,7 +494,7 @@ class FirTypeIntersectionScope private constructor( } } -private class MemberWithBaseScope>(val member: D, private val baseScope: FirTypeScope) { +private class MemberWithBaseScope>(val member: D, val baseScope: FirTypeScope) { operator fun component1() = member operator fun component2() = baseScope } 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 4e23d7b4d9c..89c84c78e4c 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 @@ -80,6 +80,8 @@ abstract class FirTypeScope : FirScope(), FirContainingNamesAwareScope { } } +typealias ProcessOverriddenWithBaseScope = FirTypeScope.(D, (D, FirTypeScope) -> ProcessorAction) -> ProcessorAction + fun FirTypeScope.processOverriddenFunctions( functionSymbol: FirFunctionSymbol<*>, processor: (FirFunctionSymbol<*>) -> ProcessorAction @@ -102,20 +104,27 @@ fun FirTypeScope.processOverriddenProperties( mutableSetOf() ) +private fun > FirTypeScope.doProcessAllOverriddenCallables( + callableSymbol: S, + processor: (S, FirTypeScope) -> ProcessorAction, + processDirectOverriddenCallablesWithBaseScope: FirTypeScope.(S, (S, FirTypeScope) -> ProcessorAction) -> ProcessorAction, + visited: MutableSet +): ProcessorAction { + if (!visited.add(callableSymbol)) return ProcessorAction.NONE + return processDirectOverriddenCallablesWithBaseScope(callableSymbol) { overridden, baseScope -> + if (!processor(overridden, baseScope)) return@processDirectOverriddenCallablesWithBaseScope ProcessorAction.STOP + + baseScope.doProcessAllOverriddenCallables(overridden, processor, processDirectOverriddenCallablesWithBaseScope, visited) + } +} private fun > FirTypeScope.doProcessAllOverriddenCallables( callableSymbol: S, processor: (S) -> ProcessorAction, processDirectOverriddenCallablesWithBaseScope: FirTypeScope.(S, (S, FirTypeScope) -> ProcessorAction) -> ProcessorAction, visited: MutableSet -): ProcessorAction { - if (!visited.add(callableSymbol)) return ProcessorAction.NONE - return processDirectOverriddenCallablesWithBaseScope(callableSymbol) { overridden, baseScope -> - if (!processor(overridden)) return@processDirectOverriddenCallablesWithBaseScope ProcessorAction.STOP - - baseScope.doProcessAllOverriddenCallables(overridden, processor, processDirectOverriddenCallablesWithBaseScope, visited) - } -} +): ProcessorAction = + doProcessAllOverriddenCallables(callableSymbol, { s, _ -> processor(s) }, processDirectOverriddenCallablesWithBaseScope, visited) inline fun FirTypeScope.processDirectlyOverriddenFunctions( functionSymbol: FirFunctionSymbol<*>,