@samitouri / QOS-React-2 / commits / 326ee664dc

Test cases for optional call

Tests, focusing on two key behaviors: * Dependencies of the args are treated as conditional, since the call may not happen * Args cannot be memoized independently, even when that would be valid for a non-optional call.

Joe Savona committed Mar 24, 2023 at 14:22 UTC 326ee664dc3c8e1694fd89f6fca8cb3f86e3b39a
7 files changed +167
compiler/forget/src/HIR/BuildHIR.ts
+7
@@ -960,8 +960,13 @@ function lowerExpression(
960 const place = buildTemporaryPlace(builder, loc);
961 const continuationBlock = builder.reserve(builder.currentBlockKind());
962
963 + // Lower the callee in the current block: the callee is always unconditionally evaluated
964 + // The test block's branch will test on this value to determine whether to evaluate the call (consequent)
965 + // or evaluate to undefined (alternate)
966 const callee = lowerExpressionToTemporary(builder, calleePath);
967
968 + // block to evaluate if the callee is non-null/undefined. arguments are lowered in this block to preserve
969 + // the semantic of conditional evaluation depending on the callee
970 const consequent = builder.enter("value", () => {
971 const args = lowerArguments(builder, expr.get("arguments"));
972 const temp = buildTemporaryPlace(builder, loc);
@@ -994,6 +999,8 @@ function lowerExpression(
999 id: makeInstructionId(0),
1000 };
1001 });
1002 +
1003 + // block to evaluate if the callee is null/undefined, this sets the result of the call to undefined.
1004 const alternate = builder.enter("value", () => {
1005 const temp = buildTemporaryPlace(builder, loc);
1006 builder.push({
compiler/forget/src/__tests__/fixtures/compiler/call-with-independently-memoizable-arg.expect.md new
+55
@@ -0,0 +1,55 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const x = makeFunction(props);
7 + const y = x(
8 + <div>
9 + <span>{props.text}</span>
10 + </div>
11 + );
12 + return y;
13 +}
14 +
15 +```
16 +
17 +## Code
18 +
19 +```javascript
20 +function Component(props) {
21 + const $ = React.unstable_useMemoCache(6);
22 + const c_0 = $[0] !== props;
23 + let t2;
24 + if (c_0) {
25 + const x = makeFunction(props);
26 + const c_2 = $[2] !== props.text;
27 + let t0;
28 + if (c_2) {
29 + t0 = <span>{props.text}</span>;
30 + $[2] = props.text;
31 + $[3] = t0;
32 + } else {
33 + t0 = $[3];
34 + }
35 + const c_4 = $[4] !== t0;
36 + let t1;
37 + if (c_4) {
38 + t1 = <div>{t0}</div>;
39 + $[4] = t0;
40 + $[5] = t1;
41 + } else {
42 + t1 = $[5];
43 + }
44 + t2 = x(t1);
45 + $[0] = props;
46 + $[1] = t2;
47 + } else {
48 + t2 = $[1];
49 + }
50 + const y = t2;
51 + return y;
52 +}
53 +
54 +```
55 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/call-with-independently-memoizable-arg.js new
+9
@@ -0,0 +1,9 @@
1 +function Component(props) {
2 + const x = makeFunction(props);
3 + const y = x(
4 + <div>
5 + <span>{props.text}</span>
6 + </div>
7 + );
8 + return y;
9 +}
compiler/forget/src/__tests__/fixtures/compiler/optional-call-with-independently-memoizable-arg.expect.md new
+42
@@ -0,0 +1,42 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const x = makeOptionalFunction(props);
7 + // for a regular call, the JSX element could be independently memoized
8 + // since it is an immutable value. however, because the call is optional,
9 + // we can't extract out independent memoization for the element w/o
10 + // forcing that argument to evaluate unconditionally
11 + const y = x?.(
12 + <div>
13 + <span>{props.text}</span>
14 + </div>
15 + );
16 + return y;
17 +}
18 +
19 +```
20 +
21 +## Code
22 +
23 +```javascript
24 +function Component(props) {
25 + const $ = React.unstable_useMemoCache(2);
26 + const c_0 = $[0] !== props;
27 + let t0;
28 + if (c_0) {
29 + const x = makeOptionalFunction(props);
30 +
31 + t0 = x?.(<div>{<span>{props.text}</span>}</div>);
32 + $[0] = props;
33 + $[1] = t0;
34 + } else {
35 + t0 = $[1];
36 + }
37 + const y = t0;
38 + return y;
39 +}
40 +
41 +```
42 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/optional-call-with-independently-memoizable-arg.js new
+13
@@ -0,0 +1,13 @@
1 +function Component(props) {
2 + const x = makeOptionalFunction(props);
3 + // for a regular call, the JSX element could be independently memoized
4 + // since it is an immutable value. however, because the call is optional,
5 + // we can't extract out independent memoization for the element w/o
6 + // forcing that argument to evaluate unconditionally
7 + const y = x?.(
8 + <div>
9 + <span>{props.text}</span>
10 + </div>
11 + );
12 + return y;
13 +}
compiler/forget/src/__tests__/fixtures/compiler/optional-call.expect.md new
+35
@@ -0,0 +1,35 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const x = makeOptionalFunction(props);
7 + const y = makeObject(props);
8 + const z = x?.(y.a, props.a, foo(y.b), bar(props.b));
9 + return z;
10 +}
11 +
12 +```
13 +
14 +## Code
15 +
16 +```javascript
17 +function Component(props) {
18 + const $ = React.unstable_useMemoCache(2);
19 + const c_0 = $[0] !== props;
20 + let t0;
21 + if (c_0) {
22 + const x = makeOptionalFunction(props);
23 + const y = makeObject(props);
24 + t0 = x?.(y.a, props.a, foo(y.b), bar(props.b));
25 + $[0] = props;
26 + $[1] = t0;
27 + } else {
28 + t0 = $[1];
29 + }
30 + const z = t0;
31 + return z;
32 +}
33 +
34 +```
35 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/optional-call.js new
+6
@@ -0,0 +1,6 @@
1 +function Component(props) {
2 + const x = makeOptionalFunction(props);
3 + const y = makeObject(props);
4 + const z = x?.(y.a, props.a, foo(y.b), bar(props.b));
5 + return z;
6 +}