[FIR] KT-55503: Prefer members-extensions over @HidesMembers extensions

Passing `EXTENSION_RECEIVER` when processing `noReceiver`
looks like a mistake in general. This change is backed
by the `hidesMembers` and
`memberWithHidesMemberAnnotationVsMemberWithout` tests.

The exact reason with `memberWithHidesMemberAnnotationVsMemberWithout`
is that it first checks `@HidesMembers` candidates,
only takes the `kotlin/collections/Iterable<T>.forEach`,
but then yields `InapplicableWrongReceiver`,
because `explicitReceiverKind = EXTENSION_RECEIVER`
(which is strange, because we really don't have an explicit receiver).
Then we visit the same scope once more (now for all candidates)
and take 2 functions:

- `kotlin/collections/Iterable<T>.forEach`
- `kotlin/sequence/Sequence<T>.forEach`

...and they both result in `RESOLVED`,
because this time `explicitReceiverKind = NO_EXPLICIT_RECEIVER`.

This change ensures the first candidate we see
while checking `@HidesMembers` is taken as `RESOLVED`.

^KT-55503 Fixed
This commit is contained in:
Nikolay Lunyak
2023-01-31 10:57:29 +02:00
committed by Space Team
parent 906b16b41e
commit 603b46e531
4 changed files with 21 additions and 26 deletions
@@ -278,7 +278,10 @@ internal open class FirTowerResolveTask(
) { ) {
val explicitReceiverValue = ExpressionReceiverValue(receiver) val explicitReceiverValue = ExpressionReceiverValue(receiver)
processExtensionsThatHideMembers(info, explicitReceiverValue, parentGroup) processExtensionsThatHideMembers(
info, explicitReceiverValue, parentGroup,
ExplicitReceiverKind.EXTENSION_RECEIVER,
)
// Member scope of expression receiver // Member scope of expression receiver
processLevel( processLevel(
@@ -314,8 +317,6 @@ internal open class FirTowerResolveTask(
suspend fun runResolverForNoReceiver( suspend fun runResolverForNoReceiver(
info: CallInfo info: CallInfo
) { ) {
processExtensionsThatHideMembers(info, explicitReceiverValue = null)
val emptyScopes = mutableSetOf<FirScope>() val emptyScopes = mutableSetOf<FirScope>()
val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>() val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>()
@@ -366,28 +367,19 @@ internal open class FirTowerResolveTask(
private suspend fun processExtensionsThatHideMembers( private suspend fun processExtensionsThatHideMembers(
info: CallInfo, info: CallInfo,
explicitReceiverValue: ReceiverValue?, receiverValue: ReceiverValue,
parentGroup: TowerGroup = TowerGroup.EmptyRoot parentGroup: TowerGroup,
explicitReceiverKind: ExplicitReceiverKind,
) { ) {
// We will process hides members only for function calls with name in HIDES_MEMBERS_NAME_LIST // We will process hides members only for function calls with name in HIDES_MEMBERS_NAME_LIST
if (info.callKind != CallKind.Function || info.name !in HIDES_MEMBERS_NAME_LIST) return if (info.callKind != CallKind.Function || info.name !in HIDES_MEMBERS_NAME_LIST) return
val importingScopes = components.fileImportsScope.asReversed() val importingScopes = components.fileImportsScope.asReversed()
for ((index, topLevelScope) in importingScopes.withIndex()) { for ((index, topLevelScope) in importingScopes.withIndex()) {
if (explicitReceiverValue != null) { processHideMembersLevel(
processHideMembersLevel( receiverValue, topLevelScope, info, index,
explicitReceiverValue, topLevelScope, info, index, depth = null, explicitReceiverKind, parentGroup
ExplicitReceiverKind.EXTENSION_RECEIVER, parentGroup )
)
} else {
// context?
for ((depth, implicitReceiverValue) in towerDataElementsForName.implicitReceivers) {
processHideMembersLevel(
implicitReceiverValue, topLevelScope, info, index, depth,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, parentGroup
)
}
}
} }
} }
@@ -411,6 +403,11 @@ internal open class FirTowerResolveTask(
implicitReceiverValuesWithEmptyScopes: MutableSet<ImplicitReceiverValue<*>>, implicitReceiverValuesWithEmptyScopes: MutableSet<ImplicitReceiverValue<*>>,
emptyScopes: MutableSet<FirScope> emptyScopes: MutableSet<FirScope>
) { ) {
processExtensionsThatHideMembers(
info, receiver, TowerGroup.EmptyRoot,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
)
processLevel( processLevel(
receiver.toMemberScopeTowerLevel(), info, parentGroup.Member, receiver.toMemberScopeTowerLevel(), info, parentGroup.Member,
onEmptyLevel = { onEmptyLevel = {
@@ -485,7 +482,6 @@ internal open class FirTowerResolveTask(
topLevelScope: FirScope, topLevelScope: FirScope,
info: CallInfo, info: CallInfo,
index: Int, index: Int,
depth: Int?,
explicitReceiverKind: ExplicitReceiverKind, explicitReceiverKind: ExplicitReceiverKind,
parentGroup: TowerGroup parentGroup: TowerGroup
) { ) {
@@ -494,7 +490,7 @@ internal open class FirTowerResolveTask(
extensionReceiver = receiverValue, withHideMembersOnly = true extensionReceiver = receiverValue, withHideMembersOnly = true
), ),
info, info,
parentGroup.TopPrioritized(index).let { if (depth != null) it.Implicit(depth) else it }, parentGroup.TopPrioritized(index),
explicitReceiverKind, explicitReceiverKind,
) )
} }
@@ -1,8 +1,8 @@
fun foo() = withIntList { fun foo() = withIntList {
withStringSequence { withStringSequence {
forEach { line -> forEach { line ->
line.rem(1) line.<!UNRESOLVED_REFERENCE!>rem<!>(1)
line.<!UNRESOLVED_REFERENCE!>length<!> line.length
} }
} }
} }
@@ -26,7 +26,7 @@ FILE: Second.kt
public final fun box(): R|kotlin/Unit| { public final fun box(): R|kotlin/Unit| {
^box R|kotlin/with|<R|sample/pack/A|, R|kotlin/Unit|>(R|sample/pack/A.A|(), <L> = with@fun R|sample/pack/A|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> { ^box R|kotlin/with|<R|sample/pack/A|, R|kotlin/Unit|>(R|sample/pack/A.A|(), <L> = with@fun R|sample/pack/A|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
R|kotlin/with|<R|sample/pack/B|, R|kotlin/Unit|>(R|sample/pack/B.B|(), <L> = with@fun R|sample/pack/B|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> { R|kotlin/with|<R|sample/pack/B|, R|kotlin/Unit|>(R|sample/pack/B.B|(), <L> = with@fun R|sample/pack/B|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
this@R|special/anonymous|.R|sample/pack/forEach|() (this@R|special/anonymous|, this@R|special/anonymous|).R|sample/pack/A.forEach|()
} }
) )
} }
+1 -2
View File
@@ -25,8 +25,7 @@ import sample.pack.*
fun box() { fun box() {
return with(A()) { return with(A()) {
with(B()) { with(B()) {
// K1 resolves to A::B.check // Both K1 & K2 resolve to A::B.check
// K2 - to ::A.check
forEach() forEach()
} }
} }