@samitouri / QOS-React-2 / commits / 80bdab7447

Support AssignmentPattern (default values in destructuring)

"Supports" default values in destructuring (AssignmentPattern) by lowering to a ternary, even in the output. Examples: ```javascript // Input: const [x = 'default'] = y; // Output: const [t0] = y; const x = t0 === undefined ? 'default' : t0; ``` ```javascript // Input 2 const [{x} = makeObject()] = y; // Output 2 const [t0] = y; const {x} = t0 === undefined ? makeObject() : t0; ``` Note that this is how Babel lowers AssignmentPattern, so it isn't too bad. This should help avoid the need to update product code, even if the output isn't perfectly ideal.

Joe Savona committed Mar 27, 2023 at 10:34 UTC 80bdab74470d237883d5c88fba3baafb3b0d447a
8 files changed +223 -16
compiler/forget/src/HIR/BuildHIR.ts
+100
@@ -2446,6 +2446,106 @@ function lowerAssignment(
2446 }
2447 return { kind: "LoadLocal", place: temporary, loc: value.loc };
2448 }
2449 + case "AssignmentPattern": {
2450 + const lvalue = lvaluePath as NodePath<t.AssignmentPattern>;
2451 + const loc = lvalue.node.loc ?? GeneratedSource;
2452 + const temp = buildTemporaryPlace(builder, loc);
2453 +
2454 + const testBlock = builder.reserve("value");
2455 + const continuationBlock = builder.reserve(builder.currentBlockKind());
2456 +
2457 + const consequent = builder.enter("value", () => {
2458 + const defaultValue = lowerExpressionToTemporary(
2459 + builder,
2460 + lvalue.get("right")
2461 + );
2462 + builder.push({
2463 + id: makeInstructionId(0),
2464 + lvalue: buildTemporaryPlace(builder, loc),
2465 + value: {
2466 + kind: "StoreLocal",
2467 + lvalue: { kind: InstructionKind.Const, place: { ...temp } },
2468 + value: { ...defaultValue },
2469 + loc,
2470 + },
2471 + loc,
2472 + });
2473 + return {
2474 + kind: "goto",
2475 + variant: GotoVariant.Break,
2476 + block: continuationBlock.id,
2477 + id: makeInstructionId(0),
2478 + loc,
2479 + };
2480 + });
2481 +
2482 + const alternate = builder.enter("value", () => {
2483 + builder.push({
2484 + id: makeInstructionId(0),
2485 + lvalue: buildTemporaryPlace(builder, loc),
2486 + value: {
2487 + kind: "StoreLocal",
2488 + lvalue: { kind: InstructionKind.Const, place: { ...temp } },
2489 + value: { ...value },
2490 + loc,
2491 + },
2492 + loc,
2493 + });
2494 + return {
2495 + kind: "goto",
2496 + variant: GotoVariant.Break,
2497 + block: continuationBlock.id,
2498 + id: makeInstructionId(0),
2499 + loc,
2500 + };
2501 + });
2502 + builder.terminateWithContinuation(
2503 + {
2504 + kind: "ternary",
2505 + test: testBlock.id,
2506 + fallthrough: continuationBlock.id,
2507 + id: makeInstructionId(0),
2508 + loc,
2509 + },
2510 + testBlock
2511 + );
2512 + const undef = buildTemporaryPlace(builder, loc);
2513 + builder.push({
2514 + id: makeInstructionId(0),
2515 + lvalue: { ...undef },
2516 + value: {
2517 + kind: "Primitive",
2518 + value: undefined,
2519 + loc,
2520 + },
2521 + loc,
2522 + });
2523 + const test = buildTemporaryPlace(builder, loc);
2524 + builder.push({
2525 + id: makeInstructionId(0),
2526 + lvalue: { ...test },
2527 + value: {
2528 + kind: "BinaryExpression",
2529 + left: { ...value },
2530 + operator: "===",
2531 + right: { ...undef },
2532 + loc,
2533 + },
2534 + loc,
2535 + });
2536 + builder.terminateWithContinuation(
2537 + {
2538 + kind: "branch",
2539 + test: { ...test },
2540 + consequent,
2541 + alternate,
2542 + id: makeInstructionId(0),
2543 + },
2544 + continuationBlock
2545 + );
2546 +
2547 + return lowerAssignment(builder, loc, kind, lvalue.get("left"), temp);
2548 + }
2549 default: {
2550 builder.errors.push({
2551 reason: `(BuildHIR::lowerAssignment) Handle ${lvaluePath.type} assignments`,
compiler/forget/src/__tests__/fixtures/compiler/destructuring-array-default.expect.md new
+32
@@ -0,0 +1,32 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const [[x] = [foo()]] = props.y;
7 + return x;
8 +}
9 +
10 +```
11 +
12 +## Code
13 +
14 +```javascript
15 +function Component(props) {
16 + const $ = React.unstable_useMemoCache(2);
17 + const [t0] = props.y;
18 + const c_0 = $[0] !== t0;
19 + let t1;
20 + if (c_0) {
21 + t1 = t0 === undefined ? [foo()] : t0;
22 + $[0] = t0;
23 + $[1] = t1;
24 + } else {
25 + t1 = $[1];
26 + }
27 + const [x] = t1;
28 + return x;
29 +}
30 +
31 +```
32 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/destructuring-array-default.js new
+4
@@ -0,0 +1,4 @@
1 +function Component(props) {
2 + const [[x] = [foo()]] = props.y;
3 + return x;
4 +}
compiler/forget/src/__tests__/fixtures/compiler/destructuring-assignment-array-default.expect.md new
+42
@@ -0,0 +1,42 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + let x;
7 + if (props.cond) {
8 + [[x] = [foo()]] = props.y;
9 + } else {
10 + x = props.fallback;
11 + }
12 + return x;
13 +}
14 +
15 +```
16 +
17 +## Code
18 +
19 +```javascript
20 +function Component(props) {
21 + const $ = React.unstable_useMemoCache(2);
22 + let x = undefined;
23 + if (props.cond) {
24 + const [t0] = props.y;
25 + const c_0 = $[0] !== t0;
26 + let t1;
27 + if (c_0) {
28 + t1 = t0 === undefined ? [foo()] : t0;
29 + $[0] = t0;
30 + $[1] = t1;
31 + } else {
32 + t1 = $[1];
33 + }
34 + [x] = t1;
35 + } else {
36 + x = props.fallback;
37 + }
38 + return x;
39 +}
40 +
41 +```
42 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/destructuring-assignment-array-default.js new
+9
@@ -0,0 +1,9 @@
1 +function Component(props) {
2 + let x;
3 + if (props.cond) {
4 + [[x] = [foo()]] = props.y;
5 + } else {
6 + x = props.fallback;
7 + }
8 + return x;
9 +}
compiler/forget/src/__tests__/fixtures/compiler/destructuring-object-default.expect.md new
+32
@@ -0,0 +1,32 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const { x: { y } = { y: "default" } } = props.y;
7 + return y;
8 +}
9 +
10 +```
11 +
12 +## Code
13 +
14 +```javascript
15 +function Component(props) {
16 + const $ = React.unstable_useMemoCache(2);
17 + const { x: t0 } = props.y;
18 + const c_0 = $[0] !== t0;
19 + let t1;
20 + if (c_0) {
21 + t1 = t0 === undefined ? { y: "default" } : t0;
22 + $[0] = t0;
23 + $[1] = t1;
24 + } else {
25 + t1 = $[1];
26 + }
27 + const { y } = t1;
28 + return y;
29 +}
30 +
31 +```
32 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/destructuring-object-default.js new
+4
@@ -0,0 +1,4 @@
1 +function Component(props) {
2 + const { x: { y } = { y: "default" } } = props.y;
3 + return y;
4 +}
compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
-16
@@ -79,13 +79,6 @@ let moduleLocal = false;
79 ## Error
80
81 ```
82 -[ReactForget] TodoError: (BuildHIR::lowerAssignment) Handle AssignmentPattern assignments
83 -> 1 | function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
84 - | ^^^^^^^
85 - 2 | let i = 0;
86 - 3 | var x = [];
87 - 4 |
88 -
82 [ReactForget] TodoError: (BuildHIR::lower) Handle AssignmentPattern params
83 > 1 | function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
84 | ^^^^^^^
@@ -127,15 +120,6 @@ let moduleLocal = false;
120 14 |
121 15 | <Button haha={1}></Button>;
122
130 -[ReactForget] TodoError: (BuildHIR::lowerAssignment) Handle AssignmentPattern assignments
131 - 11 |
132 - 12 | const g = { b() {}, c: () => {} };
133 -> 13 | const { z, aa = "aa" } = useCustom();
134 - | ^^^^^^^^^
135 - 14 |
136 - 15 | <Button haha={1}></Button>;
137 - 16 | <Button>{/** empty */}</Button>;
138 -
123 [ReactForget] TodoError: (BuildHIR::lowerJsxElement) Handle JSXEmptyExpression expressions
124 14 |
125 15 | <Button haha={1}></Button>;