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 f966a7de196..96e6d55dbc5 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 @@ -702,64 +702,11 @@ class CallAndReferenceGenerator( callableReferenceAccess: FirCallableReferenceAccess? ): IrExpression? { val classSymbol = (qualifier.typeRef.coneType as? ConeClassLikeType)?.lookupTag?.toSymbol(session) - if (callableReferenceAccess != null && classSymbol is FirRegularClassSymbol) { - val classId = qualifier.symbol?.fullyExpandedClass(session)?.classId - val classIdMatched = classSymbol.classId == classId - if (!classIdMatched) { - // Check whether we need get companion object as dispatch receiver - if (!classSymbol.fir.isCompanion || classSymbol.classId.outerClassId != classId) { - return null - } - val resolvedReference = callableReferenceAccess.calleeReference as FirResolvedNamedReference - val firCallableSymbol = resolvedReference.resolvedSymbol as FirCallableSymbol<*> - // Make sure the reference indeed refers to a member of that companion - val receiverClassLookupTag = firCallableSymbol.dispatchReceiverClassLookupTagOrNull() - ?: firCallableSymbol.receiverParameter?.typeRef?.coneTypeSafe()?.lookupTag - ?: return null - - val callableIsDefinitelyNotMemberOfCompanion = with(session.typeContext) { - !classSymbol.defaultType().anySuperTypeConstructor { it.typeConstructor() == receiverClassLookupTag } - } - if (callableIsDefinitelyNotMemberOfCompanion) { - return null - } - /* - * This check is supposed to distinguish cases when both companion and containing class have this function - * - * open class Base { - * fun foo() {} - * } - * - * class Some : Base() { - * companion object : Base() { - * fun bar() - * } - * } - * - * Some::foo // reference to Some.foo - * Some::bar // reference to Some.Companion.bar - */ - val containingClass = classSymbol.getContainingClassLookupTag()?.toFirRegularClassSymbol(session) ?: return null - val callableIsDefinitelyMemberOfOuterClass = with(session.typeContext) { - containingClass.defaultType().anySuperTypeConstructor { it.typeConstructor() == receiverClassLookupTag } - } - if (callableIsDefinitelyMemberOfOuterClass) { - 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 - } - } - } + if (callableReferenceAccess?.isBound == false) { + return null } + val irType = qualifier.typeRef.toIrType() return qualifier.convertWithOffsets { startOffset, endOffset -> if (classSymbol != null) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt index 0079c234a46..108369a1146 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.declarations.utils.isStatic import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression @@ -17,10 +18,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirBlockImpl import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock -import org.jetbrains.kotlin.fir.references.FirReference -import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference -import org.jetbrains.kotlin.fir.references.resolved -import org.jetbrains.kotlin.fir.references.toResolvedFunctionSymbol +import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef @@ -162,3 +160,12 @@ fun FirExpression.unwrapSmartcastExpression(): FirExpression = is FirSmartCastExpression -> originalExpression else -> this } + +/** + * A callable reference is bound iff + * - one of [dispatchReceiver] or [extensionReceiver] is **not** [FirNoReceiverExpression] and + * - it's not referring to a static member. + */ +val FirCallableReferenceAccess.isBound: Boolean + get() = (dispatchReceiver != FirNoReceiverExpression || extensionReceiver != FirNoReceiverExpression) && + calleeReference.toResolvedCallableSymbol()?.isStatic != true diff --git a/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt b/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt index 5943e3b98d0..4c7f6ca4f92 100644 --- a/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt +++ b/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiverInheritsFromOuter.kt @@ -55,6 +55,17 @@ fun box(): String { if (!callContext(A::instanceProp, A.Companion)) return "Fail unbound 7" if (!callContext(A::extProp, A.Companion)) return "Fail unbound 8" + with (A) { + if (!call(::instance)) return "Fail implicit bound function 1" + if (!call(::companion)) return "Fail implicit bound function 2" + if (!call(::ext)) return "Fail implicit bound function 3" + if (!call(::companionExt)) return "Fail implicit bound function 4" + if (!call(::instanceProp)) return "Fail imlicit bound prop 5" + if (!call(::companionProp)) return "Fail imlicit bound prop 6" + if (!call(::extProp)) return "Fail imlicit bound prop 7" + if (!call(::companionExtProp)) return "Fail imlicit bound prop 8" + } + val instance = A::instance val ext = A::ext val instanceProp = A::instanceProp