diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index a0978efe387..dbe2b7d0e3f 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -495,7 +495,7 @@ class Fir2IrVisitor( override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement { val explicitReceiverExpression = convertToIrReceiverExpression( - callableReferenceAccess.explicitReceiver, callableReferenceAccess.calleeReference, callableReferenceMode = true + callableReferenceAccess.explicitReceiver, callableReferenceAccess.calleeReference, callableReferenceAccess ) return callGenerator.convertToIrCallableReference(callableReferenceAccess, explicitReceiverExpression) } @@ -547,11 +547,11 @@ class Fir2IrVisitor( private fun convertToIrReceiverExpression( expression: FirExpression?, calleeReference: FirReference, - callableReferenceMode: Boolean = false + callableReferenceAccess: FirCallableReferenceAccess? = null ): IrExpression? { return when (expression) { null -> null - is FirResolvedQualifier -> callGenerator.convertToGetObject(expression, callableReferenceMode) + is FirResolvedQualifier -> callGenerator.convertToGetObject(expression, callableReferenceAccess) is FirExpressionWithSmartcast -> convertToImplicitCastExpression(expression, calleeReference) is FirFunctionCall, is FirThisReceiverExpression, is FirCallableReferenceAccess -> convertToIrExpression(expression) else -> if (expression is FirQualifiedAccessExpression && expression.explicitReceiver == null) { 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 2b8acda8dbe..aa9aec81f75 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 @@ -361,14 +361,35 @@ class CallAndReferenceGenerator( }.applyCallArguments(annotationCall, annotationMode = true) } - fun convertToGetObject(qualifier: FirResolvedQualifier): IrExpression { - return convertToGetObject(qualifier, callableReferenceMode = false)!! + internal fun convertToGetObject(qualifier: FirResolvedQualifier): IrExpression { + return convertToGetObject(qualifier, null)!! } - internal fun convertToGetObject(qualifier: FirResolvedQualifier, callableReferenceMode: Boolean): IrExpression? { + internal fun convertToGetObject( + qualifier: FirResolvedQualifier, + callableReferenceAccess: FirCallableReferenceAccess? = null + ): IrExpression? { val classSymbol = (qualifier.typeRef.coneType as? ConeClassLikeType)?.lookupTag?.toSymbol(session) - if (callableReferenceMode && classSymbol is FirRegularClassSymbol) { - if (classSymbol.classId != qualifier.classId) { + if (callableReferenceAccess != null && classSymbol is FirRegularClassSymbol) { + val classIdMatched = classSymbol.classId == qualifier.classId + val companionClassIdMatched = classSymbol.fir.isCompanion && classSymbol.classId.outerClassId == qualifier.classId + val lastClassIfCompanion = conversionScope.lastClass()?.takeIf { it.isCompanion } + val callable = + ((callableReferenceAccess.calleeReference as FirResolvedNamedReference).resolvedSymbol as FirCallableSymbol<*>) + val companionMemberReferenceThatNeedsDispatchReceiver = companionClassIdMatched && + // TODO: this can't cover delegated members. See bb test kt38664.kt + // Make sure the reference indeed refers to a member of that companion + classSymbol.fir.declarations.contains(callable.fir) && + // Built-in extensions are stored in the companion, e.g., String.Companion. + // Make sure this is not a reference to an extension function. + !callable.isExtension && + // Dispatch receiver is not needed if we're converting a callable reference inside that companion, e.g., + // class Foo { + // companion object { + // val cp = Foo::member + // } } + lastClassIfCompanion?.classId != classSymbol.classId + if (!classIdMatched && !companionMemberReferenceThatNeedsDispatchReceiver) { return null } } @@ -612,7 +633,7 @@ class CallAndReferenceGenerator( return explicitReceiverExpression } if (firReceiver is FirResolvedQualifier) { - return convertToGetObject(firReceiver, callableReferenceMode = this is FirCallableReferenceAccess) + return convertToGetObject(firReceiver, this as? FirCallableReferenceAccess) } return firReceiver.takeIf { it !is FirNoReceiverExpression }?.let { visitor.convertToIrExpression(it) } ?: explicitReceiverExpression diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt index ec45104156c..0948332cfd9 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt @@ -6,7 +6,9 @@ package org.jetbrains.kotlin.fir.symbols.impl import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration +import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.CallableId @@ -21,6 +23,13 @@ abstract class FirCallableSymbol> : AbstractFirBas val FirCallableSymbol<*>.isStatic: Boolean get() = (fir as? FirMemberDeclaration)?.status?.isStatic == true +val FirCallableSymbol<*>.isExtension: Boolean + get() = when (fir) { + is FirFunction -> fir.receiverTypeRef != null + is FirProperty -> fir.receiverTypeRef != null + else -> false + } + inline fun > E.unwrapSubstitutionOverrides(): E { var current = this while (current.overriddenSymbol != null) { diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt index 1987711bfb0..3f86a4a2292 100644 --- a/compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_REFLECT