[BE] Put context receivers before an extension receiver

This commit is contained in:
Anastasiya Shadrina
2021-06-28 18:09:52 +07:00
committed by TeamCityServer
parent 814777ba8c
commit a2403c470f
15 changed files with 70 additions and 14 deletions
@@ -529,6 +529,7 @@ public class FunctionCodegen {
} }
ParameterDescriptor annotated = ParameterDescriptor annotated =
// TODO: Generate annotations for context receivers
kind == JvmMethodParameterKind.VALUE kind == JvmMethodParameterKind.VALUE
? iterator.next() ? iterator.next()
: kind == JvmMethodParameterKind.RECEIVER : kind == JvmMethodParameterKind.RECEIVER
@@ -806,6 +807,7 @@ public class FunctionCodegen {
: nameForDestructuredParameter; : nameForDestructuredParameter;
break; break;
case RECEIVER: case RECEIVER:
case CONTEXT_RECEIVER:
parameterName = DescriptorAsmUtil.getNameForReceiverParameter( parameterName = DescriptorAsmUtil.getNameForReceiverParameter(
functionDescriptor, typeMapper.getBindingContext(), state.getLanguageVersionSettings()); functionDescriptor, typeMapper.getBindingContext(), state.getLanguageVersionSettings());
break; break;
@@ -1330,7 +1332,7 @@ public class FunctionCodegen {
} }
for (JvmMethodParameterSignature parameter : signature.getValueParameters()) { for (JvmMethodParameterSignature parameter : signature.getValueParameters()) {
if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) { if (parameter.getKind() == JvmMethodParameterKind.RECEIVER || parameter.getKind() == JvmMethodParameterKind.CONTEXT_RECEIVER) {
if (extensionReceiverParameter != null) { if (extensionReceiverParameter != null) {
frameMap.enter(extensionReceiverParameter, state.getTypeMapper().mapType(extensionReceiverParameter)); frameMap.enter(extensionReceiverParameter, state.getTypeMapper().mapType(extensionReceiverParameter));
} }
@@ -1888,7 +1888,7 @@ public abstract class StackValue {
if (kind == JvmMethodParameterKind.VALUE) { if (kind == JvmMethodParameterKind.VALUE) {
break; break;
} }
if (kind == JvmMethodParameterKind.RECEIVER || kind == JvmMethodParameterKind.THIS) { if (kind == JvmMethodParameterKind.CONTEXT_RECEIVER || kind == JvmMethodParameterKind.RECEIVER || kind == JvmMethodParameterKind.THIS) {
return false; return false;
} }
} }
@@ -46,7 +46,8 @@ fun generateParameterNames(
isEnumName = !isEnumName isEnumName = !isEnumName
if (!isEnumName) "\$enum\$name" else "\$enum\$ordinal" if (!isEnumName) "\$enum\$name" else "\$enum\$ordinal"
} }
JvmMethodParameterKind.RECEIVER -> { JvmMethodParameterKind.RECEIVER,
JvmMethodParameterKind.CONTEXT_RECEIVER -> {
DescriptorAsmUtil.getNameForReceiverParameter(functionDescriptor, state.bindingContext, state.languageVersionSettings) DescriptorAsmUtil.getNameForReceiverParameter(functionDescriptor, state.bindingContext, state.languageVersionSettings)
} }
JvmMethodParameterKind.OUTER -> AsmUtil.CAPTURED_THIS_FIELD JvmMethodParameterKind.OUTER -> AsmUtil.CAPTURED_THIS_FIELD
@@ -67,7 +68,7 @@ fun generateParameterNames(
// declared implicitly in source code (§8.8.1, §8.8.9, §8.9.3, §15.9.5.1). // declared implicitly in source code (§8.8.1, §8.8.9, §8.9.3, §15.9.5.1).
val access = when (kind) { val access = when (kind) {
JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL -> Opcodes.ACC_SYNTHETIC JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL -> Opcodes.ACC_SYNTHETIC
JvmMethodParameterKind.RECEIVER -> Opcodes.ACC_MANDATED JvmMethodParameterKind.RECEIVER, JvmMethodParameterKind.CONTEXT_RECEIVER -> Opcodes.ACC_MANDATED
JvmMethodParameterKind.OUTER -> Opcodes.ACC_MANDATED JvmMethodParameterKind.OUTER -> Opcodes.ACC_MANDATED
JvmMethodParameterKind.VALUE -> 0 JvmMethodParameterKind.VALUE -> 0
@@ -894,6 +894,10 @@ class KotlinTypeMapper @JvmOverloads constructor(
writeParameter(sw, JvmMethodParameterKind.THIS, thisIfNeeded, f) writeParameter(sw, JvmMethodParameterKind.THIS, thisIfNeeded, f)
} }
for (contextReceiverParameter in f.contextReceiverParameters) {
writeParameter(sw, JvmMethodParameterKind.CONTEXT_RECEIVER, contextReceiverParameter.type, f)
}
val receiverParameter = f.extensionReceiverParameter val receiverParameter = f.extensionReceiverParameter
if (receiverParameter != null) { if (receiverParameter != null) {
writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, f) writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, f)
@@ -16157,6 +16157,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
} }
@Test
@TestMetadata("contextAndExtensionSameName.kt")
public void testContextAndExtensionSameName() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/contextAndExtensionSameName.kt");
}
@Test @Test
@TestMetadata("dp.kt") @TestMetadata("dp.kt")
public void testDp() throws Exception { public void testDp() throws Exception {
@@ -21,6 +21,7 @@ public enum JvmMethodParameterKind {
THIS, THIS,
OUTER, OUTER,
RECEIVER, RECEIVER,
CONTEXT_RECEIVER,
CAPTURED_LOCAL_VARIABLE, CAPTURED_LOCAL_VARIABLE,
ENUM_NAME_OR_ORDINAL, ENUM_NAME_OR_ORDINAL,
SUPER_CALL_PARAM, SUPER_CALL_PARAM,
@@ -479,6 +479,16 @@ class ExpressionCodegen(
callGenerator.genValueAndPut(callee.dispatchReceiverParameter!!, receiver, type, this, data) callGenerator.genValueAndPut(callee.dispatchReceiverParameter!!, receiver, type, this, data)
} }
fun handleValueParameter(i: Int, irParameter: IrValueParameter) {
val arg = expression.getValueArgument(i)
val parameterType = callable.valueParameterTypes[i]
require(arg != null) { "Null argument in ExpressionCodegen for parameter ${irParameter.render()}" }
callGenerator.genValueAndPut(irParameter, arg, parameterType, this, data)
}
val contextReceivers = callee.valueParameters.subList(0, callee.contextReceiverParametersCount)
contextReceivers.forEachIndexed(::handleValueParameter)
expression.extensionReceiver?.let { receiver -> expression.extensionReceiver?.let { receiver ->
val type = callable.signature.valueParameters.singleOrNull { it.kind == JvmMethodParameterKind.RECEIVER }?.asmType val type = callable.signature.valueParameters.singleOrNull { it.kind == JvmMethodParameterKind.RECEIVER }?.asmType
?: error("No single extension receiver parameter: ${callable.signature.valueParameters}") ?: error("No single extension receiver parameter: ${callable.signature.valueParameters}")
@@ -486,14 +496,8 @@ class ExpressionCodegen(
} }
callGenerator.beforeValueParametersStart() callGenerator.beforeValueParametersStart()
expression.symbol.owner.valueParameters.forEachIndexed { i, irParameter -> callee.valueParameters.subList(callee.contextReceiverParametersCount, callee.valueParameters.size)
val arg = expression.getValueArgument(i) .forEachIndexed { i, valueParameter -> handleValueParameter(i + contextReceivers.size, valueParameter) }
val parameterType = callable.valueParameterTypes[i]
require(arg != null) {
"Null argument in ExpressionCodegen for parameter ${irParameter.render()}"
}
callGenerator.genValueAndPut(irParameter, arg, parameterType, this, data)
}
expression.markLineNumber(true) expression.markLineNumber(true)
@@ -253,10 +253,15 @@ class FunctionCodegen(private val irFunction: IrFunction, private val classCodeg
receiver?.let { receiver?.let {
frameMap.enter(it, context.typeMapper.mapTypeAsDeclaration(it.type)) frameMap.enter(it, context.typeMapper.mapTypeAsDeclaration(it.type))
} }
val contextReceivers = valueParameters.subList(0, contextReceiverParametersCount)
for (contextReceiver in contextReceivers) {
frameMap.enter(contextReceiver, context.typeMapper.mapType(contextReceiver.type))
}
extensionReceiverParameter?.let { extensionReceiverParameter?.let {
frameMap.enter(it, context.typeMapper.mapType(it)) frameMap.enter(it, context.typeMapper.mapType(it))
} }
for (parameter in valueParameters) { val regularParameters = valueParameters.subList(contextReceiverParametersCount, valueParameters.size)
for (parameter in regularParameters) {
frameMap.enter(parameter, context.typeMapper.mapType(parameter.type)) frameMap.enter(parameter, context.typeMapper.mapType(parameter.type))
} }
return frameMap return frameMap
@@ -241,12 +241,19 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
sw.writeParametersStart() sw.writeParametersStart()
val contextReceivers = function.valueParameters.subList(0, function.contextReceiverParametersCount)
for (contextReceiver in contextReceivers) {
writeParameter(sw, JvmMethodParameterKind.CONTEXT_RECEIVER, contextReceiver.type, function)
}
val receiverParameter = function.extensionReceiverParameter val receiverParameter = function.extensionReceiverParameter
if (receiverParameter != null) { if (receiverParameter != null) {
writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function) writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function)
} }
for (parameter in function.valueParameters) { val regularValueParameters =
function.valueParameters.subList(function.contextReceiverParametersCount, function.valueParameters.size)
for (parameter in regularValueParameters) {
val kind = when (parameter.origin) { val kind = when (parameter.origin) {
JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> JvmMethodParameterKind.OUTER JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> JvmMethodParameterKind.OUTER
JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER -> JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER -> JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL
@@ -251,6 +251,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
dispatchReceiver = dispatchReceiverValue?.load() dispatchReceiver = dispatchReceiverValue?.load()
extensionReceiver = extensionReceiverValue?.load() extensionReceiver = extensionReceiverValue?.load()
val contextReceivers = contextReceiverValues.map { it.load() } val contextReceivers = contextReceiverValues.map { it.load() }
contextReceiversCount = contextReceivers.size
addParametersToCall(startOffset, endOffset, call, this, irType, contextReceivers) addParametersToCall(startOffset, endOffset, call, this, irType, contextReceivers)
} }
} }
@@ -376,6 +377,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
dispatchReceiver = dispatchReceiverValue?.load() dispatchReceiver = dispatchReceiverValue?.load()
extensionReceiver = extensionReceiverValue?.load() extensionReceiver = extensionReceiverValue?.load()
val contextReceivers = contextReceiverValues.map { it.load() } val contextReceivers = contextReceiverValues.map { it.load() }
contextReceiversCount = contextReceivers.size
addParametersToCall(startOffset, endOffset, call, this, irType, contextReceivers) addParametersToCall(startOffset, endOffset, call, this, irType, contextReceivers)
} }
} }
@@ -328,6 +328,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
val contextReceiversNumber = ktContextReceiverParameterElements.size val contextReceiversNumber = ktContextReceiverParameterElements.size
assert(functionDescriptor.contextReceiverParameters.size == contextReceiversNumber) assert(functionDescriptor.contextReceiverParameters.size == contextReceiversNumber)
irFunction.contextReceiverParametersCount = contextReceiversNumber
irFunction.valueParameters += functionDescriptor.contextReceiverParameters.mapIndexed { i, additionalReceiver -> irFunction.valueParameters += functionDescriptor.contextReceiverParameters.mapIndexed { i, additionalReceiver ->
declareParameter(additionalReceiver, ktContextReceiverParameterElements[i], irFunction, null, i) declareParameter(additionalReceiver, ktContextReceiverParameterElements[i], irFunction, null, i)
} }
@@ -48,6 +48,8 @@ abstract class IrFunction :
abstract var body: IrBody? abstract var body: IrBody?
var contextReceiverParametersCount: Int = 0
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) { override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
typeParameters.forEach { it.accept(visitor, data) } typeParameters.forEach { it.accept(visitor, data) }
@@ -19,6 +19,8 @@ abstract class IrFunctionAccessExpression(
final override val valueArgumentsCount: Int final override val valueArgumentsCount: Int
get() = argumentsByParameterIndex.size get() = argumentsByParameterIndex.size
var contextReceiversCount: Int = 0
override fun getValueArgument(index: Int): IrExpression? { override fun getValueArgument(index: Int): IrExpression? {
if (index >= valueArgumentsCount) { if (index >= valueArgumentsCount) {
throwNoSuchArgumentSlotException("value", index, valueArgumentsCount) throwNoSuchArgumentSlotException("value", index, valueArgumentsCount)
@@ -0,0 +1,13 @@
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_FIR: JVM_IR
class A {
val ok = "OK"
context(A)
fun A.f() = ok
}
fun box(): String = with(A()) {
f()
}
@@ -16157,6 +16157,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/extensionFunctions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
} }
@Test
@TestMetadata("contextAndExtensionSameName.kt")
public void testContextAndExtensionSameName() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/contextAndExtensionSameName.kt");
}
@Test @Test
@TestMetadata("dp.kt") @TestMetadata("dp.kt")
public void testDp() throws Exception { public void testDp() throws Exception {