From 603b46e5311f93bf9ea1913b0803211afb756a03 Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Tue, 31 Jan 2023 10:57:29 +0200 Subject: [PATCH] [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.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.forEach` - `kotlin/sequence/Sequence.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 --- .../calls/tower/FirTowerResolveTask.kt | 38 +++++++++---------- .../testsWithStdLib/kt55503.fir.kt | 4 +- .../testsWithStdLib/kt55503_2.fir.txt | 2 +- .../diagnostics/testsWithStdLib/kt55503_2.kt | 3 +- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt index dda49e001bc..0ce837c10ea 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt @@ -278,7 +278,10 @@ internal open class FirTowerResolveTask( ) { val explicitReceiverValue = ExpressionReceiverValue(receiver) - processExtensionsThatHideMembers(info, explicitReceiverValue, parentGroup) + processExtensionsThatHideMembers( + info, explicitReceiverValue, parentGroup, + ExplicitReceiverKind.EXTENSION_RECEIVER, + ) // Member scope of expression receiver processLevel( @@ -314,8 +317,6 @@ internal open class FirTowerResolveTask( suspend fun runResolverForNoReceiver( info: CallInfo ) { - processExtensionsThatHideMembers(info, explicitReceiverValue = null) - val emptyScopes = mutableSetOf() val implicitReceiverValuesWithEmptyScopes = mutableSetOf>() @@ -366,28 +367,19 @@ internal open class FirTowerResolveTask( private suspend fun processExtensionsThatHideMembers( info: CallInfo, - explicitReceiverValue: ReceiverValue?, - parentGroup: TowerGroup = TowerGroup.EmptyRoot + receiverValue: ReceiverValue, + parentGroup: TowerGroup, + explicitReceiverKind: ExplicitReceiverKind, ) { // 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 val importingScopes = components.fileImportsScope.asReversed() for ((index, topLevelScope) in importingScopes.withIndex()) { - if (explicitReceiverValue != null) { - processHideMembersLevel( - explicitReceiverValue, topLevelScope, info, index, depth = null, - ExplicitReceiverKind.EXTENSION_RECEIVER, parentGroup - ) - } else { - // context? - for ((depth, implicitReceiverValue) in towerDataElementsForName.implicitReceivers) { - processHideMembersLevel( - implicitReceiverValue, topLevelScope, info, index, depth, - ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, parentGroup - ) - } - } + processHideMembersLevel( + receiverValue, topLevelScope, info, index, + explicitReceiverKind, parentGroup + ) } } @@ -411,6 +403,11 @@ internal open class FirTowerResolveTask( implicitReceiverValuesWithEmptyScopes: MutableSet>, emptyScopes: MutableSet ) { + processExtensionsThatHideMembers( + info, receiver, TowerGroup.EmptyRoot, + ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, + ) + processLevel( receiver.toMemberScopeTowerLevel(), info, parentGroup.Member, onEmptyLevel = { @@ -485,7 +482,6 @@ internal open class FirTowerResolveTask( topLevelScope: FirScope, info: CallInfo, index: Int, - depth: Int?, explicitReceiverKind: ExplicitReceiverKind, parentGroup: TowerGroup ) { @@ -494,7 +490,7 @@ internal open class FirTowerResolveTask( extensionReceiver = receiverValue, withHideMembersOnly = true ), info, - parentGroup.TopPrioritized(index).let { if (depth != null) it.Implicit(depth) else it }, + parentGroup.TopPrioritized(index), explicitReceiverKind, ) } diff --git a/compiler/testData/diagnostics/testsWithStdLib/kt55503.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/kt55503.fir.kt index cb35cb20d57..70bad42bb85 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/kt55503.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/kt55503.fir.kt @@ -1,8 +1,8 @@ fun foo() = withIntList { withStringSequence { forEach { line -> - line.rem(1) - line.length + line.rem(1) + line.length } } } diff --git a/compiler/testData/diagnostics/testsWithStdLib/kt55503_2.fir.txt b/compiler/testData/diagnostics/testsWithStdLib/kt55503_2.fir.txt index bf9ee102e0e..40bdd08bec4 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/kt55503_2.fir.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/kt55503_2.fir.txt @@ -26,7 +26,7 @@ FILE: Second.kt public final fun box(): R|kotlin/Unit| { ^box R|kotlin/with|(R|sample/pack/A.A|(), = with@fun R|sample/pack/A|.(): R|kotlin/Unit| { R|kotlin/with|(R|sample/pack/B.B|(), = with@fun R|sample/pack/B|.(): R|kotlin/Unit| { - this@R|special/anonymous|.R|sample/pack/forEach|() + (this@R|special/anonymous|, this@R|special/anonymous|).R|sample/pack/A.forEach|() } ) } diff --git a/compiler/testData/diagnostics/testsWithStdLib/kt55503_2.kt b/compiler/testData/diagnostics/testsWithStdLib/kt55503_2.kt index 8ce4bd9fb5d..f71bfbe43cd 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/kt55503_2.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/kt55503_2.kt @@ -25,8 +25,7 @@ import sample.pack.* fun box() { return with(A()) { with(B()) { - // K1 resolves to A::B.check - // K2 - to ::A.check + // Both K1 & K2 resolve to A::B.check forEach() } }