diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
index 486773d5eb91..f0c1a6b6e393 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
@@ -462,7 +462,10 @@ class Context {
}
let validated = makeIdentifierName(name).value;
let index = 0;
- while (this.uniqueIdentifiers.has(validated)) {
+ while (
+ this.uniqueIdentifiers.has(validated) ||
+ this.env.programContext.hasReference(validated)
+ ) {
validated = makeIdentifierName(`${name}${index++}`).value;
}
this.uniqueIdentifiers.add(validated);
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component-imported.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component-imported.expect.md
new file mode 100644
index 000000000000..5927ddb17ca9
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component-imported.expect.md
@@ -0,0 +1,56 @@
+
+## Input
+
+```javascript
+import {Stringify as $} from 'shared-runtime';
+
+// Regression test: when $ is imported as a binding, the compiler should not
+// use $ as the name for its synthesized memo cache variable — that would
+// shadow the import. The memo cache should be renamed to $0 (or similar).
+// See https://github.com/facebook/react/issues/36167
+
+function Component({x}: {x: number}) {
+ return <$ value={x} />;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{x: 1}],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify as $ } from "shared-runtime";
+
+// Regression test: when $ is imported as a binding, the compiler should not
+// use $ as the name for its synthesized memo cache variable — that would
+// shadow the import. The memo cache should be renamed to $0 (or similar).
+// See https://github.com/facebook/react/issues/36167
+
+function Component(t0) {
+ const $0 = _c(2);
+ const { x } = t0;
+ let t1;
+ if ($0[0] !== x) {
+ t1 = <$ value={x} />;
+ $0[0] = x;
+ $0[1] = t1;
+ } else {
+ t1 = $0[1];
+ }
+ return t1;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ x: 1 }],
+};
+
+```
+
+### Eval output
+(kind: ok)
{"value":1}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component-imported.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component-imported.tsx
new file mode 100644
index 000000000000..a19d52631efd
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component-imported.tsx
@@ -0,0 +1,15 @@
+import {Stringify as $} from 'shared-runtime';
+
+// Regression test: when $ is imported as a binding, the compiler should not
+// use $ as the name for its synthesized memo cache variable — that would
+// shadow the import. The memo cache should be renamed to $0 (or similar).
+// See https://github.com/facebook/react/issues/36167
+
+function Component({x}: {x: number}) {
+ return <$ value={x} />;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{x: 1}],
+};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component.expect.md
new file mode 100644
index 000000000000..1619cc10badf
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component.expect.md
@@ -0,0 +1,67 @@
+
+## Input
+
+```javascript
+// Regression test: when a function is named `$`, the compiler should not
+// use `$` as the name for its synthesized memo cache variable — that would
+// shadow the function name. The memo cache should be renamed to $0 (or similar).
+// See https://github.com/facebook/react/issues/36167
+
+function $(n: number) {
+ return n * 2;
+}
+
+function Component({x}: {x: number}) {
+ return {$(x)}
;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{x: 5}],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime"; // Regression test: when a function is named `$`, the compiler should not
+// use `$` as the name for its synthesized memo cache variable — that would
+// shadow the function name. The memo cache should be renamed to $0 (or similar).
+// See https://github.com/facebook/react/issues/36167
+
+function $(n) {
+ return n * 2;
+}
+
+function Component(t0) {
+ const $0 = _c(4);
+ const { x } = t0;
+ let t1;
+ if ($0[0] !== x) {
+ t1 = $(x);
+ $0[0] = x;
+ $0[1] = t1;
+ } else {
+ t1 = $0[1];
+ }
+ let t2;
+ if ($0[2] !== t1) {
+ t2 = {t1}
;
+ $0[2] = t1;
+ $0[3] = t2;
+ } else {
+ t2 = $0[3];
+ }
+ return t2;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ x: 5 }],
+};
+
+```
+
+### Eval output
+(kind: ok) 10
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component.tsx
new file mode 100644
index 000000000000..d2ccbc0288e0
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-dollar-sign-component.tsx
@@ -0,0 +1,17 @@
+// Regression test: when a function is named `$`, the compiler should not
+// use `$` as the name for its synthesized memo cache variable — that would
+// shadow the function name. The memo cache should be renamed to $0 (or similar).
+// See https://github.com/facebook/react/issues/36167
+
+function $(n: number) {
+ return n * 2;
+}
+
+function Component({x}: {x: number}) {
+ return {$(x)}
;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{x: 5}],
+};