diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 77b227712f2..169fb7cbce2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -529,6 +529,7 @@ public class FunctionCodegen { } ParameterDescriptor annotated = + // TODO: Generate annotations for context receivers kind == JvmMethodParameterKind.VALUE ? iterator.next() : kind == JvmMethodParameterKind.RECEIVER @@ -806,6 +807,7 @@ public class FunctionCodegen { : nameForDestructuredParameter; break; case RECEIVER: + case CONTEXT_RECEIVER: parameterName = DescriptorAsmUtil.getNameForReceiverParameter( functionDescriptor, typeMapper.getBindingContext(), state.getLanguageVersionSettings()); break; @@ -1330,7 +1332,7 @@ public class FunctionCodegen { } for (JvmMethodParameterSignature parameter : signature.getValueParameters()) { - if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) { + if (parameter.getKind() == JvmMethodParameterKind.RECEIVER || parameter.getKind() == JvmMethodParameterKind.CONTEXT_RECEIVER) { if (extensionReceiverParameter != null) { frameMap.enter(extensionReceiverParameter, state.getTypeMapper().mapType(extensionReceiverParameter)); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 4ac2fd6c0e0..623e3f6e993 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -1888,7 +1888,7 @@ public abstract class StackValue { if (kind == JvmMethodParameterKind.VALUE) { break; } - if (kind == JvmMethodParameterKind.RECEIVER || kind == JvmMethodParameterKind.THIS) { + if (kind == JvmMethodParameterKind.CONTEXT_RECEIVER || kind == JvmMethodParameterKind.RECEIVER || kind == JvmMethodParameterKind.THIS) { return false; } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/generateJava8ParameterNames.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/generateJava8ParameterNames.kt index 498be8f952b..861f79020b8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/generateJava8ParameterNames.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/generateJava8ParameterNames.kt @@ -46,7 +46,8 @@ fun generateParameterNames( isEnumName = !isEnumName if (!isEnumName) "\$enum\$name" else "\$enum\$ordinal" } - JvmMethodParameterKind.RECEIVER -> { + JvmMethodParameterKind.RECEIVER, + JvmMethodParameterKind.CONTEXT_RECEIVER -> { DescriptorAsmUtil.getNameForReceiverParameter(functionDescriptor, state.bindingContext, state.languageVersionSettings) } JvmMethodParameterKind.OUTER -> AsmUtil.CAPTURED_THIS_FIELD @@ -67,7 +68,7 @@ fun generateParameterNames( // declared implicitly in source code (§8.8.1, §8.8.9, §8.9.3, §15.9.5.1). val access = when (kind) { JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL -> Opcodes.ACC_SYNTHETIC - JvmMethodParameterKind.RECEIVER -> Opcodes.ACC_MANDATED + JvmMethodParameterKind.RECEIVER, JvmMethodParameterKind.CONTEXT_RECEIVER -> Opcodes.ACC_MANDATED JvmMethodParameterKind.OUTER -> Opcodes.ACC_MANDATED JvmMethodParameterKind.VALUE -> 0 diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt index 53c3a09c170..c77f986c5a8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt @@ -894,6 +894,10 @@ class KotlinTypeMapper @JvmOverloads constructor( writeParameter(sw, JvmMethodParameterKind.THIS, thisIfNeeded, f) } + for (contextReceiverParameter in f.contextReceiverParameters) { + writeParameter(sw, JvmMethodParameterKind.CONTEXT_RECEIVER, contextReceiverParameter.type, f) + } + val receiverParameter = f.extensionReceiverParameter if (receiverParameter != null) { writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, f) diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 4badf32113a..aba4f3ef2e2 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -16157,6 +16157,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("contextAndExtensionSameName.kt") + public void testContextAndExtensionSameName() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/contextAndExtensionSameName.kt"); + } + @Test @TestMetadata("dp.kt") public void testDp() throws Exception { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/jvmSignature/JvmMethodParameterKind.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/jvmSignature/JvmMethodParameterKind.java index 6971e764436..5e6f43e6039 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/jvmSignature/JvmMethodParameterKind.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/jvmSignature/JvmMethodParameterKind.java @@ -21,6 +21,7 @@ public enum JvmMethodParameterKind { THIS, OUTER, RECEIVER, + CONTEXT_RECEIVER, CAPTURED_LOCAL_VARIABLE, ENUM_NAME_OR_ORDINAL, SUPER_CALL_PARAM, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 6861e8414cf..cbdbb67b9f9 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -479,6 +479,16 @@ class ExpressionCodegen( callGenerator.genValueAndPut(callee.dispatchReceiverParameter!!, receiver, type, this, data) } + fun handleValueParameter(i: Int, irParameter: IrValueParameter) { + val arg = expression.getValueArgument(i) + val parameterType = callable.valueParameterTypes[i] + require(arg != null) { "Null argument in ExpressionCodegen for parameter ${irParameter.render()}" } + callGenerator.genValueAndPut(irParameter, arg, parameterType, this, data) + } + + val contextReceivers = callee.valueParameters.subList(0, callee.contextReceiverParametersCount) + contextReceivers.forEachIndexed(::handleValueParameter) + expression.extensionReceiver?.let { receiver -> val type = callable.signature.valueParameters.singleOrNull { it.kind == JvmMethodParameterKind.RECEIVER }?.asmType ?: error("No single extension receiver parameter: ${callable.signature.valueParameters}") @@ -486,14 +496,8 @@ class ExpressionCodegen( } callGenerator.beforeValueParametersStart() - expression.symbol.owner.valueParameters.forEachIndexed { i, irParameter -> - val arg = expression.getValueArgument(i) - val parameterType = callable.valueParameterTypes[i] - require(arg != null) { - "Null argument in ExpressionCodegen for parameter ${irParameter.render()}" - } - callGenerator.genValueAndPut(irParameter, arg, parameterType, this, data) - } + callee.valueParameters.subList(callee.contextReceiverParametersCount, callee.valueParameters.size) + .forEachIndexed { i, valueParameter -> handleValueParameter(i + contextReceivers.size, valueParameter) } expression.markLineNumber(true) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index b64fa244fd8..d0fd2e8779d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -253,10 +253,15 @@ class FunctionCodegen(private val irFunction: IrFunction, private val classCodeg receiver?.let { frameMap.enter(it, context.typeMapper.mapTypeAsDeclaration(it.type)) } + val contextReceivers = valueParameters.subList(0, contextReceiverParametersCount) + for (contextReceiver in contextReceivers) { + frameMap.enter(contextReceiver, context.typeMapper.mapType(contextReceiver.type)) + } extensionReceiverParameter?.let { frameMap.enter(it, context.typeMapper.mapType(it)) } - for (parameter in valueParameters) { + val regularParameters = valueParameters.subList(contextReceiverParametersCount, valueParameters.size) + for (parameter in regularParameters) { frameMap.enter(parameter, context.typeMapper.mapType(parameter.type)) } return frameMap diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index 34da3f298d2..a41deb14502 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -241,12 +241,19 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { sw.writeParametersStart() + val contextReceivers = function.valueParameters.subList(0, function.contextReceiverParametersCount) + for (contextReceiver in contextReceivers) { + writeParameter(sw, JvmMethodParameterKind.CONTEXT_RECEIVER, contextReceiver.type, function) + } + val receiverParameter = function.extensionReceiverParameter if (receiverParameter != null) { writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function) } - for (parameter in function.valueParameters) { + val regularValueParameters = + function.valueParameters.subList(function.contextReceiverParametersCount, function.valueParameters.size) + for (parameter in regularValueParameters) { val kind = when (parameter.origin) { JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> JvmMethodParameterKind.OUTER JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER -> JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index 0ba05d73d56..777cb32f729 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -251,6 +251,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator dispatchReceiver = dispatchReceiverValue?.load() extensionReceiver = extensionReceiverValue?.load() val contextReceivers = contextReceiverValues.map { it.load() } + contextReceiversCount = contextReceivers.size addParametersToCall(startOffset, endOffset, call, this, irType, contextReceivers) } } @@ -376,6 +377,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator dispatchReceiver = dispatchReceiverValue?.load() extensionReceiver = extensionReceiverValue?.load() val contextReceivers = contextReceiverValues.map { it.load() } + contextReceiversCount = contextReceivers.size addParametersToCall(startOffset, endOffset, call, this, irType, contextReceivers) } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt index 4d19818b5cf..50bfb062655 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt @@ -328,6 +328,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio val contextReceiversNumber = ktContextReceiverParameterElements.size assert(functionDescriptor.contextReceiverParameters.size == contextReceiversNumber) + irFunction.contextReceiverParametersCount = contextReceiversNumber irFunction.valueParameters += functionDescriptor.contextReceiverParameters.mapIndexed { i, additionalReceiver -> declareParameter(additionalReceiver, ktContextReceiverParameterElements[i], irFunction, null, i) } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt index de8b0c2b6c3..7d6a72a5d50 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt @@ -48,6 +48,8 @@ abstract class IrFunction : abstract var body: IrBody? + var contextReceiverParametersCount: Int = 0 + override fun acceptChildren(visitor: IrElementVisitor, data: D) { typeParameters.forEach { it.accept(visitor, data) } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrFunctionAccessExpression.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrFunctionAccessExpression.kt index ac1c7d94245..925709b59de 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrFunctionAccessExpression.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrFunctionAccessExpression.kt @@ -19,6 +19,8 @@ abstract class IrFunctionAccessExpression( final override val valueArgumentsCount: Int get() = argumentsByParameterIndex.size + var contextReceiversCount: Int = 0 + override fun getValueArgument(index: Int): IrExpression? { if (index >= valueArgumentsCount) { throwNoSuchArgumentSlotException("value", index, valueArgumentsCount) diff --git a/compiler/testData/codegen/box/extensionFunctions/contextReceivers/contextAndExtensionSameName.kt b/compiler/testData/codegen/box/extensionFunctions/contextReceivers/contextAndExtensionSameName.kt new file mode 100644 index 00000000000..b72e3368a9b --- /dev/null +++ b/compiler/testData/codegen/box/extensionFunctions/contextReceivers/contextAndExtensionSameName.kt @@ -0,0 +1,13 @@ +// TARGET_BACKEND: JVM_IR +// IGNORE_BACKEND_FIR: JVM_IR + +class A { + val ok = "OK" + + context(A) + fun A.f() = ok +} + +fun box(): String = with(A()) { + f() +} \ No newline at end of file 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 993b33fe099..3a948a97117 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 @@ -16157,6 +16157,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("contextAndExtensionSameName.kt") + public void testContextAndExtensionSameName() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/contextAndExtensionSameName.kt"); + } + @Test @TestMetadata("dp.kt") public void testDp() throws Exception {