[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.name == OperatorNameConventions.SET &&
functionCall.calleeReference.source?.kind == KtFakeSourceElementKind.ArrayAccessNameReference functionCall.calleeReference.source?.kind == KtFakeSourceElementKind.ArrayAccessNameReference
) { ) {
return convertToIrArrayAccessDynamicCall(functionCall) return convertToIrArraySetDynamicCall(functionCall)
} }
return convertToIrCall(functionCall, dynamicOperator = null) return convertToIrCall(functionCall, dynamicOperator = null)
} }
@@ -578,25 +578,24 @@ class Fir2IrVisitor(
) )
} }
private fun convertToIrArrayAccessDynamicCall(functionCall: FirFunctionCall): IrExpression { private fun convertToIrArraySetDynamicCall(functionCall: FirFunctionCall): IrExpression {
val explicitReceiverExpression = convertToIrCall( // `functionCall` has the form of `myDynamic.set(key1, key2, ..., newValue)`.
functionCall, dynamicOperator = IrDynamicOperator.ARRAY_ACCESS // 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
if (explicitReceiverExpression is IrDynamicOperatorExpression) { // call for `set()` (`EQ`), let's convert the whole thing as `ARRAY_ACCESS`, including
explicitReceiverExpression.arguments.removeLast() // `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) { 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"); 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 @Test
@TestMetadata("equals.kt") @TestMetadata("equals.kt")
public void testEquals() throws Exception { public void testEquals() throws Exception {
@@ -1738,6 +1738,12 @@ public class FirJsES6BoxTestGenerated extends AbstractFirJsES6BoxTest {
runTest("js/js.translator/testData/box/dynamic/compareTo.kt"); 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 @Test
@TestMetadata("equals.kt") @TestMetadata("equals.kt")
public void testEquals() throws Exception { public void testEquals() throws Exception {
@@ -1738,6 +1738,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
runTest("js/js.translator/testData/box/dynamic/compareTo.kt"); 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 @Test
@TestMetadata("equals.kt") @TestMetadata("equals.kt")
public void testEquals() throws Exception { public void testEquals() throws Exception {
@@ -1738,6 +1738,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/dynamic/compareTo.kt"); 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 @Test
@TestMetadata("equals.kt") @TestMetadata("equals.kt")
public void testEquals() throws Exception { 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"]
}