[FIR] Handle varargs in overloaded indexed access operator.
This commit is contained in:
committed by
teamcityserver
parent
c471a7735e
commit
f6ce2d893c
Generated
+5
@@ -13011,6 +13011,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classVarargGetSet.kt")
|
||||||
|
public void testClassVarargGetSet() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/increment/classVarargGetSet.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classWithGetSet.kt")
|
@TestMetadata("classWithGetSet.kt")
|
||||||
public void testClassWithGetSet() throws Exception {
|
public void testClassWithGetSet() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ class Candidate(
|
|||||||
|
|
||||||
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
||||||
var numDefaults: Int = 0
|
var numDefaults: Int = 0
|
||||||
|
var oldToNewArgumentMapping: Map<FirExpression, FirExpression>? = null
|
||||||
lateinit var typeArgumentMapping: TypeArgumentMapping
|
lateinit var typeArgumentMapping: TypeArgumentMapping
|
||||||
val postponedAtoms = mutableListOf<PostponedResolvedAtom>()
|
val postponedAtoms = mutableListOf<PostponedResolvedAtom>()
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -30,6 +30,7 @@ data class ArgumentMapping(
|
|||||||
// foo(b = bar(), a = qux())
|
// foo(b = bar(), a = qux())
|
||||||
// parameterToCallArgumentMap.values() should be [ 'bar()', 'foo()' ]
|
// parameterToCallArgumentMap.values() should be [ 'bar()', 'foo()' ]
|
||||||
val parameterToCallArgumentMap: Map<FirValueParameter, ResolvedCallArgument>,
|
val parameterToCallArgumentMap: Map<FirValueParameter, ResolvedCallArgument>,
|
||||||
|
val oldToNewArgumentMap: Map<FirExpression, FirExpression>,
|
||||||
val diagnostics: List<ResolutionDiagnostic>
|
val diagnostics: List<ResolutionDiagnostic>
|
||||||
) {
|
) {
|
||||||
fun toArgumentToParameterMapping(): Map<FirExpression, FirValueParameter> {
|
fun toArgumentToParameterMapping(): Map<FirExpression, FirValueParameter> {
|
||||||
@@ -50,7 +51,7 @@ data class ArgumentMapping(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val EmptyArgumentMapping = ArgumentMapping(emptyMap(), emptyList())
|
private val EmptyArgumentMapping = ArgumentMapping(emptyMap(), emptyMap(), emptyList())
|
||||||
|
|
||||||
fun BodyResolveComponents.mapArguments(
|
fun BodyResolveComponents.mapArguments(
|
||||||
arguments: List<FirExpression>,
|
arguments: List<FirExpression>,
|
||||||
@@ -67,11 +68,12 @@ fun BodyResolveComponents.mapArguments(
|
|||||||
arguments.subList(0, arguments.size - 1)
|
arguments.subList(0, arguments.size - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is an overloading indexed access operator, it could have default values in the middle.
|
// If this is an overloading indexed access operator, it could have default values or a vararg parameter in the middle.
|
||||||
// For proper argument mapping, wrap the last one, which is supposed to be the updated value, as a named argument.
|
// For proper argument mapping, wrap the last one, which is supposed to be the updated value, as a named argument.
|
||||||
|
val oldToNewArgumentMap = mutableMapOf<FirExpression, FirExpression>()
|
||||||
if ((function as? FirSimpleFunction)?.isOperator == true &&
|
if ((function as? FirSimpleFunction)?.isOperator == true &&
|
||||||
function.name == Name.identifier("set") &&
|
function.name == Name.identifier("set") &&
|
||||||
function.valueParameters.any { it.defaultValue != null }
|
function.valueParameters.any { it.defaultValue != null || it.isVararg }
|
||||||
) {
|
) {
|
||||||
val v = argumentsInParenthesis.last()
|
val v = argumentsInParenthesis.last()
|
||||||
if (v !is FirNamedArgumentExpression) {
|
if (v !is FirNamedArgumentExpression) {
|
||||||
@@ -82,6 +84,7 @@ fun BodyResolveComponents.mapArguments(
|
|||||||
name = function.valueParameters.last().name
|
name = function.valueParameters.last().name
|
||||||
}
|
}
|
||||||
argumentsInParenthesis = argumentsInParenthesis.dropLast(1) + listOf(namedV)
|
argumentsInParenthesis = argumentsInParenthesis.dropLast(1) + listOf(namedV)
|
||||||
|
oldToNewArgumentMap[v] = namedV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +95,7 @@ fun BodyResolveComponents.mapArguments(
|
|||||||
}
|
}
|
||||||
processor.processDefaultsAndRunChecks()
|
processor.processDefaultsAndRunChecks()
|
||||||
|
|
||||||
return ArgumentMapping(processor.result, processor.diagnostics ?: emptyList())
|
return ArgumentMapping(processor.result, oldToNewArgumentMap, processor.diagnostics ?: emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FirCallArgumentsProcessor(
|
private class FirCallArgumentsProcessor(
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ internal object MapArguments : ResolutionStage() {
|
|||||||
val mapping = context.bodyResolveComponents.mapArguments(callInfo.arguments, function, candidate.originScope)
|
val mapping = context.bodyResolveComponents.mapArguments(callInfo.arguments, function, candidate.originScope)
|
||||||
candidate.argumentMapping = mapping.toArgumentToParameterMapping()
|
candidate.argumentMapping = mapping.toArgumentToParameterMapping()
|
||||||
candidate.numDefaults = mapping.numDefaults()
|
candidate.numDefaults = mapping.numDefaults()
|
||||||
|
candidate.oldToNewArgumentMapping = mapping.oldToNewArgumentMap
|
||||||
|
|
||||||
mapping.diagnostics.forEach(sink::reportDiagnostic)
|
mapping.diagnostics.forEach(sink::reportDiagnostic)
|
||||||
sink.yieldIfNeed()
|
sink.yieldIfNeed()
|
||||||
|
|||||||
+9
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.*
|
|||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedCallableReference
|
import org.jetbrains.kotlin.fir.references.builder.buildResolvedCallableReference
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||||
@@ -165,6 +166,14 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
val expectedArgumentsTypeMapping = runIf(!calleeReference.isError) { subCandidate.createArgumentsMapping() }
|
val expectedArgumentsTypeMapping = runIf(!calleeReference.isError) { subCandidate.createArgumentsMapping() }
|
||||||
result.argumentList.transformArguments(this, expectedArgumentsTypeMapping)
|
result.argumentList.transformArguments(this, expectedArgumentsTypeMapping)
|
||||||
if (!calleeReference.isError) {
|
if (!calleeReference.isError) {
|
||||||
|
subCandidate.oldToNewArgumentMapping?.let {
|
||||||
|
result.replaceArgumentList(buildArgumentList {
|
||||||
|
source = result.argumentList.source
|
||||||
|
for (oldArgument in result.argumentList.arguments) {
|
||||||
|
arguments += it[oldArgument] ?: oldArgument
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
subCandidate.handleVarargs(result.argumentList)
|
subCandidate.handleVarargs(result.argumentList)
|
||||||
subCandidate.argumentMapping?.let {
|
subCandidate.argumentMapping?.let {
|
||||||
result.replaceArgumentList(buildResolvedArgumentList(it))
|
result.replaceArgumentList(buildResolvedArgumentList(it))
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
object A {
|
||||||
|
var x = 0
|
||||||
|
var gets = 0
|
||||||
|
var sets = 0
|
||||||
|
|
||||||
|
operator fun get(vararg va: Int): Int {
|
||||||
|
for (i in va) {
|
||||||
|
gets += i
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun set(vararg va: Int, value: Int) {
|
||||||
|
for (i in va) {
|
||||||
|
sets += i
|
||||||
|
}
|
||||||
|
x = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
A.x = 0
|
||||||
|
val xx = A[1, 2, 3]++
|
||||||
|
if (xx != 0) return "Failed xx: $xx"
|
||||||
|
if (A.x != 1) return "Failed A.x: ${A.x}"
|
||||||
|
if (A.gets != 6) return "Failed A.gets: ${A.gets}"
|
||||||
|
if (A.sets != 6) return "Failed A.sets: ${A.sets}"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -28,8 +28,8 @@ fun test() {
|
|||||||
B[0] = 2.72
|
B[0] = 2.72
|
||||||
B[0] = true
|
B[0] = true
|
||||||
|
|
||||||
<!INAPPLICABLE_CANDIDATE!>D[0] = ""<!>
|
D[0] = ""
|
||||||
<!INAPPLICABLE_CANDIDATE!>D[0] = 2.72<!>
|
D[0] = 2.72
|
||||||
|
|
||||||
<!INAPPLICABLE_CANDIDATE!>Z[0] = ""<!>
|
<!INAPPLICABLE_CANDIDATE!>Z[0] = ""<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-5
@@ -26,8 +26,13 @@ FILE fqName:<root> fileName:/kt28456a.kt
|
|||||||
FUN name:testSimpleAssignment visibility:public modality:FINAL <> (a:<root>.A) returnType:kotlin.Unit
|
FUN name:testSimpleAssignment visibility:public modality:FINAL <> (a:<root>.A) returnType:kotlin.Unit
|
||||||
VALUE_PARAMETER name:a index:0 type:<root>.A
|
VALUE_PARAMETER name:a index:0 type:<root>.A
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR): /set>#' type=kotlin.Unit
|
BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL
|
||||||
CONST Int type=kotlin.Int value=1
|
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.IntArray [val]
|
||||||
CONST Int type=kotlin.Int value=2
|
VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||||
CONST Int type=kotlin.Int value=3
|
CONST Int type=kotlin.Int value=1
|
||||||
CONST Int type=kotlin.Int value=0
|
CONST Int type=kotlin.Int value=2
|
||||||
|
CONST Int type=kotlin.Int value=3
|
||||||
|
CALL 'public final fun set (vararg i: kotlin.Int, v: kotlin.Int): kotlin.Unit [operator] declared in <root>' type=kotlin.Unit origin=null
|
||||||
|
$receiver: GET_VAR 'a: <root>.A declared in <root>.testSimpleAssignment' type=<root>.A origin=null
|
||||||
|
i: GET_VAR 'val tmp_0: kotlin.IntArray [val] declared in <root>.testSimpleAssignment' type=kotlin.IntArray origin=null
|
||||||
|
v: CONST Int type=kotlin.Int value=0
|
||||||
|
|||||||
+5
@@ -14406,6 +14406,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classVarargGetSet.kt")
|
||||||
|
public void testClassVarargGetSet() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/increment/classVarargGetSet.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classWithGetSet.kt")
|
@TestMetadata("classWithGetSet.kt")
|
||||||
public void testClassWithGetSet() throws Exception {
|
public void testClassWithGetSet() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
||||||
|
|||||||
+5
@@ -14406,6 +14406,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classVarargGetSet.kt")
|
||||||
|
public void testClassVarargGetSet() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/increment/classVarargGetSet.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classWithGetSet.kt")
|
@TestMetadata("classWithGetSet.kt")
|
||||||
public void testClassWithGetSet() throws Exception {
|
public void testClassWithGetSet() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
||||||
|
|||||||
+5
@@ -13011,6 +13011,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classVarargGetSet.kt")
|
||||||
|
public void testClassVarargGetSet() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/increment/classVarargGetSet.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classWithGetSet.kt")
|
@TestMetadata("classWithGetSet.kt")
|
||||||
public void testClassWithGetSet() throws Exception {
|
public void testClassWithGetSet() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
||||||
|
|||||||
Generated
+5
@@ -11156,6 +11156,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
|||||||
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classVarargGetSet.kt")
|
||||||
|
public void testClassVarargGetSet() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/increment/classVarargGetSet.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classWithGetSet.kt")
|
@TestMetadata("classWithGetSet.kt")
|
||||||
public void testClassWithGetSet() throws Exception {
|
public void testClassWithGetSet() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
||||||
|
|||||||
Generated
+5
@@ -11156,6 +11156,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classVarargGetSet.kt")
|
||||||
|
public void testClassVarargGetSet() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/increment/classVarargGetSet.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classWithGetSet.kt")
|
@TestMetadata("classWithGetSet.kt")
|
||||||
public void testClassWithGetSet() throws Exception {
|
public void testClassWithGetSet() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
||||||
|
|||||||
+5
@@ -11221,6 +11221,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classVarargGetSet.kt")
|
||||||
|
public void testClassVarargGetSet() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/increment/classVarargGetSet.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classWithGetSet.kt")
|
@TestMetadata("classWithGetSet.kt")
|
||||||
public void testClassWithGetSet() throws Exception {
|
public void testClassWithGetSet() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
runTest("compiler/testData/codegen/box/increment/classWithGetSet.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user