[FIR] Make MemberWithScope a data class
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`. So there actually was no such thing as "pair of two different MemberWithScope with the same symbol and different scopes" After the change of `processDirectOverriddenWithBaseScope` contract (see previous commits) each scope returns `MemberWithScope` for some symbol with the previous scope in the hierarchy even if it contains the same symbol as the current scope So now scope is actually a part of `MemberWithScope`, which should be considered as part of equality. Otherwise, we can skip some part of the overridden hierarchy, because we will start to consider symbol as visited after its first occurrence (in opposite to the previous behavior, when only the last scope was returned)
This commit is contained in:
committed by
Space Team
parent
385bff3be1
commit
bc95c5d142
+6
-1
@@ -144,8 +144,13 @@ class FirTypeIntersectionScopeContext(
|
|||||||
return members.map { ResultOfIntersection.SingleMember(it, MemberWithBaseScope(it, scope)) }
|
return members.map { ResultOfIntersection.SingleMember(it, MemberWithBaseScope(it, scope)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val uniqueSymbols = mutableSetOf<D>()
|
||||||
val allMembersWithScope = membersByScope.flatMapTo(linkedSetOf()) { (scope, members) ->
|
val allMembersWithScope = membersByScope.flatMapTo(linkedSetOf()) { (scope, members) ->
|
||||||
members.map { MemberWithBaseScope(it, scope) }
|
members.mapNotNull {
|
||||||
|
runIf(uniqueSymbols.add(it)) {
|
||||||
|
MemberWithBaseScope(it, scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = mutableListOf<ResultOfIntersection<D>>()
|
val result = mutableListOf<ResultOfIntersection<D>>()
|
||||||
|
|||||||
+23
-9
@@ -92,26 +92,30 @@ class MemberScopeTowerLevel(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (scopeWithoutSmartcast == null) {
|
if (scopeWithoutSmartcast == null) {
|
||||||
consumeCandidates(output, candidates)
|
consumeCandidates(
|
||||||
|
output,
|
||||||
|
candidatesWithoutSmartcast = candidates,
|
||||||
|
candidatesWithSmartcast = null
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
val isFromSmartCast: MutableMap<MemberWithBaseScope<T>, Boolean> = mutableMapOf()
|
val map: MutableMap<T, MemberFromSmartcastScope<T>> = mutableMapOf()
|
||||||
|
|
||||||
scopeWithoutSmartcast.collectCandidates(processScopeMembers).let { (isEmpty, originalCandidates) ->
|
scopeWithoutSmartcast.collectCandidates(processScopeMembers).let { (isEmpty, originalCandidates) ->
|
||||||
empty = empty && isEmpty
|
empty = empty && isEmpty
|
||||||
for (originalCandidate in originalCandidates) {
|
for (originalCandidate in originalCandidates) {
|
||||||
isFromSmartCast[originalCandidate] = false
|
map[originalCandidate.member] = MemberFromSmartcastScope(originalCandidate, cameFromSmartcast = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (candidateFromSmartCast in candidates) {
|
for (candidateFromSmartCast in candidates) {
|
||||||
isFromSmartCast[candidateFromSmartCast] = true
|
map[candidateFromSmartCast.member] = MemberFromSmartcastScope(candidateFromSmartCast, cameFromSmartcast = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
consumeCandidates(
|
consumeCandidates(
|
||||||
output,
|
output,
|
||||||
// all the candidates, both from original type and smart cast
|
// all the candidates, both from original type and smart cast
|
||||||
candidates = isFromSmartCast.keys,
|
candidatesWithoutSmartcast = null,
|
||||||
isFromSmartCast,
|
candidatesWithSmartcast = map
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +166,11 @@ class MemberScopeTowerLevel(
|
|||||||
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
|
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class MemberFromSmartcastScope<T : FirCallableSymbol<*>>(
|
||||||
|
val memberWithBaseScope: MemberWithBaseScope<T>,
|
||||||
|
val cameFromSmartcast: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
private fun <T : FirCallableSymbol<*>> FirTypeScope.collectCandidates(
|
private fun <T : FirCallableSymbol<*>> FirTypeScope.collectCandidates(
|
||||||
processScopeMembers: FirScope.(processor: (T) -> Unit) -> Unit
|
processScopeMembers: FirScope.(processor: (T) -> Unit) -> Unit
|
||||||
): Pair<Boolean, List<MemberWithBaseScope<T>>> {
|
): Pair<Boolean, List<MemberWithBaseScope<T>>> {
|
||||||
@@ -185,16 +194,21 @@ class MemberScopeTowerLevel(
|
|||||||
|
|
||||||
private fun <T : FirCallableSymbol<*>> consumeCandidates(
|
private fun <T : FirCallableSymbol<*>> consumeCandidates(
|
||||||
output: TowerScopeLevelProcessor<T>,
|
output: TowerScopeLevelProcessor<T>,
|
||||||
candidates: Collection<MemberWithBaseScope<T>>,
|
candidatesWithoutSmartcast: Collection<MemberWithBaseScope<T>>?,
|
||||||
// The map is not null only if there's a smart cast type on a dispatch receiver
|
// The map is not null only if there's a smart cast type on a dispatch receiver
|
||||||
// and candidates are present both in smart cast and original types.
|
// and candidates are present both in smart cast and original types.
|
||||||
// isFromSmartCast[candidate] == true iff exactly that member is present in smart cast type
|
// isFromSmartCast[candidate] == true iff exactly that member is present in smart cast type
|
||||||
isFromSmartCast: Map<MemberWithBaseScope<T>, Boolean>? = null
|
candidatesWithSmartcast: Map<T, MemberFromSmartcastScope<T>>?
|
||||||
) {
|
) {
|
||||||
|
val candidates = candidatesWithoutSmartcast
|
||||||
|
?: candidatesWithSmartcast?.values?.map { it.memberWithBaseScope }
|
||||||
|
?: error("candidatesWithoutSmartcast or candidatesWithSmartcast should be not null")
|
||||||
|
|
||||||
for (candidateWithScope in candidates) {
|
for (candidateWithScope in candidates) {
|
||||||
val (candidate, scope) = candidateWithScope
|
val (candidate, scope) = candidateWithScope
|
||||||
if (candidate.hasConsistentExtensionReceiver(givenExtensionReceiverOptions)) {
|
if (candidate.hasConsistentExtensionReceiver(givenExtensionReceiverOptions)) {
|
||||||
val isFromOriginalTypeInPresenceOfSmartCast = isFromSmartCast != null && !isFromSmartCast.getValue(candidateWithScope)
|
val isFromOriginalTypeInPresenceOfSmartCast = candidatesWithSmartcast != null &&
|
||||||
|
!candidatesWithSmartcast.getValue(candidateWithScope.member).cameFromSmartcast
|
||||||
|
|
||||||
val dispatchReceiverToUse = when {
|
val dispatchReceiverToUse = when {
|
||||||
isFromOriginalTypeInPresenceOfSmartCast ->
|
isFromOriginalTypeInPresenceOfSmartCast ->
|
||||||
|
|||||||
@@ -64,18 +64,7 @@ abstract class FirTypeScope : FirContainingNamesAwareScope() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MemberWithBaseScope<out D : FirCallableSymbol<*>>(val member: D, val baseScope: FirTypeScope) {
|
data class MemberWithBaseScope<out D : FirCallableSymbol<*>>(val member: D, val baseScope: FirTypeScope)
|
||||||
operator fun component1() = member
|
|
||||||
operator fun component2() = baseScope
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
return other is MemberWithBaseScope<*> && member == other.member
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
return member.hashCode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typealias ProcessOverriddenWithBaseScope<D> = FirTypeScope.(D, (D, FirTypeScope) -> ProcessorAction) -> ProcessorAction
|
typealias ProcessOverriddenWithBaseScope<D> = FirTypeScope.(D, (D, FirTypeScope) -> ProcessorAction) -> ProcessorAction
|
||||||
typealias ProcessAllOverridden<D> = FirTypeScope.(D, (D) -> ProcessorAction) -> ProcessorAction
|
typealias ProcessAllOverridden<D> = FirTypeScope.(D, (D) -> ProcessorAction) -> ProcessorAction
|
||||||
|
|||||||
Reference in New Issue
Block a user