[FIR2IR] Avoid converting arguments of dynamic array set twice

^KT-63593 Fixed


Merge-request: KT-MR-13152
Merged-by: Nikolay Lunyak <Nikolay.Lunyak@jetbrains.com>
This commit is contained in:
Nikolay Lunyak
2023-11-22 07:39:46 +00:00
committed by Space Team
parent fb0461f422
commit f12ecb3011
6 changed files with 52 additions and 19 deletions
@@ -557,7 +557,7 @@ class Fir2IrVisitor(
functionCall.calleeReference.name == OperatorNameConventions.SET &&
functionCall.calleeReference.source?.kind == KtFakeSourceElementKind.ArrayAccessNameReference
) {
return convertToIrArrayAccessDynamicCall(functionCall)
return convertToIrArraySetDynamicCall(functionCall)
}
return convertToIrCall(functionCall, dynamicOperator = null)
}
@@ -578,25 +578,24 @@ class Fir2IrVisitor(
)
}
private fun convertToIrArrayAccessDynamicCall(functionCall: FirFunctionCall): IrExpression {
val explicitReceiverExpression = convertToIrCall(
functionCall, dynamicOperator = IrDynamicOperator.ARRAY_ACCESS
)
if (explicitReceiverExpression is IrDynamicOperatorExpression) {
explicitReceiverExpression.arguments.removeLast()
private fun convertToIrArraySetDynamicCall(functionCall: FirFunctionCall): IrExpression {
// `functionCall` has the form of `myDynamic.set(key1, key2, ..., newValue)`.
// The resulting IR expects something like `myDynamic.ARRAY_ACCESS(key1, key2, ...).EQ(newValue)`.
// Instead of constructing a `FirFunctionCall` for `get()` (the true `ARRAY_ACCESS`), and a new
// call for `set()` (`EQ`), let's convert the whole thing as `ARRAY_ACCESS`, including
// `newValue`, and then manually move it to a newly constructed EQ call.
val arraySetAsGenericDynamicAccess = convertToIrCall(functionCall, IrDynamicOperator.ARRAY_ACCESS) as? IrDynamicOperatorExpression
?: error("Converting dynamic array access should have resulted in IrDynamicOperatorExpression")
val arraySetNewValue = arraySetAsGenericDynamicAccess.arguments.removeLast()
return IrDynamicOperatorExpressionImpl(
arraySetAsGenericDynamicAccess.startOffset,
arraySetAsGenericDynamicAccess.endOffset,
arraySetAsGenericDynamicAccess.type,
IrDynamicOperator.EQ,
).apply {
receiver = arraySetAsGenericDynamicAccess
arguments.add(arraySetNewValue)
}
val result = callGenerator.convertToIrCall(
functionCall, functionCall.resolvedType, explicitReceiverExpression,
dynamicOperator = IrDynamicOperator.EQ
)
if (result is IrDynamicOperatorExpression) {
val arguments = result.arguments
arguments[0] = arguments[arguments.lastIndex]
while (arguments.size > 1) {
arguments.removeLast()
}
}
return result
}
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Any?): IrExpression = whileAnalysing(session, functionCall) {
@@ -1738,6 +1738,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
runTest("js/js.translator/testData/box/dynamic/compareTo.kt");
}
@Test
@TestMetadata("dynamicArraySetWithLambda.kt")
public void testDynamicArraySetWithLambda() throws Exception {
runTest("js/js.translator/testData/box/dynamic/dynamicArraySetWithLambda.kt");
}
@Test
@TestMetadata("equals.kt")
public void testEquals() throws Exception {
@@ -1738,6 +1738,12 @@ public class FirJsES6BoxTestGenerated extends AbstractFirJsES6BoxTest {
runTest("js/js.translator/testData/box/dynamic/compareTo.kt");
}
@Test
@TestMetadata("dynamicArraySetWithLambda.kt")
public void testDynamicArraySetWithLambda() throws Exception {
runTest("js/js.translator/testData/box/dynamic/dynamicArraySetWithLambda.kt");
}
@Test
@TestMetadata("equals.kt")
public void testEquals() throws Exception {
@@ -1738,6 +1738,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
runTest("js/js.translator/testData/box/dynamic/compareTo.kt");
}
@Test
@TestMetadata("dynamicArraySetWithLambda.kt")
public void testDynamicArraySetWithLambda() throws Exception {
runTest("js/js.translator/testData/box/dynamic/dynamicArraySetWithLambda.kt");
}
@Test
@TestMetadata("equals.kt")
public void testEquals() throws Exception {
@@ -1738,6 +1738,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/dynamic/compareTo.kt");
}
@Test
@TestMetadata("dynamicArraySetWithLambda.kt")
public void testDynamicArraySetWithLambda() throws Exception {
runTest("js/js.translator/testData/box/dynamic/dynamicArraySetWithLambda.kt");
}
@Test
@TestMetadata("equals.kt")
public void testEquals() throws Exception {
@@ -0,0 +1,10 @@
// ISSUE: KT-63593
// WITH_STDLIB
fun <T> jso(): T = mutableMapOf<String, String>() as T
fun box(): String {
val obj = jso<dynamic>()
obj["a"] = run { "OK" }
return obj["a"]
}