diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts
index 73088fd8521..488d988b971 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts
@@ -451,6 +451,18 @@ function* generateInstructionTypes(
case 'JsxExpression':
case 'JsxFragment': {
+ if (env.config.enableTreatRefLikeIdentifiersAsRefs) {
+ if (value.kind === 'JsxExpression') {
+ for (const prop of value.props) {
+ if (prop.kind === 'JsxAttribute' && prop.name === 'ref') {
+ yield equation(prop.place.identifier.type, {
+ kind: 'Object',
+ shapeId: BuiltInUseRefId,
+ });
+ }
+ }
+ }
+ }
yield equation(left, {kind: 'Object', shapeId: BuiltInJsxId});
break;
}
diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts
index cb78fc1d874..b4fb0d171ac 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts
@@ -407,15 +407,28 @@ function validateNoRefAccessInRenderImpl(
);
}
}
+ /*
+ * If we already reported an error on this instruction, don't report
+ * duplicate errors
+ */
if (!didError) {
- /*
- * If we already reported an error on this instruction, don't report
- * duplicate errors
- */
+ const isRefLValue = isUseRefType(instr.lvalue.identifier);
for (const operand of eachInstructionValueOperand(instr.value)) {
if (hookKind != null) {
validateNoDirectRefValueAccess(errors, operand, env);
- } else {
+ } else if (!isRefLValue) {
+ /**
+ * In general passing a ref to a function may access that ref
+ * value during render, so we disallow it.
+ *
+ * The main exception is the "mergeRefs" pattern, ie a function
+ * that accepts multiple refs as arguments (or an array of refs)
+ * and returns a new, aggregated ref. If the lvalue is a ref,
+ * we assume that the user is doing this pattern and allow passing
+ * refs.
+ *
+ * Eg `const mergedRef = mergeRefs(ref1, ref2)`
+ */
validateNoRefPassedToFunction(
errors,
env,
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-merge-refs-pattern.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-merge-refs-pattern.expect.md
new file mode 100644
index 00000000000..6933edef467
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-merge-refs-pattern.expect.md
@@ -0,0 +1,44 @@
+
+## Input
+
+```javascript
+// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
+
+import {useRef} from 'react';
+
+function Component() {
+ const ref = useRef(null);
+ const ref2 = useRef(null);
+ const mergedRef = mergeRefs([ref], ref2);
+
+ return ;
+}
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime"; // @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
+
+import { useRef } from "react";
+
+function Component() {
+ const $ = _c(1);
+ const ref = useRef(null);
+ const ref2 = useRef(null);
+ const mergedRef = mergeRefs([ref], ref2);
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ t0 = ;
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ return t0;
+}
+
+```
+
+### Eval output
+(kind: exception) Fixture not implemented
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-merge-refs-pattern.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-merge-refs-pattern.js
new file mode 100644
index 00000000000..91c5f082849
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-merge-refs-pattern.js
@@ -0,0 +1,11 @@
+// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
+
+import {useRef} from 'react';
+
+function Component() {
+ const ref = useRef(null);
+ const ref2 = useRef(null);
+ const mergedRef = mergeRefs([ref], ref2);
+
+ return ;
+}