FIR: handle situations with multiple implicit receivers
This commit is contained in:
@@ -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|()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
Generated
+10
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user