[rust-compiler] Dedup async-reassignment immutability diagnostic#36496
Merged
poteto merged 2 commits intoMay 20, 2026
Conversation
When multiple async functions reassign the same outer `let`, the Rust port emits the same `Cannot reassign variable in async function` diagnostic once per reassigning function body. The reference TS compiler emits it exactly once per offending variable, regardless of how many async functions reassign it. This fixture snapshots the broken behavior with two async callbacks: the baseline records 2 errors. `yarn snap --rust` passes against this broken baseline; `yarn snap` (TS) fails because TS only emits 1. The next commit fixes the over-emission and flips the baseline.
e5b0564 to
86519cb
Compare
`validate_locals_not_reassigned_after_render` had a missing early return in the inner-function async-reassignment branch. The Rust port recorded the diagnostic, but where the TS reference does `return null;` right after `env.recordError(...)`, the Rust code fell through into the next loop iteration, re-emitting the same diagnostic for every async function body that reassigned the same outer let. Add the `return None;` the comment already promised. Found by a TS-vs-Rust differential sweep over a large real-world TSX corpus where Rust over-emitted this diagnostic in proportion to the number of reassigning callback sites (e.g. 4 in usePlanEditorState; TS emits 1). The fixture baseline flips from 2 errors to 1, matching TS. Full `yarn snap --rust` is unchanged otherwise (1782/1794 passing, +1 versus before).
86519cb to
5f452f0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
validate_locals_not_reassigned_after_renderemitted the sameCannot reassign variable in async functiondiagnostic once perasync function body that reassigned the same outer
let. The TSreference emits it exactly once per offending variable.
Reproducer (both compilers,
panicThreshold: 'none'):Before: TS emits 1 error, Rust emits 2.
After: both emit 1.
Root cause
crates/react_compiler_validation/src/validate_locals_not_reassigned_after_render.rsis a faithful port of the TS pass, except the inner-function async-reassignment branch is missing the early return. The TS reference doesenv.recordError(...); return null;. The Rust code recorded the diagnostic then fell through into the next loop iteration, so the next async function body got the same emit path.There was even a
// Return null (don't propagate further) — matches TS behaviorcomment in place of the missing return.Fix
Replace the comment with the actual
return None;. One-line change.How I found it
TS-vs-Rust differential sweep over a large real-world TSX corpus (~59k files), comparing the in-repo TS compiler vs the Rust port. Among 14k+ error events, this duplicate emission was the most concentrated divergence cluster.
Verification
error.invalid-reassign-local-variable-in-multiple-async-callbacks.tsx:yarn snapandyarn snap --rustboth pass (1 error each).error.invalid-reassign-local-variable-in-async-callback.jsfixture still passes.yarn snap --rust: 1782/1794 (+1 vs main, no regression in the 12 known frontier failures).Commit order
Found 2 errors).yarn snap --rustpasses against it,yarn snapfails — captures the bug.Found 1 error. Bothyarn snapandyarn snap --rustpass.