Improve conditional dependency tracking for optional member expr inside optional

call 

When we traverse an OptionalExpression in PropagateScopeDependencies, we 
previously considered the entire value to be optional. With the changes in this 
stack to more accurately model OptionalMemberExpression, the `object` portion of 
an OptionalMemberExpression is now evaluated within the OptionalExpression. This 
PR refines the handling of OptionalExpression accordingly, so that we only treat 
the optional portion as conditional.
This commit is contained in:
Joe Savona
2023-05-02 16:49:54 -07:00
parent a1902b263d
commit 404f627c2c
5 changed files with 95 additions and 3 deletions
@@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import { CompilerError } from "../CompilerError";
import {
Identifier,
IdentifierId,
@@ -451,9 +452,26 @@ class PropagationVisitor extends ReactiveFunctionVisitor<Context> {
): void {
switch (value.kind) {
case "OptionalExpression": {
context.enterConditional(() => {
this.visitReactiveValue(context, id, value.value);
});
const inner = value.value;
// OptionalExpression value is a SequenceExpression where the instructions
// represent the code prior to the `?` and the final value represents the
// conditional code that follows.
if (inner.kind === "SequenceExpression") {
// Instructions are the unconditionally executed portion before the `?`
for (const instr of inner.instructions) {
this.visitInstruction(instr, context);
}
// The final value is the conditional portion following the `?`
context.enterConditional(() => {
this.visitReactiveValue(context, id, inner.value);
});
} else {
CompilerError.invariant(
"Expected OptionalExpression value to be a SequenceExpression",
value.loc,
`Found a '${value.kind}'`
);
}
break;
}
case "LogicalExpression": {
@@ -0,0 +1,30 @@
## Input
```javascript
function Component(props) {
return props.post.feedback.comments?.edges?.map(render);
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(2);
const c_0 = $[0] !== props.post.feedback.comments;
let t0;
if (c_0) {
t0 = props.post.feedback.comments?.edges?.map(render);
$[0] = props.post.feedback.comments;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
```
@@ -0,0 +1,3 @@
function Component(props) {
return props.post.feedback.comments?.edges?.map(render);
}
@@ -0,0 +1,35 @@
## Input
```javascript
function Component(props) {
const x = [];
x.push(props.items?.length);
x.push(props.items?.edges?.map?.(render)?.filter?.(Boolean) ?? []);
return x;
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(2);
const c_0 = $[0] !== props.items;
let x;
if (c_0) {
x = [];
x.push(props.items?.length);
x.push(props.items?.edges?.map?.(render)?.filter?.(Boolean) ?? []);
$[0] = props.items;
$[1] = x;
} else {
x = $[1];
}
return x;
}
```
@@ -0,0 +1,6 @@
function Component(props) {
const x = [];
x.push(props.items?.length);
x.push(props.items?.edges?.map?.(render)?.filter?.(Boolean) ?? []);
return x;
}