Fix using context variable as JSX element tag
Updates the lowering for JSX element tag names to check if the identifier is a context or local variable and use the appropriate instruction kind.
Joe Savona committed
Mar 21, 2024 at 17:12 UTC
231f29f6f3ef5c8612cfbb050695d7a1e96ebd78
6 files changed
+85
-41
compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts
+3
-2
@@ -2916,8 +2916,9 @@ function lowerJsxElementName(
2916
if (exprPath.isJSXIdentifier()) {
2917
const tag: string = exprPath.node.name;
2918
if (tag.match(/^[A-Z]/)) {
2919
+ const kind = getLoadKind(builder, exprPath);
2920
return lowerValueToTemporary(builder, {
2920
- kind: "LoadLocal",
2921
+ kind: kind,
2922
place: lowerIdentifier(builder, exprPath),
2923
loc: exprLoc,
2924
});
@@ -3245,7 +3246,7 @@ function getStoreKind(
3246
3247
function getLoadKind(
3248
builder: HIRBuilder,
3248
- identifier: NodePath<t.Identifier>
3249
+ identifier: NodePath<t.Identifier | t.JSXIdentifier>
3250
): "LoadLocal" | "LoadContext" {
3251
const isContext = builder.isContextIdentifier(identifier);
3252
return isContext ? "LoadContext" : "LoadLocal";
compiler/packages/babel-plugin-react-forget/src/HIR/HIRBuilder.ts
+1
-1
@@ -267,7 +267,7 @@ export default class HIRBuilder {
267
return resolvedBinding;
268
}
269
270
- isContextIdentifier(path: NodePath<t.Identifier>): boolean {
270
+ isContextIdentifier(path: NodePath<t.Identifier | t.JSXIdentifier>): boolean {
271
const binding = this.#resolveBabelBinding(path);
272
if (binding) {
273
return this.#env.isContextIdentifier(binding.identifier);
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/context-variable-as-jsx-element-tag.expect.md
new
+64
@@ -0,0 +1,64 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import { useMemo } from "react";
6
+import { Stringify } from "shared-runtime";
7
+
8
+function Component(props) {
9
+ let Component = Stringify;
10
+
11
+ Component = useMemo(() => {
12
+ return Component;
13
+ });
14
+
15
+ return <Component {...props} />;
16
+}
17
+
18
+export const FIXTURE_ENTRYPOINT = {
19
+ fn: Component,
20
+ params: [{ name: "Sathya" }],
21
+};
22
+
23
+```
24
+
25
+## Code
26
+
27
+```javascript
28
+import { useMemo, unstable_useMemoCache as useMemoCache } from "react";
29
+import { Stringify } from "shared-runtime";
30
+
31
+function Component(props) {
32
+ const $ = useMemoCache(3);
33
+ let Component;
34
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
35
+ Component = Stringify;
36
+
37
+ Component;
38
+ let t0;
39
+ t0 = Component;
40
+ Component = t0;
41
+ $[0] = Component;
42
+ } else {
43
+ Component = $[0];
44
+ }
45
+ let t0;
46
+ if ($[1] !== props) {
47
+ t0 = <Component {...props} />;
48
+ $[1] = props;
49
+ $[2] = t0;
50
+ } else {
51
+ t0 = $[2];
52
+ }
53
+ return t0;
54
+}
55
+
56
+export const FIXTURE_ENTRYPOINT = {
57
+ fn: Component,
58
+ params: [{ name: "Sathya" }],
59
+};
60
+
61
+```
62
+
63
+### Eval output
64
+(kind: ok) <div>{"name":"Sathya"}</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/context-variable-as-jsx-element-tag.js
new
+17
@@ -0,0 +1,17 @@
1
+import { useMemo } from "react";
2
+import { Stringify } from "shared-runtime";
3
+
4
+function Component(props) {
5
+ let Component = Stringify;
6
+
7
+ Component = useMemo(() => {
8
+ return Component;
9
+ });
10
+
11
+ return <Component {...props} />;
12
+}
13
+
14
+export const FIXTURE_ENTRYPOINT = {
15
+ fn: Component,
16
+ params: [{ name: "Sathya" }],
17
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-context-variable-as-jsx-element-tag.expect.md
deleted
-29
@@ -1,29 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-function Component(props) {
6
- let Component = Foo;
7
-
8
- Component = useMemo(() => {
9
- return Component;
10
- });
11
-
12
- return <Component />;
13
-}
14
-
15
-```
16
-
17
-
18
-## Error
19
-
20
-```
21
- 6 | });
22
- 7 |
23
-> 8 | return <Component />;
24
- | ^^^^^^^^^ [ReactForget] Invariant: Expected all references to a variable to be consistently local or context references. Identifier <unknown> Component$2 is referenced as a local variable, but was previously referenced as a context variable (8:8)
25
- 9 | }
26
- 10 |
27
-```
28
-
29
-
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-context-variable-as-jsx-element-tag.js
deleted
-9
@@ -1,9 +0,0 @@
1
-function Component(props) {
2
- let Component = Foo;
3
-
4
- Component = useMemo(() => {
5
- return Component;
6
- });
7
-
8
- return <Component />;
9
-}