@samitouri / QOS-React-1 / commits / d6558f36e2

[compiler] Phase 3: Make lower() always produce HIRFunction (#35878)

--- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35878). * #35888 * #35884 * #35883 * #35882 * #35881 * #35880 * #35879 * __->__ #35878

Joseph Savona committed Feb 23, 2026 at 16:05 UTC d6558f36e2f1de6d0504de0fc6ed2f4f621aa655
10 files changed +207 -262
compiler/fault-tolerance-overview.md
+35 -32
@@ -75,49 +75,49 @@ Change `runWithEnvironment` to run all passes and check for errors at the end in
75
76 Currently `lower()` returns `Result<HIRFunction, CompilerError>`. It already accumulates errors internally via `builder.errors`, but returns `Err` when errors exist. Change it to always return `Ok(hir)` while recording errors on the environment.
77
78 -- [ ] **3.1 Change `lower` to always return HIRFunction** (`src/HIR/BuildHIR.ts`)
78 +- [x] **3.1 Change `lower` to always return HIRFunction** (`src/HIR/BuildHIR.ts`)
79 - Change return type from `Result<HIRFunction, CompilerError>` to `HIRFunction`
80 - - Instead of returning `Err(builder.errors)` at line 227-229, record errors on `env` via `env.recordError(builder.errors)` and return the (partial) HIR
80 + - Instead of returning `Err(builder.errors)` at line 227-229, record errors on `env` via `env.recordErrors(builder.errors)` and return the (partial) HIR
81 - Update the pipeline to call `lower(func, env)` directly instead of `lower(func, env).unwrap()`
82 + - Added try/catch around body lowering to catch thrown CompilerErrors (e.g., from `resolveBinding`) and record them
83
83 -- [ ] **3.2 Handle `var` declarations as `let`** (`src/HIR/BuildHIR.ts`, line ~855)
84 - - Currently throws `Todo("Handle var kinds in VariableDeclaration")`
85 - - Instead: record the Todo error on env, then treat the `var` as `let` and continue lowering
84 +- [x] **3.2 Handle `var` declarations as `let`** (`src/HIR/BuildHIR.ts`, line ~855)
85 + - Record the Todo error, then treat `var` as `let` and continue lowering (instead of skipping the declaration)
86
87 -- [ ] **3.3 Handle `try/finally` by pruning `finally`** (`src/HIR/BuildHIR.ts`, lines ~1281-1296)
88 - - Currently throws Todo for `try` without `catch` and `try` with `finally`
89 - - Instead: record the Todo error, then lower the `try/catch` portion only (put the `finally` block content in the fallthrough of the try/catch)
87 +- [x] **3.3 Handle `try/finally` by pruning `finally`** (`src/HIR/BuildHIR.ts`, lines ~1281-1296)
88 + - Already handled: `try` without `catch` pushes error and returns; `try` with `finally` pushes error and continues with `try/catch` portion only
89
91 -- [ ] **3.4 Handle `eval()` via UnsupportedNode** (`src/HIR/BuildHIR.ts`, line ~3568)
92 - - Currently throws `UnsupportedSyntax("The 'eval' function is not supported")`
93 - - Instead: record the error, emit an `UnsupportedNode` instruction value with the original AST node
90 +- [x] **3.4 Handle `eval()` via UnsupportedNode** (`src/HIR/BuildHIR.ts`, line ~3568)
91 + - Already handled: records error via `builder.errors.push()` and continues
92
95 -- [ ] **3.5 Handle `with` statement via UnsupportedNode** (`src/HIR/BuildHIR.ts`, line ~1382)
96 - - Currently throws `UnsupportedSyntax`
97 - - Instead: record the error, emit the body statements as-is (or skip them), continue
93 +- [x] **3.5 Handle `with` statement via UnsupportedNode** (`src/HIR/BuildHIR.ts`, line ~1382)
94 + - Already handled: records error and emits `UnsupportedNode`
95
99 -- [ ] **3.6 Handle inline `class` declarations** (`src/HIR/BuildHIR.ts`, line ~1402)
100 - - Currently throws `UnsupportedSyntax`
101 - - Already creates an `UnsupportedNode`; just record the error instead of throwing
96 +- [x] **3.6 Handle inline `class` declarations** (`src/HIR/BuildHIR.ts`, line ~1402)
97 + - Already handled: records error and emits `UnsupportedNode`
98
103 -- [ ] **3.7 Handle remaining Todo errors in expression lowering** (`src/HIR/BuildHIR.ts`)
104 - - For each of the ~35 Todo error sites in `lowerExpression`, `lowerAssignment`, `lowerMemberExpression`, etc.:
105 - - Record the Todo error on the environment
106 - - Emit an `UnsupportedNode` instruction value with the original Babel AST node as fallback
107 - - Key sites include: pipe operator, tagged templates with interpolations, compound logical assignment (`&&=`, `||=`, `??=`), `for await...of`, object getters/setters, UpdateExpression on context variables, complex destructuring patterns
108 - - The `UnsupportedNode` variant already exists in HIR and passes through codegen unchanged, so no new HIR types are needed for most cases
99 +- [x] **3.7 Handle remaining Todo errors in expression lowering** (`src/HIR/BuildHIR.ts`)
100 + - Already handled: all ~60 error sites use `builder.errors.push()` to accumulate errors. The try/catch around body lowering provides a safety net for any that still throw.
101
110 -- [ ] **3.8 Handle `throw` inside `try/catch`** (`src/HIR/BuildHIR.ts`, line ~284)
111 - - Currently throws Todo
112 - - Instead: record the error, and represent the `throw` as a terminal that ends the block (the existing `throw` terminal type may already handle this, or we can use `UnsupportedNode`)
102 +- [x] **3.8 Handle `throw` inside `try/catch`** (`src/HIR/BuildHIR.ts`, line ~284)
103 + - Already handled: records error via `builder.errors.push()` and continues
104
114 -- [ ] **3.9 Handle `for` loops with missing test or expression init** (`src/HIR/BuildHIR.ts`, lines ~559, ~632)
115 - - Record the error and construct a best-effort loop HIR (e.g., for `for(;;)`, use `true` as the test expression)
105 +- [x] **3.9 Handle `for` loops with missing test or expression init** (`src/HIR/BuildHIR.ts`, lines ~559, ~632)
106 + - For `for(;;)` (missing test): emit `true` as the test expression and add a branch terminal
107 + - For empty init (`for (; ...)`): add a placeholder instruction to avoid invariant about empty blocks
108 + - For expression init (`for (expr; ...)`): record error and lower the expression as best-effort
109 + - Changed `'unsupported'` terminal to `'goto'` terminal for non-variable init to maintain valid CFG structure
110
117 -- [ ] **3.10 Handle nested function lowering failures** (`src/HIR/BuildHIR.ts`, `lowerFunction` at line ~3504)
118 - - Currently calls `lower()` recursively and merges errors if it fails (`builder.errors.merge(functionErrors)`)
119 - - With the new approach, the nested `lower()` always returns an HIR, but errors are recorded on the shared environment
120 - - Ensure the parent function continues lowering even if a nested function had errors
111 +- [x] **3.10 Handle nested function lowering failures** (`src/HIR/BuildHIR.ts`, `lowerFunction` at line ~3504)
112 + - `lowerFunction()` now always returns `LoweredFunction` since `lower()` always returns `HIRFunction`
113 + - Errors from nested functions are recorded on the shared environment
114 + - Removed the `null` return case and the corresponding `UnsupportedNode` fallback in callers
115 +
116 +- [x] **3.11 Handle unreachable functions in `build()`** (`src/HIR/HIRBuilder.ts`, `build()`)
117 + - Changed `CompilerError.throwTodo()` for unreachable code with hoisted declarations to `this.errors.push()` to allow HIR construction to complete
118 +
119 +- [x] **3.12 Handle duplicate fbt tags** (`src/HIR/BuildHIR.ts`, line ~2279)
120 + - Changed `CompilerError.throwDiagnostic()` to `builder.errors.pushDiagnostic()` to record instead of throw
121
122 ### Phase 4: Update Validation Passes
123
@@ -324,4 +324,7 @@ Walk through `runWithEnvironment` and wrap each pass call site. This is the inte
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.
327 +* **Phase 3 (BuildHIR) revealed that most error sites already used `builder.errors.push()` for accumulation.** The existing lowering code was designed to accumulate errors rather than throw. The main changes were: (1) changing `lower()` return type from `Result` to `HIRFunction`, (2) recording builder errors on env, (3) adding a try/catch around body lowering to catch thrown CompilerErrors from sub-calls like `resolveBinding()`, (4) treating `var` as `let` instead of skipping declarations, and (5) fixing ForStatement init/test handling to produce valid CFG structure.
328 +* **Partial HIR can trigger downstream invariants.** When lowering skips or partially handles constructs (e.g., unreachable hoisted functions, `var` declarations before the fix), downstream passes like `InferMutationAliasingEffects` may encounter uninitialized identifiers and throw invariants. This is acceptable since the function still correctly bails out of compilation, but error messages may be less specific. The fix for `var` (treating as `let`) demonstrates how to avoid this: continue lowering with a best-effort representation rather than skipping entirely.
329 +* **Errors accumulated on `env` are lost when an invariant propagates out of the pipeline.** Since invariant CompilerErrors always re-throw through `tryRecord()`, they exit the pipeline as exceptions. The caller only sees the invariant error, not any errors previously recorded on `env`. This is a design limitation that could be addressed by aggregating env errors with caught exceptions in `tryCompileFunction()`.
330
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+1 -1
@@ -155,7 +155,7 @@ function runWithEnvironment(
155 const log = (value: CompilerPipelineValue): void => {
156 env.logger?.debugLogIRs?.(value);
157 };
158 - const hir = lower(func, env).unwrap();
158 + const hir = lower(func, env);
159 log({kind: 'hir', name: 'HIR', value: hir});
160
161 pruneMaybeThrows(hir);
compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
+117 -65
@@ -14,7 +14,6 @@ import {
14 CompilerSuggestionOperation,
15 ErrorCategory,
16 } from '../CompilerError';
17 -import {Err, Ok, Result} from '../Utils/Result';
17 import {assertExhaustive, hasNode} from '../Utils/utils';
18 import {Environment} from './Environment';
19 import {
@@ -75,7 +74,7 @@ export function lower(
74 // Bindings captured from the outer function, in case lower() is called recursively (for lambdas)
75 bindings: Bindings | null = null,
76 capturedRefs: Map<t.Identifier, SourceLocation> = new Map(),
78 -): Result<HIRFunction, CompilerError> {
77 +): HIRFunction {
78 const builder = new HIRBuilder(env, {
79 bindings,
80 context: capturedRefs,
@@ -186,32 +185,51 @@ export function lower(
185
186 let directives: Array<string> = [];
187 const body = func.get('body');
189 - if (body.isExpression()) {
190 - const fallthrough = builder.reserve('block');
191 - const terminal: ReturnTerminal = {
192 - kind: 'return',
193 - returnVariant: 'Implicit',
194 - loc: GeneratedSource,
195 - value: lowerExpressionToTemporary(builder, body),
196 - id: makeInstructionId(0),
197 - effects: null,
198 - };
199 - builder.terminateWithContinuation(terminal, fallthrough);
200 - } else if (body.isBlockStatement()) {
201 - lowerStatement(builder, body);
202 - directives = body.get('directives').map(d => d.node.value.value);
203 - } else {
204 - builder.errors.pushDiagnostic(
205 - CompilerDiagnostic.create({
206 - category: ErrorCategory.Syntax,
207 - reason: `Unexpected function body kind`,
208 - description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
209 - }).withDetails({
210 - kind: 'error',
211 - loc: body.node.loc ?? null,
212 - message: 'Expected a block statement or expression',
213 - }),
214 - );
188 + try {
189 + if (body.isExpression()) {
190 + const fallthrough = builder.reserve('block');
191 + const terminal: ReturnTerminal = {
192 + kind: 'return',
193 + returnVariant: 'Implicit',
194 + loc: GeneratedSource,
195 + value: lowerExpressionToTemporary(builder, body),
196 + id: makeInstructionId(0),
197 + effects: null,
198 + };
199 + builder.terminateWithContinuation(terminal, fallthrough);
200 + } else if (body.isBlockStatement()) {
201 + lowerStatement(builder, body);
202 + directives = body.get('directives').map(d => d.node.value.value);
203 + } else {
204 + builder.errors.pushDiagnostic(
205 + CompilerDiagnostic.create({
206 + category: ErrorCategory.Syntax,
207 + reason: `Unexpected function body kind`,
208 + description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
209 + }).withDetails({
210 + kind: 'error',
211 + loc: body.node.loc ?? null,
212 + message: 'Expected a block statement or expression',
213 + }),
214 + );
215 + }
216 + } catch (err) {
217 + if (err instanceof CompilerError) {
218 + // Re-throw invariant errors immediately
219 + for (const detail of err.details) {
220 + if (
221 + (detail instanceof CompilerDiagnostic
222 + ? detail.category
223 + : detail.category) === ErrorCategory.Invariant
224 + ) {
225 + throw err;
226 + }
227 + }
228 + // Record non-invariant errors and continue to produce partial HIR
229 + builder.errors.merge(err);
230 + } else {
231 + throw err;
232 + }
233 }
234
235 let validatedId: HIRFunction['id'] = null;
@@ -224,10 +242,6 @@ export function lower(
242 }
243 }
244
227 - if (builder.errors.hasAnyErrors()) {
228 - return Err(builder.errors);
229 - }
230 -
245 builder.terminate(
246 {
247 kind: 'return',
@@ -244,23 +258,29 @@ export function lower(
258 null,
259 );
260
247 - return Ok({
261 + const hirBody = builder.build();
262 +
263 + // Record all accumulated errors (including any from build()) on env
264 + if (builder.errors.hasAnyErrors()) {
265 + env.recordErrors(builder.errors);
266 + }
267 +
268 + return {
269 id: validatedId,
270 nameHint: null,
271 params,
272 fnType: bindings == null ? env.fnType : 'Other',
273 returnTypeAnnotation: null, // TODO: extract the actual return type node if present
274 returns: createTemporaryPlace(env, func.node.loc ?? GeneratedSource),
254 - body: builder.build(),
275 + body: hirBody,
276 context,
277 generator: func.node.generator === true,
278 async: func.node.async === true,
279 loc: func.node.loc ?? GeneratedSource,
280 env,
260 - effects: null,
281 aliasingEffects: null,
282 directives,
263 - });
283 + };
284 }
285
286 // Helper to lower a statement
@@ -555,6 +575,24 @@ function lowerStatement(
575
576 const initBlock = builder.enter('loop', _blockId => {
577 const init = stmt.get('init');
578 + if (init.node == null) {
579 + /*
580 + * No init expression (e.g., `for (; ...)`), add a placeholder to avoid
581 + * invariant about empty blocks
582 + */
583 + lowerValueToTemporary(builder, {
584 + kind: 'Primitive',
585 + value: undefined,
586 + loc: stmt.node.loc ?? GeneratedSource,
587 + });
588 + return {
589 + kind: 'goto',
590 + block: testBlock.id,
591 + variant: GotoVariant.Break,
592 + id: makeInstructionId(0),
593 + loc: stmt.node.loc ?? GeneratedSource,
594 + };
595 + }
596 if (!init.isVariableDeclaration()) {
597 builder.errors.push({
598 reason:
@@ -563,8 +601,14 @@ function lowerStatement(
601 loc: stmt.node.loc ?? null,
602 suggestions: null,
603 });
604 + // Lower the init expression as best-effort and continue
605 + if (init.isExpression()) {
606 + lowerExpressionToTemporary(builder, init as NodePath<t.Expression>);
607 + }
608 return {
567 - kind: 'unsupported',
609 + kind: 'goto',
610 + block: testBlock.id,
611 + variant: GotoVariant.Break,
612 id: makeInstructionId(0),
613 loc: init.node?.loc ?? GeneratedSource,
614 };
@@ -635,6 +679,23 @@ function lowerStatement(
679 loc: stmt.node.loc ?? null,
680 suggestions: null,
681 });
682 + // Treat `for(;;)` as `while(true)` to keep the builder state consistent
683 + builder.terminateWithContinuation(
684 + {
685 + kind: 'branch',
686 + test: lowerValueToTemporary(builder, {
687 + kind: 'Primitive',
688 + value: true,
689 + loc: stmt.node.loc ?? GeneratedSource,
690 + }),
691 + consequent: bodyBlock,
692 + alternate: continuationBlock.id,
693 + fallthrough: continuationBlock.id,
694 + id: makeInstructionId(0),
695 + loc: stmt.node.loc ?? GeneratedSource,
696 + },
697 + continuationBlock,
698 + );
699 } else {
700 builder.terminateWithContinuation(
701 {
@@ -858,10 +919,12 @@ function lowerStatement(
919 loc: stmt.node.loc ?? null,
920 suggestions: null,
921 });
861 - return;
922 + // Treat `var` as `let` so references to the variable don't break
923 }
924 const kind =
864 - nodeKind === 'let' ? InstructionKind.Let : InstructionKind.Const;
925 + nodeKind === 'let' || nodeKind === 'var'
926 + ? InstructionKind.Let
927 + : InstructionKind.Const;
928 for (const declaration of stmt.get('declarations')) {
929 const id = declaration.get('id');
930 const init = declaration.get('init');
@@ -1494,9 +1557,6 @@ function lowerObjectMethod(
1557 ): InstructionValue {
1558 const loc = property.node.loc ?? GeneratedSource;
1559 const loweredFunc = lowerFunction(builder, property);
1497 - if (!loweredFunc) {
1498 - return {kind: 'UnsupportedNode', node: property.node, loc: loc};
1499 - }
1560
1561 return {
1562 kind: 'ObjectMethod',
@@ -2276,18 +2336,20 @@ function lowerExpression(
2336 });
2337 for (const [name, locations] of Object.entries(fbtLocations)) {
2338 if (locations.length > 1) {
2279 - CompilerError.throwDiagnostic({
2280 - category: ErrorCategory.Todo,
2281 - reason: 'Support duplicate fbt tags',
2282 - description: `Support \`<${tagName}>\` tags with multiple \`<${tagName}:${name}>\` values`,
2283 - details: locations.map(loc => {
2284 - return {
2285 - kind: 'error',
2286 - message: `Multiple \`<${tagName}:${name}>\` tags found`,
2287 - loc,
2288 - };
2339 + builder.errors.pushDiagnostic(
2340 + new CompilerDiagnostic({
2341 + category: ErrorCategory.Todo,
2342 + reason: 'Support duplicate fbt tags',
2343 + description: `Support \`<${tagName}>\` tags with multiple \`<${tagName}:${name}>\` values`,
2344 + details: locations.map(loc => {
2345 + return {
2346 + kind: 'error' as const,
2347 + message: `Multiple \`<${tagName}:${name}>\` tags found`,
2348 + loc,
2349 + };
2350 + }),
2351 }),
2290 - });
2352 + );
2353 }
2354 }
2355 }
@@ -3468,9 +3530,6 @@ function lowerFunctionToValue(
3530 const exprNode = expr.node;
3531 const exprLoc = exprNode.loc ?? GeneratedSource;
3532 const loweredFunc = lowerFunction(builder, expr);
3471 - if (!loweredFunc) {
3472 - return {kind: 'UnsupportedNode', node: exprNode, loc: exprLoc};
3473 - }
3533 return {
3534 kind: 'FunctionExpression',
3535 name: loweredFunc.func.id,
@@ -3489,7 +3548,7 @@ function lowerFunction(
3548 | t.FunctionDeclaration
3549 | t.ObjectMethod
3550 >,
3492 -): LoweredFunction | null {
3551 +): LoweredFunction {
3552 const componentScope: Scope = builder.environment.parentFunction.scope;
3553 const capturedContext = gatherCapturedContext(expr, componentScope);
3554
@@ -3501,19 +3560,12 @@ function lowerFunction(
3560 * This isn't a problem in practice because use Babel's scope analysis to
3561 * identify the correct references.
3562 */
3504 - const lowering = lower(
3563 + const loweredFunc = lower(
3564 expr,
3565 builder.environment,
3566 builder.bindings,
3567 new Map([...builder.context, ...capturedContext]),
3568 );
3510 - let loweredFunc: HIRFunction;
3511 - if (lowering.isErr()) {
3512 - const functionErrors = lowering.unwrapErr();
3513 - builder.errors.merge(functionErrors);
3514 - return null;
3515 - }
3516 - loweredFunc = lowering.unwrap();
3569 return {
3570 func: loweredFunc,
3571 };
compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts
+2 -1
@@ -381,11 +381,12 @@ export default class HIRBuilder {
381 instr => instr.value.kind === 'FunctionExpression',
382 )
383 ) {
384 - CompilerError.throwTodo({
384 + this.errors.push({
385 reason: `Support functions with unreachable code that may contain hoisted declarations`,
386 loc: block.instructions[0]?.loc ?? block.terminal.loc,
387 description: null,
388 suggestions: null,
389 + category: ErrorCategory.Todo,
390 });
391 }
392 }
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md
+3 -12
@@ -24,18 +24,9 @@ function useThing(fn) {
24 ```
25 Found 1 error:
26
27 -Compilation Skipped: `this` is not supported syntax
28 -
29 -React Compiler does not support compiling functions that use `this`.
30 -
31 -error.reserved-words.ts:8:28
32 - 6 |
33 - 7 | if (ref.current === null) {
34 -> 8 | ref.current = function (this: unknown, ...args) {
35 - | ^^^^^^^^^^^^^ `this` was used here
36 - 9 | return fnRef.current.call(this, ...args);
37 - 10 | };
38 - 11 | }
27 +Invariant: [HIRBuilder] Unexpected null block
28 +
29 +expected block 0 to exist.
30 ```
31
32
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error._todo.computed-lval-in-destructure.expect.md
+8 -7
@@ -17,16 +17,17 @@ function Component(props) {
17 ```
18 Found 1 error:
19
20 -Todo: (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern
20 +Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized
21
22 -error._todo.computed-lval-in-destructure.ts:3:9
23 - 1 | function Component(props) {
24 - 2 | const computedKey = props.key;
25 -> 3 | const {[computedKey]: x} = props.val;
26 - | ^^^^^^^^^^^^^^^^ (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern
22 +<unknown> x$8.
23 +
24 +error._todo.computed-lval-in-destructure.ts:5:9
25 + 3 | const {[computedKey]: x} = props.val;
26 4 |
28 - 5 | return x;
27 +> 5 | return x;
28 + | ^ this is uninitialized
29 6 | }
30 + 7 |
31 ```
32
33
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-hoisted-function-in-unreachable-code.expect.md
+9 -6
@@ -18,15 +18,18 @@ function Component() {
18 ```
19 Found 1 error:
20
21 -Todo: Support functions with unreachable code that may contain hoisted declarations
21 +Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized
22
23 -error.todo-hoisted-function-in-unreachable-code.ts:6:2
23 +<unknown> Foo$0.
24 +
25 +error.todo-hoisted-function-in-unreachable-code.ts:3:10
26 + 1 | // @compilationMode:"infer"
27 + 2 | function Component() {
28 +> 3 | return <Foo />;
29 + | ^^^ this is uninitialized
30 4 |
31 5 | // This is unreachable from a control-flow perspective, but it gets hoisted
26 -> 6 | function Foo() {}
27 - | ^^^^^^^^^^^^^^^^^ Support functions with unreachable code that may contain hoisted declarations
28 - 7 | }
29 - 8 |
32 + 6 | function Foo() {}
33 ```
34
35
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
+6 -131
@@ -79,43 +79,11 @@ let moduleLocal = false;
79 ## Error
80
81 ```
82 -Found 10 errors:
83 -
84 -Todo: (BuildHIR::lowerStatement) Handle var kinds in VariableDeclaration
85 -
86 -error.todo-kitchensink.ts:3:2
87 - 1 | function foo([a, b], {c, d, e = 'e'}, f = 'f', ...args) {
88 - 2 | let i = 0;
89 -> 3 | var x = [];
90 - | ^^^^^^^^^^^ (BuildHIR::lowerStatement) Handle var kinds in VariableDeclaration
91 - 4 |
92 - 5 | class Bar {
93 - 6 | #secretSauce = 42;
94 -
95 -Compilation Skipped: Inline `class` declarations are not supported
96 -
97 -Move class declarations outside of components/hooks.
98 -
99 -error.todo-kitchensink.ts:5:2
100 - 3 | var x = [];
101 - 4 |
102 -> 5 | class Bar {
103 - | ^^^^^^^^^^^
104 -> 6 | #secretSauce = 42;
105 - | ^^^^^^^^^^^^^^^^^^^^^^
106 -> 7 | constructor() {
107 - | ^^^^^^^^^^^^^^^^^^^^^^
108 -> 8 | console.log(this.#secretSauce);
109 - | ^^^^^^^^^^^^^^^^^^^^^^
110 -> 9 | }
111 - | ^^^^^^^^^^^^^^^^^^^^^^
112 -> 10 | }
113 - | ^^^^ Inline `class` declarations are not supported
114 - 11 |
115 - 12 | const g = {b() {}, c: () => {}};
116 - 13 | const {z, aa = 'aa'} = useCustom();
117 -
118 -Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
82 +Found 1 error:
83 +
84 +Invariant: Expected a variable declaration
85 +
86 +Got ExpressionStatement.
87
88 error.todo-kitchensink.ts:20:2
89 18 | const j = function bar([quz, qux], ...args) {};
@@ -125,103 +93,10 @@ error.todo-kitchensink.ts:20:2
93 > 21 | x.push(i);
94 | ^^^^^^^^^^^^^^
95 > 22 | }
128 - | ^^^^ (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
96 + | ^^^^ Expected a variable declaration
97 23 | for (; i < 3; ) {
98 24 | break;
99 25 | }
132 -
133 -Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
134 -
135 -error.todo-kitchensink.ts:23:2
136 - 21 | x.push(i);
137 - 22 | }
138 -> 23 | for (; i < 3; ) {
139 - | ^^^^^^^^^^^^^^^^^
140 -> 24 | break;
141 - | ^^^^^^^^^^
142 -> 25 | }
143 - | ^^^^ (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
144 - 26 | for (;;) {
145 - 27 | break;
146 - 28 | }
147 -
148 -Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
149 -
150 -error.todo-kitchensink.ts:26:2
151 - 24 | break;
152 - 25 | }
153 -> 26 | for (;;) {
154 - | ^^^^^^^^^^
155 -> 27 | break;
156 - | ^^^^^^^^^^
157 -> 28 | }
158 - | ^^^^ (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
159 - 29 |
160 - 30 | graphql`
161 - 31 | ${g}
162 -
163 -Todo: (BuildHIR::lowerStatement) Handle empty test in ForStatement
164 -
165 -error.todo-kitchensink.ts:26:2
166 - 24 | break;
167 - 25 | }
168 -> 26 | for (;;) {
169 - | ^^^^^^^^^^
170 -> 27 | break;
171 - | ^^^^^^^^^^
172 -> 28 | }
173 - | ^^^^ (BuildHIR::lowerStatement) Handle empty test in ForStatement
174 - 29 |
175 - 30 | graphql`
176 - 31 | ${g}
177 -
178 -Todo: (BuildHIR::lowerExpression) Handle tagged template with interpolations
179 -
180 -error.todo-kitchensink.ts:30:2
181 - 28 | }
182 - 29 |
183 -> 30 | graphql`
184 - | ^^^^^^^^
185 -> 31 | ${g}
186 - | ^^^^^^^^
187 -> 32 | `;
188 - | ^^^^ (BuildHIR::lowerExpression) Handle tagged template with interpolations
189 - 33 |
190 - 34 | graphql`\\t\n`;
191 - 35 |
192 -
193 -Todo: (BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value
194 -
195 -error.todo-kitchensink.ts:34:2
196 - 32 | `;
197 - 33 |
198 -> 34 | graphql`\\t\n`;
199 - | ^^^^^^^^^^^^^^ (BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value
200 - 35 |
201 - 36 | for (c of [1, 2]) {
202 - 37 | }
203 -
204 -Todo: (BuildHIR::node.lowerReorderableExpression) Expression type `MemberExpression` cannot be safely reordered
205 -
206 -error.todo-kitchensink.ts:57:9
207 - 55 | case foo(): {
208 - 56 | }
209 -> 57 | case x.y: {
210 - | ^^^ (BuildHIR::node.lowerReorderableExpression) Expression type `MemberExpression` cannot be safely reordered
211 - 58 | }
212 - 59 | default: {
213 - 60 | }
214 -
215 -Todo: (BuildHIR::node.lowerReorderableExpression) Expression type `BinaryExpression` cannot be safely reordered
216 -
217 -error.todo-kitchensink.ts:53:9
218 - 51 |
219 - 52 | switch (i) {
220 -> 53 | case 1 + 1: {
221 - | ^^^^^ (BuildHIR::node.lowerReorderableExpression) Expression type `BinaryExpression` cannot be safely reordered
222 - 54 | }
223 - 55 | case foo(): {
224 - 56 | }
100 ```
101
102
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useMemo-callback-generator.expect.md
+18 -1
@@ -18,7 +18,7 @@ function component(a, b) {
18 ## Error
19
20 ```
21 -Found 1 error:
21 +Found 2 errors:
22
23 Todo: (BuildHIR::lowerExpression) Handle YieldExpression expressions
24
@@ -30,6 +30,23 @@ error.useMemo-callback-generator.ts:6:4
30 7 | }, []);
31 8 | return x;
32 9 | }
33 +
34 +Error: useMemo() callbacks may not be async or generator functions
35 +
36 +useMemo() callbacks are called once and must synchronously return a value.
37 +
38 +error.useMemo-callback-generator.ts:5:18
39 + 3 | // useful for now, but adding this test in case we do
40 + 4 | // add support for generators in the future.
41 +> 5 | let x = useMemo(function* () {
42 + | ^^^^^^^^^^^^^^
43 +> 6 | yield a;
44 + | ^^^^^^^^^^^^
45 +> 7 | }, []);
46 + | ^^^^ Async and generator functions are not supported
47 + 8 | return x;
48 + 9 | }
49 + 10 |
50 ```
51
52
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.error.object-pattern-computed-key.expect.md
+8 -6
@@ -23,16 +23,18 @@ export const FIXTURE_ENTRYPOINT = {
23 ```
24 Found 1 error:
25
26 -Todo: (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern
26 +Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized
27
28 -todo.error.object-pattern-computed-key.ts:5:9
29 - 3 | const SCALE = 2;
28 +<unknown> value$3.
29 +
30 +todo.error.object-pattern-computed-key.ts:6:9
31 4 | function Component(props) {
31 -> 5 | const {[props.name]: value} = props;
32 - | ^^^^^^^^^^^^^^^^^^^ (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern
33 - 6 | return value;
32 + 5 | const {[props.name]: value} = props;
33 +> 6 | return value;
34 + | ^^^^^ this is uninitialized
35 7 | }
36 8 |
37 + 9 | export const FIXTURE_ENTRYPOINT = {
38 ```
39
40
\ No newline at end of file