Skip to content

[compiler] Fix false positive refs-rule errors when forwarding props.ref#36293

Open
ousamabenyounes wants to merge 2 commits intofacebook:mainfrom
ousamabenyounes:fix/issue-34775
Open

[compiler] Fix false positive refs-rule errors when forwarding props.ref#36293
ousamabenyounes wants to merge 2 commits intofacebook:mainfrom
ousamabenyounes:fix/issue-34775

Conversation

@ousamabenyounes
Copy link
Copy Markdown

@ousamabenyounes ousamabenyounes commented Apr 16, 2026

Summary

Fixes #34775. Also fixes #34342 (same root cause, verified by the added regression fixture).

ValidateNoRefAccessInRender's collectTemporariesSidemap aliased every PropertyLoad lvalue back to its object (except ref.current). Because Env.set widens via the sidemap's canonical id, setting env[$propsRef] = Ref (from refTypeOfType on the BuiltInUseRefId-typed lvalue) also widened env[props] to Ref. Every subsequent props.<sibling> load then inherited that Ref classification and the JSX operand check flagged them with "Cannot access ref value during render".

The fix: skip the sidemap alias when the loaded property is itself typed as a ref (UseRef or RefValue). Generic property loads still alias (so the existing Structure/readRefEffect propagation used for patterns like object.foo = () => ref.current; object.foo() is preserved).

Repro (#34775)

// @validateRefAccessDuringRender
function Field(props) {
  return (
    <Control
      ref={props.ref}
      placeholder={props.placeholder}
      disabled={props.disabled}
    />
  );
}

Before: 3 errors (props.ref, props.placeholder, props.disabled all flagged).
After: 0 errors.

Repro (#34342)

// @validateRefAccessDuringRender
function Component(props) {
  return <div ref={props.ref}>{props.value}</div>;
}

Before: 2 errors (both props.ref and props.value flagged).
After: 0 errors.

props.ref.current (actual ref-value access during render) still correctly errors.

How did you test this change?

  • yarn snap1721 passed / 1721 (1719 existing + 2 new regression fixtures: allow-forwarding-props-ref-does-not-taint-sibling-props and allow-accessing-non-ref-prop-alongside-props-ref).
  • yarn workspace babel-plugin-react-compiler lint — clean.
  • yarn flow dom-node — clean.
  • yarn linc / yarn prettier — clean.
  • Existing fixtures that depend on the PropertyLoad sidemap (e.g. error.invalid-access-ref-in-render-mutate-object-with-ref-function, error.invalid-use-ref-added-to-dep-without-type-info, allow-assigning-ref-accessing-function-to-object-property-if-not-mutated) continue to pass unchanged — the sidemap is only skipped for ref-typed lvalues.

Files changed

File Change
ValidateNoRefAccessInRender.ts Skip PropertyLoad sidemap alias when the loaded value is itself ref-typed
allow-forwarding-props-ref-does-not-taint-sibling-props.{js,expect.md} Regression fixture for #34775
allow-accessing-non-ref-prop-alongside-props-ref.{js,expect.md} Regression fixture for #34342

🤖 Generated with Claude Code

In ValidateNoRefAccessInRender, collectTemporariesSidemap unconditionally
aliased every PropertyLoad lvalue to its object (except ref.current).
Combined with Env.set's widening via the sidemap, this caused
`env[props]` to be joined with the Ref classification of `props.ref`,
making every subsequent `props.<sibling>` read appear to be a RefValue
access and triggering false positive "Cannot access ref value during
render" errors on unrelated props (fixes facebook#34775).

Skip the alias when the loaded property is itself typed as a ref
(UseRef or RefValue). The sidemap is still applied for generic property
loads so the existing Structure/readRefEffect tracking (e.g. for
`object.foo = () => ref.current; object.foo()`) continues to work.

Adds a regression fixture reproducing the reported JSX snippet.

Co-Authored-By: Claude <noreply@anthropic.com>
@meta-cla meta-cla bot added the CLA Signed label Apr 16, 2026
…34342)

The fix in the previous commit also resolves facebook#34342: accessing both
`props.ref` and a non-ref sibling property (e.g. `props.value`) no
longer raises a false positive "Cannot access ref value during render"
error on the sibling read. This fixture exercises the minimal repro
from the issue.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants