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(
|
||||
towerDataConsumer: TowerDataConsumer,
|
||||
implicitReceiverValue: ImplicitReceiverValue,
|
||||
collector: CandidateCollector,
|
||||
oldGroup: Int
|
||||
): Int {
|
||||
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(
|
||||
TowerDataKind.TOWER_LEVEL,
|
||||
MemberScopeTowerLevel(session, implicitReceiverValue, scopeSession = components.scopeSession),
|
||||
group++
|
||||
)
|
||||
|
||||
// This is an equivalent to the old "BothTowerLevelAndImplicitReceiver"
|
||||
// Same receiver is dispatch & extension
|
||||
// class Foo {
|
||||
// fun Foo.bar() {}
|
||||
// fun test() { bar() }
|
||||
// }
|
||||
towerDataConsumer.consume(
|
||||
TowerDataKind.TOWER_LEVEL,
|
||||
MemberScopeTowerLevel(session, implicitReceiverValue, implicitReceiverValue, components.scopeSession),
|
||||
group++
|
||||
)
|
||||
|
||||
// Local scope extensions via implicit receiver
|
||||
// class Foo {
|
||||
// fun test() {
|
||||
// fun Foo.bar() {}
|
||||
// bar()
|
||||
// }
|
||||
// }
|
||||
for (scope in localScopes) {
|
||||
towerDataConsumer.consume(
|
||||
TowerDataKind.TOWER_LEVEL,
|
||||
@@ -53,9 +69,18 @@ class CallResolver(
|
||||
)
|
||||
}
|
||||
|
||||
var blockDispatchReceivers = false
|
||||
|
||||
for (implicitDispatchReceiverValue in implicitReceiverValues) {
|
||||
val implicitScope = implicitDispatchReceiverValue.implicitScope
|
||||
if (implicitScope != null) {
|
||||
// Extensions in outer object
|
||||
// object Outer {
|
||||
// fun Nested.foo() {}
|
||||
// class Nested {
|
||||
// fun test() { foo() }
|
||||
// }
|
||||
// }
|
||||
towerDataConsumer.consume(
|
||||
TowerDataKind.TOWER_LEVEL,
|
||||
ScopeTowerLevel(session, implicitScope, implicitExtensionReceiver = implicitReceiverValue),
|
||||
@@ -65,15 +90,33 @@ class CallResolver(
|
||||
if (implicitDispatchReceiverValue is ImplicitDispatchReceiverValue) {
|
||||
val implicitCompanionScope = implicitDispatchReceiverValue.implicitCompanionScope
|
||||
if (implicitCompanionScope != null) {
|
||||
// Extension in companion
|
||||
// class My {
|
||||
// companion object { fun My.foo() {} }
|
||||
// fun test() { foo() }
|
||||
// }
|
||||
towerDataConsumer.consume(
|
||||
TowerDataKind.TOWER_LEVEL,
|
||||
ScopeTowerLevel(session, implicitCompanionScope, implicitExtensionReceiver = implicitReceiverValue),
|
||||
group++
|
||||
)
|
||||
}
|
||||
if (blockDispatchReceivers) {
|
||||
continue
|
||||
}
|
||||
if (!implicitDispatchReceiverValue.boundSymbol.fir.isInner) {
|
||||
blockDispatchReceivers = true
|
||||
}
|
||||
}
|
||||
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(
|
||||
TowerDataKind.TOWER_LEVEL,
|
||||
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) {
|
||||
towerDataConsumer.consume(
|
||||
TowerDataKind.TOWER_LEVEL,
|
||||
@@ -106,25 +154,38 @@ class CallResolver(
|
||||
towerDataConsumer = consumer
|
||||
|
||||
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++)
|
||||
|
||||
// Member of local scope
|
||||
// fun test(x: Int) = x
|
||||
for (scope in localScopes) {
|
||||
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, scope), group++)
|
||||
}
|
||||
|
||||
var blockDispatchReceivers = false
|
||||
|
||||
// Member of implicit receiver' type
|
||||
// Member of implicit receiver' type *and* relevant scope
|
||||
for (implicitReceiverValue in implicitReceiverValues) {
|
||||
val implicitScope = implicitReceiverValue.implicitScope
|
||||
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++)
|
||||
}
|
||||
if (implicitReceiverValue is ImplicitDispatchReceiverValue) {
|
||||
val implicitCompanionScope = implicitReceiverValue.implicitCompanionScope
|
||||
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++)
|
||||
}
|
||||
if (blockDispatchReceivers) {
|
||||
@@ -134,10 +195,13 @@ class CallResolver(
|
||||
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) {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("companionExtension.kt")
|
||||
public void testCompanionExtension() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/companionExtension.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("constructor.kt")
|
||||
public void testConstructor() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("localExtension.kt")
|
||||
public void testLocalExtension() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/localExtension.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localImplicitBodies.kt")
|
||||
public void testLocalImplicitBodies() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("outerObject.kt")
|
||||
public void testOuterObject() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/outerObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("qualifiedExpressions.kt")
|
||||
public void testQualifiedExpressions() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("sameReceiver.kt")
|
||||
public void testSameReceiver() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/sameReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/simple.kt");
|
||||
|
||||
Reference in New Issue
Block a user