@samitouri / QOS-React / commits / 9b2d8013ee

[compiler] Phase 4 (batch 2), 5, 6: Update remaining passes for fault tolerance (#35876)

Update remaining validation passes to record errors on env: - validateMemoizedEffectDependencies - validatePreservedManualMemoization - validateSourceLocations (added env parameter) - validateContextVariableLValues (changed throwTodo to recordError) - validateLocalsNotReassignedAfterRender (changed throw to recordError) - validateNoDerivedComputationsInEffects (changed throw to recordError) Update inference passes: - inferMutationAliasingEffects: return void, errors on env - inferMutationAliasingRanges: return Array<AliasingEffect> directly, errors on env Update codegen: - codegenFunction: return CodegenFunction directly, errors on env - codegenReactiveFunction: same pattern Update Pipeline.ts to call all passes directly without tryRecord/unwrap. Also update AnalyseFunctions.ts which called inferMutationAliasingRanges. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35876). * #35888 * #35884 * #35883 * #35882 * #35881 * #35880 * #35879 * #35878 * #35877 * __->__ #35876

Joseph Savona committed Feb 23, 2026 at 16:01 UTC 9b2d8013eed2b02193aebc37a614b37853ada214
12 files changed +111 -107
compiler/fault-tolerance-overview.md
+9 -9
@@ -174,17 +174,17 @@ These passes already accumulate errors internally and return `Result<void, Compi
174 - Record errors on env
175 - Update Pipeline.ts call site (line 315): remove `.unwrap()`
176
177 -- [ ] **4.10 `validateMemoizedEffectDependencies`** (`src/Validation/ValidateMemoizedEffectDependencies.ts`)
177 +- [x] **4.10 `validateMemoizedEffectDependencies`** (`src/Validation/ValidateMemoizedEffectDependencies.ts`)
178 - Change signature to return void (note: operates on `ReactiveFunction`)
179 - Record errors on the function's env
180 - Update Pipeline.ts call site (line 565): remove `.unwrap()`
181
182 -- [ ] **4.11 `validatePreservedManualMemoization`** (`src/Validation/ValidatePreservedManualMemoization.ts`)
182 +- [x] **4.11 `validatePreservedManualMemoization`** (`src/Validation/ValidatePreservedManualMemoization.ts`)
183 - Change signature to return void (note: operates on `ReactiveFunction`)
184 - Record errors on the function's env
185 - Update Pipeline.ts call site (line 572): remove `.unwrap()`
186
187 -- [ ] **4.12 `validateSourceLocations`** (`src/Validation/ValidateSourceLocations.ts`)
187 +- [x] **4.12 `validateSourceLocations`** (`src/Validation/ValidateSourceLocations.ts`)
188 - Change signature to return void
189 - Record errors on env
190 - Update Pipeline.ts call site (line 585): remove `.unwrap()`
@@ -202,16 +202,16 @@ These already use a soft-logging pattern and don't block compilation. They can b
202
203 These throw `CompilerError` directly (not via Result). They need the most work.
204
205 -- [ ] **4.17 `validateContextVariableLValues`** (`src/Validation/ValidateContextVariableLValues.ts`)
205 +- [x] **4.17 `validateContextVariableLValues`** (`src/Validation/ValidateContextVariableLValues.ts`)
206 - Currently throws via `CompilerError.throwTodo()` and `CompilerError.invariant()`
207 - Change to record Todo errors on env and continue
208 - Keep invariant throws (those indicate internal bugs)
209
210 -- [ ] **4.18 `validateLocalsNotReassignedAfterRender`** (`src/Validation/ValidateLocalsNotReassignedAfterRender.ts`)
210 +- [x] **4.18 `validateLocalsNotReassignedAfterRender`** (`src/Validation/ValidateLocalsNotReassignedAfterRender.ts`)
211 - Currently constructs a `CompilerError` and `throw`s it directly
212 - Change to record errors on env
213
214 -- [ ] **4.19 `validateNoDerivedComputationsInEffects`** (`src/Validation/ValidateNoDerivedComputationsInEffects.ts`)
214 +- [x] **4.19 `validateNoDerivedComputationsInEffects`** (`src/Validation/ValidateNoDerivedComputationsInEffects.ts`)
215 - Currently throws directly
216 - Change to record errors on env
217
@@ -219,14 +219,14 @@ These throw `CompilerError` directly (not via Result). They need the most work.
219
220 The inference passes are the most critical to handle correctly because they produce side effects (populating effects on instructions, computing mutable ranges) that downstream passes depend on. They must continue producing valid (even if imprecise) output when errors are encountered.
221
222 -- [ ] **5.1 `inferMutationAliasingEffects`** (`src/Inference/InferMutationAliasingEffects.ts`)
222 +- [x] **5.1 `inferMutationAliasingEffects`** (`src/Inference/InferMutationAliasingEffects.ts`)
223 - Currently returns `Result<void, CompilerError>` — errors are about mutation of frozen/global values
224 - Change to record errors on `fn.env` instead of accumulating internally
225 - **Key recovery strategy**: When a mutation of a frozen value is detected, record the error but treat the operation as a non-mutating read. This way downstream passes see a consistent (if conservative) view
226 - When a mutation of a global is detected, record the error but continue with the global unchanged
227 - Update Pipeline.ts (lines 233-239): remove the conditional `.isErr()` / throw pattern
228
229 -- [ ] **5.2 `inferMutationAliasingRanges`** (`src/Inference/InferMutationAliasingRanges.ts`)
229 +- [x] **5.2 `inferMutationAliasingRanges`** (`src/Inference/InferMutationAliasingRanges.ts`)
230 - Currently returns `Result<Array<AliasingEffect>, CompilerError>`
231 - This pass has a meaningful success value (the function's external aliasing effects)
232 - Change to: always produce a best-effort effects array, record errors on env
@@ -235,7 +235,7 @@ The inference passes are the most critical to handle correctly because they prod
235
236 ### Phase 6: Update Codegen
237
238 -- [ ] **6.1 `codegenFunction`** (`src/ReactiveScopes/CodegenReactiveFunction.ts`)
238 +- [x] **6.1 `codegenFunction`** (`src/ReactiveScopes/CodegenReactiveFunction.ts`)
239 - Currently returns `Result<CodegenFunction, CompilerError>`
240 - Change to: always produce a `CodegenFunction`, record errors on env
241 - If codegen encounters an error (e.g., an instruction it can't generate code for), it should:
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+8 -31
@@ -161,9 +161,7 @@ function runWithEnvironment(
161 pruneMaybeThrows(hir);
162 log({kind: 'hir', name: 'PruneMaybeThrows', value: hir});
163
164 - env.tryRecord(() => {
165 - validateContextVariableLValues(hir);
166 - });
164 + validateContextVariableLValues(hir);
165 validateUseMemo(hir);
166
167 if (env.enableDropManualMemoization) {
@@ -213,13 +211,8 @@ function runWithEnvironment(
211 analyseFunctions(hir);
212 log({kind: 'hir', name: 'AnalyseFunctions', value: hir});
213
216 - const mutabilityAliasingErrors = inferMutationAliasingEffects(hir);
214 + inferMutationAliasingEffects(hir);
215 log({kind: 'hir', name: 'InferMutationAliasingEffects', value: hir});
218 - if (env.enableValidations) {
219 - if (mutabilityAliasingErrors.isErr()) {
220 - env.recordErrors(mutabilityAliasingErrors.unwrapErr());
221 - }
222 - }
216
217 if (env.outputMode === 'ssr') {
218 optimizeForSSR(hir);
@@ -232,17 +225,12 @@ function runWithEnvironment(
225 pruneMaybeThrows(hir);
226 log({kind: 'hir', name: 'PruneMaybeThrows', value: hir});
227
235 - const mutabilityAliasingRangeErrors = inferMutationAliasingRanges(hir, {
228 + inferMutationAliasingRanges(hir, {
229 isFunctionExpression: false,
230 });
231 log({kind: 'hir', name: 'InferMutationAliasingRanges', value: hir});
232 if (env.enableValidations) {
240 - if (mutabilityAliasingRangeErrors.isErr()) {
241 - env.recordErrors(mutabilityAliasingRangeErrors.unwrapErr());
242 - }
243 - env.tryRecord(() => {
244 - validateLocalsNotReassignedAfterRender(hir);
245 - });
233 + validateLocalsNotReassignedAfterRender(hir);
234 }
235
236 if (env.enableValidations) {
@@ -264,9 +252,7 @@ function runWithEnvironment(
252 ) {
253 env.logErrors(validateNoDerivedComputationsInEffects_exp(hir));
254 } else if (env.config.validateNoDerivedComputationsInEffects) {
267 - env.tryRecord(() => {
268 - validateNoDerivedComputationsInEffects(hir);
269 - });
255 + validateNoDerivedComputationsInEffects(hir);
256 }
257
258 if (env.config.validateNoSetStateInEffects && env.outputMode === 'lint') {
@@ -520,29 +506,20 @@ function runWithEnvironment(
506 env.config.enablePreserveExistingMemoizationGuarantees ||
507 env.config.validatePreserveExistingMemoizationGuarantees
508 ) {
523 - env.tryRecord(() => {
524 - validatePreservedManualMemoization(reactiveFunction).unwrap();
525 - });
509 + validatePreservedManualMemoization(reactiveFunction);
510 }
511
528 - const codegenResult = codegenFunction(reactiveFunction, {
512 + const ast = codegenFunction(reactiveFunction, {
513 uniqueIdentifiers,
514 fbtOperands,
515 });
532 - if (codegenResult.isErr()) {
533 - env.recordErrors(codegenResult.unwrapErr());
534 - return Err(env.aggregateErrors());
535 - }
536 - const ast = codegenResult.unwrap();
516 log({kind: 'ast', name: 'Codegen', value: ast});
517 for (const outlined of ast.outlined) {
518 log({kind: 'ast', name: 'Codegen (outlined)', value: outlined.fn});
519 }
520
521 if (env.config.validateSourceLocations) {
543 - env.tryRecord(() => {
544 - validateSourceLocations(func, ast).unwrap();
545 - });
522 + validateSourceLocations(func, ast, env);
523 }
524
525 /**
compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts
+1 -1
@@ -54,7 +54,7 @@ function lowerWithMutationAliasing(fn: HIRFunction): void {
54 deadCodeElimination(fn);
55 const functionEffects = inferMutationAliasingRanges(fn, {
56 isFunctionExpression: true,
57 - }).unwrap();
57 + });
58 rewriteInstructionKindsBasedOnReassignment(fn);
59 inferReactiveScopeVariables(fn);
60 fn.aliasingEffects = functionEffects;
compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts
+3 -3
@@ -45,7 +45,7 @@ import {
45 eachTerminalOperand,
46 eachTerminalSuccessor,
47 } from '../HIR/visitors';
48 -import {Ok, Result} from '../Utils/Result';
48 +
49 import {
50 assertExhaustive,
51 getOrInsertDefault,
@@ -100,7 +100,7 @@ export function inferMutationAliasingEffects(
100 {isFunctionExpression}: {isFunctionExpression: boolean} = {
101 isFunctionExpression: false,
102 },
103 -): Result<void, CompilerError> {
103 +): void {
104 const initialState = InferenceState.empty(fn.env, isFunctionExpression);
105
106 // Map of blocks to the last (merged) incoming state that was processed
@@ -220,7 +220,7 @@ export function inferMutationAliasingEffects(
220 }
221 }
222 }
223 - return Ok(undefined);
223 + return;
224 }
225
226 function findHoistedContextDeclarations(
compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingRanges.ts
+9 -5
@@ -26,7 +26,7 @@ import {
26 eachTerminalOperand,
27 } from '../HIR/visitors';
28 import {assertExhaustive, getOrInsertWith} from '../Utils/utils';
29 -import {Err, Ok, Result} from '../Utils/Result';
29 +
30 import {AliasingEffect, MutationReason} from './AliasingEffects';
31
32 /**
@@ -74,7 +74,7 @@ import {AliasingEffect, MutationReason} from './AliasingEffects';
74 export function inferMutationAliasingRanges(
75 fn: HIRFunction,
76 {isFunctionExpression}: {isFunctionExpression: boolean},
77 -): Result<Array<AliasingEffect>, CompilerError> {
77 +): Array<AliasingEffect> {
78 // The set of externally-visible effects
79 const functionEffects: Array<AliasingEffect> = [];
80
@@ -547,10 +547,14 @@ export function inferMutationAliasingRanges(
547 }
548 }
549
550 - if (errors.hasAnyErrors() && !isFunctionExpression) {
551 - return Err(errors);
550 + if (
551 + errors.hasAnyErrors() &&
552 + !isFunctionExpression &&
553 + fn.env.enableValidations
554 + ) {
555 + fn.env.recordErrors(errors);
556 }
553 - return Ok(functionEffects);
557 + return functionEffects;
558 }
559
560 function appendFunctionErrors(errors: CompilerError, fn: HIRFunction): void {
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
+12 -19
@@ -46,7 +46,7 @@ import {
46 } from '../HIR/HIR';
47 import {printIdentifier, printInstruction, printPlace} from '../HIR/PrintHIR';
48 import {eachPatternOperand} from '../HIR/visitors';
49 -import {Err, Ok, Result} from '../Utils/Result';
49 +
50 import {GuardKind} from '../Utils/RuntimeDiagnosticConstants';
51 import {assertExhaustive} from '../Utils/utils';
52 import {buildReactiveFunction} from './BuildReactiveFunction';
@@ -111,7 +111,7 @@ export function codegenFunction(
111 uniqueIdentifiers: Set<string>;
112 fbtOperands: Set<IdentifierId>;
113 },
114 -): Result<CodegenFunction, CompilerError> {
114 +): CodegenFunction {
115 const cx = new Context(
116 fn.env,
117 fn.id ?? '[[ anonymous ]]',
@@ -141,11 +141,7 @@ export function codegenFunction(
141 };
142 }
143
144 - const compileResult = codegenReactiveFunction(cx, fn);
145 - if (compileResult.isErr()) {
146 - return compileResult;
147 - }
148 - const compiled = compileResult.unwrap();
144 + const compiled = codegenReactiveFunction(cx, fn);
145
146 const hookGuard = fn.env.config.enableEmitHookGuards;
147 if (hookGuard != null && fn.env.outputMode === 'client') {
@@ -273,7 +269,7 @@ export function codegenFunction(
269 emitInstrumentForget.globalGating,
270 );
271 if (assertResult.isErr()) {
276 - return assertResult;
272 + fn.env.recordErrors(assertResult.unwrapErr());
273 }
274 }
275
@@ -323,20 +319,17 @@ export function codegenFunction(
319 ),
320 reactiveFunction,
321 );
326 - if (codegen.isErr()) {
327 - return codegen;
328 - }
329 - outlined.push({fn: codegen.unwrap(), type});
322 + outlined.push({fn: codegen, type});
323 }
324 compiled.outlined = outlined;
325
333 - return compileResult;
326 + return compiled;
327 }
328
329 function codegenReactiveFunction(
330 cx: Context,
331 fn: ReactiveFunction,
339 -): Result<CodegenFunction, CompilerError> {
332 +): CodegenFunction {
333 for (const param of fn.params) {
334 const place = param.kind === 'Identifier' ? param : param.place;
335 cx.temp.set(place.identifier.declarationId, null);
@@ -355,13 +348,13 @@ function codegenReactiveFunction(
348 }
349
350 if (cx.errors.hasAnyErrors()) {
358 - return Err(cx.errors);
351 + fn.env.recordErrors(cx.errors);
352 }
353
354 const countMemoBlockVisitor = new CountMemoBlockVisitor(fn.env);
355 visitReactiveFunction(fn, countMemoBlockVisitor, undefined);
356
364 - return Ok({
357 + return {
358 type: 'CodegenFunction',
359 loc: fn.loc,
360 id: fn.id !== null ? t.identifier(fn.id) : null,
@@ -376,7 +369,7 @@ function codegenReactiveFunction(
369 prunedMemoBlocks: countMemoBlockVisitor.prunedMemoBlocks,
370 prunedMemoValues: countMemoBlockVisitor.prunedMemoValues,
371 outlined: [],
379 - });
372 + };
373 }
374
375 class CountMemoBlockVisitor extends ReactiveFunctionVisitor<void> {
@@ -1665,7 +1658,7 @@ function codegenInstructionValue(
1658 cx.temp,
1659 ),
1660 reactiveFunction,
1668 - ).unwrap();
1661 + );
1662
1663 /*
1664 * ObjectMethod builder must be backwards compatible with older versions of babel.
@@ -1864,7 +1857,7 @@ function codegenInstructionValue(
1857 cx.temp,
1858 ),
1859 reactiveFunction,
1867 - ).unwrap();
1860 + );
1861
1862 if (instrValue.type === 'ArrowFunctionExpression') {
1863 let body: t.BlockStatement | t.Expression = fn.body;
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateContextVariableLValues.ts
+37 -21
@@ -5,7 +5,9 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError} from '..';
8 +import {CompilerDiagnostic, CompilerError} from '..';
9 +import {ErrorCategory} from '../CompilerError';
10 +import {Environment} from '../HIR/Environment';
11 import {HIRFunction, IdentifierId, Place} from '../HIR';
12 import {printPlace} from '../HIR/PrintHIR';
13 import {eachInstructionValueLValue, eachPatternOperand} from '../HIR/visitors';
@@ -17,12 +19,13 @@ import {eachInstructionValueLValue, eachPatternOperand} from '../HIR/visitors';
19 */
20 export function validateContextVariableLValues(fn: HIRFunction): void {
21 const identifierKinds: IdentifierKinds = new Map();
20 - validateContextVariableLValuesImpl(fn, identifierKinds);
22 + validateContextVariableLValuesImpl(fn, identifierKinds, fn.env);
23 }
24
25 function validateContextVariableLValuesImpl(
26 fn: HIRFunction,
27 identifierKinds: IdentifierKinds,
28 + env: Environment,
29 ): void {
30 for (const [, block] of fn.body.blocks) {
31 for (const instr of block.instructions) {
@@ -30,30 +33,30 @@ function validateContextVariableLValuesImpl(
33 switch (value.kind) {
34 case 'DeclareContext':
35 case 'StoreContext': {
33 - visit(identifierKinds, value.lvalue.place, 'context');
36 + visit(identifierKinds, value.lvalue.place, 'context', env);
37 break;
38 }
39 case 'LoadContext': {
37 - visit(identifierKinds, value.place, 'context');
40 + visit(identifierKinds, value.place, 'context', env);
41 break;
42 }
43 case 'StoreLocal':
44 case 'DeclareLocal': {
42 - visit(identifierKinds, value.lvalue.place, 'local');
45 + visit(identifierKinds, value.lvalue.place, 'local', env);
46 break;
47 }
48 case 'LoadLocal': {
46 - visit(identifierKinds, value.place, 'local');
49 + visit(identifierKinds, value.place, 'local', env);
50 break;
51 }
52 case 'PostfixUpdate':
53 case 'PrefixUpdate': {
51 - visit(identifierKinds, value.lvalue, 'local');
54 + visit(identifierKinds, value.lvalue, 'local', env);
55 break;
56 }
57 case 'Destructure': {
58 for (const lvalue of eachPatternOperand(value.lvalue.pattern)) {
56 - visit(identifierKinds, lvalue, 'destructure');
59 + visit(identifierKinds, lvalue, 'destructure', env);
60 }
61 break;
62 }
@@ -62,18 +65,24 @@ function validateContextVariableLValuesImpl(
65 validateContextVariableLValuesImpl(
66 value.loweredFunc.func,
67 identifierKinds,
68 + env,
69 );
70 break;
71 }
72 default: {
73 for (const _ of eachInstructionValueLValue(value)) {
70 - CompilerError.throwTodo({
71 - reason:
72 - 'ValidateContextVariableLValues: unhandled instruction variant',
73 - loc: value.loc,
74 - description: `Handle '${value.kind} lvalues`,
75 - suggestions: null,
76 - });
74 + fn.env.recordError(
75 + CompilerDiagnostic.create({
76 + category: ErrorCategory.Todo,
77 + reason:
78 + 'ValidateContextVariableLValues: unhandled instruction variant',
79 + description: `Handle '${value.kind} lvalues`,
80 + }).withDetails({
81 + kind: 'error',
82 + loc: value.loc,
83 + message: null,
84 + }),
85 + );
86 }
87 }
88 }
@@ -90,6 +99,7 @@ function visit(
99 identifiers: IdentifierKinds,
100 place: Place,
101 kind: 'local' | 'context' | 'destructure',
102 + env: Environment,
103 ): void {
104 const prev = identifiers.get(place.identifier.id);
105 if (prev !== undefined) {
@@ -97,12 +107,18 @@ function visit(
107 const isContext = kind === 'context';
108 if (wasContext !== isContext) {
109 if (prev.kind === 'destructure' || kind === 'destructure') {
100 - CompilerError.throwTodo({
101 - reason: `Support destructuring of context variables`,
102 - loc: kind === 'destructure' ? place.loc : prev.place.loc,
103 - description: null,
104 - suggestions: null,
105 - });
110 + env.recordError(
111 + CompilerDiagnostic.create({
112 + category: ErrorCategory.Todo,
113 + reason: `Support destructuring of context variables`,
114 + description: null,
115 + }).withDetails({
116 + kind: 'error',
117 + loc: kind === 'destructure' ? place.loc : prev.place.loc,
118 + message: null,
119 + }),
120 + );
121 + return;
122 }
123
124 CompilerError.invariant(false, {
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts
+7 -6
@@ -7,6 +7,7 @@
7
8 import {CompilerDiagnostic, CompilerError, Effect} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 +import {Environment} from '../HIR/Environment';
11 import {HIRFunction, IdentifierId, Place} from '../HIR';
12 import {
13 eachInstructionLValue,
@@ -27,15 +28,15 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void {
28 contextVariables,
29 false,
30 false,
31 + fn.env,
32 );
33 if (reassignment !== null) {
32 - const errors = new CompilerError();
34 const variable =
35 reassignment.identifier.name != null &&
36 reassignment.identifier.name.kind === 'named'
37 ? `\`${reassignment.identifier.name.value}\``
38 : 'variable';
38 - errors.pushDiagnostic(
39 + fn.env.recordError(
40 CompilerDiagnostic.create({
41 category: ErrorCategory.Immutability,
42 reason: 'Cannot reassign variable after render completes',
@@ -46,7 +47,6 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void {
47 message: `Cannot reassign ${variable} after render completes`,
48 }),
49 );
49 - throw errors;
50 }
51 }
52
@@ -55,6 +55,7 @@ function getContextReassignment(
55 contextVariables: Set<IdentifierId>,
56 isFunctionExpression: boolean,
57 isAsync: boolean,
58 + env: Environment,
59 ): Place | null {
60 const reassigningFunctions = new Map<IdentifierId, Place>();
61 for (const [, block] of fn.body.blocks) {
@@ -68,6 +69,7 @@ function getContextReassignment(
69 contextVariables,
70 true,
71 isAsync || value.loweredFunc.func.async,
72 + env,
73 );
74 if (reassignment === null) {
75 // If the function itself doesn't reassign, does one of its dependencies?
@@ -84,13 +86,12 @@ function getContextReassignment(
86 // if the function or its depends reassign, propagate that fact on the lvalue
87 if (reassignment !== null) {
88 if (isAsync || value.loweredFunc.func.async) {
87 - const errors = new CompilerError();
89 const variable =
90 reassignment.identifier.name !== null &&
91 reassignment.identifier.name.kind === 'named'
92 ? `\`${reassignment.identifier.name.value}\``
93 : 'variable';
93 - errors.pushDiagnostic(
94 + env.recordError(
95 CompilerDiagnostic.create({
96 category: ErrorCategory.Immutability,
97 reason: 'Cannot reassign variable in async function',
@@ -102,7 +103,7 @@ function getContextReassignment(
103 message: `Cannot reassign ${variable}`,
104 }),
105 );
105 - throw errors;
106 + return null;
107 }
108 reassigningFunctions.set(lvalue.identifier.id, reassignment);
109 }
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts
+2 -2
@@ -97,8 +97,8 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
97 }
98 }
99 }
100 - if (errors.hasAnyErrors()) {
101 - throw errors;
100 + for (const detail of errors.details) {
101 + fn.env.recordError(detail);
102 }
103 }
104
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts
+4 -5
@@ -37,7 +37,6 @@ import {
37 ReactiveFunctionVisitor,
38 visitReactiveFunction,
39 } from '../ReactiveScopes/visitors';
40 -import {Result} from '../Utils/Result';
40 import {getOrInsertDefault} from '../Utils/utils';
41
42 /**
@@ -47,15 +46,15 @@ import {getOrInsertDefault} from '../Utils/utils';
46 * This can occur if a value's mutable range somehow extended to include a hook and
47 * was pruned.
48 */
50 -export function validatePreservedManualMemoization(
51 - fn: ReactiveFunction,
52 -): Result<void, CompilerError> {
49 +export function validatePreservedManualMemoization(fn: ReactiveFunction): void {
50 const state = {
51 errors: new CompilerError(),
52 manualMemoState: null,
53 };
54 visitReactiveFunction(fn, new Visitor(), state);
58 - return state.errors.asResult();
55 + for (const detail of state.errors.details) {
56 + fn.env.recordError(detail);
57 + }
58 }
59
60 const DEBUG = false;
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateSourceLocations.ts
+6 -3
@@ -9,7 +9,7 @@ import {NodePath} from '@babel/traverse';
9 import * as t from '@babel/types';
10 import {CompilerDiagnostic, CompilerError, ErrorCategory} from '..';
11 import {CodegenFunction} from '../ReactiveScopes';
12 -import {Result} from '../Utils/Result';
12 +import {Environment} from '../HIR/Environment';
13
14 /**
15 * IMPORTANT: This validation is only intended for use in unit tests.
@@ -123,7 +123,8 @@ export function validateSourceLocations(
123 t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
124 >,
125 generatedAst: CodegenFunction,
126 -): Result<void, CompilerError> {
126 + env: Environment,
127 +): void {
128 const errors = new CompilerError();
129
130 /*
@@ -309,5 +310,7 @@ export function validateSourceLocations(
310 }
311 }
312
312 - return errors.asResult();
313 + for (const detail of errors.details) {
314 + env.recordError(detail);
315 + }
316 }
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-reassign-const.expect.md
+13 -2
@@ -21,7 +21,7 @@ function Component({foo}) {
21 ## Error
22
23 ```
24 -Found 2 errors:
24 +Found 3 errors:
25
26 Todo: Support destructuring of context variables
27
@@ -29,7 +29,18 @@ error.todo-reassign-const.ts:3:20
29 1 | import {Stringify} from 'shared-runtime';
30 2 |
31 > 3 | function Component({foo}) {
32 - | ^^^ Support destructuring of context variables
32 + | ^^^
33 + 4 | let bar = foo.bar;
34 + 5 | return (
35 + 6 | <Stringify
36 +
37 +Todo: Support destructuring of context variables
38 +
39 +error.todo-reassign-const.ts:3:20
40 + 1 | import {Stringify} from 'shared-runtime';
41 + 2 |
42 +> 3 | function Component({foo}) {
43 + | ^^^
44 4 | let bar = foo.bar;
45 5 | return (
46 6 | <Stringify