From 307f318c9e873e2b4be5c4aa237ff6f58b2bb10d Mon Sep 17 00:00:00 2001 From: Anastasiya Shadrina Date: Wed, 17 Feb 2021 04:53:15 +0700 Subject: [PATCH] [PSI2IR] Generate IR for functions and calls with context receivers --- .../FirBlackBoxCodegenTestGenerated.java | 28 ++++++ .../generators/ArgumentsGenerationUtils.kt | 28 ++++-- .../psi2ir/generators/AssignmentGenerator.kt | 8 +- .../kotlin/psi2ir/generators/CallGenerator.kt | 87 +++++++++++-------- .../generators/DelegatedPropertyGenerator.kt | 4 +- .../generators/EnumClassMembersGenerator.kt | 4 +- .../psi2ir/generators/FunctionGenerator.kt | 40 ++++++--- .../ReflectionReferencesGenerator.kt | 14 +-- .../kotlin/psi2ir/intermediate/CallBuilder.kt | 6 +- .../intermediate/DynamicMemberLValue.kt | 8 +- .../ExtensionInvokeCallReceiver.kt | 4 +- .../kotlin/psi2ir/intermediate/IrUtils.kt | 7 +- .../psi2ir/intermediate/PropertyLValue.kt | 18 ++-- .../psi2ir/intermediate/SafeCallReceiver.kt | 9 +- .../SafeExtensionInvokeCallReceiver.kt | 4 +- .../psi2ir/intermediate/SimpleCallReceiver.kt | 7 +- .../kotlin/psi2ir/intermediate/Values.kt | 2 +- .../kotlin/ir/expressions/impl/IrCallImpl.kt | 2 +- .../jetbrains/kotlin/ir/util/SymbolTable.kt | 3 +- .../extensionFunctions/contextReceivers/dp.kt | 18 ++++ .../contextReceivers/plusMatrix.kt | 51 +++++++++++ .../contextReceivers/simpleCall.kt | 21 +++++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 +++ .../IrBlackBoxCodegenTestGenerated.java | 28 ++++++ .../LightAnalysisModeTestGenerated.java | 13 +++ .../VisualizerBlackBoxTestGenerated.java | 13 +++ .../js/test/JsCodegenBoxTestGenerated.java | 13 +++ .../test/ir/IrJsCodegenBoxTestGenerated.java | 13 +++ .../IrCodegenBoxWasmTestGenerated.java | 13 +++ 29 files changed, 378 insertions(+), 98 deletions(-) create mode 100644 compiler/testData/codegen/box/extensionFunctions/contextReceivers/dp.kt create mode 100644 compiler/testData/codegen/box/extensionFunctions/contextReceivers/plusMatrix.kt create mode 100644 compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt 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 2a5e087f59f..53be7abf881 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 @@ -16107,6 +16107,34 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testWhenFail() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); } + + @Nested + @TestMetadata("compiler/testData/codegen/box/extensionFunctions/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + public class ContextReceivers { + @Test + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("dp.kt") + public void testDp() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/dp.kt"); + } + + @Test + @TestMetadata("plusMatrix.kt") + public void testPlusMatrix() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/plusMatrix.kt"); + } + + @Test + @TestMetadata("simpleCall.kt") + public void testSimpleCall() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt"); + } + } } @Nested diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt index b7a041ad321..c12bf2e3374 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt @@ -66,8 +66,13 @@ fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: R fun StatementGenerator.generateReceiver(defaultStartOffset: Int, defaultEndOffset: Int, receiver: ReceiverValue): IntermediateValue { val irReceiverType = when (receiver) { - is ExtensionReceiver -> - receiver.declarationDescriptor.extensionReceiverParameter!!.type.toIrType() + is ExtensionReceiver -> { + val receiverParameters = + receiver.declarationDescriptor.contextReceiverParameters + listOfNotNull(receiver.declarationDescriptor.extensionReceiverParameter) + val receiverParameter = receiverParameters.firstOrNull { it.value == receiver } + ?: receiver.declarationDescriptor.extensionReceiverParameter!! + receiverParameter.type.toIrType() + } else -> receiver.type.toIrType() } @@ -93,11 +98,16 @@ fun StatementGenerator.generateReceiver(defaultStartOffset: Int, defaultEndOffse generateThisOrSuperReceiver(receiver, receiver.thisType.constructor.declarationDescriptor as ClassDescriptor) is ExpressionReceiver -> generateExpression(receiver.expression) - is ExtensionReceiver -> + is ExtensionReceiver -> { + val receiverParameters = listOfNotNull(receiver.declarationDescriptor.extensionReceiverParameter) + + receiver.declarationDescriptor.contextReceiverParameters + val receiverParameter = receiverParameters.singleOrNull { it.value == receiver } + ?: receiver.declarationDescriptor.extensionReceiverParameter!! IrGetValueImpl( defaultStartOffset, defaultStartOffset, irReceiverType, - context.symbolTable.referenceValueParameter(receiver.declarationDescriptor.extensionReceiverParameter!!) + context.symbolTable.referenceValueParameter(receiverParameter) ) + } else -> throw AssertionError("Unexpected receiver: ${receiver::class.java.simpleName}") } @@ -170,11 +180,13 @@ fun StatementGenerator.generateCallReceiver( calleeDescriptor: CallableDescriptor, dispatchReceiver: ReceiverValue?, extensionReceiver: ReceiverValue?, + contextReceivers: List, isSafe: Boolean, isAssignmentReceiver: Boolean = false ): CallReceiver { val dispatchReceiverValue: IntermediateValue? val extensionReceiverValue: IntermediateValue? + val contextReceiverValues: List val startOffset = ktDefaultElement.startOffsetSkippingComments val endOffset = ktDefaultElement.endOffset when (calleeDescriptor) { @@ -184,6 +196,7 @@ fun StatementGenerator.generateCallReceiver( } dispatchReceiverValue = generateReceiverForCalleeImportedFromObject(startOffset, endOffset, calleeDescriptor) extensionReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver) + contextReceiverValues = contextReceivers.mapNotNull { generateReceiverOrNull(ktDefaultElement, it) } } is TypeAliasConstructorDescriptor -> { assert(!(dispatchReceiver != null && extensionReceiver != null)) { @@ -192,20 +205,22 @@ fun StatementGenerator.generateCallReceiver( } dispatchReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver ?: dispatchReceiver) extensionReceiverValue = null + contextReceiverValues = emptyList() } else -> { dispatchReceiverValue = generateReceiverOrNull(ktDefaultElement, dispatchReceiver) extensionReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver) + contextReceiverValues = contextReceivers.mapNotNull { generateReceiverOrNull(ktDefaultElement, it) } } } return when { !isSafe -> - SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue) + SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue, contextReceiverValues) extensionReceiverValue != null || dispatchReceiverValue != null -> SafeCallReceiver( this, startOffset, endOffset, - extensionReceiverValue, dispatchReceiverValue, isAssignmentReceiver + extensionReceiverValue, contextReceiverValues, dispatchReceiverValue, isAssignmentReceiver ) else -> throw AssertionError("Safe call should have an explicit receiver: ${ktDefaultElement.text}") @@ -697,6 +712,7 @@ fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>): resolvedCall.resultingDescriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, + resolvedCall.contextReceivers, isSafe = resolvedCall.call.isSafeCall() ) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt index 5f034b45c28..6fc2d0abb77 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt @@ -273,7 +273,9 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen descriptor.type.toIrType(), descriptor.name.asString(), statementGenerator.generateCallReceiver( - ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, + ktLeft, descriptor, resolvedCall.dispatchReceiver, + resolvedCall.extensionReceiver, + resolvedCall.contextReceivers, isSafe = resolvedCall.call.isSafeCall(), isAssignmentReceiver = isAssignmentStatement ) @@ -285,7 +287,9 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen } else -> { val propertyReceiver = statementGenerator.generateCallReceiver( - ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, + ktLeft, descriptor, resolvedCall.dispatchReceiver, + resolvedCall.extensionReceiver, + resolvedCall.contextReceivers, isSafe = resolvedCall.call.isSafeCall(), isAssignmentReceiver = isAssignmentStatement ) 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 44e705e7224..0ba05d73d56 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 @@ -55,7 +55,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator is FunctionDescriptor -> generateFunctionCall(descriptor, startOffset, endOffset, origin, call) else -> - call.callReceiver.call { _, _ -> + call.callReceiver.call { _, _, _ -> generateValueReference(startOffset, endOffset, descriptor, call.original, origin) } } @@ -155,7 +155,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator } fun generateDelegatingConstructorCall(startOffset: Int, endOffset: Int, call: CallBuilder): IrExpression = - call.callReceiver.call { dispatchReceiver, extensionReceiver -> + call.callReceiver.call { dispatchReceiver, extensionReceiver, contextReceivers -> val descriptor = call.descriptor as? ClassConstructorDescriptor ?: throw AssertionError("Class constructor expected: ${call.descriptor}") val constructorSymbol = context.symbolTable.referenceConstructor(descriptor.original) @@ -169,7 +169,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator this.dispatchReceiver = dispatchReceiver?.load() this.extensionReceiver = extensionReceiver?.load() } - addParametersToCall(startOffset, endOffset, call, irCall, context.irBuiltIns.unitType) + addParametersToCall(startOffset, endOffset, call, irCall, context.irBuiltIns.unitType, contextReceivers.map { it.load() }) } fun generateEnumConstructorSuperCall(startOffset: Int, endOffset: Int, call: CallBuilder): IrExpression { @@ -178,9 +178,10 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator val classDescriptor = constructorDescriptor.containingDeclaration if (classDescriptor.kind != ClassKind.ENUM_CLASS) throw AssertionError("Enum class constructor expected: $classDescriptor") - return call.callReceiver.call { dispatchReceiver, extensionReceiver -> + return call.callReceiver.call { dispatchReceiver, extensionReceiver, contextReceivers -> if (dispatchReceiver != null) throw AssertionError("Dispatch receiver should be null: $dispatchReceiver") if (extensionReceiver != null) throw AssertionError("Extension receiver should be null: $extensionReceiver") + if (contextReceivers.isNotEmpty()) throw AssertionError("Context receivers should be empty: $contextReceivers") val descriptor = constructorDescriptor.original val constructorSymbol = context.symbolTable.referenceConstructor(descriptor) val returnType = constructorDescriptor.returnType.toIrType() @@ -188,7 +189,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator startOffset, endOffset, returnType, constructorSymbol, descriptor.typeParametersCount, descriptor.valueParameters.size ) context.callToSubstitutedDescriptorMap[irCall] = constructorDescriptor - addParametersToCall(startOffset, endOffset, call, irCall, irCall.type) + addParametersToCall(startOffset, endOffset, call, irCall, irCall.type, emptyList()) } } @@ -208,7 +209,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator } val fieldSymbol = context.symbolTable.referenceField(context.extensions.remapDebuggerFieldPropertyDescriptor(descriptor.resolveFakeOverride().original)) - call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> + call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue, _ -> IrGetFieldImpl( startOffset, endOffset, fieldSymbol, @@ -220,36 +221,40 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator } } else { val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) } - call.callReceiver.adjustForCallee(getMethodDescriptor).call { dispatchReceiverValue, extensionReceiverValue -> - if (descriptor.isDynamic()) { - val dispatchReceiver = getDynamicExpressionReceiver(dispatchReceiverValue, extensionReceiverValue, descriptor) + call.callReceiver.adjustForCallee(getMethodDescriptor) + .call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues -> + if (descriptor.isDynamic()) { + val dispatchReceiver = getDynamicExpressionReceiver(dispatchReceiverValue, extensionReceiverValue, descriptor) - IrDynamicMemberExpressionImpl( - startOffset, endOffset, - irType, - descriptor.name.asString(), - dispatchReceiver - ) - } else { - val getterSymbol = context.symbolTable.referenceSimpleFunction(getMethodDescriptor.original) - IrCallImpl( - startOffset, endOffset, - irType, - getterSymbol, - descriptor.typeParametersCount, - 0, - IrStatementOrigin.GET_PROPERTY, - superQualifierSymbol - ).apply { - context.callToSubstitutedDescriptorMap[this] = computeSubstitutedSyntheticAccessor( - descriptor, getMethodDescriptor, descriptor.getter!! + IrDynamicMemberExpressionImpl( + startOffset, endOffset, + irType, + descriptor.name.asString(), + dispatchReceiver ) - putTypeArguments(call.typeArguments) { it.toIrType() } - dispatchReceiver = dispatchReceiverValue?.load() - extensionReceiver = extensionReceiverValue?.load() + } else { + val getterSymbol = context.symbolTable.referenceSimpleFunction(getMethodDescriptor.original) + IrCallImpl( + startOffset, endOffset, + irType, + getterSymbol, + descriptor.typeParametersCount, + descriptor.contextReceiverParameters.size, + IrStatementOrigin.GET_PROPERTY, + superQualifierSymbol + ).apply { + context.callToSubstitutedDescriptorMap[this] = computeSubstitutedSyntheticAccessor( + descriptor, getMethodDescriptor, descriptor.getter!! + ) + + putTypeArguments(call.typeArguments) { it.toIrType() } + dispatchReceiver = dispatchReceiverValue?.load() + extensionReceiver = extensionReceiverValue?.load() + val contextReceivers = contextReceiverValues.map { it.load() } + addParametersToCall(startOffset, endOffset, call, this, irType, contextReceivers) + } } } - } } } @@ -280,7 +285,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator origin: IrStatementOrigin?, call: CallBuilder ): IrExpression = - call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> + call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues -> val irType = constructorDescriptor.returnType.toIrType() val originalSymbol = context.symbolTable.referenceConstructor(constructorDescriptor.original) @@ -294,7 +299,8 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator putTypeArguments(call.typeArguments) { it.toIrType() } dispatchReceiver = dispatchReceiverValue?.load() extensionReceiver = extensionReceiverValue?.load() - addParametersToCall(startOffset, endOffset, call, this, irType) + val contextReceivers = contextReceiverValues.map { it.load() } + addParametersToCall(startOffset, endOffset, call, this, irType, contextReceivers) } } @@ -305,7 +311,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator origin: IrStatementOrigin?, call: CallBuilder ): IrExpression = - call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> + call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues -> val irType = functionDescriptor.returnType!!.toIrType() if (functionDescriptor.isDynamic()) { @@ -369,7 +375,8 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator putTypeArguments(call.typeArguments) { it.toIrType() } dispatchReceiver = dispatchReceiverValue?.load() extensionReceiver = extensionReceiverValue?.load() - addParametersToCall(startOffset, endOffset, call, this, irType) + val contextReceivers = contextReceiverValues.map { it.load() } + addParametersToCall(startOffset, endOffset, call, this, irType, contextReceivers) } } } @@ -379,14 +386,18 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator endOffset: Int, call: CallBuilder, irCall: IrFunctionAccessExpression, - irResultType: IrType + irResultType: IrType, + contextReceivers: List ): IrExpression = if (call.isValueArgumentReorderingRequired()) { generateCallWithArgumentReordering(irCall, startOffset, endOffset, call, irResultType) } else { + for ((index, valueArgument) in contextReceivers.withIndex()) { + irCall.putValueArgument(index, valueArgument) + } val valueArguments = call.getValueArgumentsInParameterOrder() for ((index, valueArgument) in valueArguments.withIndex()) { - irCall.putValueArgument(index, valueArgument) + irCall.putValueArgument(index + contextReceivers.size, valueArgument) } irCall } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt index f9ee95beb29..9db0cf2f792 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt @@ -103,7 +103,7 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR, accessorDescriptor ).buildWithScope { irAccessor -> - FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irAccessor, ktProperty, null) + FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irAccessor, ktProperty, null, emptyList()) irAccessor.body = generateBody(irAccessor) } @@ -363,7 +363,7 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR, getterDescriptor ).buildWithScope { irAccessor -> - FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irAccessor, ktDelegate, null) + FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irAccessor, ktDelegate, null, emptyList()) irAccessor.body = generateBody(irAccessor) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/EnumClassMembersGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/EnumClassMembersGenerator.kt index ef69853cf47..a1081f77d0e 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/EnumClassMembersGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/EnumClassMembersGenerator.kt @@ -44,7 +44,7 @@ class EnumClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER, valuesFunction ).also { irFunction -> - FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irFunction, null, null) + FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irFunction, null, null, emptyList()) irFunction.body = IrSyntheticBodyImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrSyntheticBodyKind.ENUM_VALUES) } ) @@ -63,7 +63,7 @@ class EnumClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER, valueOfFunction ).also { irFunction -> - FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irFunction, null, null) + FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irFunction, null, null, emptyList()) irFunction.body = IrSyntheticBodyImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrSyntheticBodyKind.ENUM_VALUEOF) } ) 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 9a896f36e7a..ea791ddb330 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 @@ -50,6 +50,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio declareSimpleFunction( ktFunction, ktFunction.receiverTypeReference, + ktFunction.contextReceiverTypeReferences, origin, getOrFail(BindingContext.FUNCTION, ktFunction) ) { @@ -60,6 +61,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio declareSimpleFunction( ktFunction, null, + emptyList(), IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA, getOrFail(BindingContext.FUNCTION, ktFunction) ) { @@ -71,19 +73,20 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio ?.let { declareSimpleFunctionInner(it, ktElement, IrDeclarationOrigin.FAKE_OVERRIDE) .buildWithScope { irFunction -> - generateFunctionParameterDeclarationsAndReturnType(irFunction, ktElement, null) + generateFunctionParameterDeclarationsAndReturnType(irFunction, ktElement, null, emptyList()) } } private inline fun declareSimpleFunction( ktFunction: KtFunction, ktReceiver: KtElement?, + ktContextReceivers: List, origin: IrDeclarationOrigin, descriptor: FunctionDescriptor, generateBody: BodyGenerator.() -> IrBody? ): IrSimpleFunction = declareSimpleFunctionInner(descriptor, ktFunction, origin).buildWithScope { irFunction -> - generateFunctionParameterDeclarationsAndReturnType(irFunction, ktFunction, ktReceiver) + generateFunctionParameterDeclarationsAndReturnType(irFunction, ktFunction, ktReceiver, ktContextReceivers) irFunction.body = createBodyGenerator(irFunction.symbol).generateBody() } @@ -102,11 +105,12 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio fun generateFunctionParameterDeclarationsAndReturnType( irFunction: IrFunction, ktParameterOwner: KtPureElement?, - ktReceiverParameterElement: KtElement? + ktReceiverParameterElement: KtElement?, + ktContextReceiverParametersElements: List ) { declarationGenerator.generateScopedTypeParameterDeclarations(irFunction, irFunction.descriptor.propertyIfAccessor.typeParameters) irFunction.returnType = irFunction.descriptor.returnType!!.toIrType() - generateValueParameterDeclarations(irFunction, ktParameterOwner, ktReceiverParameterElement) + generateValueParameterDeclarations(irFunction, ktParameterOwner, ktReceiverParameterElement, ktContextReceiverParametersElements) } fun generatePropertyAccessor( @@ -121,7 +125,10 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio ).buildWithScope { irAccessor -> declarationGenerator.generateScopedTypeParameterDeclarations(irAccessor, descriptor.correspondingProperty.typeParameters) irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType() - generateValueParameterDeclarations(irAccessor, ktAccessor ?: ktProperty, ktProperty.receiverTypeReference) + generateValueParameterDeclarations( + irAccessor, ktAccessor ?: ktProperty, ktProperty.receiverTypeReference, + ktProperty.contextReceiverTypeReferences + ) val ktBodyExpression = ktAccessor?.bodyExpression irAccessor.body = if (ktBodyExpression != null) @@ -272,7 +279,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio metadata = DescriptorMetadataSource.Function(it.descriptor) } }.buildWithScope { irConstructor -> - generateValueParameterDeclarations(irConstructor, ktParametersElement, null) + generateValueParameterDeclarations(irConstructor, ktParametersElement, null, emptyList()) irConstructor.body = createBodyGenerator(irConstructor.symbol).generateBody() irConstructor.returnType = constructorDescriptor.returnType.toIrType() } @@ -286,13 +293,14 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio else descriptor.typeParameters declarationGenerator.generateScopedTypeParameterDeclarations(irFunction, typeParameters) - generateValueParameterDeclarations(irFunction, null, null, withDefaultValues = false) + generateValueParameterDeclarations(irFunction, null, null, emptyList(), withDefaultValues = false) } private fun generateValueParameterDeclarations( irFunction: IrFunction, ktParameterOwner: KtPureElement?, ktReceiverParameterElement: KtPureElement?, + ktContextReceiverParameterElements: List, withDefaultValues: Boolean = true ) { val functionDescriptor = irFunction.descriptor @@ -307,10 +315,16 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio val bodyGenerator = createBodyGenerator(irFunction.symbol) + val contextReceiversNumber = ktContextReceiverParameterElements.size + assert(functionDescriptor.contextReceiverParameters.size == contextReceiversNumber) + irFunction.valueParameters += functionDescriptor.contextReceiverParameters.mapIndexed { i, additionalReceiver -> + declareParameter(additionalReceiver, ktContextReceiverParameterElements[i], irFunction, null, i) + } + // Declare all the value parameters up first. - irFunction.valueParameters += functionDescriptor.valueParameters.map { valueParameterDescriptor -> + irFunction.valueParameters += functionDescriptor.valueParameters.mapIndexed { i, valueParameterDescriptor -> val ktParameter = DescriptorToSourceUtils.getSourceFromDescriptor(valueParameterDescriptor) as? KtParameter - declareParameter(valueParameterDescriptor, ktParameter, irFunction) + declareParameter(valueParameterDescriptor, ktParameter, irFunction, null, i + contextReceiversNumber) } // Only after value parameters have been declared, generate default values. This ensures // that forward references to other parameters works in default value lambdas. For example: @@ -318,7 +332,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio // fun f(f1: () -> String = { f2() }, // f2: () -> String) = f1() if (withDefaultValues) { - irFunction.valueParameters.forEachIndexed { index, irValueParameter -> + irFunction.valueParameters.drop(contextReceiversNumber).forEachIndexed { index, irValueParameter -> val valueParameterDescriptor = functionDescriptor.valueParameters[index] val ktParameter = DescriptorToSourceUtils.getSourceFromDescriptor(valueParameterDescriptor) as? KtParameter irValueParameter.defaultValue = ktParameter?.defaultValue?.let { defaultValue -> @@ -376,7 +390,8 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio descriptor: ParameterDescriptor, ktElement: KtPureElement?, irOwnerElement: IrElement, - name: Name? = null + name: Name? = null, + index: Int? = null ): IrValueParameter { var origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED if (ktElement is KtParameter) { @@ -392,7 +407,8 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio origin, descriptor, descriptor.type.toIrType(), (descriptor as? ValueParameterDescriptor)?.varargElementType?.toIrType(), - name + name, + index ) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt index 1ab5b2eea7a..3bd20c38617 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt @@ -80,10 +80,11 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St return statementGenerator.generateCallReceiver( ktCallableReference, - resolvedDescriptor, - resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, + resolvedDescriptor, resolvedCall.dispatchReceiver, + resolvedCall.extensionReceiver, + resolvedCall.contextReceivers, isSafe = false - ).call { dispatchReceiverValue, extensionReceiverValue -> + ).call { dispatchReceiverValue, extensionReceiverValue, _ -> generateCallableReference( ktCallableReference, callableReferenceType, @@ -150,10 +151,11 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St val resolvedCall = callBuilder.original return statementGenerator.generateCallReceiver( ktCallableReference, - resolvedCall.resultingDescriptor, - resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, + resolvedCall.resultingDescriptor, resolvedCall.dispatchReceiver, + resolvedCall.extensionReceiver, + resolvedCall.contextReceivers, isSafe = false - ).call { dispatchReceiverValue, extensionReceiverValue -> + ).call { dispatchReceiverValue, extensionReceiverValue, _ -> val irDispatchReceiver = dispatchReceiverValue?.loadIfExists() val irExtensionReceiver = extensionReceiverValue?.loadIfExists() check(irDispatchReceiver == null || irExtensionReceiver == null) { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt index 1e5460d00c9..4689604e3f2 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt @@ -84,11 +84,11 @@ val CallBuilder.explicitReceiverType: KotlinType? fun CallBuilder.setExplicitReceiverValue(explicitReceiverValue: IntermediateValue) { val previousCallReceiver = callReceiver callReceiver = object : CallReceiver { - override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { - return previousCallReceiver.call { dispatchReceiverValue, _ -> + override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List) -> IrExpression): IrExpression { + return previousCallReceiver.call { dispatchReceiverValue, _, contextReceiverValues -> val newDispatchReceiverValue = if (hasExtensionReceiver) dispatchReceiverValue else explicitReceiverValue val newExtensionReceiverValue = if (hasExtensionReceiver) explicitReceiverValue else null - withDispatchAndExtensionReceivers(newDispatchReceiverValue, newExtensionReceiverValue) + withDispatchAndExtensionAndContextReceivers(newDispatchReceiverValue, newExtensionReceiverValue, contextReceiverValues) } } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/DynamicMemberLValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/DynamicMemberLValue.kt index d2743238bc1..048ce987033 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/DynamicMemberLValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/DynamicMemberLValue.kt @@ -24,7 +24,7 @@ class DynamicMemberLValue( ) : LValue, AssignmentReceiver { override fun load(): IrExpression = - receiver.call { dispatchReceiverValue, extensionReceiverValue -> + receiver.call { dispatchReceiverValue, extensionReceiverValue, _ -> val dynamicReceiver = getDynamicReceiver(dispatchReceiverValue, extensionReceiverValue) IrDynamicMemberExpressionImpl( @@ -36,7 +36,7 @@ class DynamicMemberLValue( } override fun store(irExpression: IrExpression): IrExpression = - receiver.call { dispatchReceiverValue, extensionReceiverValue -> + receiver.call { dispatchReceiverValue, extensionReceiverValue, _ -> val dynamicReceiver = getDynamicReceiver(dispatchReceiverValue, extensionReceiverValue) IrDynamicOperatorExpressionImpl( @@ -55,11 +55,11 @@ class DynamicMemberLValue( } override fun assign(withLValue: (LValue) -> IrExpression): IrExpression = - receiver.call { dispatchReceiverValue, extensionReceiverValue -> + receiver.call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues -> withLValue( DynamicMemberLValue( context, startOffset, endOffset, type, memberName, - SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue) + SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue, contextReceiverValues) ) ) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ExtensionInvokeCallReceiver.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ExtensionInvokeCallReceiver.kt index 4742a5cc3ba..bd05ec35911 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ExtensionInvokeCallReceiver.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ExtensionInvokeCallReceiver.kt @@ -24,7 +24,7 @@ class ExtensionInvokeCallReceiver( private val extensionInvokeReceiver: IntermediateValue ) : CallReceiver { - override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { + override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List) -> IrExpression): IrExpression { // extensionInvokeReceiver is actually a first argument: // receiver.extFun(p1, ..., pN) // => @@ -34,6 +34,6 @@ class ExtensionInvokeCallReceiver( "Extension 'invoke' call should have null as its 1st value argument, got: ${callBuilder.irValueArgumentsByIndex[0]}" } callBuilder.irValueArgumentsByIndex[0] = extensionInvokeReceiver.load() - return withDispatchAndExtensionReceivers(functionReceiver, null) + return withDispatchAndExtensionAndContextReceivers(functionReceiver, null, emptyList()) } } \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt index 82f70b820eb..bf6419b2885 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt @@ -27,8 +27,8 @@ fun IrVariable.loadAt(startOffset: Int, endOffset: Int): IrExpression = fun CallReceiver.adjustForCallee(callee: CallableMemberDescriptor): CallReceiver = object : CallReceiver { - override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression = - this@adjustForCallee.call { dispatchReceiverValue, extensionReceiverValue -> + override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List) -> IrExpression): IrExpression = + this@adjustForCallee.call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues -> val numReceiversPresent = listOfNotNull(dispatchReceiverValue, extensionReceiverValue).size val numReceiversExpected = listOfNotNull(callee.dispatchReceiverParameter, callee.extensionReceiverParameter).size if (numReceiversPresent != numReceiversExpected) @@ -46,7 +46,8 @@ fun CallReceiver.adjustForCallee(callee: CallableMemberDescriptor): CallReceiver dispatchReceiverValue != null && callee.dispatchReceiverParameter == null -> dispatchReceiverValue else -> extensionReceiverValue } - withDispatchAndExtensionReceivers(newDispatchReceiverValue, newExtensionReceiverValue) + // TODO: Create new context receiver values + withDispatchAndExtensionAndContextReceivers(newDispatchReceiverValue, newExtensionReceiverValue, contextReceiverValues) } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/PropertyLValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/PropertyLValue.kt index 983bc792550..ceade335154 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/PropertyLValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/PropertyLValue.kt @@ -40,7 +40,7 @@ abstract class PropertyLValueBase( val superQualifier: IrClassSymbol? ) : LValue, AssignmentReceiver { override fun assign(withLValue: (LValue) -> IrExpression) = - callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> + callReceiver.call { dispatchReceiverValue, extensionReceiverValue, _ -> val dispatchReceiverVariable2 = dispatchReceiverValue?.let { scope.createTemporaryVariable(dispatchReceiverValue.load(), "this") } @@ -81,7 +81,8 @@ class FieldPropertyLValue( PropertyLValueBase(context, scope, startOffset, endOffset, origin, type, callReceiver, superQualifier) { override fun load(): IrExpression = - callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> + // TODO: Use context receiver values + callReceiver.call { dispatchReceiverValue, extensionReceiverValue, _ -> assert(extensionReceiverValue == null) { "Field can't have an extension receiver: ${field.descriptor}" } IrGetFieldImpl( startOffset, endOffset, @@ -94,7 +95,8 @@ class FieldPropertyLValue( } override fun store(irExpression: IrExpression) = - callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> + // TODO: Use context receiver values + callReceiver.call { dispatchReceiverValue, extensionReceiverValue, _ -> assert(extensionReceiverValue == null) { "Field can't have an extension receiver: ${field.descriptor}" } IrSetFieldImpl( startOffset, endOffset, @@ -114,7 +116,7 @@ class FieldPropertyLValue( field, descriptor, type, - SimpleCallReceiver(dispatchReceiver, extensionReceiver), + SimpleCallReceiver(dispatchReceiver, extensionReceiver, emptyList()), superQualifier ) } @@ -144,7 +146,8 @@ class AccessorPropertyLValue( } override fun load(): IrExpression = - callReceiver.adjustForCallee(getterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue -> + // TODO: Use context receiver values + callReceiver.adjustForCallee(getterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue, _ -> IrCallImpl( startOffset, endOffset, type, @@ -161,7 +164,8 @@ class AccessorPropertyLValue( } override fun store(irExpression: IrExpression) = - callReceiver.adjustForCallee(setterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue -> + // TODO: Use context receiver values + callReceiver.adjustForCallee(setterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue, _ -> IrCallImpl( startOffset, endOffset, context.irBuiltIns.unitType, @@ -184,7 +188,7 @@ class AccessorPropertyLValue( startOffset, endOffset, origin, type, getter, getterDescriptor, setter, setterDescriptor, typeArguments, - SimpleCallReceiver(dispatchReceiver, extensionReceiver), + SimpleCallReceiver(dispatchReceiver, extensionReceiver, emptyList()), superQualifier ) } \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeCallReceiver.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeCallReceiver.kt index 7e16d273b16..12a2ff81515 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeCallReceiver.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeCallReceiver.kt @@ -31,11 +31,13 @@ class SafeCallReceiver( val startOffset: Int, val endOffset: Int, val extensionReceiver: IntermediateValue?, + // TODO: Use context receivers + val contextReceivers: List, val dispatchReceiver: IntermediateValue?, val isStatement: Boolean ) : CallReceiver { - override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { + override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List) -> IrExpression): IrExpression { val irTmp = generator.scope.createTemporaryVariable(extensionReceiver?.load() ?: dispatchReceiver!!.load(), "safe_receiver") val safeReceiverValue = VariableLValue(generator.context, irTmp) @@ -49,7 +51,7 @@ class SafeCallReceiver( extensionReceiverValue = null } - val irResult = withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue) + val irResult = withDispatchAndExtensionAndContextReceivers(dispatchReceiverValue, extensionReceiverValue, emptyList()) val resultType = if (isStatement) generator.context.irBuiltIns.unitType else irResult.type.makeNullable() @@ -77,8 +79,9 @@ fun IrExpression.safeCallOnDispatchReceiver( SafeCallReceiver( generator, startOffset, endOffset, extensionReceiver = null, + contextReceivers = emptyList(), dispatchReceiver = OnceExpressionValue(this), isStatement = false - ).call { dispatchReceiverValue, _ -> + ).call { dispatchReceiverValue, _, _ -> ifNotNull(dispatchReceiverValue!!.load()) } \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeExtensionInvokeCallReceiver.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeExtensionInvokeCallReceiver.kt index a2bcd14afb9..23ef3f17c1a 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeExtensionInvokeCallReceiver.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeExtensionInvokeCallReceiver.kt @@ -33,7 +33,7 @@ class SafeExtensionInvokeCallReceiver( val extensionInvokeReceiver: IntermediateValue ) : CallReceiver { - override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { + override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List) -> IrExpression): IrExpression { // extensionInvokeReceiver is actually a first argument: // receiver?.extFun(p1, ..., pN) // => @@ -49,7 +49,7 @@ class SafeExtensionInvokeCallReceiver( "Safe extension 'invoke' call should have null as its 1st value argument, got: ${callBuilder.irValueArgumentsByIndex[0]}" } callBuilder.irValueArgumentsByIndex[0] = safeReceiverValue.load() - val irResult = withDispatchAndExtensionReceivers(functionReceiver, null) + val irResult = withDispatchAndExtensionAndContextReceivers(functionReceiver, null, emptyList()) val resultType = irResult.type.makeNullable() diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SimpleCallReceiver.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SimpleCallReceiver.kt index 365ec119d9c..43e44753f72 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SimpleCallReceiver.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SimpleCallReceiver.kt @@ -20,10 +20,11 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression class SimpleCallReceiver( private val dispatchReceiverValue: IntermediateValue?, - private val extensionReceiverValue: IntermediateValue? + private val extensionReceiverValue: IntermediateValue?, + private val contextReceiverValues: List ) : CallReceiver { - override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { - return withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue) + override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List) -> IrExpression): IrExpression { + return withDispatchAndExtensionAndContextReceivers(dispatchReceiverValue, extensionReceiverValue, contextReceiverValues) } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/Values.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/Values.kt index 63ac6187160..178c462f2a9 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/Values.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/Values.kt @@ -36,5 +36,5 @@ interface AssignmentReceiver { } interface CallReceiver { - fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression + fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List) -> IrExpression): IrExpression } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrCallImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrCallImpl.kt index 1a1d4b7f488..b31e0dc04b9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrCallImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrCallImpl.kt @@ -54,7 +54,7 @@ class IrCallImpl( type: IrType, symbol: IrSimpleFunctionSymbol, typeArgumentsCount: Int = symbol.descriptor.typeParametersCount, - valueArgumentsCount: Int = symbol.descriptor.valueParameters.size, + valueArgumentsCount: Int = symbol.descriptor.valueParameters.size + symbol.descriptor.contextReceiverParameters.size, origin: IrStatementOrigin? = null, superQualifierSymbol: IrClassSymbol? = null, ) = diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt index 66c64061933..e5c52688211 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt @@ -933,11 +933,12 @@ open class SymbolTable( type: IrType, varargElementType: IrType? = null, name: Name? = null, + index: Int? = null, isAssignable: Boolean = false, valueParameterFactory: (IrValueParameterSymbol) -> IrValueParameter = { irFactory.createValueParameter( startOffset, endOffset, origin, it, name ?: nameProvider.nameForDeclaration(descriptor), - descriptor.indexOrMinusOne, type, varargElementType, descriptor.isCrossinline, descriptor.isNoinline, + index ?: descriptor.indexOrMinusOne, type, varargElementType, descriptor.isCrossinline, descriptor.isNoinline, isHidden = false, isAssignable = isAssignable ) } diff --git a/compiler/testData/codegen/box/extensionFunctions/contextReceivers/dp.kt b/compiler/testData/codegen/box/extensionFunctions/contextReceivers/dp.kt new file mode 100644 index 00000000000..6dc0377731b --- /dev/null +++ b/compiler/testData/codegen/box/extensionFunctions/contextReceivers/dp.kt @@ -0,0 +1,18 @@ +// TARGET_BACKEND: JVM_IR +// IGNORE_BACKEND_FIR: JVM_IR +// WITH_RUNTIME + +class View { + val coefficient = 42 +} + +context(View) val Int.dp get() = coefficient * this + +fun box(): String { + with(View()) { + if (listOf(1, 2, 10).map { it.dp } == listOf(42, 84, 420)) { + return "OK" + } + return "fail" + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/extensionFunctions/contextReceivers/plusMatrix.kt b/compiler/testData/codegen/box/extensionFunctions/contextReceivers/plusMatrix.kt new file mode 100644 index 00000000000..0d50c402f09 --- /dev/null +++ b/compiler/testData/codegen/box/extensionFunctions/contextReceivers/plusMatrix.kt @@ -0,0 +1,51 @@ +// TARGET_BACKEND: JVM_IR +// IGNORE_BACKEND_FIR: JVM_IR +// WITH_RUNTIME + +interface NumberOperations { + operator fun Number.plus(other: Number): Number +} + +object DoubleOperations : NumberOperations { + override operator fun Number.plus(other: Number) = this.toDouble() + other.toDouble() +} + +data class Matrix(val rows: Int, val columns: Int, val data: Array) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Matrix + + if (rows != other.rows) return false + if (columns != other.columns) return false + if (!data.contentEquals(other.data)) return false + + return true + } + + override fun hashCode(): Int { + var result = rows + result = 31 * result + columns + result = 31 * result + data.contentHashCode() + return result + } +} + +fun matrixOf(rows: Int, columns: Int, vararg data: Number): Matrix { + assert(rows * columns == data.size) { "Wrong dimentions" } + return Matrix(rows, columns, data) +} + +context(NumberOperations) operator fun Matrix.plus(other: Matrix): Matrix { + assert(rows == other.rows && columns == other.columns) { "Matrices should have the same dimentions" } + return matrixOf(rows, columns, *data.mapIndexed { i, element -> element + other.data[i] }.toTypedArray()) +} + +fun box(): String { + val m1 = matrixOf(2, 2, 1, 2, 3, 4) + val m2 = matrixOf(2, 2, .4, .3, .2, .1) + with(DoubleOperations) { + return if (m1 + m2 == matrixOf(2, 2, 1.4, 2.3, 3.2, 4.1)) "OK" else "fail" + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt b/compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt new file mode 100644 index 00000000000..7b3743decc2 --- /dev/null +++ b/compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt @@ -0,0 +1,21 @@ +// TARGET_BACKEND: JVM_IR +// IGNORE_BACKEND_FIR: JVM_IR + +class A { + val o = "O" +} +class B { + val k = "K" +} + +context(B) fun A.f(a: Any, b: Any) = o + k + +fun B.g(a: A): String { + with (a) { + return f(1, "2") + } +} + +fun box(): String { + return B().g(A()) +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 4438aa392fb..91043f06c77 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -16029,6 +16029,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testWhenFail() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); } + + @Nested + @TestMetadata("compiler/testData/codegen/box/extensionFunctions/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + public class ContextReceivers { + @Test + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + } } @Nested 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 373155dcbd3..585c6afa239 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 @@ -16107,6 +16107,34 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testWhenFail() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); } + + @Nested + @TestMetadata("compiler/testData/codegen/box/extensionFunctions/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + public class ContextReceivers { + @Test + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("dp.kt") + public void testDp() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/dp.kt"); + } + + @Test + @TestMetadata("plusMatrix.kt") + public void testPlusMatrix() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/plusMatrix.kt"); + } + + @Test + @TestMetadata("simpleCall.kt") + public void testSimpleCall() throws Exception { + runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt"); + } + } } @Nested diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 2ba741c2e43..abdbadcd0fb 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -13192,6 +13192,19 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testWhenFail() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); } + + @TestMetadata("compiler/testData/codegen/box/extensionFunctions/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + } } @TestMetadata("compiler/testData/codegen/box/extensionProperties") diff --git a/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/VisualizerBlackBoxTestGenerated.java b/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/VisualizerBlackBoxTestGenerated.java index d9efa92dfb7..783f04cb402 100644 --- a/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/VisualizerBlackBoxTestGenerated.java +++ b/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/VisualizerBlackBoxTestGenerated.java @@ -14778,6 +14778,19 @@ public class VisualizerBlackBoxTestGenerated extends AbstractVisualizerBlackBoxT public void testWhenFail() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); } + + @TestMetadata("compiler/testData/codegen/box/extensionFunctions/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractIrJsCodegenBoxES6Test { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); + } + } } @Nested diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index 8641be6e7b4..13a3d654746 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -12443,6 +12443,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testWhenFail() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); } + + @TestMetadata("compiler/testData/codegen/box/extensionFunctions/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); + } + } } @Nested diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index 79e61c7e733..120afe46726 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -12485,6 +12485,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testWhenFail() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); } + + @TestMetadata("compiler/testData/codegen/box/extensionFunctions/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractIrJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + } } @Nested diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 928e6170188..14841e24a30 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -10359,6 +10359,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest public void testWhenFail() throws Exception { runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); } + + @TestMetadata("compiler/testData/codegen/box/extensionFunctions/contextReceivers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ContextReceivers extends AbstractIrCodegenBoxWasmTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath); + } + + public void testAllFilesPresentInContextReceivers() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); + } + } } @TestMetadata("compiler/testData/codegen/box/extensionProperties")