[deps] Add DeclareLocal to ReactiveScope decls
--- Try to fix bug from #1589: > If a declaration for an immutable identifier (i.e. one that is not later re-assigned, since undefined is a primitive) is sandwiched between mutations, we currently do not record it as an output or hoist it out of the reactive scope. One simple fix is to add all declared (and later referenced) identifiers as declarations of a reactive scope. This has some undesired effects (e.g. additional instructions + memo cache slots), but in practice, this shouldn't be happening often. Alternatively, we could 1.) add a pass to hoist declarations, 2.) account for this in constant propagation, or 3.) add a bailout
Mofei Zhang committed
May 11, 2023 at 16:24 UTC
d1e044b81ab311b74427ebc58fc541a53bc3c711
3 files changed
+19
-7
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+9
@@ -537,6 +537,15 @@ class PropagationVisitor extends ReactiveFunctionVisitor<Context> {
537
id,
538
scope: context.currentScope,
539
});
540
+ } else if (value.kind === "DeclareLocal") {
541
+ // Some variables may be declared and never initialized. We need
542
+ // to retain (and hoist) these declarations if they are included
543
+ // in a reactive scope. One approach is to simply add all `DeclareLocal`s
544
+ // as scope declarations.
545
+ context.declare(value.lvalue.place.identifier, {
546
+ id,
547
+ scope: context.currentScope,
548
+ });
549
} else if (value.kind === "Destructure") {
550
context.visitOperand(value.value);
551
for (const place of eachPatternOperand(value.lvalue.pattern)) {
compiler/forget/src/__tests__/fixtures/compiler/uninitialized-declaration-in-reactive-scope.expect.md
renamed
+10
-7
@@ -16,22 +16,25 @@ function Component(props) {
16
```javascript
17
import { unstable_useMemoCache as useMemoCache } from "react";
18
function Component(props) {
19
- const $ = useMemoCache(2);
19
+ const $ = useMemoCache(3);
20
+ let y;
21
let x;
22
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
23
x = mutate();
23
- let y;
24
+
25
foo(x);
25
- $[0] = x;
26
+ $[0] = y;
27
+ $[1] = x;
28
} else {
27
- x = $[0];
29
+ y = $[0];
30
+ x = $[1];
31
}
32
let t0;
30
- if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
33
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
34
t0 = [y, x];
32
- $[1] = t0;
35
+ $[2] = t0;
36
} else {
34
- t0 = $[1];
37
+ t0 = $[2];
38
}
39
return t0;
40
}