@@ -13,13 +13,19 @@ import org.jetbrains.kotlin.descriptors.ClassKind
1313import org.jetbrains.kotlin.fir.*
1414import org.jetbrains.kotlin.fir.backend.*
1515import org.jetbrains.kotlin.fir.backend.utils.*
16+ import org.jetbrains.kotlin.fir.backend.utils.buildSubstitutorByCalledCallable
1617import org.jetbrains.kotlin.fir.declarations.*
1718import org.jetbrains.kotlin.fir.declarations.utils.*
1819import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
1920import org.jetbrains.kotlin.fir.expressions.*
21+ import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
22+ import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
23+ import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
2024import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
25+ import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
2126import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
2227import org.jetbrains.kotlin.fir.references.*
28+ import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
2329import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
2430import org.jetbrains.kotlin.fir.resolve.*
2531import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
@@ -32,6 +38,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.toConeType
3238import org.jetbrains.kotlin.fir.scopes.impl.typeAliasConstructorInfo
3339import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
3440import org.jetbrains.kotlin.fir.symbols.impl.*
41+ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
3542import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
3643import org.jetbrains.kotlin.fir.types.*
3744import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -222,7 +229,7 @@ class CallAndReferenceGenerator(
222229 val calleeReference = calleeReference as ? FirResolvedNamedReference ? : return null
223230 val fir = calleeReference.resolvedSymbol.fir
224231 if (this is FirFunctionCall && fir is FirNamedFunction && fir.origin == FirDeclarationOrigin .SamConstructor ) {
225- val (_, _, substitutor) = extractArgumentsMapping( this )
232+ val substitutor = buildSubstitutorByCalledCallable( )
226233 val irArgument = convertArgument(argument, fir.valueParameters.first(), substitutor)
227234 return convertWithOffsets { startOffset, endOffset ->
228235 IrTypeOperatorCallImpl (
@@ -425,13 +432,13 @@ class CallAndReferenceGenerator(
425432
426433 if (noArguments || qualifiedAccess !is FirCall ) return @apply
427434
428- val (valueParameters, argumentMapping, substitutor) = extractArgumentsMapping( qualifiedAccess)
429- if (valueParameters == null || argumentMapping == null || ! visitor.annotationMode && argumentMapping.isEmpty()) return @apply
435+ val argumentMapping = qualifiedAccess.resolvedArgumentMapping
436+ if (argumentMapping == null || ! visitor.annotationMode && argumentMapping.isEmpty()) return @apply
430437
431438 val dynamicCallVarargArgument = argumentMapping.keys.firstOrNull() as ? FirVarargArgumentsExpression
432439 ? : error(" Dynamic call must have a single vararg argument: ${qualifiedAccess.render()} " )
433440 for (argument in dynamicCallVarargArgument.arguments) {
434- val irArgument = convertArgument(argument, null , substitutor )
441+ val irArgument = convertArgument(argument, null , ConeSubstitutor . Empty )
435442 arguments.add(irArgument)
436443 }
437444 }
@@ -1019,22 +1026,6 @@ class CallAndReferenceGenerator(
10191026 }
10201027 }
10211028
1022- private fun extractArgumentsMapping (
1023- call : FirCall ,
1024- ): Triple <List <FirValueParameter >? , Map<FirExpression, FirValueParameter>?, ConeSubstitutor> {
1025- val calleeReference = when (call) {
1026- is FirFunctionCall -> call.calleeReference
1027- is FirDelegatedConstructorCall -> call.calleeReference
1028- is FirAnnotationCall -> call.calleeReference
1029- else -> null
1030- }
1031- val function = ((calleeReference as ? FirResolvedNamedReference )?.resolvedSymbol as ? FirFunctionSymbol <* >)?.fir
1032- val valueParameters = function?.valueParameters
1033- val argumentMapping = call.resolvedArgumentMapping
1034- val substitutor = (call as ? FirFunctionCall )?.buildSubstitutorByCalledCallable() ? : ConeSubstitutor .Empty
1035- return Triple (valueParameters, argumentMapping, substitutor)
1036- }
1037-
10381029 private fun convertArgument (
10391030 argument : FirExpression ,
10401031 parameter : FirValueParameter ? ,
@@ -1444,19 +1435,19 @@ class CallAndReferenceGenerator(
14441435 val call = statement as ? FirCall
14451436 return when (this ) {
14461437 is IrMemberAccessExpression <* > -> {
1447- val contextArgumentCount = putContextArguments(statement, receiverInfo)
1448- if (call == null ) return this
1438+ if (call == null ) {
1439+ // Property access has implicit context arguments but no explicit arguments.
1440+ putContextArguments(statement, receiverInfo)
1441+ return this
1442+ }
14491443 val argumentsCount = call.arguments.size
14501444 if (declarationSiteSymbol != null && argumentsCount <= declarationSiteSymbol.valueParametersSize()) {
1451- apply {
1452- val (valueParameters, argumentMapping, substitutor) = extractArgumentsMapping(call)
1453- if (argumentMapping != null && (visitor.annotationMode || argumentMapping.isNotEmpty()) && valueParameters != null ) {
1454- return applyArgumentsWithReorderingIfNeeded(
1455- argumentMapping, valueParameters, substitutor, receiverInfo, contextArgumentCount, call,
1456- )
1457- }
1458- check(argumentsCount == 0 ) { " Non-empty unresolved argument list." }
1445+ applyArgumentsWithReorderingIfNeeded(receiverInfo, call)?.let {
1446+ return it
14591447 }
1448+
1449+ check(argumentsCount == 0 ) { " Non-empty unresolved argument list." }
1450+ this
14601451 } else {
14611452 val calleeSymbol = (this as ? IrCallImpl )?.symbol
14621453
@@ -1486,18 +1477,56 @@ class CallAndReferenceGenerator(
14861477 }
14871478
14881479 private fun IrMemberAccessExpression <* >.applyArgumentsWithReorderingIfNeeded (
1489- argumentMapping : Map <FirExpression , FirValueParameter >,
1490- valueParameters : List <FirValueParameter >,
1491- substitutor : ConeSubstitutor ,
14921480 receiverInfo : ReceiverInfo ,
1493- contextArgumentCount : Int ,
14941481 call : FirCall ,
1495- ): IrExpression {
1496- val converted = convertArguments(argumentMapping, substitutor)
1482+ ): IrExpression ? {
1483+ val function = (call as ? FirResolvable )?.calleeReference?.toResolvedFunctionSymbol()?.fir
1484+ val argumentList = call.argumentList as ? FirResolvedArgumentList
1485+ if (function == null || argumentList == null || ! visitor.annotationMode && argumentList.mappingIncludingContextArguments.isEmpty()) {
1486+ putContextArguments(call, receiverInfo)
1487+ return null
1488+ }
1489+
1490+ val contextParameters = function.contextParameters
1491+ val valueParameters = function.valueParameters
1492+ val substitutor = (call as ? FirFunctionCall )?.buildSubstitutorByCalledCallable() ? : ConeSubstitutor .Empty
1493+ val contextArgumentCount = contextParameters.size
1494+
1495+ data class ArgumentInfo (val parameter : FirValueParameter , val expression : IrExpression , val parameterIndex : Int )
1496+
1497+ // Convert all context and value arguments.
1498+ // It's important to preserve the order of the explicit arguments including explicit context arguments
1499+ // because they can have side effects.
1500+ // Implicit context arguments are also in the list for convenience but their order doesn't matter because they can't have
1501+ // side effects.
1502+ val converted = buildList {
1503+ (call as ? FirContextArgumentListOwner )?.contextArguments?.forEachIndexed { index, contextArgument ->
1504+ // Only convert implicit context arguments here, explicit ones will be converted below to preserve the order.
1505+ if (contextArgument in argumentList.mappingIncludingContextArguments) return @forEachIndexed
1506+ val parameter = contextParameters[index]
1507+ val parameterIndex = receiverInfo.contextArgumentOffset() + index
1508+
1509+ val irExpression = convertArgument(contextArgument, parameter, substitutor)
1510+ add(ArgumentInfo (parameter, irExpression, parameterIndex))
1511+ }
1512+
1513+ argumentList.mappingIncludingContextArguments.entries.forEach { (argument, parameter) ->
1514+ if (! visitor.isGetClassOfUnresolvedTypeInAnnotation(argument)) {
1515+ val parameterIndex = if (parameter.valueParameterKind == FirValueParameterKind .Regular ) {
1516+ receiverInfo.valueArgumentOffset(contextArgumentCount) + valueParameters.indexOf(parameter)
1517+ } else {
1518+ receiverInfo.contextArgumentOffset() + contextParameters.indexOf(parameter)
1519+ }
1520+ val irExpression = convertArgument(argument, parameter, substitutor)
1521+ add(ArgumentInfo (parameter, irExpression, parameterIndex))
1522+ }
1523+ }
1524+ }
1525+
14971526 // If none of the parameters have side effects, the evaluation order doesn't matter anyway.
14981527 // For annotations, this is always true, since arguments have to be compile-time constants.
14991528 if (! visitor.annotationMode && ! converted.all { (_, irArgument) -> irArgument.hasNoSideEffects() } &&
1500- needArgumentReordering(argumentMapping. values, valueParameters)
1529+ needArgumentReordering(argumentList.mappingIncludingContextArguments. values, contextParameters + valueParameters)
15011530 ) {
15021531 return IrBlockImpl (startOffset, endOffset, type, IrStatementOrigin .ARGUMENTS_REORDERING_FOR_CALL ).apply {
15031532 fun IrExpression.freeze (nameHint : String ): IrExpression {
@@ -1507,6 +1536,7 @@ class CallAndReferenceGenerator(
15071536 return IrGetValueImpl (startOffset, endOffset, symbol, null )
15081537 }
15091538
1539+ // Freeze receivers first
15101540 if (receiverInfo.hasDispatchReceiver) {
15111541 arguments[0 ] = arguments[0 ]?.freeze($$" $this " )
15121542 }
@@ -1516,21 +1546,20 @@ class CallAndReferenceGenerator(
15161546 arguments[extensionReceiverIndex] = arguments[extensionReceiverIndex]?.freeze($$" $receiver " )
15171547 }
15181548
1519- val valueArgumentOffset = receiverInfo.valueArgumentOffset(contextArgumentCount)
1520- for ((parameter, irArgument) in converted) {
1521- arguments[valueArgumentOffset + valueParameters.indexOf(parameter) ] = irArgument.freeze(parameter.name.asString())
1549+ // Add and freeze context and value arguments in source order
1550+ for ((parameter, irArgument, parameterIndex ) in converted) {
1551+ arguments[parameterIndex ] = irArgument.freeze(parameter.name.asString())
15221552 }
15231553 statements.add(this @applyArgumentsWithReorderingIfNeeded)
15241554 }
15251555 } else {
1526- val valueArgumentOffset = receiverInfo.valueArgumentOffset(contextArgumentCount)
1527- for ((parameter, irArgument) in converted) {
1528- arguments[valueArgumentOffset + valueParameters.indexOf(parameter)] = irArgument
1556+ for ((_, irArgument, parameterIndex) in converted) {
1557+ arguments[parameterIndex] = irArgument
15291558 }
15301559 if (visitor.annotationMode) {
15311560 val function = call.toReference(session)?.toResolvedCallableSymbol()?.fir as ? FirFunction
15321561 for ((index, parameter) in valueParameters.withIndex()) {
1533- if (parameter.isVararg && ! argumentMapping .containsValue(parameter)) {
1562+ if (parameter.isVararg && ! argumentList.mapping .containsValue(parameter)) {
15341563 val value = if (function?.itOrExpectHasDefaultParameterValue(index) == true ) {
15351564 null
15361565 } else {
@@ -1542,30 +1571,21 @@ class CallAndReferenceGenerator(
15421571 varargType.getArrayElementType(builtins)
15431572 )
15441573 }
1545- arguments[valueArgumentOffset + index] = value
1574+ arguments[receiverInfo. valueArgumentOffset(contextArgumentCount) + index] = value
15461575 }
15471576 }
15481577 }
15491578 return this
15501579 }
15511580 }
15521581
1553- private fun convertArguments (
1554- argumentMapping : Map <FirExpression , FirValueParameter >,
1555- substitutor : ConeSubstitutor ,
1556- ): List <Pair <FirValueParameter , IrExpression >> =
1557- argumentMapping.entries.mapNotNull { (argument, parameter) ->
1558- if (visitor.isGetClassOfUnresolvedTypeInAnnotation(argument)) null
1559- else (parameter to convertArgument(argument, parameter, substitutor))
1560- }
1561-
15621582 private fun needArgumentReordering (
1563- parametersInActualOrder : Collection <FirValueParameter >,
1564- valueParameters : List <FirValueParameter >,
1583+ parametersInArgumentOrder : Collection <FirValueParameter >,
1584+ contextAndValueParameters : List <FirValueParameter >,
15651585 ): Boolean {
15661586 var lastValueParameterIndex = UNDEFINED_PARAMETER_INDEX
1567- for (parameter in parametersInActualOrder ) {
1568- val index = valueParameters .indexOf(parameter)
1587+ for (parameter in parametersInArgumentOrder ) {
1588+ val index = contextAndValueParameters .indexOf(parameter)
15691589 if (index < lastValueParameterIndex) {
15701590 return true
15711591 }
0 commit comments