[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
+1
-1
@@ -30,4 +30,4 @@ fun test_1(x: String?) {
|
||||
fun test_2(x: String?) {
|
||||
trickyRequireNotNull(x)
|
||||
x.length
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -144,8 +144,13 @@ class FirTypeIntersectionScopeContext(
|
||||
return members.map { ResultOfIntersection.SingleMember(it, MemberWithBaseScope(it, scope)) }
|
||||
}
|
||||
|
||||
val uniqueSymbols = mutableSetOf<D>()
|
||||
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>>()
|
||||
|
||||
+23
-9
@@ -92,26 +92,30 @@ class MemberScopeTowerLevel(
|
||||
)
|
||||
|
||||
if (scopeWithoutSmartcast == null) {
|
||||
consumeCandidates(output, candidates)
|
||||
consumeCandidates(
|
||||
output,
|
||||
candidatesWithoutSmartcast = candidates,
|
||||
candidatesWithSmartcast = null
|
||||
)
|
||||
} else {
|
||||
val isFromSmartCast: MutableMap<MemberWithBaseScope<T>, Boolean> = mutableMapOf()
|
||||
val map: MutableMap<T, MemberFromSmartcastScope<T>> = mutableMapOf()
|
||||
|
||||
scopeWithoutSmartcast.collectCandidates(processScopeMembers).let { (isEmpty, originalCandidates) ->
|
||||
empty = empty && isEmpty
|
||||
for (originalCandidate in originalCandidates) {
|
||||
isFromSmartCast[originalCandidate] = false
|
||||
map[originalCandidate.member] = MemberFromSmartcastScope(originalCandidate, cameFromSmartcast = false)
|
||||
}
|
||||
}
|
||||
|
||||
for (candidateFromSmartCast in candidates) {
|
||||
isFromSmartCast[candidateFromSmartCast] = true
|
||||
map[candidateFromSmartCast.member] = MemberFromSmartcastScope(candidateFromSmartCast, cameFromSmartcast = true)
|
||||
}
|
||||
|
||||
consumeCandidates(
|
||||
output,
|
||||
// all the candidates, both from original type and smart cast
|
||||
candidates = isFromSmartCast.keys,
|
||||
isFromSmartCast,
|
||||
candidatesWithoutSmartcast = null,
|
||||
candidatesWithSmartcast = map
|
||||
)
|
||||
}
|
||||
|
||||
@@ -162,6 +166,11 @@ class MemberScopeTowerLevel(
|
||||
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(
|
||||
processScopeMembers: FirScope.(processor: (T) -> Unit) -> Unit
|
||||
): Pair<Boolean, List<MemberWithBaseScope<T>>> {
|
||||
@@ -185,16 +194,21 @@ class MemberScopeTowerLevel(
|
||||
|
||||
private fun <T : FirCallableSymbol<*>> consumeCandidates(
|
||||
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
|
||||
// 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: 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) {
|
||||
val (candidate, scope) = candidateWithScope
|
||||
if (candidate.hasConsistentExtensionReceiver(givenExtensionReceiverOptions)) {
|
||||
val isFromOriginalTypeInPresenceOfSmartCast = isFromSmartCast != null && !isFromSmartCast.getValue(candidateWithScope)
|
||||
val isFromOriginalTypeInPresenceOfSmartCast = candidatesWithSmartcast != null &&
|
||||
!candidatesWithSmartcast.getValue(candidateWithScope.member).cameFromSmartcast
|
||||
|
||||
val dispatchReceiverToUse = when {
|
||||
isFromOriginalTypeInPresenceOfSmartCast ->
|
||||
|
||||
@@ -64,18 +64,7 @@ abstract class FirTypeScope : FirContainingNamesAwareScope() {
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
data class MemberWithBaseScope<out D : FirCallableSymbol<*>>(val member: D, val baseScope: FirTypeScope)
|
||||
|
||||
typealias ProcessOverriddenWithBaseScope<D> = FirTypeScope.(D, (D, FirTypeScope) -> ProcessorAction) -> ProcessorAction
|
||||
typealias ProcessAllOverridden<D> = FirTypeScope.(D, (D) -> ProcessorAction) -> ProcessorAction
|
||||
|
||||
Reference in New Issue
Block a user