[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
This commit is contained in:
committed by
Space Team
parent
fc96eb6d8d
commit
1f0e6321b0
+18
-4
@@ -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<ConeClassLikeType>()?.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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+1
-1
@@ -5,4 +5,4 @@ class A {
|
||||
}
|
||||
}
|
||||
|
||||
fun box() = (A.Companion::ok).let { it() }
|
||||
fun box() = (A.Companion::ok).let { it() }
|
||||
|
||||
Vendored
+69
@@ -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"
|
||||
}
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user