[hir] Use a stable identity for undefined value
InferReferenceEffects uses object identity to merge states, which breaks when we create a new object to model `undefined`. Two value objects representing `undefined` are not equal due to referential equality. Instead, let's use a singleton to represent `undefined` value.
Sathya Gunasekaran committed
Oct 4, 2023 at 12:11 UTC
3aaf8be25cc4db8307eb3f6ce65a0bc4101d43e8
6 files changed
+97
-5
compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts
+8
-5
@@ -12,6 +12,7 @@ import {
12
BlockId,
13
CallExpression,
14
Effect,
15
+ GeneratedSource,
16
HIRFunction,
17
IdentifierId,
18
InstructionKind,
@@ -39,6 +40,12 @@ import {
40
} from "../HIR/visitors";
41
import { assertExhaustive } from "../Utils/utils";
42
43
+const UndefinedValue: InstructionValue = {
44
+ kind: "Primitive",
45
+ loc: GeneratedSource,
46
+ value: undefined,
47
+};
48
+
49
/**
50
* For every usage of a value in the given function, infers the effect or action
51
* taken at that reference. Each reference is inferred as exactly one of:
@@ -933,11 +940,7 @@ function inferBlock(
940
continue;
941
}
942
case "DeclareLocal": {
936
- const value: InstructionValue = {
937
- kind: "Primitive",
938
- loc: instrValue.loc,
939
- value: undefined,
940
- };
943
+ const value = UndefinedValue;
944
state.initialize(
945
value,
946
// Catch params may be aliased to mutable values
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/for-loop-let-undefined-decl.expect.md
new
+46
@@ -0,0 +1,46 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function useFoo() {
6
+ for (let i = 0; i <= 5; i++) {
7
+ let color;
8
+ if (isSelected) {
9
+ color = isCurrent ? "#FFCC22" : "#FF5050";
10
+ } else {
11
+ color = isCurrent ? "#CCFF03" : "#CCCCCC";
12
+ }
13
+ console.log(color);
14
+ }
15
+}
16
+
17
+export const FIXTURE_ENTRYPOINT = {
18
+ params: [],
19
+ fn: useFoo,
20
+};
21
+
22
+```
23
+
24
+## Code
25
+
26
+```javascript
27
+function useFoo() {
28
+ for (let i = 0; i <= 5; i++) {
29
+ let color = undefined;
30
+ if (isSelected) {
31
+ color = isCurrent ? "#FFCC22" : "#FF5050";
32
+ } else {
33
+ color = isCurrent ? "#CCFF03" : "#CCCCCC";
34
+ }
35
+
36
+ console.log(color);
37
+ }
38
+}
39
+
40
+export const FIXTURE_ENTRYPOINT = {
41
+ params: [],
42
+ fn: useFoo,
43
+};
44
+
45
+```
46
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/for-loop-let-undefined-decl.js
new
+16
@@ -0,0 +1,16 @@
1
+function useFoo() {
2
+ for (let i = 0; i <= 5; i++) {
3
+ let color;
4
+ if (isSelected) {
5
+ color = isCurrent ? "#FFCC22" : "#FF5050";
6
+ } else {
7
+ color = isCurrent ? "#CCFF03" : "#CCCCCC";
8
+ }
9
+ console.log(color);
10
+ }
11
+}
12
+
13
+export const FIXTURE_ENTRYPOINT = {
14
+ params: [],
15
+ fn: useFoo,
16
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/loop-unused-let.expect.md
new
+21
@@ -0,0 +1,21 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function useFoo() {
6
+ while (1) {
7
+ let foo;
8
+ }
9
+}
10
+
11
+```
12
+
13
+## Code
14
+
15
+```javascript
16
+function useFoo() {
17
+ while (1) {}
18
+}
19
+
20
+```
21
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/loop-unused-let.js
new
+5
@@ -0,0 +1,5 @@
1
+function useFoo() {
2
+ while (1) {
3
+ let foo;
4
+ }
5
+}
compiler/packages/sprout/src/SproutTodoFilter.ts
+1
@@ -461,6 +461,7 @@ const skipFilter = new Set([
461
"fbtparam-with-jsx-fragment-value",
462
"fbt-preserve-jsxtext",
463
"useContext-mutable-value",
464
+ "loop-unused-let",
465
]);
466
467
export default skipFilter;