[hir] Handle OptionalMemberExpression syntax
(Implemented as per discussions with @gsathya ) Handle OptionalMemberExpression by adding an 'optional' flag to `PropertyLoad` instruction, which is set during `BuildHIR` and read during `CodegenReactiveFunction`.
mofeiZ committed
Jan 25, 2023 at 10:16 UTC
62b75269294f9c1a39d6f6ea8c64363696efde40
5 files changed
+72
-7
compiler/forget/src/HIR/BuildHIR.ts
+8
-2
@@ -1193,6 +1193,7 @@ function lowerExpression(
1193
object: { ...object },
1194
property: property.node.name,
1195
loc: leftExpr.node.loc ?? GeneratedSource,
1196
+ optional: false, // LVal cannot be optional
1197
},
1198
loc: leftExpr.node.loc ?? GeneratedSource,
1199
});
@@ -1233,8 +1234,11 @@ function lowerExpression(
1234
}
1235
}
1236
}
1237
+ case "OptionalMemberExpression":
1238
case "MemberExpression": {
1237
- const expr = exprPath as NodePath<t.MemberExpression>;
1239
+ const expr = exprPath as NodePath<
1240
+ t.MemberExpression | t.OptionalMemberExpression
1241
+ >;
1242
const { value } = lowerMemberExpression(builder, expr);
1243
const place: Place = buildTemporaryPlace(builder, exprLoc);
1244
builder.push({
@@ -1424,7 +1428,7 @@ function lowerExpression(
1428
1429
function lowerMemberExpression(
1430
builder: HIRBuilder,
1427
- expr: NodePath<t.MemberExpression>
1431
+ expr: NodePath<t.MemberExpression | t.OptionalMemberExpression>
1432
): { object: Place; property: Place | string; value: InstructionValue } {
1433
const exprNode = expr.node;
1434
const exprLoc = exprNode.loc ?? GeneratedSource;
@@ -1448,6 +1452,7 @@ function lowerMemberExpression(
1452
object: { ...object },
1453
property: property.node.name,
1454
loc: exprLoc,
1455
+ optional: t.isOptionalMemberExpression(expr),
1456
};
1457
return { object, property: property.node.name, value };
1458
} else {
@@ -1895,6 +1900,7 @@ function lowerAssignment(
1900
loc,
1901
object: { ...objectPlace },
1902
property: key.node.name,
1903
+ optional: false, // Key of ObjectPattern (evaluation of LVal) cannot be optional.
1904
};
1905
lowerAssignment(builder, loc, kind, element, value);
1906
}
compiler/forget/src/HIR/HIR.ts
+1
-1
@@ -392,7 +392,7 @@ export type InstructionData =
392
// store `object.property = value`
393
| { kind: "PropertyStore"; object: Place; property: string; value: Place }
394
// load `object.property`
395
- | { kind: "PropertyLoad"; object: Place; property: string }
395
+ | { kind: "PropertyLoad"; object: Place; property: string; optional: boolean }
396
397
// store `object[index] = value` - like PropertyStore but with a dynamic property
398
| { kind: "ComputedStore"; object: Place; property: Place; value: Place }
compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+13
-4
@@ -631,10 +631,19 @@ function codegenInstructionValue(
631
break;
632
}
633
case "PropertyLoad": {
634
- value = t.memberExpression(
635
- codegenPlace(temp, instrValue.object),
636
- t.identifier(instrValue.property)
637
- );
634
+ if (instrValue.optional) {
635
+ value = t.optionalMemberExpression(
636
+ codegenPlace(temp, instrValue.object),
637
+ t.identifier(instrValue.property),
638
+ undefined,
639
+ true
640
+ );
641
+ } else {
642
+ value = t.memberExpression(
643
+ codegenPlace(temp, instrValue.object),
644
+ t.identifier(instrValue.property)
645
+ );
646
+ }
647
break;
648
}
649
case "ComputedStore": {
compiler/forget/src/__tests__/fixtures/hir/optional-member-expression.expect.md
new
+43
@@ -0,0 +1,43 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Foo(props) {
6
+ let x = bar(props.a);
7
+ let y = x?.b;
8
+
9
+ let z = useBar(y);
10
+ return z;
11
+}
12
+
13
+```
14
+
15
+## Code
16
+
17
+```javascript
18
+function Foo(props) {
19
+ const $ = React.useMemoCache();
20
+ const c_0 = $[0] !== props.a;
21
+ let x;
22
+ if (c_0) {
23
+ x = bar(props.a);
24
+ $[0] = props.a;
25
+ $[1] = x;
26
+ } else {
27
+ x = $[1];
28
+ }
29
+ const y = x?.b;
30
+ const c_2 = $[2] !== y;
31
+ let z;
32
+ if (c_2) {
33
+ z = useBar(y);
34
+ $[2] = y;
35
+ $[3] = z;
36
+ } else {
37
+ z = $[3];
38
+ }
39
+ return z;
40
+}
41
+
42
+```
43
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/optional-member-expression.js
new
+7
@@ -0,0 +1,7 @@
1
+function Foo(props) {
2
+ let x = bar(props.a);
3
+ let y = x?.b;
4
+
5
+ let z = useBar(y);
6
+ return z;
7
+}