Skip to content

[compiler] Phase 1: Add error accumulation infrastructure to Environment#561

Closed
everettbu wants to merge 2 commits into
mainfrom
pr35841
Closed

[compiler] Phase 1: Add error accumulation infrastructure to Environment#561
everettbu wants to merge 2 commits into
mainfrom
pr35841

Conversation

@everettbu

Copy link
Copy Markdown

Mirror of facebook/react#35841
Original author: josephsavona


Add error accumulation methods to the Environment class:

  • #errors field to accumulate CompilerErrors across passes
  • recordError() to record a single diagnostic (throws if Invariant)
  • recordErrors() to record all diagnostics from a CompilerError
  • hasErrors() to check if any errors have been recorded
  • aggregateErrors() to retrieve the accumulated CompilerError
  • tryRecord() to wrap callbacks and catch CompilerErrors

Stack created with Sapling. Best reviewed with ReviewStack.

  • #35853
  • #35852
  • #35851
  • #35850
  • #35849
  • #35848
  • #35847
  • #35845
  • #35844
  • #35843
  • #35842
  • -> #35841
  • #35840

Add detailed plan for making the React Compiler fault-tolerant by
accumulating errors across all passes instead of stopping at the first
error. This enables reporting multiple compilation errors at once.
Add error accumulation methods to the Environment class:
- #errors field to accumulate CompilerErrors across passes
- recordError() to record a single diagnostic (throws if Invariant)
- recordErrors() to record all diagnostics from a CompilerError
- hasErrors() to check if any errors have been recorded
- aggregateErrors() to retrieve the accumulated CompilerError
- tryRecord() to wrap callbacks and catch CompilerErrors
@everettbu everettbu added CLA Signed React Core Team Opened by a member of the React Core Team labels Feb 21, 2026
@greptile-apps

greptile-apps Bot commented Feb 21, 2026

Copy link
Copy Markdown

Greptile Summary

This PR implements Phase 1 of the React Compiler fault tolerance initiative by adding error accumulation infrastructure to the Environment class. It also adds a comprehensive design document outlining the full 8-phase plan for making the compiler continue through all passes and report all errors at once, rather than aborting on the first error.

  • Adds #errors: CompilerError private field to Environment for accumulating compilation errors across passes
  • Adds recordError() / recordErrors() methods that accumulate non-invariant diagnostics and immediately throw invariants (internal bugs)
  • Adds hasErrors() and aggregateErrors() for querying accumulated state
  • Adds tryRecord() as a migration bridge — wraps existing pass calls in try/catch to convert thrown CompilerErrors into recorded errors
  • Adds compiler/fault-tolerance-overview.md documenting the full design and phased implementation plan
  • The new methods follow the existing pattern established by logErrors() and integrate correctly with the Logger event system

Confidence Score: 4/5

  • This PR is safe to merge — it adds new methods to Environment without modifying existing behavior or call sites.
  • Phase 1 is purely additive infrastructure: new private field and methods on Environment with no changes to existing code paths. The methods are not yet called anywhere, so there is zero risk of regression. The implementation correctly handles the CompilerError/CompilerDiagnostic type hierarchy and logger integration. One minor inconsistency in invariant handling between recordErrors() and tryRecord() noted as a style suggestion.
  • No files require special attention. The Environment.ts changes are additive and well-isolated.

Important Files Changed

Filename Overview
compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts Adds error accumulation infrastructure: #errors field, recordError(), recordErrors(), hasErrors(), aggregateErrors(), and tryRecord() methods. Implementation is clean and consistent with existing patterns (logErrors, CompilerError API). Minor inconsistency: recordErrors() can partially record before throwing on invariant, while tryRecord() checks upfront.
compiler/fault-tolerance-overview.md Comprehensive design document outlining an 8-phase plan for fault tolerance in the React Compiler pipeline. Only Phase 1 is implemented in this PR; the rest are future work documented for reference.

Last reviewed commit: 0524307

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +756 to +759
recordErrors(error: CompilerError): void {
for (const detail of error.details) {
this.recordError(detail);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent invariant handling with tryRecord
recordErrors() iterates through error.details and calls recordError() on each one sequentially. If a CompilerError contains a mix of non-invariant and invariant details, the non-invariant details processed before the invariant one will be recorded and logged onto #errors before recordError throws on the invariant detail. In contrast, tryRecord() checks all details upfront and re-throws the entire CompilerError without recording any details.

In practice, CompilerError.invariant() creates single-detail errors so this is unlikely to be hit, but it's worth being aware of. Consider adding an upfront check for invariants to keep behavior consistent:

Suggested change
recordErrors(error: CompilerError): void {
for (const detail of error.details) {
this.recordError(detail);
}
recordErrors(error: CompilerError): void {
for (const detail of error.details) {
if (detail.category === ErrorCategory.Invariant) {
throw error;
}
}
for (const detail of error.details) {
this.recordError(detail);
}
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
Line: 756-759

Comment:
**Inconsistent invariant handling with `tryRecord`**
`recordErrors()` iterates through `error.details` and calls `recordError()` on each one sequentially. If a `CompilerError` contains a mix of non-invariant and invariant details, the non-invariant details processed before the invariant one will be recorded and logged onto `#errors` before `recordError` throws on the invariant detail. In contrast, `tryRecord()` checks all details upfront and re-throws the entire `CompilerError` without recording any details.

In practice, `CompilerError.invariant()` creates single-detail errors so this is unlikely to be hit, but it's worth being aware of. Consider adding an upfront check for invariants to keep behavior consistent:

```suggestion
  recordErrors(error: CompilerError): void {
    for (const detail of error.details) {
      if (detail.category === ErrorCategory.Invariant) {
        throw error;
      }
    }
    for (const detail of error.details) {
      this.recordError(detail);
    }
  }
```

How can I resolve this? If you propose a fix, please make it concise.

@everettbu

Copy link
Copy Markdown
Author

Upstream PR was closed or merged. Code is synced via branch mirror.

@everettbu everettbu closed this Feb 23, 2026
@everettbu
everettbu deleted the pr35841 branch February 23, 2026 17:35
@everettbu
everettbu restored the pr35841 branch February 23, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants