[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:
committed by
Space Team
parent
906b16b41e
commit
603b46e531
+15
-19
@@ -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(
|
||||||
explicitReceiverValue, topLevelScope, info, index, depth = null,
|
receiverValue, topLevelScope, info, index,
|
||||||
ExplicitReceiverKind.EXTENSION_RECEIVER, parentGroup
|
explicitReceiverKind, 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|()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user