You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[compiler] Phase 2+7: Wrap pipeline passes in tryRecord for fault tolerance
- Change runWithEnvironment/run/compileFn to return Result<CodegenFunction, CompilerError>
- Wrap all pipeline passes in env.tryRecord() to catch and record CompilerErrors
- Record inference pass errors via env.recordErrors() instead of throwing
- Handle codegen Result explicitly, returning Err on failure
- Add final error check: return Err(env.aggregateErrors()) if any errors accumulated
- Update tryCompileFunction and retryCompileFunction in Program.ts to handle Result
- Keep lint-only passes using env.logErrors() (non-blocking)
- Update 52 test fixture expectations that now report additional errors
This is the core integration that enables fault tolerance: errors are caught,
recorded, and the pipeline continues to discover more errors.
- After Phase 4.13-4.16, these passes record on env directly
264
264
- Remove the `env.logErrors()` wrapper calls
265
265
266
-
-[]**7.5 Wrap codegen** (lines 575-578)
266
+
-[x]**7.5 Wrap codegen** (lines 575-578)
267
267
- After Phase 6.1, `codegenFunction` returns directly
268
268
- Remove the `.unwrap()`
269
269
270
-
-[]**7.6 Add final error check** (end of `runWithEnvironment`)
270
+
-[x]**7.6 Add final error check** (end of `runWithEnvironment`)
271
271
- After all passes complete, check `env.hasErrors()`
272
272
- If no errors: return `Ok(ast)`
273
273
- If errors: return `Err(env.aggregateErrors())`
274
274
275
-
-[]**7.7 Consider wrapping each pass in `env.tryRecord()`** as a safety net
275
+
-[x]**7.7 Consider wrapping each pass in `env.tryRecord()`** as a safety net
276
276
- Even after individual passes are updated, wrapping each pass call in `env.tryRecord()` provides defense-in-depth
277
277
- If a pass unexpectedly throws a CompilerError (e.g., from a code path we missed), it gets caught and recorded rather than aborting the pipeline
278
278
- Non-CompilerError exceptions and invariants still propagate immediately
@@ -318,3 +318,10 @@ Walk through `runWithEnvironment` and wrap each pass call site. This is the inte
318
318
- The `assertConsistentIdentifiers`, `assertTerminalSuccessorsExist`, `assertTerminalPredsExist`, `assertValidBlockNesting`, `assertValidMutableRanges`, `assertWellFormedBreakTargets`, `assertScopeInstructionsWithinScopes` assertion functions should continue to throw — they are invariant checks on internal data structure consistency
319
319
- The `panicThreshold` mechanism in Program.ts should continue to work — it now operates on the aggregated error from the Result rather than a caught exception, but the behavior is the same
320
320
321
+
## Key Learnings
322
+
323
+
***Phase 2+7 (Pipeline tryRecord wrapping) was sufficient for basic fault tolerance.** Wrapping all passes in `env.tryRecord()` immediately enabled the compiler to continue past errors that previously threw. This caused 52 test fixtures to produce additional errors that were previously masked by the first error bailing out. For example, `error.todo-reassign-const` previously reported only "Support destructuring of context variables" but now also reports the immutability violation.
324
+
***Lint-only passes (Pattern B: `env.logErrors()`) should not use `tryRecord()`/`recordError()`** because those errors are intentionally non-blocking. They are reported via the logger only and should not cause the pipeline to return `Err`. The `logErrors` pattern was kept for `validateNoDerivedComputationsInEffects_exp`, `validateNoSetStateInEffects`, `validateNoJSXInTryStatement`, and `validateStaticComponents`.
325
+
***Inference passes that return `Result` with validation errors** (`inferMutationAliasingEffects`, `inferMutationAliasingRanges`) were changed to record errors via `env.recordErrors()` instead of throwing, allowing subsequent passes to proceed.
326
+
***Value-producing passes** (`memoizeFbtAndMacroOperandsInSameScope`, `renameVariables`, `buildReactiveFunction`) need safe default values when wrapped in `tryRecord()` since the callback can't return values. We initialize with empty defaults (e.g., `new Set()`) before the `tryRecord()` call.
Copy file name to clipboardExpand all lines: compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-memberexpr.expect.md
Error: Cannot modify local variables after render completes
48
+
49
+
This argument is a function which may reassign or mutate `x` after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead.
0 commit comments