FIR: add comments & tests for tower resolver, block some receiver pairs

This commit is contained in:
Mikhail Glukhikh
2019-08-21 17:06:43 +03:00
parent c9a600c5ce
commit 9c3821ddba
10 changed files with 199 additions and 7 deletions
@@ -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|()
}
}
@@ -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");