FIR: handle situations with multiple implicit receivers

This commit is contained in:
Mikhail Glukhikh
2019-08-21 13:37:11 +03:00
parent 5d6a526eec
commit a4d89b9829
7 changed files with 166 additions and 9 deletions
@@ -72,6 +72,18 @@ class CallResolver(
)
}
}
if (implicitDispatchReceiverValue !== implicitReceiverValue) {
// Two different implicit receivers
towerDataConsumer.consume(
TowerDataKind.TOWER_LEVEL,
MemberScopeTowerLevel(
session, scopeSession = components.scopeSession,
dispatchReceiver = implicitDispatchReceiverValue,
implicitExtensionReceiver = implicitReceiverValue
),
group++
)
}
}
for (scope in topLevelScopes) {
@@ -52,11 +52,11 @@ internal object CheckExplicitReceiverConsistency : ResolutionStage() {
internal sealed class CheckReceivers : ResolutionStage() {
object Dispatch : CheckReceivers() {
override fun ExplicitReceiverKind.shouldBeResolvedAsImplicit(): Boolean {
return this == EXTENSION_RECEIVER || this == NO_EXPLICIT_RECEIVER
override fun ExplicitReceiverKind.shouldBeCheckedAgainstImplicit(): Boolean {
return this == EXTENSION_RECEIVER // For NO_EXPLICIT_RECEIVER we can check extension receiver only
}
override fun ExplicitReceiverKind.shouldBeResolvedAsExplicit(): Boolean {
override fun ExplicitReceiverKind.shouldBeCheckedAgainstExplicit(): Boolean {
return this == DISPATCH_RECEIVER || this == BOTH_RECEIVERS
}
@@ -66,11 +66,11 @@ internal sealed class CheckReceivers : ResolutionStage() {
}
object Extension : CheckReceivers() {
override fun ExplicitReceiverKind.shouldBeResolvedAsImplicit(): Boolean {
override fun ExplicitReceiverKind.shouldBeCheckedAgainstImplicit(): Boolean {
return this == DISPATCH_RECEIVER || this == NO_EXPLICIT_RECEIVER
}
override fun ExplicitReceiverKind.shouldBeResolvedAsExplicit(): Boolean {
override fun ExplicitReceiverKind.shouldBeCheckedAgainstExplicit(): Boolean {
return this == EXTENSION_RECEIVER || this == BOTH_RECEIVERS
}
@@ -88,9 +88,9 @@ internal sealed class CheckReceivers : ResolutionStage() {
abstract fun Candidate.getReceiverValue(): ReceiverValue?
abstract fun ExplicitReceiverKind.shouldBeResolvedAsExplicit(): Boolean
abstract fun ExplicitReceiverKind.shouldBeCheckedAgainstExplicit(): Boolean
abstract fun ExplicitReceiverKind.shouldBeResolvedAsImplicit(): Boolean
abstract fun ExplicitReceiverKind.shouldBeCheckedAgainstImplicit(): Boolean
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
val expectedReceiverParameterValue = candidate.getReceiverValue()
@@ -98,7 +98,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
val explicitReceiverKind = candidate.explicitReceiverKind
if (expectedReceiverParameterValue != null) {
if (explicitReceiverExpression != null && explicitReceiverKind.shouldBeResolvedAsExplicit()) {
if (explicitReceiverExpression != null && explicitReceiverKind.shouldBeCheckedAgainstExplicit()) {
resolveArgumentExpression(
candidate.csBuilder,
argument = explicitReceiverExpression,
@@ -113,7 +113,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
sink.yield()
} else {
val argumentExtensionReceiverValue = candidate.implicitExtensionReceiverValue
if (argumentExtensionReceiverValue != null && explicitReceiverKind.shouldBeResolvedAsImplicit()) {
if (argumentExtensionReceiverValue != null && explicitReceiverKind.shouldBeCheckedAgainstImplicit()) {
resolvePlainArgumentType(
candidate.csBuilder,
argumentType = argumentExtensionReceiverValue.type,
@@ -0,0 +1,26 @@
class A {
fun foo() = 1
fun B.bar() = 3
}
class B {
fun foo() = 2
fun A.bar() = 4
}
fun test(a: A, b: B) {
with(b) {
with(a) {
foo()
bar()
}
}
with(a) {
with(b) {
foo()
bar()
}
}
}
@@ -0,0 +1,47 @@
FILE: implicitReceiverOrder.kt
public final class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
public final fun foo(): R|kotlin/Int| {
^foo Int(1)
}
public final fun R|B|.bar(): R|kotlin/Int| {
^bar Int(3)
}
}
public final class B : R|kotlin/Any| {
public constructor(): R|B| {
super<R|kotlin/Any|>()
}
public final fun foo(): R|kotlin/Int| {
^foo Int(2)
}
public final fun R|A|.bar(): R|kotlin/Int| {
^bar Int(4)
}
}
public final fun test(a: R|A|, b: R|B|): R|kotlin/Unit| {
R|kotlin/with|<R|B|, R|kotlin/Int|>(R|<local>/b|, <L> = with@fun R|B|.<anonymous>(it: R|B|): R|kotlin/Unit| {
R|kotlin/with|<R|A|, R|kotlin/Int|>(R|<local>/a|, <L> = with@fun R|A|.<anonymous>(it: R|A|): R|kotlin/Unit| {
R|/A.foo|()
R|/B.bar|()
}
)
}
)
R|kotlin/with|<R|A|, R|kotlin/Int|>(R|<local>/a|, <L> = with@fun R|A|.<anonymous>(it: R|A|): R|kotlin/Unit| {
R|kotlin/with|<R|B|, R|kotlin/Int|>(R|<local>/b|, <L> = with@fun R|B|.<anonymous>(it: R|B|): R|kotlin/Unit| {
R|/B.foo|()
R|/A.bar|()
}
)
}
)
}
@@ -0,0 +1,23 @@
// Copy of IR test
object A
object B
interface IFoo {
val A.foo: B get() = B
}
interface IInvoke {
operator fun B.invoke() = 42
}
fun test(fooImpl: IFoo, invokeImpl: IInvoke) {
with(A) {
with(fooImpl) {
foo
with(invokeImpl) {
foo()
}
}
}
}
@@ -0,0 +1,39 @@
FILE: multipleImplicitReceivers.kt
public final object A : R|kotlin/Any| {
private constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public final object B : R|kotlin/Any| {
private constructor(): R|B| {
super<R|kotlin/Any|>()
}
}
public abstract interface IFoo : R|kotlin/Any| {
public open val R|A|.foo: R|B|
public get(): R|B| {
^ Q|B|
}
}
public abstract interface IInvoke : R|kotlin/Any| {
public open operator fun R|B|.invoke(): R|kotlin/Int| {
^invoke Int(42)
}
}
public final fun test(fooImpl: R|IFoo|, invokeImpl: R|IInvoke|): R|kotlin/Unit| {
R|kotlin/with|<R|A|, R|kotlin/Int|>(Q|A|, <L> = with@fun R|A|.<anonymous>(it: R|A|): R|kotlin/Unit| {
R|kotlin/with|<R|IFoo|, R|kotlin/Int|>(R|<local>/fooImpl|, <L> = with@fun R|IFoo|.<anonymous>(it: R|IFoo|): R|kotlin/Unit| {
R|/IFoo.foo|
R|kotlin/with|<R|IInvoke|, R|kotlin/Int|>(R|<local>/invokeImpl|, <L> = with@fun R|IInvoke|.<anonymous>(it: R|IInvoke|): R|kotlin/Unit| {
R|/IFoo.foo|.R|/IInvoke.invoke|()
}
)
}
)
}
)
}
@@ -79,11 +79,21 @@ public class FirResolveTestCaseWithStdlibGenerated extends AbstractFirResolveTes
runTest("compiler/fir/resolve/testData/resolve/stdlib/helloWorld.kt");
}
@TestMetadata("implicitReceiverOrder.kt")
public void testImplicitReceiverOrder() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/implicitReceiverOrder.kt");
}
@TestMetadata("mapList.kt")
public void testMapList() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/mapList.kt");
}
@TestMetadata("multipleImplicitReceivers.kt")
public void testMultipleImplicitReceivers() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/multipleImplicitReceivers.kt");
}
@TestMetadata("recursiveBug.kt")
public void testRecursiveBug() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/recursiveBug.kt");