[compiler] Handle member expr as computed property (#31344)
This PR loosens the restriction on the types of computed properties we can handle. Previously, we would disallow anything that is not an identifier because non-identifiers could be mutating. But member expressions are not mutating so we can treat them similar to identifiers.
Sathya Gunasekaran committed
Oct 28, 2024 at 13:10 UTC
aded0ef831e100a5ee9d9e674cb0482326279118
5 files changed
+122
-1
compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
+1
-1
@@ -1418,7 +1418,7 @@ function lowerObjectPropertyKey(
1418
name: key.node.value,
1419
};
1420
} else if (property.node.computed && key.isExpression()) {
1421
- if (!key.isIdentifier()) {
1421
+ if (!key.isIdentifier() && !key.isMemberExpression()) {
1422
/*
1423
* NOTE: allowing complex key expressions can trigger a bug where a mutation is made conditional
1424
* see fixture
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.expect.md
new
+37
@@ -0,0 +1,37 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import {identity, mutate, mutateAndReturn} from 'shared-runtime';
6
+
7
+function Component(props) {
8
+ const obj = {mutateAndReturn};
9
+ const key = {};
10
+ const context = {
11
+ [obj.mutateAndReturn(key)]: identity([props.value]),
12
+ };
13
+ mutate(key);
14
+ return context;
15
+}
16
+
17
+export const FIXTURE_ENTRYPOINT = {
18
+ fn: Component,
19
+ params: [{value: 42}],
20
+};
21
+
22
+```
23
+
24
+
25
+## Error
26
+
27
+```
28
+ 5 | const key = {};
29
+ 6 | const context = {
30
+> 7 | [obj.mutateAndReturn(key)]: identity([props.value]),
31
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ Todo: (BuildHIR::lowerExpression) Expected Identifier, got CallExpression key in ObjectExpression (7:7)
32
+ 8 | };
33
+ 9 | mutate(key);
34
+ 10 | return context;
35
+```
36
+
37
+
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.js
new
+16
@@ -0,0 +1,16 @@
1
+import {identity, mutate, mutateAndReturn} from 'shared-runtime';
2
+
3
+function Component(props) {
4
+ const obj = {mutateAndReturn};
5
+ const key = {};
6
+ const context = {
7
+ [obj.mutateAndReturn(key)]: identity([props.value]),
8
+ };
9
+ mutate(key);
10
+ return context;
11
+}
12
+
13
+export const FIXTURE_ENTRYPOINT = {
14
+ fn: Component,
15
+ params: [{value: 42}],
16
+};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.expect.md
new
+53
@@ -0,0 +1,53 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import {identity, mutate, mutateAndReturn} from 'shared-runtime';
6
+
7
+function Component(props) {
8
+ const key = {a: 'key'};
9
+ const context = {
10
+ [key.a]: identity([props.value]),
11
+ };
12
+ mutate(key);
13
+ return context;
14
+}
15
+
16
+export const FIXTURE_ENTRYPOINT = {
17
+ fn: Component,
18
+ params: [{value: 42}],
19
+};
20
+
21
+```
22
+
23
+## Code
24
+
25
+```javascript
26
+import { c as _c } from "react/compiler-runtime";
27
+import { identity, mutate, mutateAndReturn } from "shared-runtime";
28
+
29
+function Component(props) {
30
+ const $ = _c(2);
31
+ let context;
32
+ if ($[0] !== props.value) {
33
+ const key = { a: "key" };
34
+ context = { [key.a]: identity([props.value]) };
35
+
36
+ mutate(key);
37
+ $[0] = props.value;
38
+ $[1] = context;
39
+ } else {
40
+ context = $[1];
41
+ }
42
+ return context;
43
+}
44
+
45
+export const FIXTURE_ENTRYPOINT = {
46
+ fn: Component,
47
+ params: [{ value: 42 }],
48
+};
49
+
50
+```
51
+
52
+### Eval output
53
+(kind: ok) {"key":[42]}
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.js
new
+15
@@ -0,0 +1,15 @@
1
+import {identity, mutate, mutateAndReturn} from 'shared-runtime';
2
+
3
+function Component(props) {
4
+ const key = {a: 'key'};
5
+ const context = {
6
+ [key.a]: identity([props.value]),
7
+ };
8
+ mutate(key);
9
+ return context;
10
+}
11
+
12
+export const FIXTURE_ENTRYPOINT = {
13
+ fn: Component,
14
+ params: [{value: 42}],
15
+};