@samitouri / QOS-React-2 / commits / bd99d06a5f

Support computed property access/assignment

Supports computed properties (as LHS and RHS) correctly. Previously we only handled member expressions where the property was an identifier, and would incorrect treat `a[b]` the same as `a.b`. Now we correctly distinguish these and convert `a[b]` as an IndexLoad and `a.b` as a PropertyLoad. Similar for assignment, `a[b] = c` is an IndexStore. For both IndexLoad and IndexStore we lower the property to a Place first.

Joe Savona committed Jan 3, 2023 at 16:59 UTC bd99d06a5fc5c739086e9961d9d0d35283989de6
5 files changed +98 -24
compiler/forget/src/HIR/BuildHIR.ts
+48 -24
@@ -1061,16 +1061,28 @@ function lowerExpression(
1061 const object = lowerExpressionToPlace(builder, expr.get("object"));
1062 invariant(object.kind === "Identifier", "scope cannot appear here");
1063 const property = expr.get("property");
1064 - todoInvariant(
1065 - property.isIdentifier(),
1066 - "Handle non-identifier properties"
1067 - );
1068 - const value: InstructionValue = {
1069 - kind: "PropertyLoad",
1070 - object,
1071 - property: property.node.name,
1072 - loc: exprLoc,
1073 - };
1064 + let value: InstructionValue;
1065 + if (!expr.node.computed) {
1066 + todoInvariant(property.isIdentifier(), "Support private names");
1067 + value = {
1068 + kind: "PropertyLoad",
1069 + object,
1070 + property: property.node.name,
1071 + loc: exprLoc,
1072 + };
1073 + } else {
1074 + invariant(
1075 + property.isExpression(),
1076 + "Expected private names to be non-computed"
1077 + );
1078 + const propertyPlace = lowerExpressionToPlace(builder, property);
1079 + value = {
1080 + kind: "IndexLoad",
1081 + object,
1082 + property: propertyPlace,
1083 + loc: exprLoc,
1084 + };
1085 + }
1086 const place: Place = buildTemporaryPlace(builder, exprLoc);
1087 builder.push({
1088 id: makeInstructionId(0),
@@ -1380,13 +1392,9 @@ function lowerAssignment(
1392 return place;
1393 }
1394 case "MemberExpression": {
1383 - const leftExpr = lvaluePath as NodePath<t.MemberExpression>;
1384 - const property = leftExpr.get("property");
1385 - invariant(
1386 - property.isIdentifier(),
1387 - "Assignment expression to dynamic properties is not yet supported"
1388 - );
1389 - const object = lowerExpressionToPlace(builder, leftExpr.get("object"));
1395 + const lvalue = lvaluePath as NodePath<t.MemberExpression>;
1396 + const property = lvalue.get("property");
1397 + const object = lowerExpressionToPlace(builder, lvalue.get("object"));
1398 let valuePlace: Place;
1399 if (value.kind === "Identifier") {
1400 valuePlace = value;
@@ -1399,13 +1407,29 @@ function lowerAssignment(
1407 loc,
1408 });
1409 }
1402 - return {
1403 - kind: "PropertyStore",
1404 - object,
1405 - property: property.node.name,
1406 - value: valuePlace,
1407 - loc,
1408 - };
1410 + if (!lvalue.node.computed) {
1411 + todoInvariant(property.isIdentifier(), "Support private names");
1412 + return {
1413 + kind: "PropertyStore",
1414 + object,
1415 + property: property.node.name,
1416 + value: valuePlace,
1417 + loc,
1418 + };
1419 + } else {
1420 + invariant(
1421 + property.isExpression(),
1422 + "Expected private name to appear as a non-computed property"
1423 + );
1424 + const propertyPlace = lowerExpressionToPlace(builder, property);
1425 + return {
1426 + kind: "IndexStore",
1427 + object,
1428 + property: propertyPlace,
1429 + value: valuePlace,
1430 + loc,
1431 + };
1432 + }
1433 }
1434 case "ArrayPattern": {
1435 const lvalue = lvaluePath as NodePath<t.ArrayPattern>;
compiler/forget/src/__tests__/fixtures/hir/array-access-assignment.expect.md new
+21
@@ -0,0 +1,21 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(a, b, c) {
6 + a[0] = b[1];
7 + c[0][0] = a[0];
8 +}
9 +
10 +```
11 +
12 +## Code
13 +
14 +```javascript
15 +function foo(a, b, c) {
16 + a[0] = b[1];
17 + c[0][0] = a[0];
18 +}
19 +
20 +```
21 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/array-access-assignment.js new
+4
@@ -0,0 +1,4 @@
1 +function foo(a, b, c) {
2 + a[0] = b[1];
3 + c[0][0] = a[0];
4 +}
compiler/forget/src/__tests__/fixtures/hir/object-computed-access-assignment.expect.md new
+21
@@ -0,0 +1,21 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(a, b, c) {
6 + a[b] = c[b];
7 + a[1 + 2] = c[b * 4];
8 +}
9 +
10 +```
11 +
12 +## Code
13 +
14 +```javascript
15 +function foo(a, b, c) {
16 + a[b] = c[b];
17 + a[1 + 2] = c[b * 4];
18 +}
19 +
20 +```
21 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/object-computed-access-assignment.js new
+4
@@ -0,0 +1,4 @@
1 +function foo(a, b, c) {
2 + a[b] = c[b];
3 + a[1 + 2] = c[b * 4];
4 +}