[hir] Don't track ref.current as a valid dep
Sathya Gunasekaran committed
May 31, 2023 at 13:54 UTC
bedf0cc6c50b4d738f4022e48188c0166e63bed8
12 files changed
+284
compiler/forget/src/HIR/HIR.ts
+8
@@ -979,6 +979,14 @@ export function isPrimitiveType(id: Identifier): boolean {
979
return id.type.kind === "Primitive";
980
}
981
982
+export function isRefValueType(id: Identifier): boolean {
983
+ return id.type.kind === "Object" && id.type.shapeId === "BuiltInRefValue";
984
+}
985
+
986
+export function isUseRefType(id: Identifier): boolean {
987
+ return id.type.kind === "Object" && id.type.shapeId === "BuiltInUseRefId";
988
+}
989
+
990
export function getHookKind(env: Environment, id: Identifier): HookKind | null {
991
const idType = id.type;
992
if (idType.kind === "Function") {
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+9
@@ -11,6 +11,7 @@ import {
11
IdentifierId,
12
InstructionId,
13
InstructionKind,
14
+ isUseRefType,
15
makeInstructionId,
16
Place,
17
ReactiveFunction,
@@ -314,6 +315,14 @@ class Context {
315
316
// Checks if identifier is a valid dependency in the current scope
317
#checkValidDependency(maybeDependency: ReactiveScopeDependency): boolean {
318
+ // ref.current access is not a valid dep
319
+ if (
320
+ isUseRefType(maybeDependency.identifier) &&
321
+ maybeDependency.path.at(0) === "current"
322
+ ) {
323
+ return false;
324
+ }
325
+
326
const identifier = maybeDependency.identifier;
327
// If this operand is used in a scope, has a dynamic value, and was defined
328
// before this scope, then its a dependency of the scope.
compiler/forget/src/__tests__/fixtures/compiler/ref-current-field-not-added-to-dep.expect.md
new
+46
@@ -0,0 +1,46 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function VideoTab() {
6
+ const ref = useRef();
7
+ let x = () => {
8
+ ref.current.x;
9
+ };
10
+
11
+ return <VideoList videos={x} />;
12
+}
13
+
14
+```
15
+
16
+## Code
17
+
18
+```javascript
19
+import { unstable_useMemoCache as useMemoCache } from "react";
20
+function VideoTab() {
21
+ const $ = useMemoCache(3);
22
+ const ref = useRef();
23
+ let t0;
24
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
+ t0 = () => {
26
+ ref.current.x;
27
+ };
28
+ $[0] = t0;
29
+ } else {
30
+ t0 = $[0];
31
+ }
32
+ const x = t0;
33
+ const c_1 = $[1] !== x;
34
+ let t1;
35
+ if (c_1) {
36
+ t1 = <VideoList videos={x} />;
37
+ $[1] = x;
38
+ $[2] = t1;
39
+ } else {
40
+ t1 = $[2];
41
+ }
42
+ return t1;
43
+}
44
+
45
+```
46
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/ref-current-field-not-added-to-dep.js
new
+8
@@ -0,0 +1,8 @@
1
+function VideoTab() {
2
+ const ref = useRef();
3
+ let x = () => {
4
+ ref.current.x;
5
+ };
6
+
7
+ return <VideoList videos={x} />;
8
+}
compiler/forget/src/__tests__/fixtures/compiler/ref-current-not-added-to-dep-2.expect.md
new
+45
@@ -0,0 +1,45 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Foo({ a }) {
6
+ const ref = useRef();
7
+ const x = { a, val: ref.current };
8
+
9
+ return <VideoList videos={x} />;
10
+}
11
+
12
+```
13
+
14
+## Code
15
+
16
+```javascript
17
+import { unstable_useMemoCache as useMemoCache } from "react";
18
+function Foo(t18) {
19
+ const $ = useMemoCache(4);
20
+ const { a } = t18;
21
+ const ref = useRef();
22
+ const c_0 = $[0] !== a;
23
+ let t0;
24
+ if (c_0) {
25
+ t0 = { a, val: ref.current };
26
+ $[0] = a;
27
+ $[1] = t0;
28
+ } else {
29
+ t0 = $[1];
30
+ }
31
+ const x = t0;
32
+ const c_2 = $[2] !== x;
33
+ let t1;
34
+ if (c_2) {
35
+ t1 = <VideoList videos={x} />;
36
+ $[2] = x;
37
+ $[3] = t1;
38
+ } else {
39
+ t1 = $[3];
40
+ }
41
+ return t1;
42
+}
43
+
44
+```
45
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/ref-current-not-added-to-dep-2.js
new
+6
@@ -0,0 +1,6 @@
1
+function Foo({ a }) {
2
+ const ref = useRef();
3
+ const x = { a, val: ref.current };
4
+
5
+ return <VideoList videos={x} />;
6
+}
compiler/forget/src/__tests__/fixtures/compiler/ref-current-not-added-to-dep.expect.md
new
+46
@@ -0,0 +1,46 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function VideoTab() {
6
+ const ref = useRef();
7
+ let x = () => {
8
+ ref.current;
9
+ };
10
+
11
+ return <VideoList videos={x} />;
12
+}
13
+
14
+```
15
+
16
+## Code
17
+
18
+```javascript
19
+import { unstable_useMemoCache as useMemoCache } from "react";
20
+function VideoTab() {
21
+ const $ = useMemoCache(3);
22
+ const ref = useRef();
23
+ let t0;
24
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
+ t0 = () => {
26
+ ref.current;
27
+ };
28
+ $[0] = t0;
29
+ } else {
30
+ t0 = $[0];
31
+ }
32
+ const x = t0;
33
+ const c_1 = $[1] !== x;
34
+ let t1;
35
+ if (c_1) {
36
+ t1 = <VideoList videos={x} />;
37
+ $[1] = x;
38
+ $[2] = t1;
39
+ } else {
40
+ t1 = $[2];
41
+ }
42
+ return t1;
43
+}
44
+
45
+```
46
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/ref-current-not-added-to-dep.js
new
+8
@@ -0,0 +1,8 @@
1
+function VideoTab() {
2
+ const ref = useRef();
3
+ let x = () => {
4
+ ref.current;
5
+ };
6
+
7
+ return <VideoList videos={x} />;
8
+}
compiler/forget/src/__tests__/fixtures/compiler/ref-current-optional-field-no-added-to-dep.expect.md
new
+46
@@ -0,0 +1,46 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function VideoTab() {
6
+ const ref = useRef();
7
+ let x = () => {
8
+ ref.current?.x;
9
+ };
10
+
11
+ return <VideoList videos={x} />;
12
+}
13
+
14
+```
15
+
16
+## Code
17
+
18
+```javascript
19
+import { unstable_useMemoCache as useMemoCache } from "react";
20
+function VideoTab() {
21
+ const $ = useMemoCache(3);
22
+ const ref = useRef();
23
+ let t0;
24
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
+ t0 = () => {
26
+ ref.current?.x;
27
+ };
28
+ $[0] = t0;
29
+ } else {
30
+ t0 = $[0];
31
+ }
32
+ const x = t0;
33
+ const c_1 = $[1] !== x;
34
+ let t1;
35
+ if (c_1) {
36
+ t1 = <VideoList videos={x} />;
37
+ $[1] = x;
38
+ $[2] = t1;
39
+ } else {
40
+ t1 = $[2];
41
+ }
42
+ return t1;
43
+}
44
+
45
+```
46
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/ref-current-optional-field-no-added-to-dep.js
new
+8
@@ -0,0 +1,8 @@
1
+function VideoTab() {
2
+ const ref = useRef();
3
+ let x = () => {
4
+ ref.current?.x;
5
+ };
6
+
7
+ return <VideoList videos={x} />;
8
+}
compiler/forget/src/__tests__/fixtures/compiler/ref-current-write-not-added-to-dep.expect.md
new
+46
@@ -0,0 +1,46 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function VideoTab() {
6
+ const ref = useRef();
7
+ let x = () => {
8
+ ref.current = 1;
9
+ };
10
+
11
+ return <VideoList videos={x} />;
12
+}
13
+
14
+```
15
+
16
+## Code
17
+
18
+```javascript
19
+import { unstable_useMemoCache as useMemoCache } from "react";
20
+function VideoTab() {
21
+ const $ = useMemoCache(3);
22
+ const ref = useRef();
23
+ let t0;
24
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
+ t0 = () => {
26
+ ref.current = 1;
27
+ };
28
+ $[0] = t0;
29
+ } else {
30
+ t0 = $[0];
31
+ }
32
+ const x = t0;
33
+ const c_1 = $[1] !== x;
34
+ let t1;
35
+ if (c_1) {
36
+ t1 = <VideoList videos={x} />;
37
+ $[1] = x;
38
+ $[2] = t1;
39
+ } else {
40
+ t1 = $[2];
41
+ }
42
+ return t1;
43
+}
44
+
45
+```
46
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/ref-current-write-not-added-to-dep.js
new
+8
@@ -0,0 +1,8 @@
1
+function VideoTab() {
2
+ const ref = useRef();
3
+ let x = () => {
4
+ ref.current = 1;
5
+ };
6
+
7
+ return <VideoList videos={x} />;
8
+}