From 1f0e6321b04991ec97abe85c9135d96ca967172b Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Tue, 28 Feb 2023 15:55:04 +0100 Subject: [PATCH] [FIR2IR] Use companion as bound receiver if expected type requires it A::foo is preferably resolved as an unbound reference to A.foo, however if A.Companion is a subtype of A and the expected type has one fewer parameter than the type of the unbound reference, generate a bound reference with the companion as receiver. ^KT-56519 Fixed --- .../generators/CallAndReferenceGenerator.kt | 22 ++++-- ...LightTreeBlackBoxCodegenTestGenerated.java | 6 ++ .../FirPsiBlackBoxCodegenTestGenerated.java | 6 ++ .../bound/companionObjectReceiver.kt | 2 +- ...ompanionObjectReceiverInheritsFromOuter.kt | 69 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++ .../LightAnalysisModeTestGenerated.java | 5 ++ .../js/test/JsCodegenBoxTestGenerated.java | 6 ++ .../fir/FirJsCodegenBoxTestGenerated.java | 6 ++ .../test/ir/IrJsCodegenBoxTestGenerated.java | 6 ++ .../ir/IrJsES6CodegenBoxTestGenerated.java | 6 ++ .../K2NativeCodegenBoxTestGenerated.java | 6 ++ .../NativeCodegenBoxTestGenerated.java | 6 ++ .../test/IrCodegenBoxWasmTestGenerated.java | 5 ++ 15 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index 8329c152ec4..3eae14e9c10 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -709,9 +709,12 @@ class CallAndReferenceGenerator( val firCallableSymbol = resolvedReference.resolvedSymbol as FirCallableSymbol<*> // Make sure the reference indeed refers to a member of that companion - val dispatchReceiverClassLookupTag = firCallableSymbol.dispatchReceiverClassLookupTagOrNull() ?: return null + val receiverClassLookupTag = firCallableSymbol.dispatchReceiverClassLookupTagOrNull() + ?: firCallableSymbol.receiverParameter?.typeRef?.coneTypeSafe()?.lookupTag + ?: return null + val callableIsDefinitelyNotMemberOfCompanion = with(session.typeContext) { - !classSymbol.defaultType().anySuperTypeConstructor { it.typeConstructor() == dispatchReceiverClassLookupTag } + !classSymbol.defaultType().anySuperTypeConstructor { it.typeConstructor() == receiverClassLookupTag } } if (callableIsDefinitelyNotMemberOfCompanion) { return null @@ -734,10 +737,21 @@ class CallAndReferenceGenerator( */ val containingClass = classSymbol.getContainingClassLookupTag()?.toFirRegularClassSymbol(session) ?: return null val callableIsDefinitelyMemberOfOuterClass = with(session.typeContext) { - containingClass.defaultType().anySuperTypeConstructor { it.typeConstructor() == dispatchReceiverClassLookupTag } + containingClass.defaultType().anySuperTypeConstructor { it.typeConstructor() == receiverClassLookupTag } } if (callableIsDefinitelyMemberOfOuterClass) { - return null + val expectedParameterCount = callableReferenceAccess.typeRef.coneType.typeArguments.size - 1 + + val declaration = firCallableSymbol.fir + val requiredParameterCount = ((declaration as? FirFunction)?.valueParameters?.size ?: 0) + + (if (declaration.dispatchReceiverType != null) 1 else 0) + + (if (declaration.receiverParameter != null) 1 else 0) + + // However, if the number of parameters only match, if the receiver is bound, allow using the companion as receiver. + val boundCallableIsExpected = requiredParameterCount == expectedParameterCount + 1 + if (!boundCallableIsExpected) { + return null + } } } } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index 96ee2e6ee18..1224a6d50ad 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -3668,6 +3668,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index d3b1a1eea26..741f2becd79 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -3668,6 +3668,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt b/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt index dea1d40855b..039f9dae955 100644 --- a/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt +++ b/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt @@ -5,4 +5,4 @@ class A { } } -fun box() = (A.Companion::ok).let { it() } \ No newline at end of file +fun box() = (A.Companion::ok).let { it() } diff --git a/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt b/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt new file mode 100644 index 00000000000..5943e3b98d0 --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt @@ -0,0 +1,69 @@ +// !LANGUAGE: +ContextReceivers +// IGNORE_BACKEND_K1: JS, NATIVE +// SKIP_NODE_JS + +open class A { + fun instance() = true + val instanceProp = true + + companion object : A() { + fun companion() = true + val companionProp = true + } +} + +fun A.ext() = true +val A.extProp get() = true + +fun A.Companion.companionExt() = true +val A.Companion.companionExtProp get() = true + +inline fun call(f: () -> Boolean) = f() +inline fun callExtension(f: A.() -> Boolean, receiver: A) = receiver.f() +inline fun callParameter(f: (A) -> Boolean, parameter: A) = f(parameter) +inline fun callContext(f: context(A) () -> Boolean, receiver: A) = f(receiver) + +fun box(): String { + if (!call(A::instance)) return "Fail bound function 1" + if (!call(A.Companion::instance)) return "Fail bound function 2" + if (!call(A::companion)) return "Fail bound function 3" + if (!call(A.Companion::companion)) return "Fail bound function 4" + if (!call(A::ext)) return "Fail bound function 5" + if (!call(A.Companion::ext)) return "Fail bound function 6" + if (!call(A::companionExt)) return "Fail bound function 7" + if (!call(A.Companion::companionExt)) return "Fail bound function 8" + + if (!call(A::instanceProp)) return "Fail bound prop 1" + if (!call(A.Companion::instanceProp)) return "Fail bound prop 2" + if (!call(A::companionProp)) return "Fail bound prop 3" + if (!call(A.Companion::companionProp)) return "Fail bound prop 4" + if (!call(A::extProp)) return "Fail bound prop 5" + if (!call(A.Companion::extProp)) return "Fail bound prop 6" + if (!call(A::companionExtProp)) return "Fail bound prop 7" + if (!call(A.Companion::companionExtProp)) return "Fail bound prop 8" + + if (!callParameter(A::instance, A.Companion)) return "Fail unbound 1" + if (!callParameter(A::ext, A.Companion)) return "Fail unbound 2" + if (!callParameter(A::instanceProp, A.Companion)) return "Fail unbound 3" + if (!callParameter(A::extProp, A.Companion)) return "Fail unbound 4" + if (!callExtension(A::instance, A.Companion)) return "Fail unbound 5" + if (!callExtension(A::ext, A.Companion)) return "Fail unbound 6" + if (!callExtension(A::instanceProp, A.Companion)) return "Fail unbound 7" + if (!callExtension(A::extProp, A.Companion)) return "Fail unbound 8" + if (!callContext(A::instance, A.Companion)) return "Fail unbound 5" + if (!callContext(A::ext, A.Companion)) return "Fail unbound 6" + if (!callContext(A::instanceProp, A.Companion)) return "Fail unbound 7" + if (!callContext(A::extProp, A.Companion)) return "Fail unbound 8" + + val instance = A::instance + val ext = A::ext + val instanceProp = A::instanceProp + val extProp = A::extProp + + if (!callParameter(instance, A.Companion)) return "Fail unbound variable 1" + if (!callParameter(ext, A.Companion)) return "Fail unbound variable 2" + if (!callParameter(instanceProp, A.Companion)) return "Fail unbound variable 3" + if (!callParameter(extProp, A.Companion)) return "Fail unbound variable 4" + + return "OK" +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 4178f5f9856..365c124a6ff 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -3524,6 +3524,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 4af285af6e0..f313f087a74 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -3668,6 +3668,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index aa69ac9b663..d1334c843df 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -3086,6 +3086,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { runTest("compiler/testData/codegen/box/callableReference/bound/dontShareReceiver.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index f5be8e77df0..bf169b3f665 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -2354,6 +2354,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java index f1b25cef5a5..16b78ed1e08 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java @@ -2408,6 +2408,12 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest { runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index 5be13879850..bd62eaf69aa 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -2408,6 +2408,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java index 2f673a5d7c3..a493c207d89 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java @@ -2408,6 +2408,12 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java index a1904b62bae..c5cbf0c71a7 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java @@ -2497,6 +2497,12 @@ public class K2NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTes runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java index 9e21896f68e..5edecce063e 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java @@ -2466,6 +2466,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @Test + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @Test @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java index b7237451742..4433f288136 100644 --- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java +++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java @@ -2141,6 +2141,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); } + @TestMetadata("companionObjectReceiverInheritsFromOuter.kt") + public void testCompanionObjectReceiverInheritsFromOuter() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt"); + } + @TestMetadata("dontShareReceiver.kt") public void testDontShareReceiver() throws Exception { runTest("compiler/testData/codegen/box/callableReference/bound/dontShareReceiver.kt");