Repository: facebook/react
Pull request: [compiler] Don't include current field accesses in auto-deps


## Summary

Drops .current field accesses in inferred dep arrays
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31652).
* #31657
* __->__ #31652

Changed files:
filename: compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts
patch: @@ -222,6 +222,13 @@ function writeDependencyToInstructions(
        */
       break;
     }
+    if (path.property === 'current') {
+      /*
+       * Prune ref.current accesses. This may over-capture for non-ref values with
+       * a current property, but that's fine.
+       */
+      break;
+    }
     const nextValue = createTemporaryPlace(env, GeneratedSource);
     nextValue.reactive = reactive;
     instructions.push({

filename: compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonreactive-ref-helper.expect.md
patch: @@ -0,0 +1,89 @@
+
+## Input
+
+```javascript
+// @inferEffectDependencies
+import {useEffect} from 'react';
+import {print} from 'shared-runtime';
+
+/**
+ * We never include a .current access in a dep array because it may be a ref access.
+ * This might over-capture objects that are not refs and happen to have fields named
+ * current, but that should be a rare case and the result would still be correct
+ * (assuming the effect is idempotent). In the worst case, you can always write a manual
+ * dep array.
+ */
+function RefsInEffects() {
+  const ref = useRefHelper();
+  const wrapped = useDeeperRefHelper();
+  useEffect(() => {
+    print(ref.current);
+    print(wrapped.foo.current);
+  });
+}
+
+function useRefHelper() {
+  return useRef(0);
+}
+
+function useDeeperRefHelper() {
+  return {foo: useRefHelper()};
+}
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
+import { useEffect } from "react";
+import { print } from "shared-runtime";
+
+/**
+ * We never include a .current access in a dep array because it may be a ref access.
+ * This might over-capture objects that are not refs and happen to have fields named
+ * current, but that should be a rare case and the result would still be correct
+ * (assuming the effect is idempotent). In the worst case, you can always write a manual
+ * dep array.
+ */
+function RefsInEffects() {
+  const $ = _c(3);
+  const ref = useRefHelper();
+  const wrapped = useDeeperRefHelper();
+  let t0;
+  if ($[0] !== ref.current || $[1] !== wrapped.foo.current) {
+    t0 = () => {
+      print(ref.current);
+      print(wrapped.foo.current);
+    };
+    $[0] = ref.current;
+    $[1] = wrapped.foo.current;
+    $[2] = t0;
+  } else {
+    t0 = $[2];
+  }
+  useEffect(t0, [ref, wrapped.foo]);
+}
+
+function useRefHelper() {
+  return useRef(0);
+}
+
+function useDeeperRefHelper() {
+  const $ = _c(2);
+  const t0 = useRefHelper();
+  let t1;
+  if ($[0] !== t0) {
+    t1 = { foo: t0 };
+    $[0] = t0;
+    $[1] = t1;
+  } else {
+    t1 = $[1];
+  }
+  return t1;
+}
+
+```
+      
+### Eval output
+(kind: exception) Fixture not implemented
\ No newline at end of file

filename: compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonreactive-ref-helper.js
patch: @@ -0,0 +1,27 @@
+// @inferEffectDependencies
+import {useEffect} from 'react';
+import {print} from 'shared-runtime';
+
+/**
+ * We never include a .current access in a dep array because it may be a ref access.
+ * This might over-capture objects that are not refs and happen to have fields named
+ * current, but that should be a rare case and the result would still be correct
+ * (assuming the effect is idempotent). In the worst case, you can always write a manual
+ * dep array.
+ */
+function RefsInEffects() {
+  const ref = useRefHelper();
+  const wrapped = useDeeperRefHelper();
+  useEffect(() => {
+    print(ref.current);
+    print(wrapped.foo.current);
+  });
+}
+
+function useRefHelper() {
+  return useRef(0);
+}
+
+function useDeeperRefHelper() {
+  return {foo: useRefHelper()};
+}