FIR: add comments & tests for tower resolver, block some receiver pairs
This commit is contained in:
@@ -28,23 +28,39 @@ class CallResolver(
|
|||||||
private fun processImplicitReceiver(
|
private fun processImplicitReceiver(
|
||||||
towerDataConsumer: TowerDataConsumer,
|
towerDataConsumer: TowerDataConsumer,
|
||||||
implicitReceiverValue: ImplicitReceiverValue,
|
implicitReceiverValue: ImplicitReceiverValue,
|
||||||
collector: CandidateCollector,
|
|
||||||
oldGroup: Int
|
oldGroup: Int
|
||||||
): Int {
|
): Int {
|
||||||
var group = oldGroup
|
var group = oldGroup
|
||||||
|
// Member (no explicit receiver) / extension member (with explicit receiver) access via implicit receiver
|
||||||
|
// class Foo(val x: Int) {
|
||||||
|
// fun Bar.baz() {}
|
||||||
|
// fun test() { x }
|
||||||
|
// fun test(b: Bar) { b.baz() }
|
||||||
|
// }
|
||||||
towerDataConsumer.consume(
|
towerDataConsumer.consume(
|
||||||
TowerDataKind.TOWER_LEVEL,
|
TowerDataKind.TOWER_LEVEL,
|
||||||
MemberScopeTowerLevel(session, implicitReceiverValue, scopeSession = components.scopeSession),
|
MemberScopeTowerLevel(session, implicitReceiverValue, scopeSession = components.scopeSession),
|
||||||
group++
|
group++
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is an equivalent to the old "BothTowerLevelAndImplicitReceiver"
|
// Same receiver is dispatch & extension
|
||||||
|
// class Foo {
|
||||||
|
// fun Foo.bar() {}
|
||||||
|
// fun test() { bar() }
|
||||||
|
// }
|
||||||
towerDataConsumer.consume(
|
towerDataConsumer.consume(
|
||||||
TowerDataKind.TOWER_LEVEL,
|
TowerDataKind.TOWER_LEVEL,
|
||||||
MemberScopeTowerLevel(session, implicitReceiverValue, implicitReceiverValue, components.scopeSession),
|
MemberScopeTowerLevel(session, implicitReceiverValue, implicitReceiverValue, components.scopeSession),
|
||||||
group++
|
group++
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Local scope extensions via implicit receiver
|
||||||
|
// class Foo {
|
||||||
|
// fun test() {
|
||||||
|
// fun Foo.bar() {}
|
||||||
|
// bar()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
for (scope in localScopes) {
|
for (scope in localScopes) {
|
||||||
towerDataConsumer.consume(
|
towerDataConsumer.consume(
|
||||||
TowerDataKind.TOWER_LEVEL,
|
TowerDataKind.TOWER_LEVEL,
|
||||||
@@ -53,9 +69,18 @@ class CallResolver(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var blockDispatchReceivers = false
|
||||||
|
|
||||||
for (implicitDispatchReceiverValue in implicitReceiverValues) {
|
for (implicitDispatchReceiverValue in implicitReceiverValues) {
|
||||||
val implicitScope = implicitDispatchReceiverValue.implicitScope
|
val implicitScope = implicitDispatchReceiverValue.implicitScope
|
||||||
if (implicitScope != null) {
|
if (implicitScope != null) {
|
||||||
|
// Extensions in outer object
|
||||||
|
// object Outer {
|
||||||
|
// fun Nested.foo() {}
|
||||||
|
// class Nested {
|
||||||
|
// fun test() { foo() }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
towerDataConsumer.consume(
|
towerDataConsumer.consume(
|
||||||
TowerDataKind.TOWER_LEVEL,
|
TowerDataKind.TOWER_LEVEL,
|
||||||
ScopeTowerLevel(session, implicitScope, implicitExtensionReceiver = implicitReceiverValue),
|
ScopeTowerLevel(session, implicitScope, implicitExtensionReceiver = implicitReceiverValue),
|
||||||
@@ -65,15 +90,33 @@ class CallResolver(
|
|||||||
if (implicitDispatchReceiverValue is ImplicitDispatchReceiverValue) {
|
if (implicitDispatchReceiverValue is ImplicitDispatchReceiverValue) {
|
||||||
val implicitCompanionScope = implicitDispatchReceiverValue.implicitCompanionScope
|
val implicitCompanionScope = implicitDispatchReceiverValue.implicitCompanionScope
|
||||||
if (implicitCompanionScope != null) {
|
if (implicitCompanionScope != null) {
|
||||||
|
// Extension in companion
|
||||||
|
// class My {
|
||||||
|
// companion object { fun My.foo() {} }
|
||||||
|
// fun test() { foo() }
|
||||||
|
// }
|
||||||
towerDataConsumer.consume(
|
towerDataConsumer.consume(
|
||||||
TowerDataKind.TOWER_LEVEL,
|
TowerDataKind.TOWER_LEVEL,
|
||||||
ScopeTowerLevel(session, implicitCompanionScope, implicitExtensionReceiver = implicitReceiverValue),
|
ScopeTowerLevel(session, implicitCompanionScope, implicitExtensionReceiver = implicitReceiverValue),
|
||||||
group++
|
group++
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (blockDispatchReceivers) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (!implicitDispatchReceiverValue.boundSymbol.fir.isInner) {
|
||||||
|
blockDispatchReceivers = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (implicitDispatchReceiverValue !== implicitReceiverValue) {
|
if (implicitDispatchReceiverValue !== implicitReceiverValue) {
|
||||||
// Two different implicit receivers
|
// Two different implicit receivers (dispatch & extension)
|
||||||
|
// class A
|
||||||
|
// class B {
|
||||||
|
// fun A.foo() {}
|
||||||
|
// }
|
||||||
|
// fun test(a: A, b: B) {
|
||||||
|
// with(a) { with(b) { foo() } }
|
||||||
|
// }
|
||||||
towerDataConsumer.consume(
|
towerDataConsumer.consume(
|
||||||
TowerDataKind.TOWER_LEVEL,
|
TowerDataKind.TOWER_LEVEL,
|
||||||
MemberScopeTowerLevel(
|
MemberScopeTowerLevel(
|
||||||
@@ -86,6 +129,11 @@ class CallResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Top-level extensions via implicit receiver
|
||||||
|
// fun Foo.bar() {}
|
||||||
|
// class Foo {
|
||||||
|
// fun test() { bar() }
|
||||||
|
// }
|
||||||
for (scope in topLevelScopes) {
|
for (scope in topLevelScopes) {
|
||||||
towerDataConsumer.consume(
|
towerDataConsumer.consume(
|
||||||
TowerDataKind.TOWER_LEVEL,
|
TowerDataKind.TOWER_LEVEL,
|
||||||
@@ -106,25 +154,38 @@ class CallResolver(
|
|||||||
towerDataConsumer = consumer
|
towerDataConsumer = consumer
|
||||||
|
|
||||||
var group = 0
|
var group = 0
|
||||||
// Member of explicit receiver' type
|
// Member of explicit receiver' type (this stage does nothing without explicit receiver)
|
||||||
|
// class Foo(val x: Int)
|
||||||
|
// fun test(f: Foo) { f.x }
|
||||||
towerDataConsumer.consume(TowerDataKind.EMPTY, TowerScopeLevel.Empty, group++)
|
towerDataConsumer.consume(TowerDataKind.EMPTY, TowerScopeLevel.Empty, group++)
|
||||||
|
|
||||||
// Member of local scope
|
// Member of local scope
|
||||||
|
// fun test(x: Int) = x
|
||||||
for (scope in localScopes) {
|
for (scope in localScopes) {
|
||||||
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, scope), group++)
|
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, scope), group++)
|
||||||
}
|
}
|
||||||
|
|
||||||
var blockDispatchReceivers = false
|
var blockDispatchReceivers = false
|
||||||
|
|
||||||
// Member of implicit receiver' type
|
// Member of implicit receiver' type *and* relevant scope
|
||||||
for (implicitReceiverValue in implicitReceiverValues) {
|
for (implicitReceiverValue in implicitReceiverValues) {
|
||||||
val implicitScope = implicitReceiverValue.implicitScope
|
val implicitScope = implicitReceiverValue.implicitScope
|
||||||
if (implicitScope != null) {
|
if (implicitScope != null) {
|
||||||
|
// Regular implicit receiver scope (outer objects only?)
|
||||||
|
// object Outer {
|
||||||
|
// val x = 0
|
||||||
|
// class Nested { val y = x }
|
||||||
|
// }
|
||||||
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, implicitScope), group++)
|
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, implicitScope), group++)
|
||||||
}
|
}
|
||||||
if (implicitReceiverValue is ImplicitDispatchReceiverValue) {
|
if (implicitReceiverValue is ImplicitDispatchReceiverValue) {
|
||||||
val implicitCompanionScope = implicitReceiverValue.implicitCompanionScope
|
val implicitCompanionScope = implicitReceiverValue.implicitCompanionScope
|
||||||
if (implicitCompanionScope != null) {
|
if (implicitCompanionScope != null) {
|
||||||
|
// Companion scope bound to implicit receiver scope
|
||||||
|
// class Outer {
|
||||||
|
// companion object { val x = 0 }
|
||||||
|
// class Nested { val y = x }
|
||||||
|
// }
|
||||||
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, implicitCompanionScope), group++)
|
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, implicitCompanionScope), group++)
|
||||||
}
|
}
|
||||||
if (blockDispatchReceivers) {
|
if (blockDispatchReceivers) {
|
||||||
@@ -134,10 +195,13 @@ class CallResolver(
|
|||||||
blockDispatchReceivers = true
|
blockDispatchReceivers = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
group = processImplicitReceiver(towerDataConsumer, implicitReceiverValue, collector, group)
|
// Direct use of implicit receiver (see inside)
|
||||||
|
group = processImplicitReceiver(towerDataConsumer, implicitReceiverValue, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Member of top-level scope
|
// Member of top-level scope & importing scope
|
||||||
|
// val x = 0
|
||||||
|
// fun test() { x }
|
||||||
for (scope in topLevelScopes) {
|
for (scope in topLevelScopes) {
|
||||||
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, scope), group++)
|
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, scope), group++)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class My {
|
||||||
|
companion object {
|
||||||
|
fun My.foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
FILE: companionExtension.kt
|
||||||
|
public final class My : R|kotlin/Any| {
|
||||||
|
public constructor(): R|My| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final companion object Companion : R|kotlin/Any| {
|
||||||
|
private constructor(): R|My.Companion| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun R|My|.foo(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun test(): R|kotlin/Unit| {
|
||||||
|
R|/My.Companion.foo|()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class Foo {
|
||||||
|
fun test() {
|
||||||
|
fun Foo.bar() {}
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
FILE: localExtension.kt
|
||||||
|
public final class Foo : R|kotlin/Any| {
|
||||||
|
public constructor(): R|Foo| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun test(): R|kotlin/Unit| {
|
||||||
|
local final fun R|Foo|.bar(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
R|<local>/bar|()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
object Outer {
|
||||||
|
val x = 0
|
||||||
|
fun Nested.foo() {}
|
||||||
|
class Nested {
|
||||||
|
val y = x
|
||||||
|
fun test() {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
FILE: outerObject.kt
|
||||||
|
public final object Outer : R|kotlin/Any| {
|
||||||
|
private constructor(): R|Outer| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final val x: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final fun R|Outer.Nested|.foo(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Nested : R|kotlin/Any| {
|
||||||
|
public constructor(): R|Outer.Nested| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final val y: R|kotlin/Int| = R|/Outer.x|
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final fun test(): R|kotlin/Unit| {
|
||||||
|
R|/Outer.foo|()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class Foo {
|
||||||
|
fun Foo.bar() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
FILE: sameReceiver.kt
|
||||||
|
public final class Foo : R|kotlin/Any| {
|
||||||
|
public constructor(): R|Foo| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun R|Foo|.bar(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun test(): R|kotlin/Unit| {
|
||||||
|
R|/Foo.bar|()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+20
@@ -272,6 +272,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/companion.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/companion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("companionExtension.kt")
|
||||||
|
public void testCompanionExtension() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/companionExtension.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("constructor.kt")
|
@TestMetadata("constructor.kt")
|
||||||
public void testConstructor() throws Exception {
|
public void testConstructor() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/constructor.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/constructor.kt");
|
||||||
@@ -292,6 +297,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/lambda.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/lambda.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localExtension.kt")
|
||||||
|
public void testLocalExtension() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/localExtension.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localImplicitBodies.kt")
|
@TestMetadata("localImplicitBodies.kt")
|
||||||
public void testLocalImplicitBodies() throws Exception {
|
public void testLocalImplicitBodies() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/localImplicitBodies.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/localImplicitBodies.kt");
|
||||||
@@ -312,6 +322,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/objects.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/objects.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("outerObject.kt")
|
||||||
|
public void testOuterObject() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/outerObject.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("qualifiedExpressions.kt")
|
@TestMetadata("qualifiedExpressions.kt")
|
||||||
public void testQualifiedExpressions() throws Exception {
|
public void testQualifiedExpressions() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/qualifiedExpressions.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/qualifiedExpressions.kt");
|
||||||
@@ -322,6 +337,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/receiverConsistency.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/receiverConsistency.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sameReceiver.kt")
|
||||||
|
public void testSameReceiver() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/sameReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/simple.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/simple.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user