diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt index 62227664272..7ddd46191bd 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt @@ -570,8 +570,6 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) return fakeTypeParameters } - private val receiverField = context.ir.symbols.functionReferenceReceiverField.owner - fun build(): IrExpression = context.createJvmIrBuilder(currentScope!!).run { irBlock(irFunctionReference.startOffset, irFunctionReference.endOffset) { val constructor = createConstructor() @@ -826,7 +824,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) irImplicitCast( irGetField( irGet(dispatchReceiverParameter!!), - this@FunctionReferenceBuilder.receiverField + functionReferenceClass.getReceiverField(backendContext) ), boundReceiver.second.type ) @@ -1010,5 +1008,18 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) internal fun JvmIrBuilder.calculateOwnerKClass(irContainer: IrDeclarationParent): IrExpression = kClassReference(irContainer.getCallableReferenceOwnerKClassType(backendContext)) + + // This method creates an IrField for the field `kotlin.jvm.internal.CallableReference.receiver`, as if this field was declared + // in the anonymous class for this callable reference. Technically it's incorrect because this field is not declared here. It would + // be more correct to create a fake override but that seems like more work for no clear benefit. Codegen will generate the correct + // field access anyway, even if the field is not present in this parent. + internal fun IrClass.getReceiverField(context: JvmBackendContext): IrField = + context.irFactory.buildField { + name = Name.identifier("receiver") + type = context.irBuiltIns.anyNType + visibility = DescriptorVisibilities.PROTECTED + }.apply { + parent = this@getReceiverField + } } } diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt index f495ab23f42..05398bef076 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt @@ -413,7 +413,6 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle } val boundReceiver = expression.getBoundReceiver() - val backingField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!! val get = superClass.functions.find { it.name.asString() == "get" } val set = superClass.functions.find { it.name.asString() == "set" } val invoke = superClass.functions.find { it.name.asString() == "invoke" } @@ -421,6 +420,8 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle val field = expression.field?.owner if (field == null) { fun IrBuilderWithScope.setCallArguments(call: IrCall, arguments: List) { + val backingField = + with(FunctionReferenceLowering) { referenceClass.getReceiverField(this@PropertyReferenceLowering.context) } val receiverFromField = boundReceiver?.let { irImplicitCast(irGetField(irGet(arguments[0]), backingField), it.type) } if (expression.isJavaSyntheticPropertyReference) { assert(call.typeArgumentsCount == 0) { "Unexpected type arguments: ${call.typeArgumentsCount}" } @@ -458,8 +459,11 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle fun IrBuilderWithScope.fieldReceiver(arguments: List) = when { field.isStatic -> null - expression.dispatchReceiver != null -> + expression.dispatchReceiver != null -> { + val backingField = + with(FunctionReferenceLowering) { referenceClass.getReceiverField(this@PropertyReferenceLowering.context) } irImplicitCast(irGetField(irGet(arguments[0]), backingField), expression.receiverType) + } else -> irImplicitCast(irGet(arguments[1]), expression.receiverType) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index 6582fae6b1d..1bd175d2540 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -371,7 +371,6 @@ class JvmSymbols( generateCallableReferenceMethods(klass) } - val functionReferenceReceiverField: IrFieldSymbol = functionReference.fieldByName("receiver") val functionReferenceGetSignature: IrSimpleFunctionSymbol = functionReference.functionByName("getSignature") val functionReferenceGetName: IrSimpleFunctionSymbol = functionReference.functionByName("getName") val functionReferenceGetOwner: IrSimpleFunctionSymbol = functionReference.functionByName("getOwner") diff --git a/compiler/testData/codegen/bytecodeListing/callableReference/adaptedReference.ir.txt b/compiler/testData/codegen/bytecodeListing/callableReference/adaptedReference.ir.txt index e045311ae93..d4d857854b9 100644 --- a/compiler/testData/codegen/bytecodeListing/callableReference/adaptedReference.ir.txt +++ b/compiler/testData/codegen/bytecodeListing/callableReference/adaptedReference.ir.txt @@ -4,7 +4,6 @@ synthetic final class A$testDefaultArguments$1 { enclosing method A.testDefaultArguments()V inner (anonymous) class A$testDefaultArguments$1 method (p0: java.lang.Object): void - public synthetic final static method access$getReceiver$p(p0: A$testDefaultArguments$1): java.lang.Object public synthetic bridge method invoke(): java.lang.Object public final @org.jetbrains.annotations.NotNull method invoke(): java.lang.String } @@ -15,7 +14,6 @@ synthetic final class A$testDefaultArguments$2 { enclosing method A.testDefaultArguments()V inner (anonymous) class A$testDefaultArguments$2 method (p0: java.lang.Object): void - public synthetic final static method access$getReceiver$p(p0: A$testDefaultArguments$2): java.lang.Object public final @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object public synthetic bridge method invoke(p0: java.lang.Object): java.lang.Object }