[FIR] Fix arguments mapping for indexed set operator

Now processPositionArgument changes STATE as well as processNamedArgument

^KT-59386
This commit is contained in:
Ivan Kochurkin
2023-07-12 22:50:26 +02:00
committed by Space Team
parent 8f5294a508
commit 43c66ee0e5
4 changed files with 38 additions and 32 deletions
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.utils.isOperator import org.jetbrains.kotlin.fir.declarations.utils.isOperator
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildNamedArgumentExpression
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.defaultParameterResolver import org.jetbrains.kotlin.fir.resolve.defaultParameterResolver
@@ -95,22 +94,6 @@ fun BodyResolveComponents.mapArguments(
&& function.name == OperatorNameConventions.SET && function.name == OperatorNameConventions.SET
&& function.origin !is FirDeclarationOrigin.DynamicScope && function.origin !is FirDeclarationOrigin.DynamicScope
if (isIndexedSetOperator &&
function.valueParameters.any { it.defaultValue != null || it.isVararg }
) {
val v = nonLambdaArguments.last()
if (v !is FirNamedArgumentExpression) {
val namedV = buildNamedArgumentExpression {
source = v.source
expression = v
isSpread = false
name = function.valueParameters.last().name
}
nonLambdaArguments.removeAt(nonLambdaArguments.size - 1)
nonLambdaArguments.add(namedV)
}
}
val processor = FirCallArgumentsProcessor(session, function, this, originScope, isIndexedSetOperator) val processor = FirCallArgumentsProcessor(session, function, this, originScope, isIndexedSetOperator)
processor.processNonLambdaArguments(nonLambdaArguments) processor.processNonLambdaArguments(nonLambdaArguments)
if (externalArgument != null) { if (externalArgument != null) {
@@ -172,15 +155,16 @@ private class FirCallArgumentsProcessor(
when { when {
// process position argument // process position argument
argument !is FirNamedArgumentExpression -> { argument !is FirNamedArgumentExpression -> {
if (processPositionArgument(argument, isLastArgument)) { if (state == State.VARARG_POSITION && isIndexedSetOperator && isLastArgument) {
state = State.VARARG_POSITION // The last argument of an indexed set operator should be reserved for the last argument (the assigned value).
// That's why if vararg presented, they should be completed
completeVarargPositionArguments()
} }
processPositionArgument(argument, isLastArgument)
} }
// process named argument // process named argument
function.origin == FirDeclarationOrigin.DynamicScope -> { function.origin == FirDeclarationOrigin.DynamicScope -> {
if (processPositionArgument(argument.expression, isLastArgument)) { processPositionArgument(argument.expression, isLastArgument)
state = State.VARARG_POSITION
}
} }
else -> { else -> {
if (state == State.VARARG_POSITION) { if (state == State.VARARG_POSITION) {
@@ -191,11 +175,10 @@ private class FirCallArgumentsProcessor(
} }
} }
// return true, if it was mapped to vararg parameter private fun processPositionArgument(argument: FirExpression, isLastArgument: Boolean) {
private fun processPositionArgument(argument: FirExpression, isLastArgument: Boolean): Boolean {
if (state == State.NAMED_ONLY_ARGUMENTS) { if (state == State.NAMED_ONLY_ARGUMENTS) {
addDiagnostic(MixingNamedAndPositionArguments(argument)) addDiagnostic(MixingNamedAndPositionArguments(argument))
return false return
} }
// The last parameter of an indexed set operator should be reserved for the last argument (the assigned value). // The last parameter of an indexed set operator should be reserved for the last argument (the assigned value).
@@ -219,19 +202,19 @@ private class FirCallArgumentsProcessor(
val parameter = parameters.getOrNull(assignedParameterIndex) val parameter = parameters.getOrNull(assignedParameterIndex)
if (parameter == null) { if (parameter == null) {
addDiagnostic(TooManyArguments(argument, function)) addDiagnostic(TooManyArguments(argument, function))
return false return
} }
return if (!parameter.isVararg) { return if (!parameter.isVararg) {
currentPositionedParameterIndex++ currentPositionedParameterIndex++
result[parameter] = ResolvedCallArgument.SimpleArgument(argument) result[parameter] = ResolvedCallArgument.SimpleArgument(argument)
false state = State.POSITION_ARGUMENTS
} }
// all position arguments will be mapped to current vararg parameter // all position arguments will be mapped to current vararg parameter
else { else {
addVarargArgument(argument) addVarargArgument(argument)
true state = State.VARARG_POSITION
} }
} }
@@ -20,16 +20,23 @@ object Z {
} }
} }
object W {
operator fun set(vararg va: Int, value: Int) {
}
}
fun test() { fun test() {
A[0] = "" A[0] = <!ARGUMENT_TYPE_MISMATCH!>""<!>
A[0] = 2.72 A[0] = 2.72
B[0] = "" B[0] = <!ARGUMENT_TYPE_MISMATCH!>""<!>
B[0] = 2.72 B[0] = <!ARGUMENT_TYPE_MISMATCH!>2.72<!>
B[0] = true B[0] = true
D[0] = "" D[0] = <!ARGUMENT_TYPE_MISMATCH!>""<!>
D[0] = 2.72 D[0] = 2.72
Z[<!TOO_MANY_ARGUMENTS!>0<!>] = <!TOO_MANY_ARGUMENTS!>""<!> Z[<!TOO_MANY_ARGUMENTS!>0<!>] = <!TOO_MANY_ARGUMENTS!>""<!>
W[0] = 1
} }
@@ -20,6 +20,11 @@ object Z {
} }
} }
object W {
operator fun set(vararg va: Int, value: Int) {
}
}
fun test() { fun test() {
A[0] = <!TYPE_MISMATCH!>""<!> A[0] = <!TYPE_MISMATCH!>""<!>
A[0] = 2.72 A[0] = 2.72
@@ -32,4 +37,6 @@ fun test() {
D[0] = 2.72 D[0] = 2.72
Z[<!TOO_MANY_ARGUMENTS!>0<!>] = <!TOO_MANY_ARGUMENTS!>""<!> Z[<!TOO_MANY_ARGUMENTS!>0<!>] = <!TOO_MANY_ARGUMENTS!>""<!>
W[0] = 1
} }
@@ -26,6 +26,14 @@ public object D {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
} }
public object W {
private constructor W()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final operator fun set(/*0*/ vararg va: kotlin.Int /*kotlin.IntArray*/, /*1*/ value: kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public object Z { public object Z {
private constructor Z() private constructor Z()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -33,3 +41,4 @@ public object Z {
public final operator fun set(): kotlin.Unit public final operator fun set(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
} }