[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 {
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
@@ -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<ReceiverValue>,
isSafe: Boolean,
isAssignmentReceiver: Boolean = false
): CallReceiver {
val dispatchReceiverValue: IntermediateValue?
val extensionReceiverValue: IntermediateValue?
val contextReceiverValues: List<IntermediateValue>
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()
)
@@ -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
)
@@ -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>
): 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
}
@@ -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)
}
@@ -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)
}
)
@@ -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<KtElement>,
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<KtElement>
) {
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<KtPureElement>,
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
)
}
@@ -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) {
@@ -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<IntermediateValue>) -> 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)
}
}
}
@@ -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)
)
)
}
@@ -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<IntermediateValue>) -> 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())
}
}
@@ -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<IntermediateValue>) -> 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)
}
}
@@ -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
)
}
@@ -31,11 +31,13 @@ class SafeCallReceiver(
val startOffset: Int,
val endOffset: Int,
val extensionReceiver: IntermediateValue?,
// TODO: Use context receivers
val contextReceivers: List<IntermediateValue>,
val dispatchReceiver: IntermediateValue?,
val isStatement: Boolean
) : 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 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())
}
@@ -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<IntermediateValue>) -> 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()
@@ -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<IntermediateValue>
) : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression {
return withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue)
override fun call(withDispatchAndExtensionAndContextReceivers: (IntermediateValue?, IntermediateValue?, List<IntermediateValue>) -> IrExpression): IrExpression {
return withDispatchAndExtensionAndContextReceivers(dispatchReceiverValue, extensionReceiverValue, contextReceiverValues)
}
}
@@ -36,5 +36,5 @@ interface AssignmentReceiver {
}
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,
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,
) =
@@ -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
)
}
@@ -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 {
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
@@ -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
@@ -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")
@@ -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
@@ -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
@@ -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
@@ -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")