[hir] Mark MethodCalls as escaping
Treat MethodCalls similar to general CallExpressions and mark them as escaping in PruneNonEscapingScopes pass. ghstack-source-id: 3c81bdb17f58fbeef8be24e7cb363172d1867217 Pull Request resolved: https://github.com/facebook/react-forget/pull/2925
Sathya Gunsasekaran committed
May 1, 2024 at 15:58 UTC
85e6e9b469d6b1c437764d7662341c2f532bb3c4
7 files changed
+232
-9
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/PruneNonEscapingScopes.ts
+9
-3
@@ -872,12 +872,18 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<State> {
872
instruction.lvalue.identifier.id,
873
instruction.value.place.identifier.id
874
);
875
- } else if (instruction.value.kind === "CallExpression") {
876
- const callee = instruction.value.callee;
875
+ } else if (
876
+ instruction.value.kind === "CallExpression" ||
877
+ instruction.value.kind === "MethodCall"
878
+ ) {
879
+ let callee =
880
+ instruction.value.kind === "CallExpression"
881
+ ? instruction.value.callee
882
+ : instruction.value.property;
883
if (getHookKind(state.env, callee.identifier) != null) {
884
const signature = getFunctionCallSignature(
885
this.env,
880
- instruction.value.callee.identifier.type
886
+ callee.identifier.type
887
);
888
/*
889
* Hook values are assumed to escape by default since they can be inputs
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rules-of-hooks/rules-of-hooks-93dc5d5e538a.expect.md
+10
-3
@@ -17,14 +17,21 @@ function RegressionTest() {
17
## Code
18
19
```javascript
20
-// Valid because the loop doesn't change the order of hooks calls.
20
+import { unstable_useMemoCache as useMemoCache } from "react"; // Valid because the loop doesn't change the order of hooks calls.
21
function RegressionTest() {
22
+ const $ = useMemoCache(1);
23
const res = [];
24
for (let i = 0; i !== 10 && true; ++i) {
25
res.push(i);
26
}
26
-
27
- React.useLayoutEffect(() => {});
27
+ let t0;
28
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
29
+ t0 = () => {};
30
+ $[0] = t0;
31
+ } else {
32
+ t0 = $[0];
33
+ }
34
+ React.useLayoutEffect(t0);
35
}
36
37
```
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-global-pruned.expect.md
new
+77
@@ -0,0 +1,77 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import { useEffect } from "react";
6
+
7
+function someGlobal() {}
8
+function useFoo() {
9
+ const fn = React.useMemo(
10
+ () =>
11
+ function () {
12
+ someGlobal();
13
+ },
14
+ []
15
+ );
16
+ useEffect(() => {
17
+ fn();
18
+ }, [fn]);
19
+
20
+ return null;
21
+}
22
+
23
+export const FIXTURE_ENTRYPOINT = {
24
+ fn: useFoo,
25
+ params: [],
26
+ isComponent: false,
27
+};
28
+
29
+```
30
+
31
+## Code
32
+
33
+```javascript
34
+import { useEffect, unstable_useMemoCache as useMemoCache } from "react";
35
+
36
+function someGlobal() {}
37
+function useFoo() {
38
+ const $ = useMemoCache(3);
39
+ let t0;
40
+ let t1;
41
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
42
+ t1 = function () {
43
+ someGlobal();
44
+ };
45
+ $[0] = t1;
46
+ } else {
47
+ t1 = $[0];
48
+ }
49
+ t0 = t1;
50
+ const fn = t0;
51
+ let t2;
52
+ let t3;
53
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
54
+ t2 = () => {
55
+ fn();
56
+ };
57
+ t3 = [fn];
58
+ $[1] = t2;
59
+ $[2] = t3;
60
+ } else {
61
+ t2 = $[1];
62
+ t3 = $[2];
63
+ }
64
+ useEffect(t2, t3);
65
+ return null;
66
+}
67
+
68
+export const FIXTURE_ENTRYPOINT = {
69
+ fn: useFoo,
70
+ params: [],
71
+ isComponent: false,
72
+};
73
+
74
+```
75
+
76
+### Eval output
77
+(kind: ok) null
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-global-pruned.js
new
+23
@@ -0,0 +1,23 @@
1
+import { useEffect } from "react";
2
+
3
+function someGlobal() {}
4
+function useFoo() {
5
+ const fn = React.useMemo(
6
+ () =>
7
+ function () {
8
+ someGlobal();
9
+ },
10
+ []
11
+ );
12
+ useEffect(() => {
13
+ fn();
14
+ }, [fn]);
15
+
16
+ return null;
17
+}
18
+
19
+export const FIXTURE_ENTRYPOINT = {
20
+ fn: useFoo,
21
+ params: [],
22
+ isComponent: false,
23
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-method-call.expect.md
+12
-3
@@ -19,11 +19,20 @@ export const FIXTURE_ENTRYPOINT = {
19
## Code
20
21
```javascript
22
+import { unstable_useMemoCache as useMemoCache } from "react";
23
let x = {};
24
function Component() {
24
- React.useEffect(() => {
25
- x.foo = 1;
26
- });
25
+ const $ = useMemoCache(1);
26
+ let t0;
27
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28
+ t0 = () => {
29
+ x.foo = 1;
30
+ };
31
+ $[0] = t0;
32
+ } else {
33
+ t0 = $[0];
34
+ }
35
+ React.useEffect(t0);
36
}
37
38
export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-namespace-pruned.expect.md
new
+78
@@ -0,0 +1,78 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import * as React from "react";
6
+
7
+function someGlobal() {}
8
+function useFoo() {
9
+ const fn = React.useMemo(
10
+ () =>
11
+ function () {
12
+ someGlobal();
13
+ },
14
+ []
15
+ );
16
+ React.useEffect(() => {
17
+ fn();
18
+ }, [fn]);
19
+
20
+ return null;
21
+}
22
+
23
+export const FIXTURE_ENTRYPOINT = {
24
+ fn: useFoo,
25
+ params: [],
26
+ isComponent: false,
27
+};
28
+
29
+```
30
+
31
+## Code
32
+
33
+```javascript
34
+import { unstable_useMemoCache as useMemoCache } from "react";
35
+import * as React from "react";
36
+
37
+function someGlobal() {}
38
+function useFoo() {
39
+ const $ = useMemoCache(3);
40
+ let t0;
41
+ let t1;
42
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
43
+ t1 = function () {
44
+ someGlobal();
45
+ };
46
+ $[0] = t1;
47
+ } else {
48
+ t1 = $[0];
49
+ }
50
+ t0 = t1;
51
+ const fn = t0;
52
+ let t2;
53
+ let t3;
54
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
55
+ t2 = () => {
56
+ fn();
57
+ };
58
+ t3 = [fn];
59
+ $[1] = t2;
60
+ $[2] = t3;
61
+ } else {
62
+ t2 = $[1];
63
+ t3 = $[2];
64
+ }
65
+ React.useEffect(t2, t3);
66
+ return null;
67
+}
68
+
69
+export const FIXTURE_ENTRYPOINT = {
70
+ fn: useFoo,
71
+ params: [],
72
+ isComponent: false,
73
+};
74
+
75
+```
76
+
77
+### Eval output
78
+(kind: ok) null
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-namespace-pruned.js
new
+23
@@ -0,0 +1,23 @@
1
+import * as React from "react";
2
+
3
+function someGlobal() {}
4
+function useFoo() {
5
+ const fn = React.useMemo(
6
+ () =>
7
+ function () {
8
+ someGlobal();
9
+ },
10
+ []
11
+ );
12
+ React.useEffect(() => {
13
+ fn();
14
+ }, [fn]);
15
+
16
+ return null;
17
+}
18
+
19
+export const FIXTURE_ENTRYPOINT = {
20
+ fn: useFoo,
21
+ params: [],
22
+ isComponent: false,
23
+};