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
+}