[PSI2IR] Generate IR for functions and calls with context receivers

This commit is contained in:
Anastasiya Shadrina
2021-02-17 04:53:15 +07:00
committed by TeamCityServer
parent f4ddf66ac4
commit 307f318c9e
29 changed files with 378 additions and 98 deletions
@@ -16107,6 +16107,34 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
public void testWhenFail() throws Exception { public void testWhenFail() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); 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 @Nested
@@ -66,8 +66,13 @@ fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: R
fun StatementGenerator.generateReceiver(defaultStartOffset: Int, defaultEndOffset: Int, receiver: ReceiverValue): IntermediateValue { fun StatementGenerator.generateReceiver(defaultStartOffset: Int, defaultEndOffset: Int, receiver: ReceiverValue): IntermediateValue {
val irReceiverType = val irReceiverType =
when (receiver) { when (receiver) {
is ExtensionReceiver -> is ExtensionReceiver -> {
receiver.declarationDescriptor.extensionReceiverParameter!!.type.toIrType() val receiverParameters =
receiver.declarationDescriptor.contextReceiverParameters + listOfNotNull(receiver.declarationDescriptor.extensionReceiverParameter)
val receiverParameter = receiverParameters.firstOrNull { it.value == receiver }
?: receiver.declarationDescriptor.extensionReceiverParameter!!
receiverParameter.type.toIrType()
}
else -> else ->
receiver.type.toIrType() receiver.type.toIrType()
} }
@@ -93,11 +98,16 @@ fun StatementGenerator.generateReceiver(defaultStartOffset: Int, defaultEndOffse
generateThisOrSuperReceiver(receiver, receiver.thisType.constructor.declarationDescriptor as ClassDescriptor) generateThisOrSuperReceiver(receiver, receiver.thisType.constructor.declarationDescriptor as ClassDescriptor)
is ExpressionReceiver -> is ExpressionReceiver ->
generateExpression(receiver.expression) 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( IrGetValueImpl(
defaultStartOffset, defaultStartOffset, irReceiverType, defaultStartOffset, defaultStartOffset, irReceiverType,
context.symbolTable.referenceValueParameter(receiver.declarationDescriptor.extensionReceiverParameter!!) context.symbolTable.referenceValueParameter(receiverParameter)
) )
}
else -> else ->
throw AssertionError("Unexpected receiver: ${receiver::class.java.simpleName}") throw AssertionError("Unexpected receiver: ${receiver::class.java.simpleName}")
} }
@@ -170,11 +180,13 @@ fun StatementGenerator.generateCallReceiver(
calleeDescriptor: CallableDescriptor, calleeDescriptor: CallableDescriptor,
dispatchReceiver: ReceiverValue?, dispatchReceiver: ReceiverValue?,
extensionReceiver: ReceiverValue?, extensionReceiver: ReceiverValue?,
contextReceivers: List<ReceiverValue>,
isSafe: Boolean, isSafe: Boolean,
isAssignmentReceiver: Boolean = false isAssignmentReceiver: Boolean = false
): CallReceiver { ): CallReceiver {
val dispatchReceiverValue: IntermediateValue? val dispatchReceiverValue: IntermediateValue?
val extensionReceiverValue: IntermediateValue? val extensionReceiverValue: IntermediateValue?
val contextReceiverValues: List<IntermediateValue>
val startOffset = ktDefaultElement.startOffsetSkippingComments val startOffset = ktDefaultElement.startOffsetSkippingComments
val endOffset = ktDefaultElement.endOffset val endOffset = ktDefaultElement.endOffset
when (calleeDescriptor) { when (calleeDescriptor) {
@@ -184,6 +196,7 @@ fun StatementGenerator.generateCallReceiver(
} }
dispatchReceiverValue = generateReceiverForCalleeImportedFromObject(startOffset, endOffset, calleeDescriptor) dispatchReceiverValue = generateReceiverForCalleeImportedFromObject(startOffset, endOffset, calleeDescriptor)
extensionReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver) extensionReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver)
contextReceiverValues = contextReceivers.mapNotNull { generateReceiverOrNull(ktDefaultElement, it) }
} }
is TypeAliasConstructorDescriptor -> { is TypeAliasConstructorDescriptor -> {
assert(!(dispatchReceiver != null && extensionReceiver != null)) { assert(!(dispatchReceiver != null && extensionReceiver != null)) {
@@ -192,20 +205,22 @@ fun StatementGenerator.generateCallReceiver(
} }
dispatchReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver ?: dispatchReceiver) dispatchReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver ?: dispatchReceiver)
extensionReceiverValue = null extensionReceiverValue = null
contextReceiverValues = emptyList()
} }
else -> { else -> {
dispatchReceiverValue = generateReceiverOrNull(ktDefaultElement, dispatchReceiver) dispatchReceiverValue = generateReceiverOrNull(ktDefaultElement, dispatchReceiver)
extensionReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver) extensionReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver)
contextReceiverValues = contextReceivers.mapNotNull { generateReceiverOrNull(ktDefaultElement, it) }
} }
} }
return when { return when {
!isSafe -> !isSafe ->
SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue) SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue, contextReceiverValues)
extensionReceiverValue != null || dispatchReceiverValue != null -> extensionReceiverValue != null || dispatchReceiverValue != null ->
SafeCallReceiver( SafeCallReceiver(
this, startOffset, endOffset, this, startOffset, endOffset,
extensionReceiverValue, dispatchReceiverValue, isAssignmentReceiver extensionReceiverValue, contextReceiverValues, dispatchReceiverValue, isAssignmentReceiver
) )
else -> else ->
throw AssertionError("Safe call should have an explicit receiver: ${ktDefaultElement.text}") throw AssertionError("Safe call should have an explicit receiver: ${ktDefaultElement.text}")
@@ -697,6 +712,7 @@ fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>):
resolvedCall.resultingDescriptor, resolvedCall.resultingDescriptor,
resolvedCall.dispatchReceiver, resolvedCall.dispatchReceiver,
resolvedCall.extensionReceiver, resolvedCall.extensionReceiver,
resolvedCall.contextReceivers,
isSafe = resolvedCall.call.isSafeCall() isSafe = resolvedCall.call.isSafeCall()
) )
@@ -273,7 +273,9 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
descriptor.type.toIrType(), descriptor.type.toIrType(),
descriptor.name.asString(), descriptor.name.asString(),
statementGenerator.generateCallReceiver( statementGenerator.generateCallReceiver(
ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, ktLeft, descriptor, resolvedCall.dispatchReceiver,
resolvedCall.extensionReceiver,
resolvedCall.contextReceivers,
isSafe = resolvedCall.call.isSafeCall(), isSafe = resolvedCall.call.isSafeCall(),
isAssignmentReceiver = isAssignmentStatement isAssignmentReceiver = isAssignmentStatement
) )
@@ -285,7 +287,9 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
} }
else -> { else -> {
val propertyReceiver = statementGenerator.generateCallReceiver( val propertyReceiver = statementGenerator.generateCallReceiver(
ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, ktLeft, descriptor, resolvedCall.dispatchReceiver,
resolvedCall.extensionReceiver,
resolvedCall.contextReceivers,
isSafe = resolvedCall.call.isSafeCall(), isSafe = resolvedCall.call.isSafeCall(),
isAssignmentReceiver = isAssignmentStatement isAssignmentReceiver = isAssignmentStatement
) )
@@ -55,7 +55,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
is FunctionDescriptor -> is FunctionDescriptor ->
generateFunctionCall(descriptor, startOffset, endOffset, origin, call) generateFunctionCall(descriptor, startOffset, endOffset, origin, call)
else -> else ->
call.callReceiver.call { _, _ -> call.callReceiver.call { _, _, _ ->
generateValueReference(startOffset, endOffset, descriptor, call.original, origin) 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 = 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 val descriptor = call.descriptor as? ClassConstructorDescriptor
?: throw AssertionError("Class constructor expected: ${call.descriptor}") ?: throw AssertionError("Class constructor expected: ${call.descriptor}")
val constructorSymbol = context.symbolTable.referenceConstructor(descriptor.original) val constructorSymbol = context.symbolTable.referenceConstructor(descriptor.original)
@@ -169,7 +169,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
this.dispatchReceiver = dispatchReceiver?.load() this.dispatchReceiver = dispatchReceiver?.load()
this.extensionReceiver = extensionReceiver?.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 { fun generateEnumConstructorSuperCall(startOffset: Int, endOffset: Int, call: CallBuilder): IrExpression {
@@ -178,9 +178,10 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
val classDescriptor = constructorDescriptor.containingDeclaration val classDescriptor = constructorDescriptor.containingDeclaration
if (classDescriptor.kind != ClassKind.ENUM_CLASS) throw AssertionError("Enum class constructor expected: $classDescriptor") 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 (dispatchReceiver != null) throw AssertionError("Dispatch receiver should be null: $dispatchReceiver")
if (extensionReceiver != null) throw AssertionError("Extension receiver should be null: $extensionReceiver") 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 descriptor = constructorDescriptor.original
val constructorSymbol = context.symbolTable.referenceConstructor(descriptor) val constructorSymbol = context.symbolTable.referenceConstructor(descriptor)
val returnType = constructorDescriptor.returnType.toIrType() val returnType = constructorDescriptor.returnType.toIrType()
@@ -188,7 +189,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
startOffset, endOffset, returnType, constructorSymbol, descriptor.typeParametersCount, descriptor.valueParameters.size startOffset, endOffset, returnType, constructorSymbol, descriptor.typeParametersCount, descriptor.valueParameters.size
) )
context.callToSubstitutedDescriptorMap[irCall] = constructorDescriptor 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 = val fieldSymbol =
context.symbolTable.referenceField(context.extensions.remapDebuggerFieldPropertyDescriptor(descriptor.resolveFakeOverride().original)) context.symbolTable.referenceField(context.extensions.remapDebuggerFieldPropertyDescriptor(descriptor.resolveFakeOverride().original))
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue, _ ->
IrGetFieldImpl( IrGetFieldImpl(
startOffset, endOffset, startOffset, endOffset,
fieldSymbol, fieldSymbol,
@@ -220,36 +221,40 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
} }
} else { } else {
val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) } val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) }
call.callReceiver.adjustForCallee(getMethodDescriptor).call { dispatchReceiverValue, extensionReceiverValue -> call.callReceiver.adjustForCallee(getMethodDescriptor)
if (descriptor.isDynamic()) { .call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues ->
val dispatchReceiver = getDynamicExpressionReceiver(dispatchReceiverValue, extensionReceiverValue, descriptor) if (descriptor.isDynamic()) {
val dispatchReceiver = getDynamicExpressionReceiver(dispatchReceiverValue, extensionReceiverValue, descriptor)
IrDynamicMemberExpressionImpl( IrDynamicMemberExpressionImpl(
startOffset, endOffset, startOffset, endOffset,
irType, irType,
descriptor.name.asString(), descriptor.name.asString(),
dispatchReceiver 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!!
) )
putTypeArguments(call.typeArguments) { it.toIrType() } } else {
dispatchReceiver = dispatchReceiverValue?.load() val getterSymbol = context.symbolTable.referenceSimpleFunction(getMethodDescriptor.original)
extensionReceiver = extensionReceiverValue?.load() 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?, origin: IrStatementOrigin?,
call: CallBuilder call: CallBuilder
): IrExpression = ): IrExpression =
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues ->
val irType = constructorDescriptor.returnType.toIrType() val irType = constructorDescriptor.returnType.toIrType()
val originalSymbol = context.symbolTable.referenceConstructor(constructorDescriptor.original) val originalSymbol = context.symbolTable.referenceConstructor(constructorDescriptor.original)
@@ -294,7 +299,8 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
putTypeArguments(call.typeArguments) { it.toIrType() } putTypeArguments(call.typeArguments) { it.toIrType() }
dispatchReceiver = dispatchReceiverValue?.load() dispatchReceiver = dispatchReceiverValue?.load()
extensionReceiver = extensionReceiverValue?.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?, origin: IrStatementOrigin?,
call: CallBuilder call: CallBuilder
): IrExpression = ): IrExpression =
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues ->
val irType = functionDescriptor.returnType!!.toIrType() val irType = functionDescriptor.returnType!!.toIrType()
if (functionDescriptor.isDynamic()) { if (functionDescriptor.isDynamic()) {
@@ -369,7 +375,8 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
putTypeArguments(call.typeArguments) { it.toIrType() } putTypeArguments(call.typeArguments) { it.toIrType() }
dispatchReceiver = dispatchReceiverValue?.load() dispatchReceiver = dispatchReceiverValue?.load()
extensionReceiver = extensionReceiverValue?.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, endOffset: Int,
call: CallBuilder, call: CallBuilder,
irCall: IrFunctionAccessExpression, irCall: IrFunctionAccessExpression,
irResultType: IrType irResultType: IrType,
contextReceivers: List<IrExpression>
): IrExpression = ): IrExpression =
if (call.isValueArgumentReorderingRequired()) { if (call.isValueArgumentReorderingRequired()) {
generateCallWithArgumentReordering(irCall, startOffset, endOffset, call, irResultType) generateCallWithArgumentReordering(irCall, startOffset, endOffset, call, irResultType)
} else { } else {
for ((index, valueArgument) in contextReceivers.withIndex()) {
irCall.putValueArgument(index, valueArgument)
}
val valueArguments = call.getValueArgumentsInParameterOrder() val valueArguments = call.getValueArgumentsInParameterOrder()
for ((index, valueArgument) in valueArguments.withIndex()) { for ((index, valueArgument) in valueArguments.withIndex()) {
irCall.putValueArgument(index, valueArgument) irCall.putValueArgument(index + contextReceivers.size, valueArgument)
} }
irCall irCall
} }
@@ -103,7 +103,7 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D
IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR, IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR,
accessorDescriptor accessorDescriptor
).buildWithScope { irAccessor -> ).buildWithScope { irAccessor ->
FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irAccessor, ktProperty, null) FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irAccessor, ktProperty, null, emptyList())
irAccessor.body = generateBody(irAccessor) irAccessor.body = generateBody(irAccessor)
} }
@@ -363,7 +363,7 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D
IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR, IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR,
getterDescriptor getterDescriptor
).buildWithScope { irAccessor -> ).buildWithScope { irAccessor ->
FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irAccessor, ktDelegate, null) FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irAccessor, ktDelegate, null, emptyList())
irAccessor.body = generateBody(irAccessor) irAccessor.body = generateBody(irAccessor)
} }
@@ -44,7 +44,7 @@ class EnumClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De
IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER, IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER,
valuesFunction valuesFunction
).also { irFunction -> ).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) irFunction.body = IrSyntheticBodyImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrSyntheticBodyKind.ENUM_VALUES)
} }
) )
@@ -63,7 +63,7 @@ class EnumClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De
IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER, IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER,
valueOfFunction valueOfFunction
).also { irFunction -> ).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) irFunction.body = IrSyntheticBodyImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrSyntheticBodyKind.ENUM_VALUEOF)
} }
) )
@@ -50,6 +50,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
declareSimpleFunction( declareSimpleFunction(
ktFunction, ktFunction,
ktFunction.receiverTypeReference, ktFunction.receiverTypeReference,
ktFunction.contextReceiverTypeReferences,
origin, origin,
getOrFail(BindingContext.FUNCTION, ktFunction) getOrFail(BindingContext.FUNCTION, ktFunction)
) { ) {
@@ -60,6 +61,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
declareSimpleFunction( declareSimpleFunction(
ktFunction, ktFunction,
null, null,
emptyList(),
IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA, IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA,
getOrFail(BindingContext.FUNCTION, ktFunction) getOrFail(BindingContext.FUNCTION, ktFunction)
) { ) {
@@ -71,19 +73,20 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
?.let { ?.let {
declareSimpleFunctionInner(it, ktElement, IrDeclarationOrigin.FAKE_OVERRIDE) declareSimpleFunctionInner(it, ktElement, IrDeclarationOrigin.FAKE_OVERRIDE)
.buildWithScope { irFunction -> .buildWithScope { irFunction ->
generateFunctionParameterDeclarationsAndReturnType(irFunction, ktElement, null) generateFunctionParameterDeclarationsAndReturnType(irFunction, ktElement, null, emptyList())
} }
} }
private inline fun declareSimpleFunction( private inline fun declareSimpleFunction(
ktFunction: KtFunction, ktFunction: KtFunction,
ktReceiver: KtElement?, ktReceiver: KtElement?,
ktContextReceivers: List<KtElement>,
origin: IrDeclarationOrigin, origin: IrDeclarationOrigin,
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
generateBody: BodyGenerator.() -> IrBody? generateBody: BodyGenerator.() -> IrBody?
): IrSimpleFunction = ): IrSimpleFunction =
declareSimpleFunctionInner(descriptor, ktFunction, origin).buildWithScope { irFunction -> declareSimpleFunctionInner(descriptor, ktFunction, origin).buildWithScope { irFunction ->
generateFunctionParameterDeclarationsAndReturnType(irFunction, ktFunction, ktReceiver) generateFunctionParameterDeclarationsAndReturnType(irFunction, ktFunction, ktReceiver, ktContextReceivers)
irFunction.body = createBodyGenerator(irFunction.symbol).generateBody() irFunction.body = createBodyGenerator(irFunction.symbol).generateBody()
} }
@@ -102,11 +105,12 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
fun generateFunctionParameterDeclarationsAndReturnType( fun generateFunctionParameterDeclarationsAndReturnType(
irFunction: IrFunction, irFunction: IrFunction,
ktParameterOwner: KtPureElement?, ktParameterOwner: KtPureElement?,
ktReceiverParameterElement: KtElement? ktReceiverParameterElement: KtElement?,
ktContextReceiverParametersElements: List<KtElement>
) { ) {
declarationGenerator.generateScopedTypeParameterDeclarations(irFunction, irFunction.descriptor.propertyIfAccessor.typeParameters) declarationGenerator.generateScopedTypeParameterDeclarations(irFunction, irFunction.descriptor.propertyIfAccessor.typeParameters)
irFunction.returnType = irFunction.descriptor.returnType!!.toIrType() irFunction.returnType = irFunction.descriptor.returnType!!.toIrType()
generateValueParameterDeclarations(irFunction, ktParameterOwner, ktReceiverParameterElement) generateValueParameterDeclarations(irFunction, ktParameterOwner, ktReceiverParameterElement, ktContextReceiverParametersElements)
} }
fun generatePropertyAccessor( fun generatePropertyAccessor(
@@ -121,7 +125,10 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
).buildWithScope { irAccessor -> ).buildWithScope { irAccessor ->
declarationGenerator.generateScopedTypeParameterDeclarations(irAccessor, descriptor.correspondingProperty.typeParameters) declarationGenerator.generateScopedTypeParameterDeclarations(irAccessor, descriptor.correspondingProperty.typeParameters)
irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType() irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType()
generateValueParameterDeclarations(irAccessor, ktAccessor ?: ktProperty, ktProperty.receiverTypeReference) generateValueParameterDeclarations(
irAccessor, ktAccessor ?: ktProperty, ktProperty.receiverTypeReference,
ktProperty.contextReceiverTypeReferences
)
val ktBodyExpression = ktAccessor?.bodyExpression val ktBodyExpression = ktAccessor?.bodyExpression
irAccessor.body = irAccessor.body =
if (ktBodyExpression != null) if (ktBodyExpression != null)
@@ -272,7 +279,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
metadata = DescriptorMetadataSource.Function(it.descriptor) metadata = DescriptorMetadataSource.Function(it.descriptor)
} }
}.buildWithScope { irConstructor -> }.buildWithScope { irConstructor ->
generateValueParameterDeclarations(irConstructor, ktParametersElement, null) generateValueParameterDeclarations(irConstructor, ktParametersElement, null, emptyList())
irConstructor.body = createBodyGenerator(irConstructor.symbol).generateBody() irConstructor.body = createBodyGenerator(irConstructor.symbol).generateBody()
irConstructor.returnType = constructorDescriptor.returnType.toIrType() irConstructor.returnType = constructorDescriptor.returnType.toIrType()
} }
@@ -286,13 +293,14 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
else else
descriptor.typeParameters descriptor.typeParameters
declarationGenerator.generateScopedTypeParameterDeclarations(irFunction, typeParameters) declarationGenerator.generateScopedTypeParameterDeclarations(irFunction, typeParameters)
generateValueParameterDeclarations(irFunction, null, null, withDefaultValues = false) generateValueParameterDeclarations(irFunction, null, null, emptyList(), withDefaultValues = false)
} }
private fun generateValueParameterDeclarations( private fun generateValueParameterDeclarations(
irFunction: IrFunction, irFunction: IrFunction,
ktParameterOwner: KtPureElement?, ktParameterOwner: KtPureElement?,
ktReceiverParameterElement: KtPureElement?, ktReceiverParameterElement: KtPureElement?,
ktContextReceiverParameterElements: List<KtPureElement>,
withDefaultValues: Boolean = true withDefaultValues: Boolean = true
) { ) {
val functionDescriptor = irFunction.descriptor val functionDescriptor = irFunction.descriptor
@@ -307,10 +315,16 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
val bodyGenerator = createBodyGenerator(irFunction.symbol) 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. // 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 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 // 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: // 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() }, // fun f(f1: () -> String = { f2() },
// f2: () -> String) = f1() // f2: () -> String) = f1()
if (withDefaultValues) { if (withDefaultValues) {
irFunction.valueParameters.forEachIndexed { index, irValueParameter -> irFunction.valueParameters.drop(contextReceiversNumber).forEachIndexed { index, irValueParameter ->
val valueParameterDescriptor = functionDescriptor.valueParameters[index] val valueParameterDescriptor = functionDescriptor.valueParameters[index]
val ktParameter = DescriptorToSourceUtils.getSourceFromDescriptor(valueParameterDescriptor) as? KtParameter val ktParameter = DescriptorToSourceUtils.getSourceFromDescriptor(valueParameterDescriptor) as? KtParameter
irValueParameter.defaultValue = ktParameter?.defaultValue?.let { defaultValue -> irValueParameter.defaultValue = ktParameter?.defaultValue?.let { defaultValue ->
@@ -376,7 +390,8 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
descriptor: ParameterDescriptor, descriptor: ParameterDescriptor,
ktElement: KtPureElement?, ktElement: KtPureElement?,
irOwnerElement: IrElement, irOwnerElement: IrElement,
name: Name? = null name: Name? = null,
index: Int? = null
): IrValueParameter { ): IrValueParameter {
var origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED var origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
if (ktElement is KtParameter) { if (ktElement is KtParameter) {
@@ -392,7 +407,8 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
origin, origin,
descriptor, descriptor.type.toIrType(), descriptor, descriptor.type.toIrType(),
(descriptor as? ValueParameterDescriptor)?.varargElementType?.toIrType(), (descriptor as? ValueParameterDescriptor)?.varargElementType?.toIrType(),
name name,
index
) )
} }
@@ -80,10 +80,11 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
return statementGenerator.generateCallReceiver( return statementGenerator.generateCallReceiver(
ktCallableReference, ktCallableReference,
resolvedDescriptor, resolvedDescriptor, resolvedCall.dispatchReceiver,
resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, resolvedCall.extensionReceiver,
resolvedCall.contextReceivers,
isSafe = false isSafe = false
).call { dispatchReceiverValue, extensionReceiverValue -> ).call { dispatchReceiverValue, extensionReceiverValue, _ ->
generateCallableReference( generateCallableReference(
ktCallableReference, ktCallableReference,
callableReferenceType, callableReferenceType,
@@ -150,10 +151,11 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
val resolvedCall = callBuilder.original val resolvedCall = callBuilder.original
return statementGenerator.generateCallReceiver( return statementGenerator.generateCallReceiver(
ktCallableReference, ktCallableReference,
resolvedCall.resultingDescriptor, resolvedCall.resultingDescriptor, resolvedCall.dispatchReceiver,
resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, resolvedCall.extensionReceiver,
resolvedCall.contextReceivers,
isSafe = false isSafe = false
).call { dispatchReceiverValue, extensionReceiverValue -> ).call { dispatchReceiverValue, extensionReceiverValue, _ ->
val irDispatchReceiver = dispatchReceiverValue?.loadIfExists() val irDispatchReceiver = dispatchReceiverValue?.loadIfExists()
val irExtensionReceiver = extensionReceiverValue?.loadIfExists() val irExtensionReceiver = extensionReceiverValue?.loadIfExists()
check(irDispatchReceiver == null || irExtensionReceiver == null) { check(irDispatchReceiver == null || irExtensionReceiver == null) {
@@ -84,11 +84,11 @@ val CallBuilder.explicitReceiverType: KotlinType?
fun CallBuilder.setExplicitReceiverValue(explicitReceiverValue: IntermediateValue) { fun CallBuilder.setExplicitReceiverValue(explicitReceiverValue: IntermediateValue) {
val previousCallReceiver = callReceiver val previousCallReceiver = callReceiver
callReceiver = object : CallReceiver { callReceiver = object : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List<IntermediateValue>) -> IrExpression): IrExpression {
return previousCallReceiver.call { dispatchReceiverValue, _ -> return previousCallReceiver.call { dispatchReceiverValue, _, contextReceiverValues ->
val newDispatchReceiverValue = if (hasExtensionReceiver) dispatchReceiverValue else explicitReceiverValue val newDispatchReceiverValue = if (hasExtensionReceiver) dispatchReceiverValue else explicitReceiverValue
val newExtensionReceiverValue = if (hasExtensionReceiver) explicitReceiverValue else null val newExtensionReceiverValue = if (hasExtensionReceiver) explicitReceiverValue else null
withDispatchAndExtensionReceivers(newDispatchReceiverValue, newExtensionReceiverValue) withDispatchAndExtensionAndContextReceivers(newDispatchReceiverValue, newExtensionReceiverValue, contextReceiverValues)
} }
} }
} }
@@ -24,7 +24,7 @@ class DynamicMemberLValue(
) : LValue, AssignmentReceiver { ) : LValue, AssignmentReceiver {
override fun load(): IrExpression = override fun load(): IrExpression =
receiver.call { dispatchReceiverValue, extensionReceiverValue -> receiver.call { dispatchReceiverValue, extensionReceiverValue, _ ->
val dynamicReceiver = getDynamicReceiver(dispatchReceiverValue, extensionReceiverValue) val dynamicReceiver = getDynamicReceiver(dispatchReceiverValue, extensionReceiverValue)
IrDynamicMemberExpressionImpl( IrDynamicMemberExpressionImpl(
@@ -36,7 +36,7 @@ class DynamicMemberLValue(
} }
override fun store(irExpression: IrExpression): IrExpression = override fun store(irExpression: IrExpression): IrExpression =
receiver.call { dispatchReceiverValue, extensionReceiverValue -> receiver.call { dispatchReceiverValue, extensionReceiverValue, _ ->
val dynamicReceiver = getDynamicReceiver(dispatchReceiverValue, extensionReceiverValue) val dynamicReceiver = getDynamicReceiver(dispatchReceiverValue, extensionReceiverValue)
IrDynamicOperatorExpressionImpl( IrDynamicOperatorExpressionImpl(
@@ -55,11 +55,11 @@ class DynamicMemberLValue(
} }
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression = override fun assign(withLValue: (LValue) -> IrExpression): IrExpression =
receiver.call { dispatchReceiverValue, extensionReceiverValue -> receiver.call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues ->
withLValue( withLValue(
DynamicMemberLValue( DynamicMemberLValue(
context, startOffset, endOffset, type, memberName, context, startOffset, endOffset, type, memberName,
SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue) SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue, contextReceiverValues)
) )
) )
} }
@@ -24,7 +24,7 @@ class ExtensionInvokeCallReceiver(
private val extensionInvokeReceiver: IntermediateValue private val extensionInvokeReceiver: IntermediateValue
) : CallReceiver { ) : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List<IntermediateValue>) -> IrExpression): IrExpression {
// extensionInvokeReceiver is actually a first argument: // extensionInvokeReceiver is actually a first argument:
// receiver.extFun(p1, ..., pN) // 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]}" "Extension 'invoke' call should have null as its 1st value argument, got: ${callBuilder.irValueArgumentsByIndex[0]}"
} }
callBuilder.irValueArgumentsByIndex[0] = extensionInvokeReceiver.load() callBuilder.irValueArgumentsByIndex[0] = extensionInvokeReceiver.load()
return withDispatchAndExtensionReceivers(functionReceiver, null) return withDispatchAndExtensionAndContextReceivers(functionReceiver, null, emptyList())
} }
} }
@@ -27,8 +27,8 @@ fun IrVariable.loadAt(startOffset: Int, endOffset: Int): IrExpression =
fun CallReceiver.adjustForCallee(callee: CallableMemberDescriptor): CallReceiver = fun CallReceiver.adjustForCallee(callee: CallableMemberDescriptor): CallReceiver =
object : CallReceiver { object : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression = override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List<IntermediateValue>) -> IrExpression): IrExpression =
this@adjustForCallee.call { dispatchReceiverValue, extensionReceiverValue -> this@adjustForCallee.call { dispatchReceiverValue, extensionReceiverValue, contextReceiverValues ->
val numReceiversPresent = listOfNotNull(dispatchReceiverValue, extensionReceiverValue).size val numReceiversPresent = listOfNotNull(dispatchReceiverValue, extensionReceiverValue).size
val numReceiversExpected = listOfNotNull(callee.dispatchReceiverParameter, callee.extensionReceiverParameter).size val numReceiversExpected = listOfNotNull(callee.dispatchReceiverParameter, callee.extensionReceiverParameter).size
if (numReceiversPresent != numReceiversExpected) if (numReceiversPresent != numReceiversExpected)
@@ -46,7 +46,8 @@ fun CallReceiver.adjustForCallee(callee: CallableMemberDescriptor): CallReceiver
dispatchReceiverValue != null && callee.dispatchReceiverParameter == null -> dispatchReceiverValue dispatchReceiverValue != null && callee.dispatchReceiverParameter == null -> dispatchReceiverValue
else -> extensionReceiverValue else -> extensionReceiverValue
} }
withDispatchAndExtensionReceivers(newDispatchReceiverValue, newExtensionReceiverValue) // TODO: Create new context receiver values
withDispatchAndExtensionAndContextReceivers(newDispatchReceiverValue, newExtensionReceiverValue, contextReceiverValues)
} }
} }
@@ -40,7 +40,7 @@ abstract class PropertyLValueBase(
val superQualifier: IrClassSymbol? val superQualifier: IrClassSymbol?
) : LValue, AssignmentReceiver { ) : LValue, AssignmentReceiver {
override fun assign(withLValue: (LValue) -> IrExpression) = override fun assign(withLValue: (LValue) -> IrExpression) =
callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> callReceiver.call { dispatchReceiverValue, extensionReceiverValue, _ ->
val dispatchReceiverVariable2 = dispatchReceiverValue?.let { val dispatchReceiverVariable2 = dispatchReceiverValue?.let {
scope.createTemporaryVariable(dispatchReceiverValue.load(), "this") scope.createTemporaryVariable(dispatchReceiverValue.load(), "this")
} }
@@ -81,7 +81,8 @@ class FieldPropertyLValue(
PropertyLValueBase(context, scope, startOffset, endOffset, origin, type, callReceiver, superQualifier) { PropertyLValueBase(context, scope, startOffset, endOffset, origin, type, callReceiver, superQualifier) {
override fun load(): IrExpression = 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}" } assert(extensionReceiverValue == null) { "Field can't have an extension receiver: ${field.descriptor}" }
IrGetFieldImpl( IrGetFieldImpl(
startOffset, endOffset, startOffset, endOffset,
@@ -94,7 +95,8 @@ class FieldPropertyLValue(
} }
override fun store(irExpression: IrExpression) = 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}" } assert(extensionReceiverValue == null) { "Field can't have an extension receiver: ${field.descriptor}" }
IrSetFieldImpl( IrSetFieldImpl(
startOffset, endOffset, startOffset, endOffset,
@@ -114,7 +116,7 @@ class FieldPropertyLValue(
field, field,
descriptor, descriptor,
type, type,
SimpleCallReceiver(dispatchReceiver, extensionReceiver), SimpleCallReceiver(dispatchReceiver, extensionReceiver, emptyList()),
superQualifier superQualifier
) )
} }
@@ -144,7 +146,8 @@ class AccessorPropertyLValue(
} }
override fun load(): IrExpression = override fun load(): IrExpression =
callReceiver.adjustForCallee(getterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue -> // TODO: Use context receiver values
callReceiver.adjustForCallee(getterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue, _ ->
IrCallImpl( IrCallImpl(
startOffset, endOffset, startOffset, endOffset,
type, type,
@@ -161,7 +164,8 @@ class AccessorPropertyLValue(
} }
override fun store(irExpression: IrExpression) = override fun store(irExpression: IrExpression) =
callReceiver.adjustForCallee(setterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue -> // TODO: Use context receiver values
callReceiver.adjustForCallee(setterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue, _ ->
IrCallImpl( IrCallImpl(
startOffset, endOffset, startOffset, endOffset,
context.irBuiltIns.unitType, context.irBuiltIns.unitType,
@@ -184,7 +188,7 @@ class AccessorPropertyLValue(
startOffset, endOffset, origin, startOffset, endOffset, origin,
type, getter, getterDescriptor, setter, setterDescriptor, type, getter, getterDescriptor, setter, setterDescriptor,
typeArguments, typeArguments,
SimpleCallReceiver(dispatchReceiver, extensionReceiver), SimpleCallReceiver(dispatchReceiver, extensionReceiver, emptyList()),
superQualifier superQualifier
) )
} }
@@ -31,11 +31,13 @@ class SafeCallReceiver(
val startOffset: Int, val startOffset: Int,
val endOffset: Int, val endOffset: Int,
val extensionReceiver: IntermediateValue?, val extensionReceiver: IntermediateValue?,
// TODO: Use context receivers
val contextReceivers: List<IntermediateValue>,
val dispatchReceiver: IntermediateValue?, val dispatchReceiver: IntermediateValue?,
val isStatement: Boolean val isStatement: Boolean
) : CallReceiver { ) : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List<IntermediateValue>) -> IrExpression): IrExpression {
val irTmp = generator.scope.createTemporaryVariable(extensionReceiver?.load() ?: dispatchReceiver!!.load(), "safe_receiver") val irTmp = generator.scope.createTemporaryVariable(extensionReceiver?.load() ?: dispatchReceiver!!.load(), "safe_receiver")
val safeReceiverValue = VariableLValue(generator.context, irTmp) val safeReceiverValue = VariableLValue(generator.context, irTmp)
@@ -49,7 +51,7 @@ class SafeCallReceiver(
extensionReceiverValue = null 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() val resultType = if (isStatement) generator.context.irBuiltIns.unitType else irResult.type.makeNullable()
@@ -77,8 +79,9 @@ fun IrExpression.safeCallOnDispatchReceiver(
SafeCallReceiver( SafeCallReceiver(
generator, startOffset, endOffset, generator, startOffset, endOffset,
extensionReceiver = null, extensionReceiver = null,
contextReceivers = emptyList(),
dispatchReceiver = OnceExpressionValue(this), dispatchReceiver = OnceExpressionValue(this),
isStatement = false isStatement = false
).call { dispatchReceiverValue, _ -> ).call { dispatchReceiverValue, _, _ ->
ifNotNull(dispatchReceiverValue!!.load()) ifNotNull(dispatchReceiverValue!!.load())
} }
@@ -33,7 +33,7 @@ class SafeExtensionInvokeCallReceiver(
val extensionInvokeReceiver: IntermediateValue val extensionInvokeReceiver: IntermediateValue
) : CallReceiver { ) : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List<IntermediateValue>) -> IrExpression): IrExpression {
// extensionInvokeReceiver is actually a first argument: // extensionInvokeReceiver is actually a first argument:
// receiver?.extFun(p1, ..., pN) // 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]}" "Safe extension 'invoke' call should have null as its 1st value argument, got: ${callBuilder.irValueArgumentsByIndex[0]}"
} }
callBuilder.irValueArgumentsByIndex[0] = safeReceiverValue.load() callBuilder.irValueArgumentsByIndex[0] = safeReceiverValue.load()
val irResult = withDispatchAndExtensionReceivers(functionReceiver, null) val irResult = withDispatchAndExtensionAndContextReceivers(functionReceiver, null, emptyList())
val resultType = irResult.type.makeNullable() val resultType = irResult.type.makeNullable()
@@ -20,10 +20,11 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
class SimpleCallReceiver( class SimpleCallReceiver(
private val dispatchReceiverValue: IntermediateValue?, private val dispatchReceiverValue: IntermediateValue?,
private val extensionReceiverValue: IntermediateValue? private val extensionReceiverValue: IntermediateValue?,
private val contextReceiverValues: List<IntermediateValue>
) : CallReceiver { ) : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List<IntermediateValue>) -> IrExpression): IrExpression {
return withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue) return withDispatchAndExtensionAndContextReceivers(dispatchReceiverValue, extensionReceiverValue, contextReceiverValues)
} }
} }
@@ -36,5 +36,5 @@ interface AssignmentReceiver {
} }
interface CallReceiver { interface CallReceiver {
fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List<IntermediateValue>) -> IrExpression): IrExpression
} }
@@ -54,7 +54,7 @@ class IrCallImpl(
type: IrType, type: IrType,
symbol: IrSimpleFunctionSymbol, symbol: IrSimpleFunctionSymbol,
typeArgumentsCount: Int = symbol.descriptor.typeParametersCount, typeArgumentsCount: Int = symbol.descriptor.typeParametersCount,
valueArgumentsCount: Int = symbol.descriptor.valueParameters.size, valueArgumentsCount: Int = symbol.descriptor.valueParameters.size + symbol.descriptor.contextReceiverParameters.size,
origin: IrStatementOrigin? = null, origin: IrStatementOrigin? = null,
superQualifierSymbol: IrClassSymbol? = null, superQualifierSymbol: IrClassSymbol? = null,
) = ) =
@@ -933,11 +933,12 @@ open class SymbolTable(
type: IrType, type: IrType,
varargElementType: IrType? = null, varargElementType: IrType? = null,
name: Name? = null, name: Name? = null,
index: Int? = null,
isAssignable: Boolean = false, isAssignable: Boolean = false,
valueParameterFactory: (IrValueParameterSymbol) -> IrValueParameter = { valueParameterFactory: (IrValueParameterSymbol) -> IrValueParameter = {
irFactory.createValueParameter( irFactory.createValueParameter(
startOffset, endOffset, origin, it, name ?: nameProvider.nameForDeclaration(descriptor), 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 isHidden = false, isAssignable = isAssignable
) )
} }
@@ -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"
}
}
@@ -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<out Number>) {
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"
}
}
@@ -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())
}
@@ -16029,6 +16029,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
public void testWhenFail() throws Exception { public void testWhenFail() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); 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 @Nested
@@ -16107,6 +16107,34 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testWhenFail() throws Exception { public void testWhenFail() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); 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 @Nested
@@ -13192,6 +13192,19 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
public void testWhenFail() throws Exception { public void testWhenFail() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); 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") @TestMetadata("compiler/testData/codegen/box/extensionProperties")
@@ -14778,6 +14778,19 @@ public class VisualizerBlackBoxTestGenerated extends AbstractVisualizerBlackBoxT
public void testWhenFail() throws Exception { public void testWhenFail() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); 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 @Nested
@@ -12443,6 +12443,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
public void testWhenFail() throws Exception { public void testWhenFail() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); 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 @Nested
@@ -12485,6 +12485,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
public void testWhenFail() throws Exception { public void testWhenFail() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); 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 @Nested
@@ -10359,6 +10359,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
public void testWhenFail() throws Exception { public void testWhenFail() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/whenFail.kt"); 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") @TestMetadata("compiler/testData/codegen/box/extensionProperties")