[BE] Put context receivers before an extension receiver
This commit is contained in:
committed by
TeamCityServer
parent
814777ba8c
commit
a2403c470f
@@ -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)
|
||||||
|
|||||||
+6
@@ -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 {
|
||||||
|
|||||||
+1
@@ -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,
|
||||||
|
|||||||
+12
-8
@@ -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)
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -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
|
||||||
|
|||||||
+8
-1
@@ -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) }
|
||||||
|
|
||||||
|
|||||||
+2
@@ -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)
|
||||||
|
|||||||
Vendored
+13
@@ -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()
|
||||||
|
}
|
||||||
+6
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user