@samitouri / QOS-React / commits / 474f25842a

[compiler] Migrate CompilerError.invariant to new CompilerDiagnostic infra (#34403)

Mechanical PR to migrate existing invariants to use the new CompilerDiagnostic infra @josephsavona added. Will tackle the others at a later time. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34403). * #34409 * #34404 * __->__ #34403

lauren committed Sep 6, 2025 at 12:58 UTC 474f25842a90f67a7aa8c6329afb5faec52181b6
84 files changed +1974 -338
compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts
+12 -11
@@ -37,7 +37,7 @@ export enum ErrorSeverity {
37 export type CompilerDiagnosticOptions = {
38 category: ErrorCategory;
39 reason: string;
40 - description: string;
40 + description: string | null;
41 details: Array<CompilerDiagnosticDetail>;
42 suggestions?: Array<CompilerSuggestion> | null | undefined;
43 };
@@ -49,7 +49,7 @@ export type CompilerDiagnosticDetail =
49 | {
50 kind: 'error';
51 loc: SourceLocation | null;
52 - message: string;
52 + message: string | null;
53 }
54 | {
55 kind: 'hint';
@@ -126,8 +126,8 @@ export class CompilerDiagnostic {
126 return this.options.category;
127 }
128
129 - withDetail(detail: CompilerDiagnosticDetail): CompilerDiagnostic {
130 - this.options.details.push(detail);
129 + withDetails(...details: Array<CompilerDiagnosticDetail>): CompilerDiagnostic {
130 + this.options.details.push(...details);
131 return this;
132 }
133
@@ -155,9 +155,9 @@ export class CompilerDiagnostic {
155 }
156 let codeFrame: string;
157 try {
158 - codeFrame = printCodeFrame(source, loc, detail.message);
158 + codeFrame = printCodeFrame(source, loc, detail.message ?? '');
159 } catch (e) {
160 - codeFrame = detail.message;
160 + codeFrame = detail.message ?? '';
161 }
162 buffer.push('\n\n');
163 if (loc.filename != null) {
@@ -284,15 +284,16 @@ export class CompilerError extends Error {
284
285 static invariant(
286 condition: unknown,
287 - options: Omit<CompilerErrorDetailOptions, 'category'>,
287 + options: Omit<CompilerDiagnosticOptions, 'category'>,
288 ): asserts condition {
289 if (!condition) {
290 const errors = new CompilerError();
291 - errors.pushErrorDetail(
292 - new CompilerErrorDetail({
293 - ...options,
291 + errors.pushDiagnostic(
292 + CompilerDiagnostic.create({
293 + reason: options.reason,
294 + description: options.description,
295 category: ErrorCategory.Invariant,
295 - }),
296 + }).withDetails(...options.details),
297 );
298 throw errors;
299 }
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Gating.ts
+23 -3
@@ -51,12 +51,26 @@ function insertAdditionalFunctionDeclaration(
51 CompilerError.invariant(originalFnName != null && compiled.id != null, {
52 reason:
53 'Expected function declarations that are referenced elsewhere to have a named identifier',
54 - loc: fnPath.node.loc ?? null,
54 + description: null,
55 + details: [
56 + {
57 + kind: 'error',
58 + loc: fnPath.node.loc ?? null,
59 + message: null,
60 + },
61 + ],
62 });
63 CompilerError.invariant(originalFnParams.length === compiledParams.length, {
64 reason:
65 'Expected React Compiler optimized function declarations to have the same number of parameters as source',
59 - loc: fnPath.node.loc ?? null,
66 + description: null,
67 + details: [
68 + {
69 + kind: 'error',
70 + loc: fnPath.node.loc ?? null,
71 + message: null,
72 + },
73 + ],
74 });
75
76 const gatingCondition = t.identifier(
@@ -140,7 +154,13 @@ export function insertGatedFunctionDeclaration(
154 CompilerError.invariant(compiled.type === 'FunctionDeclaration', {
155 reason: 'Expected compiled node type to match input type',
156 description: `Got ${compiled.type} but expected FunctionDeclaration`,
143 - loc: fnPath.node.loc ?? null,
157 + details: [
158 + {
159 + kind: 'error',
160 + loc: fnPath.node.loc ?? null,
161 + message: null,
162 + },
163 + ],
164 });
165 insertAdditionalFunctionDeclaration(
166 fnPath,
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts
+14 -2
@@ -257,7 +257,13 @@ export function addImportsToProgram(
257 reason:
258 'Encountered conflicting import specifiers in generated program',
259 description: `Conflict from import ${loweredImport.module}:(${loweredImport.imported} as ${loweredImport.name}).`,
260 - loc: GeneratedSource,
260 + details: [
261 + {
262 + kind: 'error',
263 + loc: GeneratedSource,
264 + message: null,
265 + },
266 + ],
267 suggestions: null,
268 },
269 );
@@ -268,7 +274,13 @@ export function addImportsToProgram(
274 reason:
275 'Found inconsistent import specifier. This is an internal bug.',
276 description: `Expected import ${moduleName}:${specifierName} but found ${loweredImport.module}:${loweredImport.imported}`,
271 - loc: GeneratedSource,
277 + details: [
278 + {
279 + kind: 'error',
280 + loc: GeneratedSource,
281 + message: null,
282 + },
283 + ],
284 },
285 );
286 }
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
+22 -3
@@ -310,7 +310,13 @@ function insertNewOutlinedFunctionNode(
310 CompilerError.invariant(insertedFuncDecl.isFunctionDeclaration(), {
311 reason: 'Expected inserted function declaration',
312 description: `Got: ${insertedFuncDecl}`,
313 - loc: insertedFuncDecl.node?.loc ?? null,
313 + details: [
314 + {
315 + kind: 'error',
316 + loc: insertedFuncDecl.node?.loc ?? null,
317 + message: null,
318 + },
319 + ],
320 });
321 return insertedFuncDecl;
322 }
@@ -419,7 +425,14 @@ export function compileProgram(
425 for (const outlined of compiled.outlined) {
426 CompilerError.invariant(outlined.fn.outlined.length === 0, {
427 reason: 'Unexpected nested outlined functions',
422 - loc: outlined.fn.loc,
428 + description: null,
429 + details: [
430 + {
431 + kind: 'error',
432 + loc: outlined.fn.loc,
433 + message: null,
434 + },
435 + ],
436 });
437 const fn = insertNewOutlinedFunctionNode(
438 program,
@@ -1407,7 +1420,13 @@ export function getReactCompilerRuntimeModule(
1420 {
1421 reason: 'Expected target to already be validated',
1422 description: null,
1410 - loc: null,
1423 + details: [
1424 + {
1425 + kind: 'error',
1426 + loc: null,
1427 + message: null,
1428 + },
1429 + ],
1430 suggestions: null,
1431 },
1432 );
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts
+9 -2
@@ -152,7 +152,14 @@ export function suppressionsToCompilerError(
152 ): CompilerError {
153 CompilerError.invariant(suppressionRanges.length !== 0, {
154 reason: `Expected at least suppression comment source range`,
155 - loc: GeneratedSource,
155 + description: null,
156 + details: [
157 + {
158 + kind: 'error',
159 + loc: GeneratedSource,
160 + message: null,
161 + },
162 + ],
163 });
164 const error = new CompilerError();
165 for (const suppressionRange of suppressionRanges) {
@@ -196,7 +203,7 @@ export function suppressionsToCompilerError(
203 op: CompilerSuggestionOperation.Remove,
204 },
205 ],
199 - }).withDetail({
206 + }).withDetails({
207 kind: 'error',
208 loc: suppressionRange.disableComment.loc ?? null,
209 message: 'Found React rule suppression',
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts
+16 -2
@@ -217,7 +217,14 @@ function validateImportSpecifier(
217 const binding = local.scope.getBinding(local.node.name);
218 CompilerError.invariant(binding != null, {
219 reason: 'Expected binding to be found for import specifier',
220 - loc: local.node.loc ?? null,
220 + description: null,
221 + details: [
222 + {
223 + kind: 'error',
224 + loc: local.node.loc ?? null,
225 + message: null,
226 + },
227 + ],
228 });
229 checkFn(binding.referencePaths, state);
230 }
@@ -237,7 +244,14 @@ function validateNamespacedImport(
244
245 CompilerError.invariant(binding != null, {
246 reason: 'Expected binding to be found for import specifier',
240 - loc: local.node.loc ?? null,
247 + description: null,
248 + details: [
249 + {
250 + kind: 'error',
251 + loc: local.node.loc ?? null,
252 + message: null,
253 + },
254 + ],
255 });
256 const filteredReferences = new Map<
257 CheckInvalidReferenceFn,
compiler/packages/babel-plugin-react-compiler/src/Flood/TypeErrors.ts
+8 -1
@@ -46,7 +46,14 @@ export function raiseUnificationErrors(
46 if (errs.length === 0) {
47 CompilerError.invariant(false, {
48 reason: 'Should not have array of zero errors',
49 - loc,
49 + description: null,
50 + details: [
51 + {
52 + kind: 'error',
53 + loc,
54 + message: null,
55 + },
56 + ],
57 });
58 } else if (errs.length === 1) {
59 CompilerError.throwInvalidJS({
compiler/packages/babel-plugin-react-compiler/src/Flood/Types.ts
+69 -9
@@ -152,7 +152,13 @@ export function makeLinearId(id: number): LinearId {
152 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
153 reason: 'Expected LinearId id to be a non-negative integer',
154 description: null,
155 - loc: null,
155 + details: [
156 + {
157 + kind: 'error',
158 + loc: null,
159 + message: null,
160 + },
161 + ],
162 suggestions: null,
163 });
164 return id as LinearId;
@@ -167,7 +173,13 @@ export function makeTypeParameterId(id: number): TypeParameterId {
173 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
174 reason: 'Expected TypeParameterId to be a non-negative integer',
175 description: null,
170 - loc: null,
176 + details: [
177 + {
178 + kind: 'error',
179 + loc: null,
180 + message: null,
181 + },
182 + ],
183 suggestions: null,
184 });
185 return id as TypeParameterId;
@@ -191,7 +203,13 @@ export function makeVariableId(id: number): VariableId {
203 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
204 reason: 'Expected VariableId id to be a non-negative integer',
205 description: null,
194 - loc: null,
206 + details: [
207 + {
208 + kind: 'error',
209 + loc: null,
210 + message: null,
211 + },
212 + ],
213 suggestions: null,
214 });
215 return id as VariableId;
@@ -399,7 +417,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType {
417 } else {
418 CompilerError.invariant(false, {
419 reason: `Unsupported property kind ${prop.kind}`,
402 - loc: GeneratedSource,
420 + description: null,
421 + details: [
422 + {
423 + kind: 'error',
424 + loc: GeneratedSource,
425 + message: null,
426 + },
427 + ],
428 });
429 }
430 }
@@ -468,7 +493,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType {
493 } else {
494 CompilerError.invariant(false, {
495 reason: `Unsupported property kind ${prop.kind}`,
471 - loc: GeneratedSource,
496 + description: null,
497 + details: [
498 + {
499 + kind: 'error',
500 + loc: GeneratedSource,
501 + message: null,
502 + },
503 + ],
504 });
505 }
506 }
@@ -487,7 +519,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType {
519 } else {
520 CompilerError.invariant(false, {
521 reason: `Unsupported property kind ${prop.kind}`,
490 - loc: GeneratedSource,
522 + description: null,
523 + details: [
524 + {
525 + kind: 'error',
526 + loc: GeneratedSource,
527 + message: null,
528 + },
529 + ],
530 });
531 }
532 }
@@ -500,7 +539,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType {
539 }
540 CompilerError.invariant(false, {
541 reason: `Unsupported class instance type ${flowType.def.type.kind}`,
503 - loc: GeneratedSource,
542 + description: null,
543 + details: [
544 + {
545 + kind: 'error',
546 + loc: GeneratedSource,
547 + message: null,
548 + },
549 + ],
550 });
551 }
552 case 'Fun':
@@ -559,7 +605,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType {
605 } else {
606 CompilerError.invariant(false, {
607 reason: `Unsupported component props type ${propsType.type.kind}`,
562 - loc: GeneratedSource,
608 + description: null,
609 + details: [
610 + {
611 + kind: 'error',
612 + loc: GeneratedSource,
613 + message: null,
614 + },
615 + ],
616 });
617 }
618
@@ -712,7 +765,14 @@ export class FlowTypeEnv implements ITypeEnv {
765 // TODO: use flow-js only for web environments (e.g. playground)
766 CompilerError.invariant(env.config.flowTypeProvider != null, {
767 reason: 'Expected flowDumpTypes to be defined in environment config',
715 - loc: GeneratedSource,
768 + description: null,
769 + details: [
770 + {
771 + kind: 'error',
772 + loc: GeneratedSource,
773 + message: null,
774 + },
775 + ],
776 });
777 let stdout: any;
778 if (source === lastFlowSource) {
compiler/packages/babel-plugin-react-compiler/src/HIR/AssertConsistentIdentifiers.ts
+21 -3
@@ -38,7 +38,13 @@ export function assertConsistentIdentifiers(fn: HIRFunction): void {
38 CompilerError.invariant(instr.lvalue.identifier.name === null, {
39 reason: `Expected all lvalues to be temporaries`,
40 description: `Found named lvalue \`${instr.lvalue.identifier.name}\``,
41 - loc: instr.lvalue.loc,
41 + details: [
42 + {
43 + kind: 'error',
44 + loc: instr.lvalue.loc,
45 + message: null,
46 + },
47 + ],
48 suggestions: null,
49 });
50 CompilerError.invariant(!assignments.has(instr.lvalue.identifier.id), {
@@ -46,7 +52,13 @@ export function assertConsistentIdentifiers(fn: HIRFunction): void {
52 description: `Found duplicate assignment of '${printPlace(
53 instr.lvalue,
54 )}'`,
49 - loc: instr.lvalue.loc,
55 + details: [
56 + {
57 + kind: 'error',
58 + loc: instr.lvalue.loc,
59 + message: null,
60 + },
61 + ],
62 suggestions: null,
63 });
64 assignments.add(instr.lvalue.identifier.id);
@@ -77,7 +89,13 @@ function validate(
89 CompilerError.invariant(identifier === previous, {
90 reason: `Duplicate identifier object`,
91 description: `Found duplicate identifier object for id ${identifier.id}`,
80 - loc: loc ?? GeneratedSource,
92 + details: [
93 + {
94 + kind: 'error',
95 + loc: loc ?? GeneratedSource,
96 + message: null,
97 + },
98 + ],
99 suggestions: null,
100 });
101 }
compiler/packages/babel-plugin-react-compiler/src/HIR/AssertTerminalBlocksExist.ts
+21 -3
@@ -18,7 +18,13 @@ export function assertTerminalSuccessorsExist(fn: HIRFunction): void {
18 description: `Block bb${successor} does not exist for terminal '${printTerminal(
19 block.terminal,
20 )}'`,
21 - loc: (block.terminal as any).loc ?? GeneratedSource,
21 + details: [
22 + {
23 + kind: 'error',
24 + loc: (block.terminal as any).loc ?? GeneratedSource,
25 + message: null,
26 + },
27 + ],
28 suggestions: null,
29 });
30 return successor;
@@ -33,14 +39,26 @@ export function assertTerminalPredsExist(fn: HIRFunction): void {
39 CompilerError.invariant(predBlock != null, {
40 reason: 'Expected predecessor block to exist',
41 description: `Block ${block.id} references non-existent ${pred}`,
36 - loc: GeneratedSource,
42 + details: [
43 + {
44 + kind: 'error',
45 + loc: GeneratedSource,
46 + message: null,
47 + },
48 + ],
49 });
50 CompilerError.invariant(
51 [...eachTerminalSuccessor(predBlock.terminal)].includes(block.id),
52 {
53 reason: 'Terminal successor does not reference correct predecessor',
54 description: `Block bb${block.id} has bb${predBlock.id} as a predecessor, but bb${predBlock.id}'s successors do not include bb${block.id}`,
43 - loc: GeneratedSource,
55 + details: [
56 + {
57 + kind: 'error',
58 + loc: GeneratedSource,
59 + message: null,
60 + },
61 + ],
62 },
63 );
64 }
compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting.ts
+7 -1
@@ -131,7 +131,13 @@ export function recursivelyTraverseItems<T, TContext>(
131 CompilerError.invariant(disjoint || nested, {
132 reason: 'Invalid nesting in program blocks or scopes',
133 description: `Items overlap but are not nested: ${maybeParentRange.start}:${maybeParentRange.end}(${currRange.start}:${currRange.end})`,
134 - loc: GeneratedSource,
134 + details: [
135 + {
136 + kind: 'error',
137 + loc: GeneratedSource,
138 + message: null,
139 + },
140 + ],
141 });
142 if (disjoint) {
143 exit(maybeParent, context);
compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts
+7 -1
@@ -57,7 +57,13 @@ function validateMutableRange(
57 {
58 reason: `Invalid mutable range: [${range.start}:${range.end}]`,
59 description: `${printPlace(place)} in ${description}`,
60 - loc: place.loc,
60 + details: [
61 + {
62 + kind: 'error',
63 + loc: place.loc,
64 + message: null,
65 + },
66 + ],
67 },
68 );
69 }
compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
+104 -17
@@ -110,7 +110,7 @@ export function lower(
110 category: ErrorCategory.Invariant,
111 reason: 'Could not find binding',
112 description: `[BuildHIR] Could not find binding for param \`${param.node.name}\`.`,
113 - }).withDetail({
113 + }).withDetails({
114 kind: 'error',
115 loc: param.node.loc ?? null,
116 message: 'Could not find binding',
@@ -174,7 +174,7 @@ export function lower(
174 category: ErrorCategory.Todo,
175 reason: `Handle ${param.node.type} parameters`,
176 description: `[BuildHIR] Add support for ${param.node.type} parameters.`,
177 - }).withDetail({
177 + }).withDetails({
178 kind: 'error',
179 loc: param.node.loc ?? null,
180 message: 'Unsupported parameter type',
@@ -205,7 +205,7 @@ export function lower(
205 category: ErrorCategory.Syntax,
206 reason: `Unexpected function body kind`,
207 description: `Expected function body to be an expression or a block statement, got \`${body.type}\`.`,
208 - }).withDetail({
208 + }).withDetails({
209 kind: 'error',
210 loc: body.node.loc ?? null,
211 message: 'Expected a block statement or expression',
@@ -439,7 +439,13 @@ function lowerStatement(
439 reason: 'Expected to find binding for hoisted identifier',
440 description: `Could not find a binding for ${id.node.name}`,
441 suggestions: null,
442 - loc: id.node.loc ?? GeneratedSource,
442 + details: [
443 + {
444 + kind: 'error',
445 + loc: id.node.loc ?? GeneratedSource,
446 + message: null,
447 + },
448 + ],
449 });
450 if (builder.environment.isHoistedIdentifier(binding.identifier)) {
451 // Already hoisted
@@ -481,7 +487,14 @@ function lowerStatement(
487 CompilerError.invariant(identifier.kind === 'Identifier', {
488 reason:
489 'Expected hoisted binding to be a local identifier, not a global',
484 - loc: id.node.loc ?? GeneratedSource,
490 + description: null,
491 + details: [
492 + {
493 + kind: 'error',
494 + loc: id.node.loc ?? GeneratedSource,
495 + message: null,
496 + },
497 + ],
498 });
499 const place: Place = {
500 effect: Effect.Unknown,
@@ -1014,7 +1027,13 @@ function lowerStatement(
1027 CompilerError.invariant(stmt.get('id').type === 'Identifier', {
1028 reason: 'function declarations must have a name',
1029 description: null,
1017 - loc: stmt.node.loc ?? null,
1030 + details: [
1031 + {
1032 + kind: 'error',
1033 + loc: stmt.node.loc ?? null,
1034 + message: null,
1035 + },
1036 + ],
1037 suggestions: null,
1038 });
1039 const id = stmt.get('id') as NodePath<t.Identifier>;
@@ -1114,7 +1133,13 @@ function lowerStatement(
1133 CompilerError.invariant(declarations.length === 1, {
1134 reason: `Expected only one declaration in the init of a ForOfStatement, got ${declarations.length}`,
1135 description: null,
1117 - loc: left.node.loc ?? null,
1136 + details: [
1137 + {
1138 + kind: 'error',
1139 + loc: left.node.loc ?? null,
1140 + message: null,
1141 + },
1142 + ],
1143 suggestions: null,
1144 });
1145 const id = declarations[0].get('id');
@@ -1129,8 +1154,15 @@ function lowerStatement(
1154 test = lowerValueToTemporary(builder, assign);
1155 } else {
1156 CompilerError.invariant(left.isLVal(), {
1132 - loc: leftLoc,
1157 reason: 'Expected ForOf init to be a variable declaration or lval',
1158 + description: null,
1159 + details: [
1160 + {
1161 + kind: 'error',
1162 + loc: leftLoc,
1163 + message: null,
1164 + },
1165 + ],
1166 });
1167 const assign = lowerAssignment(
1168 builder,
@@ -1207,7 +1239,13 @@ function lowerStatement(
1239 CompilerError.invariant(declarations.length === 1, {
1240 reason: `Expected only one declaration in the init of a ForInStatement, got ${declarations.length}`,
1241 description: null,
1210 - loc: left.node.loc ?? null,
1242 + details: [
1243 + {
1244 + kind: 'error',
1245 + loc: left.node.loc ?? null,
1246 + message: null,
1247 + },
1248 + ],
1249 suggestions: null,
1250 });
1251 const id = declarations[0].get('id');
@@ -1222,8 +1260,15 @@ function lowerStatement(
1260 test = lowerValueToTemporary(builder, assign);
1261 } else {
1262 CompilerError.invariant(left.isLVal(), {
1225 - loc: leftLoc,
1263 reason: 'Expected ForIn init to be a variable declaration or lval',
1264 + description: null,
1265 + details: [
1266 + {
1267 + kind: 'error',
1268 + loc: leftLoc,
1269 + message: null,
1270 + },
1271 + ],
1272 });
1273 const assign = lowerAssignment(
1274 builder,
@@ -2202,7 +2247,13 @@ function lowerExpression(
2247 CompilerError.invariant(namePath.isJSXNamespacedName(), {
2248 reason: 'Refinement',
2249 description: null,
2205 - loc: namePath.node.loc ?? null,
2250 + details: [
2251 + {
2252 + kind: 'error',
2253 + loc: namePath.node.loc ?? null,
2254 + message: null,
2255 + },
2256 + ],
2257 suggestions: null,
2258 });
2259 const namespace = namePath.node.namespace.name;
@@ -2256,8 +2307,14 @@ function lowerExpression(
2307 // This is already checked in builder.resolveIdentifier
2308 CompilerError.invariant(tagIdentifier.kind !== 'Identifier', {
2309 reason: `<${tagName}> tags should be module-level imports`,
2259 - loc: openingIdentifier.node.loc ?? GeneratedSource,
2310 description: null,
2311 + details: [
2312 + {
2313 + kind: 'error',
2314 + loc: openingIdentifier.node.loc ?? GeneratedSource,
2315 + message: null,
2316 + },
2317 + ],
2318 suggestions: null,
2319 });
2320 }
@@ -2361,7 +2418,13 @@ function lowerExpression(
2418 reason:
2419 "there should be only one quasi as we don't support interpolations yet",
2420 description: null,
2364 - loc: expr.node.loc ?? null,
2421 + details: [
2422 + {
2423 + kind: 'error',
2424 + loc: expr.node.loc ?? null,
2425 + message: null,
2426 + },
2427 + ],
2428 suggestions: null,
2429 });
2430 const value = expr.get('quasi').get('quasis').at(0)!.node.value;
@@ -2759,7 +2822,13 @@ function lowerOptionalMemberExpression(
2822 CompilerError.invariant(object !== null, {
2823 reason: 'Satisfy type checker',
2824 description: null,
2762 - loc: null,
2825 + details: [
2826 + {
2827 + kind: 'error',
2828 + loc: null,
2829 + message: null,
2830 + },
2831 + ],
2832 suggestions: null,
2833 });
2834
@@ -3327,7 +3396,13 @@ function lowerJsxMemberExpression(
3396 CompilerError.invariant(object.isJSXIdentifier(), {
3397 reason: `TypeScript refinement fail: expected 'JsxIdentifier', got \`${object.node.type}\``,
3398 description: null,
3330 - loc: object.node.loc ?? null,
3399 + details: [
3400 + {
3401 + kind: 'error',
3402 + loc: object.node.loc ?? null,
3403 + message: null,
3404 + },
3405 + ],
3406 suggestions: null,
3407 });
3408
@@ -3369,7 +3444,13 @@ function lowerJsxElement(
3444 CompilerError.invariant(expression.isExpression(), {
3445 reason: `(BuildHIR::lowerJsxElement) Expected Expression but found ${expression.type}!`,
3446 description: null,
3372 - loc: expression.node.loc ?? null,
3447 + details: [
3448 + {
3449 + kind: 'error',
3450 + loc: expression.node.loc ?? null,
3451 + message: null,
3452 + },
3453 + ],
3454 suggestions: null,
3455 });
3456 return lowerExpressionToTemporary(builder, expression);
@@ -3770,7 +3851,13 @@ function lowerAssignment(
3851 CompilerError.invariant(kind === InstructionKind.Reassign, {
3852 reason: 'MemberExpression may only appear in an assignment expression',
3853 description: null,
3773 - loc: lvaluePath.node.loc ?? null,
3854 + details: [
3855 + {
3856 + kind: 'error',
3857 + loc: lvaluePath.node.loc ?? null,
3858 + message: null,
3859 + },
3860 + ],
3861 suggestions: null,
3862 });
3863 const lvalue = lvaluePath as NodePath<t.MemberExpression>;
compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts
+8 -1
@@ -234,7 +234,14 @@ function pushEndScopeTerminal(
234 const fallthroughId = context.fallthroughs.get(scope.id);
235 CompilerError.invariant(fallthroughId != null, {
236 reason: 'Expected scope to exist',
237 - loc: GeneratedSource,
237 + description: null,
238 + details: [
239 + {
240 + kind: 'error',
241 + loc: GeneratedSource,
242 + message: null,
243 + },
244 + ],
245 });
246 context.rewrites.push({
247 kind: 'EndScope',
compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts
+31 -4
@@ -269,7 +269,14 @@ class PropertyPathRegistry {
269 CompilerError.invariant(reactive === rootNode.fullPath.reactive, {
270 reason:
271 '[HoistablePropertyLoads] Found inconsistencies in `reactive` flag when deduping identifier reads within the same scope',
272 - loc: identifier.loc,
272 + description: null,
273 + details: [
274 + {
275 + kind: 'error',
276 + loc: identifier.loc,
277 + message: null,
278 + },
279 + ],
280 });
281 }
282 return rootNode;
@@ -498,7 +505,14 @@ function propagateNonNull(
505 if (node == null) {
506 CompilerError.invariant(false, {
507 reason: `Bad node ${nodeId}, kind: ${direction}`,
501 - loc: GeneratedSource,
508 + description: null,
509 + details: [
510 + {
511 + kind: 'error',
512 + loc: GeneratedSource,
513 + message: null,
514 + },
515 + ],
516 });
517 }
518 const neighbors = Array.from(
@@ -570,7 +584,14 @@ function propagateNonNull(
584 CompilerError.invariant(i++ < 100, {
585 reason:
586 '[CollectHoistablePropertyLoads] fixed point iteration did not terminate after 100 loops',
573 - loc: GeneratedSource,
587 + description: null,
588 + details: [
589 + {
590 + kind: 'error',
591 + loc: GeneratedSource,
592 + message: null,
593 + },
594 + ],
595 });
596
597 changed = false;
@@ -602,7 +623,13 @@ export function assertNonNull<T extends NonNullable<U>, U>(
623 CompilerError.invariant(value != null, {
624 reason: 'Unexpected null',
625 description: source != null ? `(from ${source})` : null,
605 - loc: GeneratedSource,
626 + details: [
627 + {
628 + kind: 'error',
629 + loc: GeneratedSource,
630 + message: null,
631 + },
632 + ],
633 });
634 return value;
635 }
compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts
+54 -7
@@ -186,7 +186,13 @@ function matchOptionalTestBlock(
186 reason:
187 '[OptionalChainDeps] Inconsistent optional chaining property load',
188 description: `Test=${printIdentifier(terminal.test.identifier)} PropertyLoad base=${printIdentifier(propertyLoad.value.object.identifier)}`,
189 - loc: propertyLoad.loc,
189 + details: [
190 + {
191 + kind: 'error',
192 + loc: propertyLoad.loc,
193 + message: null,
194 + },
195 + ],
196 },
197 );
198
@@ -194,7 +200,14 @@ function matchOptionalTestBlock(
200 storeLocal.value.identifier.id === propertyLoad.lvalue.identifier.id,
201 {
202 reason: '[OptionalChainDeps] Unexpected storeLocal',
197 - loc: propertyLoad.loc,
203 + description: null,
204 + details: [
205 + {
206 + kind: 'error',
207 + loc: propertyLoad.loc,
208 + message: null,
209 + },
210 + ],
211 },
212 );
213 if (
@@ -211,7 +224,14 @@ function matchOptionalTestBlock(
224 alternate.instructions[1].value.kind === 'StoreLocal',
225 {
226 reason: 'Unexpected alternate structure',
214 - loc: terminal.loc,
227 + description: null,
228 + details: [
229 + {
230 + kind: 'error',
231 + loc: terminal.loc,
232 + message: null,
233 + },
234 + ],
235 },
236 );
237
@@ -247,7 +267,14 @@ function traverseOptionalBlock(
267 if (maybeTest.terminal.kind === 'branch') {
268 CompilerError.invariant(optional.terminal.optional, {
269 reason: '[OptionalChainDeps] Expect base case to be always optional',
250 - loc: optional.terminal.loc,
270 + description: null,
271 + details: [
272 + {
273 + kind: 'error',
274 + loc: optional.terminal.loc,
275 + message: null,
276 + },
277 + ],
278 });
279 /**
280 * Optional base expressions are currently within value blocks which cannot
@@ -285,7 +312,14 @@ function traverseOptionalBlock(
312 maybeTest.instructions.at(-1)!.lvalue.identifier.id,
313 {
314 reason: '[OptionalChainDeps] Unexpected test expression',
288 - loc: maybeTest.terminal.loc,
315 + description: null,
316 + details: [
317 + {
318 + kind: 'error',
319 + loc: maybeTest.terminal.loc,
320 + message: null,
321 + },
322 + ],
323 },
324 );
325 baseObject = {
@@ -374,7 +408,14 @@ function traverseOptionalBlock(
408 reason:
409 '[OptionalChainDeps] Unexpected instructions an inner optional block. ' +
410 'This indicates that the compiler may be incorrectly concatenating two unrelated optional chains',
377 - loc: optional.terminal.loc,
411 + description: null,
412 + details: [
413 + {
414 + kind: 'error',
415 + loc: optional.terminal.loc,
416 + message: null,
417 + },
418 + ],
419 });
420 }
421 const matchConsequentResult = matchOptionalTestBlock(test, context.blocks);
@@ -387,7 +428,13 @@ function traverseOptionalBlock(
428 {
429 reason: '[OptionalChainDeps] Unexpected optional goto-fallthrough',
430 description: `${matchConsequentResult.consequentGoto} != ${optional.terminal.fallthrough}`,
390 - loc: optional.terminal.loc,
431 + details: [
432 + {
433 + kind: 'error',
434 + loc: optional.terminal.loc,
435 + message: null,
436 + },
437 + ],
438 },
439 );
440 const load = {
compiler/packages/babel-plugin-react-compiler/src/HIR/ComputeUnconditionalBlocks.ts
+8 -1
@@ -24,7 +24,14 @@ export function computeUnconditionalBlocks(fn: HIRFunction): Set<BlockId> {
24 CompilerError.invariant(!unconditionalBlocks.has(current), {
25 reason:
26 'Internal error: non-terminating loop in ComputeUnconditionalBlocks',
27 - loc: null,
27 + description: null,
28 + details: [
29 + {
30 + kind: 'error',
31 + loc: null,
32 + message: null,
33 + },
34 + ],
35 suggestions: null,
36 });
37 unconditionalBlocks.add(current);
compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts
+15 -2
@@ -54,7 +54,14 @@ export class ReactiveScopeDependencyTreeHIR {
54 prevAccessType == null || prevAccessType === accessType,
55 {
56 reason: 'Conflicting access types',
57 - loc: GeneratedSource,
57 + description: null,
58 + details: [
59 + {
60 + kind: 'error',
61 + loc: GeneratedSource,
62 + message: null,
63 + },
64 + ],
65 },
66 );
67 let nextNode = currNode.properties.get(path[i].property);
@@ -90,7 +97,13 @@ export class ReactiveScopeDependencyTreeHIR {
97 CompilerError.invariant(reactive === rootNode.reactive, {
98 reason: '[DeriveMinimalDependenciesHIR] Conflicting reactive root flag',
99 description: `Identifier ${printIdentifier(identifier)}`,
93 - loc: GeneratedSource,
100 + details: [
101 + {
102 + kind: 'error',
103 + loc: GeneratedSource,
104 + message: null,
105 + },
106 + ],
107 });
108 }
109 return rootNode;
compiler/packages/babel-plugin-react-compiler/src/HIR/Dominator.ts
+21 -3
@@ -89,7 +89,13 @@ export class Dominator<T> {
89 CompilerError.invariant(dominator !== undefined, {
90 reason: 'Unknown node',
91 description: null,
92 - loc: null,
92 + details: [
93 + {
94 + kind: 'error',
95 + loc: null,
96 + message: null,
97 + },
98 + ],
99 suggestions: null,
100 });
101 return dominator === id ? null : dominator;
@@ -130,7 +136,13 @@ export class PostDominator<T> {
136 CompilerError.invariant(dominator !== undefined, {
137 reason: 'Unknown node',
138 description: null,
133 - loc: null,
139 + details: [
140 + {
141 + kind: 'error',
142 + loc: null,
143 + message: null,
144 + },
145 + ],
146 suggestions: null,
147 });
148 return dominator === id ? null : dominator;
@@ -175,7 +187,13 @@ function computeImmediateDominators<T>(graph: Graph<T>): Map<T, T> {
187 CompilerError.invariant(newIdom !== null, {
188 reason: `At least one predecessor must have been visited for block ${id}`,
189 description: null,
178 - loc: null,
190 + details: [
191 + {
192 + kind: 'error',
193 + loc: null,
194 + message: null,
195 + },
196 + ],
197 suggestions: null,
198 });
199
compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
+44 -6
@@ -750,7 +750,13 @@ export class Environment {
750 CompilerError.invariant(!this.#globals.has(hookName), {
751 reason: `[Globals] Found existing definition in global registry for custom hook ${hookName}`,
752 description: null,
753 - loc: null,
753 + details: [
754 + {
755 + kind: 'error',
756 + loc: null,
757 + message: null,
758 + },
759 + ],
760 suggestions: null,
761 });
762 this.#globals.set(
@@ -783,7 +789,14 @@ export class Environment {
789 CompilerError.invariant(code != null, {
790 reason:
791 'Expected Environment to be initialized with source code when a Flow type provider is specified',
786 - loc: null,
792 + description: null,
793 + details: [
794 + {
795 + kind: 'error',
796 + loc: null,
797 + message: null,
798 + },
799 + ],
800 });
801 this.#flowTypeEnvironment.init(this, code);
802 } else {
@@ -794,7 +807,14 @@ export class Environment {
807 get typeContext(): FlowTypeEnv {
808 CompilerError.invariant(this.#flowTypeEnvironment != null, {
809 reason: 'Flow type environment not initialized',
797 - loc: null,
810 + description: null,
811 + details: [
812 + {
813 + kind: 'error',
814 + loc: null,
815 + message: null,
816 + },
817 + ],
818 });
819 return this.#flowTypeEnvironment;
820 }
@@ -1044,7 +1064,13 @@ export class Environment {
1064 CompilerError.invariant(shape !== undefined, {
1065 reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`,
1066 description: null,
1047 - loc: null,
1067 + details: [
1068 + {
1069 + kind: 'error',
1070 + loc: null,
1071 + message: null,
1072 + },
1073 + ],
1074 suggestions: null,
1075 });
1076 return shape.properties.get('*') ?? null;
@@ -1069,7 +1095,13 @@ export class Environment {
1095 CompilerError.invariant(shape !== undefined, {
1096 reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`,
1097 description: null,
1072 - loc: null,
1098 + details: [
1099 + {
1100 + kind: 'error',
1101 + loc: null,
1102 + message: null,
1103 + },
1104 + ],
1105 suggestions: null,
1106 });
1107 if (typeof property === 'string') {
@@ -1094,7 +1126,13 @@ export class Environment {
1126 CompilerError.invariant(shape !== undefined, {
1127 reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`,
1128 description: null,
1097 - loc: null,
1129 + details: [
1130 + {
1131 + kind: 'error',
1132 + loc: null,
1133 + message: null,
1134 + },
1135 + ],
1136 suggestions: null,
1137 });
1138 return shape.functionType;
compiler/packages/babel-plugin-react-compiler/src/HIR/FindContextIdentifiers.ts
+14 -2
@@ -184,7 +184,13 @@ function handleAssignment(
184 CompilerError.invariant(valuePath.isLVal(), {
185 reason: `[FindContextIdentifiers] Expected object property value to be an LVal, got: ${valuePath.type}`,
186 description: null,
187 - loc: valuePath.node.loc ?? GeneratedSource,
187 + details: [
188 + {
189 + kind: 'error',
190 + loc: valuePath.node.loc ?? GeneratedSource,
191 + message: null,
192 + },
193 + ],
194 suggestions: null,
195 });
196 handleAssignment(currentFn, identifiers, valuePath);
@@ -192,7 +198,13 @@ function handleAssignment(
198 CompilerError.invariant(property.isRestElement(), {
199 reason: `[FindContextIdentifiers] Invalid assumptions for babel types.`,
200 description: null,
195 - loc: property.node.loc ?? GeneratedSource,
201 + details: [
202 + {
203 + kind: 'error',
204 + loc: property.node.loc ?? GeneratedSource,
205 + message: null,
206 + },
207 + ],
208 suggestions: null,
209 });
210 handleAssignment(currentFn, identifiers, property);
compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
+63 -9
@@ -1314,8 +1314,14 @@ export function makeIdentifierName(name: string): ValidatedIdentifier {
1314 } else {
1315 CompilerError.invariant(t.isValidIdentifier(name), {
1316 reason: `Expected a valid identifier name`,
1317 - loc: GeneratedSource,
1317 description: `\`${name}\` is not a valid JavaScript identifier`,
1318 + details: [
1319 + {
1320 + kind: 'error',
1321 + loc: GeneratedSource,
1322 + message: null,
1323 + },
1324 + ],
1325 suggestions: null,
1326 });
1327 }
@@ -1334,8 +1340,14 @@ export function makeIdentifierName(name: string): ValidatedIdentifier {
1340 export function promoteTemporary(identifier: Identifier): void {
1341 CompilerError.invariant(identifier.name === null, {
1342 reason: `Expected a temporary (unnamed) identifier`,
1337 - loc: GeneratedSource,
1343 description: `Identifier already has a name, \`${identifier.name}\``,
1344 + details: [
1345 + {
1346 + kind: 'error',
1347 + loc: GeneratedSource,
1348 + message: null,
1349 + },
1350 + ],
1351 suggestions: null,
1352 });
1353 identifier.name = {
@@ -1358,8 +1370,14 @@ export function isPromotedTemporary(name: string): boolean {
1370 export function promoteTemporaryJsxTag(identifier: Identifier): void {
1371 CompilerError.invariant(identifier.name === null, {
1372 reason: `Expected a temporary (unnamed) identifier`,
1361 - loc: GeneratedSource,
1373 description: `Identifier already has a name, \`${identifier.name}\``,
1374 + details: [
1375 + {
1376 + kind: 'error',
1377 + loc: GeneratedSource,
1378 + message: null,
1379 + },
1380 + ],
1381 suggestions: null,
1382 });
1383 identifier.name = {
@@ -1527,7 +1545,13 @@ export function isMutableEffect(
1545 CompilerError.invariant(false, {
1546 reason: 'Unexpected unknown effect',
1547 description: null,
1530 - loc: location,
1548 + details: [
1549 + {
1550 + kind: 'error',
1551 + loc: location,
1552 + message: null,
1553 + },
1554 + ],
1555 suggestions: null,
1556 });
1557 }
@@ -1660,7 +1684,13 @@ export function makeBlockId(id: number): BlockId {
1684 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
1685 reason: 'Expected block id to be a non-negative integer',
1686 description: null,
1663 - loc: null,
1687 + details: [
1688 + {
1689 + kind: 'error',
1690 + loc: null,
1691 + message: null,
1692 + },
1693 + ],
1694 suggestions: null,
1695 });
1696 return id as BlockId;
@@ -1677,7 +1707,13 @@ export function makeScopeId(id: number): ScopeId {
1707 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
1708 reason: 'Expected block id to be a non-negative integer',
1709 description: null,
1680 - loc: null,
1710 + details: [
1711 + {
1712 + kind: 'error',
1713 + loc: null,
1714 + message: null,
1715 + },
1716 + ],
1717 suggestions: null,
1718 });
1719 return id as ScopeId;
@@ -1694,7 +1730,13 @@ export function makeIdentifierId(id: number): IdentifierId {
1730 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
1731 reason: 'Expected identifier id to be a non-negative integer',
1732 description: null,
1697 - loc: null,
1733 + details: [
1734 + {
1735 + kind: 'error',
1736 + loc: null,
1737 + message: null,
1738 + },
1739 + ],
1740 suggestions: null,
1741 });
1742 return id as IdentifierId;
@@ -1711,7 +1753,13 @@ export function makeDeclarationId(id: number): DeclarationId {
1753 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
1754 reason: 'Expected declaration id to be a non-negative integer',
1755 description: null,
1714 - loc: null,
1756 + details: [
1757 + {
1758 + kind: 'error',
1759 + loc: null,
1760 + message: null,
1761 + },
1762 + ],
1763 suggestions: null,
1764 });
1765 return id as DeclarationId;
@@ -1728,7 +1776,13 @@ export function makeInstructionId(id: number): InstructionId {
1776 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
1777 reason: 'Expected instruction id to be a non-negative integer',
1778 description: null,
1731 - loc: null,
1779 + details: [
1780 + {
1781 + kind: 'error',
1782 + loc: null,
1783 + message: null,
1784 + },
1785 + ],
1786 suggestions: null,
1787 });
1788 return id as InstructionId;
compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts
+70 -10
@@ -507,7 +507,13 @@ export default class HIRBuilder {
507 {
508 reason: 'Mismatched label',
509 description: null,
510 - loc: null,
510 + details: [
511 + {
512 + kind: 'error',
513 + loc: null,
514 + message: null,
515 + },
516 + ],
517 suggestions: null,
518 },
519 );
@@ -530,7 +536,13 @@ export default class HIRBuilder {
536 {
537 reason: 'Mismatched label',
538 description: null,
533 - loc: null,
539 + details: [
540 + {
541 + kind: 'error',
542 + loc: null,
543 + message: null,
544 + },
545 + ],
546 suggestions: null,
547 },
548 );
@@ -566,7 +578,13 @@ export default class HIRBuilder {
578 {
579 reason: 'Mismatched loops',
580 description: null,
569 - loc: null,
581 + details: [
582 + {
583 + kind: 'error',
584 + loc: null,
585 + message: null,
586 + },
587 + ],
588 suggestions: null,
589 },
590 );
@@ -591,7 +609,13 @@ export default class HIRBuilder {
609 CompilerError.invariant(false, {
610 reason: 'Expected a loop or switch to be in scope',
611 description: null,
594 - loc: null,
612 + details: [
613 + {
614 + kind: 'error',
615 + loc: null,
616 + message: null,
617 + },
618 + ],
619 suggestions: null,
620 });
621 }
@@ -612,7 +636,13 @@ export default class HIRBuilder {
636 CompilerError.invariant(false, {
637 reason: 'Continue may only refer to a labeled loop',
638 description: null,
615 - loc: null,
639 + details: [
640 + {
641 + kind: 'error',
642 + loc: null,
643 + message: null,
644 + },
645 + ],
646 suggestions: null,
647 });
648 }
@@ -620,7 +650,13 @@ export default class HIRBuilder {
650 CompilerError.invariant(false, {
651 reason: 'Expected a loop to be in scope',
652 description: null,
623 - loc: null,
653 + details: [
654 + {
655 + kind: 'error',
656 + loc: null,
657 + message: null,
658 + },
659 + ],
660 suggestions: null,
661 });
662 }
@@ -643,7 +679,13 @@ function _shrink(func: HIR): void {
679 CompilerError.invariant(block != null, {
680 reason: `expected block ${blockId} to exist`,
681 description: null,
646 - loc: null,
682 + details: [
683 + {
684 + kind: 'error',
685 + loc: null,
686 + message: null,
687 + },
688 + ],
689 suggestions: null,
690 });
691 target = getTargetIfIndirection(block);
@@ -775,7 +817,13 @@ function getReversePostorderedBlocks(func: HIR): HIR['blocks'] {
817 CompilerError.invariant(block != null, {
818 reason: '[HIRBuilder] Unexpected null block',
819 description: `expected block ${blockId} to exist`,
778 - loc: GeneratedSource,
820 + details: [
821 + {
822 + kind: 'error',
823 + loc: GeneratedSource,
824 + message: null,
825 + },
826 + ],
827 });
828 const successors = [...eachTerminalSuccessor(block.terminal)].reverse();
829 const fallthrough = terminalFallthrough(block.terminal);
@@ -831,7 +879,13 @@ export function markInstructionIds(func: HIR): void {
879 CompilerError.invariant(!visited.has(instr), {
880 reason: `${printInstruction(instr)} already visited!`,
881 description: null,
834 - loc: instr.loc,
882 + details: [
883 + {
884 + kind: 'error',
885 + loc: instr.loc,
886 + message: null,
887 + },
888 + ],
889 suggestions: null,
890 });
891 visited.add(instr);
@@ -854,7 +908,13 @@ export function markPredecessors(func: HIR): void {
908 CompilerError.invariant(block != null, {
909 reason: 'unexpected missing block',
910 description: `block ${blockId}`,
857 - loc: GeneratedSource,
911 + details: [
912 + {
913 + kind: 'error',
914 + loc: GeneratedSource,
915 + message: null,
916 + },
917 + ],
918 });
919 if (prevBlock) {
920 block.preds.add(prevBlock.id);
compiler/packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks.ts
+14 -2
@@ -61,7 +61,13 @@ export function mergeConsecutiveBlocks(fn: HIRFunction): void {
61 CompilerError.invariant(predecessor !== undefined, {
62 reason: `Expected predecessor ${predecessorId} to exist`,
63 description: null,
64 - loc: null,
64 + details: [
65 + {
66 + kind: 'error',
67 + loc: null,
68 + message: null,
69 + },
70 + ],
71 suggestions: null,
72 });
73 if (predecessor.terminal.kind !== 'goto' || predecessor.kind !== 'block') {
@@ -77,7 +83,13 @@ export function mergeConsecutiveBlocks(fn: HIRFunction): void {
83 CompilerError.invariant(phi.operands.size === 1, {
84 reason: `Found a block with a single predecessor but where a phi has multiple (${phi.operands.size}) operands`,
85 description: null,
80 - loc: null,
86 + details: [
87 + {
88 + kind: 'error',
89 + loc: null,
90 + message: null,
91 + },
92 + ],
93 suggestions: null,
94 });
95 const operand = Array.from(phi.operands.values())[0]!;
compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts
+21 -3
@@ -119,7 +119,13 @@ function parseAliasingSignatureConfig(
119 CompilerError.invariant(!lifetimes.has(temp), {
120 reason: `Invalid type configuration for module`,
121 description: `Expected aliasing signature to have unique names for receiver, params, rest, returns, and temporaries in module '${moduleName}'`,
122 - loc,
122 + details: [
123 + {
124 + kind: 'error',
125 + loc,
126 + message: null,
127 + },
128 + ],
129 });
130 const place = signatureArgument(lifetimes.size);
131 lifetimes.set(temp, place);
@@ -130,7 +136,13 @@ function parseAliasingSignatureConfig(
136 CompilerError.invariant(place != null, {
137 reason: `Invalid type configuration for module`,
138 description: `Expected aliasing signature effects to reference known names from receiver/params/rest/returns/temporaries, but '${temp}' is not a known name in '${moduleName}'`,
133 - loc,
139 + details: [
140 + {
141 + kind: 'error',
142 + loc,
143 + message: null,
144 + },
145 + ],
146 });
147 return place;
148 }
@@ -265,7 +277,13 @@ function addShape(
277 CompilerError.invariant(!registry.has(id), {
278 reason: `[ObjectShape] Could not add shape to registry: name ${id} already exists.`,
279 description: null,
268 - loc: null,
280 + details: [
281 + {
282 + kind: 'error',
283 + loc: null,
284 + message: null,
285 + },
286 + ],
287 suggestions: null,
288 });
289 registry.set(id, shape);
compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts
+15 -2
@@ -596,7 +596,13 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
596 {
597 reason: 'Bad assumption about quasi length.',
598 description: null,
599 - loc: instrValue.loc,
599 + details: [
600 + {
601 + kind: 'error',
602 + loc: instrValue.loc,
603 + message: null,
604 + },
605 + ],
606 suggestions: null,
607 },
608 );
@@ -865,8 +871,15 @@ export function printManualMemoDependency(
871 } else {
872 CompilerError.invariant(val.root.value.identifier.name?.kind === 'named', {
873 reason: 'DepsValidation: expected named local variable in depslist',
874 + description: null,
875 suggestions: null,
869 - loc: val.root.value.loc,
876 + details: [
877 + {
878 + kind: 'error',
879 + loc: val.root.value.loc,
880 + message: null,
881 + },
882 + ],
883 });
884 rootStr = nameOnly
885 ? val.root.value.identifier.name.value
compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts
+16 -2
@@ -86,7 +86,14 @@ export function propagateScopeDependenciesHIR(fn: HIRFunction): void {
86 const hoistables = hoistablePropertyLoads.get(scope.id);
87 CompilerError.invariant(hoistables != null, {
88 reason: '[PropagateScopeDependencies] Scope not found in tracked blocks',
89 - loc: GeneratedSource,
89 + description: null,
90 + details: [
91 + {
92 + kind: 'error',
93 + loc: GeneratedSource,
94 + message: null,
95 + },
96 + ],
97 });
98 /**
99 * Step 2: Calculate hoistable dependencies.
@@ -428,7 +435,14 @@ export class DependencyCollectionContext {
435 const scopedDependencies = this.#dependencies.value;
436 CompilerError.invariant(scopedDependencies != null, {
437 reason: '[PropagateScopeDeps]: Unexpected scope mismatch',
431 - loc: scope.loc,
438 + description: null,
439 + details: [
440 + {
441 + kind: 'error',
442 + loc: scope.loc,
443 + message: null,
444 + },
445 + ],
446 });
447
448 // Restore context of previous scope
compiler/packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR.ts
+16 -2
@@ -53,7 +53,14 @@ export function pruneUnusedLabelsHIR(fn: HIRFunction): void {
53 next.phis.size === 0 && fallthrough.phis.size === 0,
54 {
55 reason: 'Unexpected phis when merging label blocks',
56 - loc: label.terminal.loc,
56 + description: null,
57 + details: [
58 + {
59 + kind: 'error',
60 + loc: label.terminal.loc,
61 + message: null,
62 + },
63 + ],
64 },
65 );
66
@@ -64,7 +71,14 @@ export function pruneUnusedLabelsHIR(fn: HIRFunction): void {
71 fallthrough.preds.has(nextId),
72 {
73 reason: 'Unexpected block predecessors when merging label blocks',
67 - loc: label.terminal.loc,
74 + description: null,
75 + details: [
76 + {
77 + kind: 'error',
78 + loc: label.terminal.loc,
79 + message: null,
80 + },
81 + ],
82 },
83 );
84
compiler/packages/babel-plugin-react-compiler/src/HIR/ScopeDependencyUtils.ts
+14 -2
@@ -202,8 +202,14 @@ function writeOptionalDependency(
202 CompilerError.invariant(firstOptional !== -1, {
203 reason:
204 '[ScopeDependencyUtils] Internal invariant broken: expected optional path',
205 - loc: dep.identifier.loc,
205 description: null,
206 + details: [
207 + {
208 + kind: 'error',
209 + loc: dep.identifier.loc,
210 + message: null,
211 + },
212 + ],
213 suggestions: null,
214 });
215 if (firstOptional === dep.path.length - 1) {
@@ -239,7 +245,13 @@ function writeOptionalDependency(
245 CompilerError.invariant(testIdentifier !== null, {
246 reason: 'Satisfy type checker',
247 description: null,
242 - loc: null,
248 + details: [
249 + {
250 + kind: 'error',
251 + loc: null,
252 + message: null,
253 + },
254 + ],
255 suggestions: null,
256 });
257
compiler/packages/babel-plugin-react-compiler/src/HIR/Types.ts
+7 -1
@@ -87,7 +87,13 @@ export function makeTypeId(id: number): TypeId {
87 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
88 reason: 'Expected instruction id to be a non-negative integer',
89 description: null,
90 - loc: null,
90 + details: [
91 + {
92 + kind: 'error',
93 + loc: null,
94 + message: null,
95 + },
96 + ],
97 suggestions: null,
98 });
99 return id as TypeId;
compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts
+16 -2
@@ -1233,7 +1233,14 @@ export class ScopeBlockTraversal {
1233 CompilerError.invariant(blockInfo.scope.id === top, {
1234 reason:
1235 'Expected traversed block fallthrough to match top-most active scope',
1236 - loc: block.instructions[0]?.loc ?? block.terminal.id,
1236 + description: null,
1237 + details: [
1238 + {
1239 + kind: 'error',
1240 + loc: block.instructions[0]?.loc ?? block.terminal.id,
1241 + message: null,
1242 + },
1243 + ],
1244 });
1245 this.#activeScopes.pop();
1246 }
@@ -1247,7 +1254,14 @@ export class ScopeBlockTraversal {
1254 !this.blockInfos.has(block.terminal.fallthrough),
1255 {
1256 reason: 'Expected unique scope blocks and fallthroughs',
1250 - loc: block.terminal.loc,
1257 + description: null,
1258 + details: [
1259 + {
1260 + kind: 'error',
1261 + loc: block.terminal.loc,
1262 + message: null,
1263 + },
1264 + ],
1265 },
1266 );
1267 this.blockInfos.set(block.terminal.block, {
compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts
+8 -1
@@ -78,7 +78,14 @@ function lowerWithMutationAliasing(fn: HIRFunction): void {
78 case 'Apply': {
79 CompilerError.invariant(false, {
80 reason: `[AnalyzeFunctions] Expected Apply effects to be replaced with more precise effects`,
81 - loc: effect.function.loc,
81 + description: null,
82 + details: [
83 + {
84 + kind: 'error',
85 + loc: effect.function.loc,
86 + message: null,
87 + },
88 + ],
89 });
90 }
91 case 'Mutate':
compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts
+14 -7
@@ -300,7 +300,7 @@ function extractManualMemoizationArgs(
300 reason: `Expected a callback function to be passed to ${kind}`,
301 description: `Expected a callback function to be passed to ${kind}`,
302 suggestions: null,
303 - }).withDetail({
303 + }).withDetails({
304 kind: 'error',
305 loc: instr.value.loc,
306 message: `Expected a callback function to be passed to ${kind}`,
@@ -315,7 +315,7 @@ function extractManualMemoizationArgs(
315 reason: `Unexpected spread argument to ${kind}`,
316 description: `Unexpected spread argument to ${kind}`,
317 suggestions: null,
318 - }).withDetail({
318 + }).withDetails({
319 kind: 'error',
320 loc: instr.value.loc,
321 message: `Unexpected spread argument to ${kind}`,
@@ -335,7 +335,7 @@ function extractManualMemoizationArgs(
335 reason: `Expected the dependency list for ${kind} to be an array literal`,
336 description: `Expected the dependency list for ${kind} to be an array literal`,
337 suggestions: null,
338 - }).withDetail({
338 + }).withDetails({
339 kind: 'error',
340 loc: depsListPlace.loc,
341 message: `Expected the dependency list for ${kind} to be an array literal`,
@@ -353,7 +353,7 @@ function extractManualMemoizationArgs(
353 reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
354 description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
355 suggestions: null,
356 - }).withDetail({
356 + }).withDetails({
357 kind: 'error',
358 loc: dep.loc,
359 message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
@@ -462,7 +462,7 @@ export function dropManualMemoization(
462 : 'useMemo'
463 } callback doesn't return a value. useMemo is for computing and caching values, not for arbitrary side effects.`,
464 suggestions: null,
465 - }).withDetail({
465 + }).withDetails({
466 kind: 'error',
467 loc: instr.value.loc,
468 message: 'useMemo() callbacks must return a value',
@@ -498,7 +498,7 @@ export function dropManualMemoization(
498 reason: `Expected the first argument to be an inline function expression`,
499 description: `Expected the first argument to be an inline function expression`,
500 suggestions: [],
501 - }).withDetail({
501 + }).withDetails({
502 kind: 'error',
503 loc: fnPlace.loc,
504 message: `Expected the first argument to be an inline function expression`,
@@ -613,7 +613,14 @@ function findOptionalPlaces(fn: HIRFunction): Set<IdentifierId> {
613 default: {
614 CompilerError.invariant(false, {
615 reason: `Unexpected terminal in optional`,
616 - loc: terminal.loc,
616 + description: null,
617 + details: [
618 + {
619 + kind: 'error',
620 + loc: terminal.loc,
621 + message: `Unexpected ${terminal.kind} in optional`,
622 + },
623 + ],
624 });
625 }
626 }
compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts
+40 -5
@@ -438,7 +438,14 @@ function rewriteSplices(
438 {
439 reason:
440 '[InferEffectDependencies] Internal invariant broken: expected block instructions to be sorted',
441 - loc: originalInstrs[cursor].loc,
441 + description: null,
442 + details: [
443 + {
444 + kind: 'error',
445 + loc: originalInstrs[cursor].loc,
446 + message: null,
447 + },
448 + ],
449 },
450 );
451 currBlock.instructions.push(originalInstrs[cursor]);
@@ -447,7 +454,14 @@ function rewriteSplices(
454 CompilerError.invariant(originalInstrs[cursor].id === rewrite.location, {
455 reason:
456 '[InferEffectDependencies] Internal invariant broken: splice location not found',
450 - loc: originalInstrs[cursor].loc,
457 + description: null,
458 + details: [
459 + {
460 + kind: 'error',
461 + loc: originalInstrs[cursor].loc,
462 + message: null,
463 + },
464 + ],
465 });
466
467 if (rewrite.kind === 'instr') {
@@ -467,7 +481,14 @@ function rewriteSplices(
481 {
482 reason:
483 '[InferEffectDependencies] Internal invariant broken: expected entry block to have a fallthrough',
470 - loc: entryBlock.terminal.loc,
484 + description: null,
485 + details: [
486 + {
487 + kind: 'error',
488 + loc: entryBlock.terminal.loc,
489 + message: null,
490 + },
491 + ],
492 },
493 );
494 const originalTerminal = currBlock.terminal;
@@ -566,7 +587,14 @@ function inferMinimalDependencies(
587 CompilerError.invariant(hoistableToFnEntry != null, {
588 reason:
589 '[InferEffectDependencies] Internal invariant broken: missing entry block',
569 - loc: fnInstr.loc,
590 + description: null,
591 + details: [
592 + {
593 + kind: 'error',
594 + loc: fnInstr.loc,
595 + message: null,
596 + },
597 + ],
598 });
599
600 const dependencies = inferDependencies(
@@ -622,7 +650,14 @@ function inferDependencies(
650 CompilerError.invariant(resultUnfiltered != null, {
651 reason:
652 '[InferEffectDependencies] Internal invariant broken: missing scope dependencies',
625 - loc: fn.loc,
653 + description: null,
654 + details: [
655 + {
656 + kind: 'error',
657 + loc: fn.loc,
658 + message: null,
659 + },
660 + ],
661 });
662
663 const fnContext = new Set(fn.context.map(dep => dep.identifier.id));
compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts
+138 -31
@@ -58,7 +58,6 @@ import {
58 printInstruction,
59 printInstructionValue,
60 printPlace,
61 - printSourceLocation,
61 } from '../HIR/PrintHIR';
62 import {FunctionSignature} from '../HIR/ObjectShape';
63 import prettyFormat from 'pretty-format';
@@ -135,7 +134,13 @@ export function inferMutationAliasingEffects(
134 reason:
135 'Expected React component to have not more than two parameters: one for props and for ref',
136 description: null,
138 - loc: fn.loc,
137 + details: [
138 + {
139 + kind: 'error',
140 + loc: fn.loc,
141 + message: null,
142 + },
143 + ],
144 suggestions: null,
145 });
146 const [props, ref] = fn.params;
@@ -202,7 +207,13 @@ export function inferMutationAliasingEffects(
207 CompilerError.invariant(false, {
208 reason: `[InferMutationAliasingEffects] Potential infinite loop`,
209 description: `A value, temporary place, or effect was not cached properly`,
205 - loc: fn.loc,
210 + details: [
211 + {
212 + kind: 'error',
213 + loc: fn.loc,
214 + message: null,
215 + },
216 + ],
217 });
218 }
219 for (const [blockId, block] of fn.body.blocks) {
@@ -357,7 +368,14 @@ function inferBlock(
368 CompilerError.invariant(state.kind(handlerParam) != null, {
369 reason:
370 'Expected catch binding to be intialized with a DeclareLocal Catch instruction',
360 - loc: terminal.loc,
371 + description: null,
372 + details: [
373 + {
374 + kind: 'error',
375 + loc: terminal.loc,
376 + message: null,
377 + },
378 + ],
379 });
380 const effects: Array<AliasingEffect> = [];
381 for (const instr of block.instructions) {
@@ -456,7 +474,7 @@ function applySignature(
474 category: ErrorCategory.Immutability,
475 reason: 'This value cannot be modified',
476 description: `${reason}.`,
459 - }).withDetail({
477 + }).withDetails({
478 kind: 'error',
479 loc: effect.value.loc,
480 message: `${variable} cannot be modified`,
@@ -465,7 +483,7 @@ function applySignature(
483 effect.kind === 'Mutate' &&
484 effect.reason?.kind === 'AssignCurrentProperty'
485 ) {
468 - diagnostic.withDetail({
486 + diagnostic.withDetails({
487 kind: 'hint',
488 message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`,
489 });
@@ -507,7 +525,14 @@ function applySignature(
525 ) {
526 CompilerError.invariant(false, {
527 reason: `Expected instruction lvalue to be initialized`,
510 - loc: instruction.loc,
528 + description: null,
529 + details: [
530 + {
531 + kind: 'error',
532 + loc: instruction.loc,
533 + message: null,
534 + },
535 + ],
536 });
537 }
538 return effects.length !== 0 ? effects : null;
@@ -536,7 +561,13 @@ function applyEffect(
561 CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
562 reason: `Cannot re-initialize variable within an instruction`,
563 description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
539 - loc: effect.into.loc,
564 + details: [
565 + {
566 + kind: 'error',
567 + loc: effect.into.loc,
568 + message: null,
569 + },
570 + ],
571 });
572 initialized.add(effect.into.identifier.id);
573
@@ -575,7 +606,13 @@ function applyEffect(
606 CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
607 reason: `Cannot re-initialize variable within an instruction`,
608 description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
578 - loc: effect.into.loc,
609 + details: [
610 + {
611 + kind: 'error',
612 + loc: effect.into.loc,
613 + message: null,
614 + },
615 + ],
616 });
617 initialized.add(effect.into.identifier.id);
618
@@ -635,7 +672,13 @@ function applyEffect(
672 CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
673 reason: `Cannot re-initialize variable within an instruction`,
674 description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
638 - loc: effect.into.loc,
675 + details: [
676 + {
677 + kind: 'error',
678 + loc: effect.into.loc,
679 + message: null,
680 + },
681 + ],
682 });
683 initialized.add(effect.into.identifier.id);
684
@@ -709,7 +752,13 @@ function applyEffect(
752 {
753 reason: `Expected destination value to already be initialized within this instruction for Alias effect`,
754 description: `Destination ${printPlace(effect.into)} is not initialized in this instruction`,
712 - loc: effect.into.loc,
755 + details: [
756 + {
757 + kind: 'error',
758 + loc: effect.into.loc,
759 + message: null,
760 + },
761 + ],
762 },
763 );
764 /*
@@ -768,7 +817,13 @@ function applyEffect(
817 CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
818 reason: `Cannot re-initialize variable within an instruction`,
819 description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
771 - loc: effect.into.loc,
820 + details: [
821 + {
822 + kind: 'error',
823 + loc: effect.into.loc,
824 + message: null,
825 + },
826 + ],
827 });
828 initialized.add(effect.into.identifier.id);
829
@@ -1042,13 +1097,13 @@ function applyEffect(
1097 description: `${variable ?? 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time.`,
1098 });
1099 if (hoistedAccess != null && hoistedAccess.loc != effect.value.loc) {
1045 - diagnostic.withDetail({
1100 + diagnostic.withDetails({
1101 kind: 'error',
1102 loc: hoistedAccess.loc,
1103 message: `${variable ?? 'variable'} accessed before it is declared`,
1104 });
1105 }
1051 - diagnostic.withDetail({
1106 + diagnostic.withDetails({
1107 kind: 'error',
1108 loc: effect.value.loc,
1109 message: `${variable ?? 'variable'} is declared here`,
@@ -1079,7 +1134,7 @@ function applyEffect(
1134 category: ErrorCategory.Immutability,
1135 reason: 'This value cannot be modified',
1136 description: `${reason}.`,
1082 - }).withDetail({
1137 + }).withDetails({
1138 kind: 'error',
1139 loc: effect.value.loc,
1140 message: `${variable} cannot be modified`,
@@ -1088,7 +1143,7 @@ function applyEffect(
1143 effect.kind === 'Mutate' &&
1144 effect.reason?.kind === 'AssignCurrentProperty'
1145 ) {
1091 - diagnostic.withDetail({
1146 + diagnostic.withDetails({
1147 kind: 'hint',
1148 message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`,
1149 });
@@ -1169,7 +1224,13 @@ class InferenceState {
1224 reason:
1225 '[InferMutationAliasingEffects] Expected all top-level identifiers to be defined as variables, not values',
1226 description: null,
1172 - loc: value.loc,
1227 + details: [
1228 + {
1229 + kind: 'error',
1230 + loc: value.loc,
1231 + message: null,
1232 + },
1233 + ],
1234 suggestions: null,
1235 });
1236 this.#values.set(value, kind);
@@ -1180,7 +1241,13 @@ class InferenceState {
1241 CompilerError.invariant(values != null, {
1242 reason: `[InferMutationAliasingEffects] Expected value kind to be initialized`,
1243 description: `${printPlace(place)}`,
1183 - loc: place.loc,
1244 + details: [
1245 + {
1246 + kind: 'error',
1247 + loc: place.loc,
1248 + message: 'this is uninitialized',
1249 + },
1250 + ],
1251 suggestions: null,
1252 });
1253 return Array.from(values);
@@ -1192,7 +1259,13 @@ class InferenceState {
1259 CompilerError.invariant(values != null, {
1260 reason: `[InferMutationAliasingEffects] Expected value kind to be initialized`,
1261 description: `${printPlace(place)}`,
1195 - loc: place.loc,
1262 + details: [
1263 + {
1264 + kind: 'error',
1265 + loc: place.loc,
1266 + message: 'this is uninitialized',
1267 + },
1268 + ],
1269 suggestions: null,
1270 });
1271 let mergedKind: AbstractValue | null = null;
@@ -1204,7 +1277,13 @@ class InferenceState {
1277 CompilerError.invariant(mergedKind !== null, {
1278 reason: `[InferMutationAliasingEffects] Expected at least one value`,
1279 description: `No value found at \`${printPlace(place)}\``,
1207 - loc: place.loc,
1280 + details: [
1281 + {
1282 + kind: 'error',
1283 + loc: place.loc,
1284 + message: null,
1285 + },
1286 + ],
1287 suggestions: null,
1288 });
1289 return mergedKind;
@@ -1216,7 +1295,13 @@ class InferenceState {
1295 CompilerError.invariant(values != null, {
1296 reason: `[InferMutationAliasingEffects] Expected value for identifier to be initialized`,
1297 description: `${printIdentifier(value.identifier)}`,
1219 - loc: value.loc,
1298 + details: [
1299 + {
1300 + kind: 'error',
1301 + loc: value.loc,
1302 + message: 'Expected value for identifier to be initialized',
1303 + },
1304 + ],
1305 suggestions: null,
1306 });
1307 this.#variables.set(place.identifier.id, new Set(values));
@@ -1227,7 +1312,13 @@ class InferenceState {
1312 CompilerError.invariant(values != null, {
1313 reason: `[InferMutationAliasingEffects] Expected value for identifier to be initialized`,
1314 description: `${printIdentifier(value.identifier)}`,
1230 - loc: value.loc,
1315 + details: [
1316 + {
1317 + kind: 'error',
1318 + loc: value.loc,
1319 + message: 'Expected value for identifier to be initialized',
1320 + },
1321 + ],
1322 suggestions: null,
1323 });
1324 const prevValues = this.values(place);
@@ -1240,11 +1331,15 @@ class InferenceState {
1331 // Defines (initializing or updating) a variable with a specific kind of value.
1332 define(place: Place, value: InstructionValue): void {
1333 CompilerError.invariant(this.#values.has(value), {
1243 - reason: `[InferMutationAliasingEffects] Expected value to be initialized at '${printSourceLocation(
1244 - value.loc,
1245 - )}'`,
1334 + reason: `[InferMutationAliasingEffects] Expected value to be initialized`,
1335 description: printInstructionValue(value),
1247 - loc: value.loc,
1336 + details: [
1337 + {
1338 + kind: 'error',
1339 + loc: value.loc,
1340 + message: 'Expected value for identifier to be initialized',
1341 + },
1342 + ],
1343 suggestions: null,
1344 });
1345 this.#variables.set(place.identifier.id, new Set([value]));
@@ -2055,7 +2150,7 @@ function computeSignatureForInstruction(
2150 reason:
2151 'Cannot reassign variables declared outside of the component/hook',
2152 description: `Variable ${variable} is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)`,
2058 - }).withDetail({
2153 + }).withDetails({
2154 kind: 'error',
2155 loc: instr.loc,
2156 message: `${variable} cannot be reassigned`,
@@ -2157,7 +2252,7 @@ function computeEffectsForLegacySignature(
2252 ? `\`${signature.canonicalName}\` is an impure function. `
2253 : '') +
2254 'Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)',
2160 - }).withDetail({
2255 + }).withDetails({
2256 kind: 'error',
2257 loc,
2258 message: 'Cannot call impure function',
@@ -2176,7 +2271,7 @@ function computeEffectsForLegacySignature(
2271 'However, you may see issues if values from this API are passed to other components/hooks that are ' +
2272 'memoized.',
2273 ].join(''),
2179 - }).withDetail({
2274 + }).withDetails({
2275 kind: 'error',
2276 loc: receiver.loc,
2277 message: signature.knownIncompatible,
@@ -2676,7 +2771,13 @@ export function isKnownMutableEffect(effect: Effect): boolean {
2771 CompilerError.invariant(false, {
2772 reason: 'Unexpected unknown effect',
2773 description: null,
2679 - loc: GeneratedSource,
2774 + details: [
2775 + {
2776 + kind: 'error',
2777 + loc: GeneratedSource,
2778 + message: null,
2779 + },
2780 + ],
2781 suggestions: null,
2782 });
2783 }
@@ -2785,7 +2886,13 @@ function mergeValueKinds(a: ValueKind, b: ValueKind): ValueKind {
2886 {
2887 reason: `Unexpected value kind in mergeValues()`,
2888 description: `Found kinds ${a} and ${b}`,
2788 - loc: GeneratedSource,
2889 + details: [
2890 + {
2891 + kind: 'error',
2892 + loc: GeneratedSource,
2893 + message: null,
2894 + },
2895 + ],
2896 },
2897 );
2898 return ValueKind.Primitive;
compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingRanges.ts
+24 -3
@@ -229,7 +229,14 @@ export function inferMutationAliasingRanges(
229 } else {
230 CompilerError.invariant(effect.kind === 'Freeze', {
231 reason: `Unexpected '${effect.kind}' effect for MaybeThrow terminal`,
232 - loc: block.terminal.loc,
232 + description: null,
233 + details: [
234 + {
235 + kind: 'error',
236 + loc: block.terminal.loc,
237 + message: null,
238 + },
239 + ],
240 });
241 }
242 }
@@ -378,7 +385,14 @@ export function inferMutationAliasingRanges(
385 case 'Apply': {
386 CompilerError.invariant(false, {
387 reason: `[AnalyzeFunctions] Expected Apply effects to be replaced with more precise effects`,
381 - loc: effect.function.loc,
388 + description: null,
389 + details: [
390 + {
391 + kind: 'error',
392 + loc: effect.function.loc,
393 + message: null,
394 + },
395 + ],
396 });
397 }
398 case 'MutateTransitive':
@@ -525,7 +539,14 @@ export function inferMutationAliasingRanges(
539 const fromNode = state.nodes.get(from.identifier);
540 CompilerError.invariant(fromNode != null, {
541 reason: `Expected a node to exist for all parameters and context variables`,
528 - loc: into.loc,
542 + description: null,
543 + details: [
544 + {
545 + kind: 'error',
546 + loc: into.loc,
547 + message: null,
548 + },
549 + ],
550 });
551 if (fromNode.lastMutated === mutationIndex) {
552 if (into.identifier.id === fn.returns.identifier.id) {
compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts
+7 -1
@@ -349,7 +349,13 @@ export function inferReactivePlaces(fn: HIRFunction): void {
349 CompilerError.invariant(false, {
350 reason: 'Unexpected unknown effect',
351 description: null,
352 - loc: operand.loc,
352 + details: [
353 + {
354 + kind: 'error',
355 + loc: operand.loc,
356 + message: null,
357 + },
358 + ],
359 suggestions: null,
360 });
361 }
compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts
+16 -2
@@ -191,7 +191,14 @@ function evaluatePhi(phi: Phi, constants: Constants): Constant | null {
191 case 'Primitive': {
192 CompilerError.invariant(value.kind === 'Primitive', {
193 reason: 'value kind expected to be Primitive',
194 - loc: null,
194 + description: null,
195 + details: [
196 + {
197 + kind: 'error',
198 + loc: null,
199 + message: null,
200 + },
201 + ],
202 suggestions: null,
203 });
204
@@ -204,7 +211,14 @@ function evaluatePhi(phi: Phi, constants: Constants): Constant | null {
211 case 'LoadGlobal': {
212 CompilerError.invariant(value.kind === 'LoadGlobal', {
213 reason: 'value kind expected to be LoadGlobal',
207 - loc: null,
214 + description: null,
215 + details: [
216 + {
217 + kind: 'error',
218 + loc: null,
219 + message: null,
220 + },
221 + ],
222 suggestions: null,
223 });
224
compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts
+8 -1
@@ -709,7 +709,14 @@ function createPropsProperties(
709 const spreadProp = jsxSpreadAttributes[0];
710 CompilerError.invariant(spreadProp.kind === 'JsxSpreadAttribute', {
711 reason: 'Spread prop attribute must be of kind JSXSpreadAttribute',
712 - loc: instr.loc,
712 + description: null,
713 + details: [
714 + {
715 + kind: 'error',
716 + loc: instr.loc,
717 + message: null,
718 + },
719 + ],
720 });
721 propsProperty = {
722 kind: 'ObjectProperty',
compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts
+18 -5
@@ -78,10 +78,17 @@ export function instructionReordering(fn: HIRFunction): void {
78 }
79 CompilerError.invariant(shared.size === 0, {
80 reason: `InstructionReordering: expected all reorderable nodes to have been emitted`,
81 - loc:
82 - [...shared.values()]
83 - .map(node => node.instruction?.loc)
84 - .filter(loc => loc != null)[0] ?? GeneratedSource,
81 + description: null,
82 + details: [
83 + {
84 + kind: 'error',
85 + loc:
86 + [...shared.values()]
87 + .map(node => node.instruction?.loc)
88 + .filter(loc => loc != null)[0] ?? GeneratedSource,
89 + message: null,
90 + },
91 + ],
92 });
93 markInstructionIds(fn.body);
94 }
@@ -302,7 +309,13 @@ function reorderBlock(
309 node.reorderability === Reorderability.Reorderable,
310 {
311 reason: `Expected all remaining instructions to be reorderable`,
305 - loc: node.instruction?.loc ?? block.terminal.loc,
312 + details: [
313 + {
314 + kind: 'error',
315 + loc: node.instruction?.loc ?? block.terminal.loc,
316 + message: null,
317 + },
318 + ],
319 description:
320 node.instruction != null
321 ? `Instruction [${node.instruction.id}] was not emitted yet but is not reorderable`
compiler/packages/babel-plugin-react-compiler/src/Optimization/PruneMaybeThrows.ts
+7 -1
@@ -52,7 +52,13 @@ export function pruneMaybeThrows(fn: HIRFunction): void {
52 const mappedTerminal = terminalMapping.get(predecessor);
53 CompilerError.invariant(mappedTerminal != null, {
54 reason: `Expected non-existing phi operand's predecessor to have been mapped to a new terminal`,
55 - loc: GeneratedSource,
55 + details: [
56 + {
57 + kind: 'error',
58 + loc: GeneratedSource,
59 + message: null,
60 + },
61 + ],
62 description: `Could not find mapping for predecessor bb${predecessor} in block bb${
63 block.id
64 } for phi ${printPlace(phi.place)}`,
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignObjectMethodScopes.ts
+8 -1
@@ -41,8 +41,15 @@ function findScopesToMerge(fn: HIRFunction): DisjointSet<ReactiveScope> {
41 {
42 reason:
43 'Internal error: Expected all ObjectExpressions and ObjectMethods to have non-null scope.',
44 + description: null,
45 suggestions: null,
45 - loc: GeneratedSource,
46 + details: [
47 + {
48 + kind: 'error',
49 + loc: GeneratedSource,
50 + message: null,
51 + },
52 + ],
53 },
54 );
55 mergeScopesBuilder.union([operandScope, lvalueScope]);
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts
+16 -2
@@ -170,7 +170,14 @@ export function alignReactiveScopesToBlockScopesHIR(fn: HIRFunction): void {
170
171 CompilerError.invariant(!valueBlockNodes.has(fallthrough), {
172 reason: 'Expect hir blocks to have unique fallthroughs',
173 - loc: terminal.loc,
173 + description: null,
174 + details: [
175 + {
176 + kind: 'error',
177 + loc: terminal.loc,
178 + message: null,
179 + },
180 + ],
181 });
182 if (node != null) {
183 valueBlockNodes.set(fallthrough, node);
@@ -252,7 +259,14 @@ export function alignReactiveScopesToBlockScopesHIR(fn: HIRFunction): void {
259 // Transition from block->value block, derive the outer block range
260 CompilerError.invariant(fallthrough !== null, {
261 reason: `Expected a fallthrough for value block`,
255 - loc: terminal.loc,
262 + description: null,
263 + details: [
264 + {
265 + kind: 'error',
266 + loc: terminal.loc,
267 + message: null,
268 + },
269 + ],
270 });
271 const fallthroughBlock = fn.body.blocks.get(fallthrough)!;
272 const nextId =
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertScopeInstructionsWithinScope.ts
+8 -2
@@ -81,10 +81,16 @@ class CheckInstructionsAgainstScopesVisitor extends ReactiveFunctionVisitor<
81 !this.activeScopes.has(scope.id)
82 ) {
83 CompilerError.invariant(false, {
84 - description: `Instruction [${id}] is part of scope @${scope.id}, but that scope has already completed.`,
85 - loc: place.loc,
84 reason:
85 'Encountered an instruction that should be part of a scope, but where that scope has already completed',
86 + description: `Instruction [${id}] is part of scope @${scope.id}, but that scope has already completed.`,
87 + details: [
88 + {
89 + kind: 'error',
90 + loc: place.loc,
91 + message: null,
92 + },
93 + ],
94 suggestions: null,
95 });
96 }
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertWellFormedBreakTargets.ts
+8 -1
@@ -28,7 +28,14 @@ class Visitor extends ReactiveFunctionVisitor<Set<BlockId>> {
28 if (terminal.kind === 'break' || terminal.kind === 'continue') {
29 CompilerError.invariant(seenLabels.has(terminal.target), {
30 reason: 'Unexpected break to invalid label',
31 - loc: stmt.terminal.loc,
31 + description: null,
32 + details: [
33 + {
34 + kind: 'error',
35 + loc: stmt.terminal.loc,
36 + message: null,
37 + },
38 + ],
39 });
40 }
41 }
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts
+166 -22
@@ -70,7 +70,13 @@ class Driver {
70 CompilerError.invariant(!this.cx.emitted.has(block.id), {
71 reason: `Cannot emit the same block twice: bb${block.id}`,
72 description: null,
73 - loc: null,
73 + details: [
74 + {
75 + kind: 'error',
76 + loc: null,
77 + message: null,
78 + },
79 + ],
80 suggestions: null,
81 });
82 this.cx.emitted.add(block.id);
@@ -130,7 +136,14 @@ class Driver {
136 if (this.cx.isScheduled(terminal.consequent)) {
137 CompilerError.invariant(false, {
138 reason: `Unexpected 'if' where the consequent is already scheduled`,
133 - loc: terminal.loc,
139 + description: null,
140 + details: [
141 + {
142 + kind: 'error',
143 + loc: terminal.loc,
144 + message: null,
145 + },
146 + ],
147 });
148 } else {
149 consequent = this.traverseBlock(
@@ -143,7 +156,14 @@ class Driver {
156 if (this.cx.isScheduled(alternateId)) {
157 CompilerError.invariant(false, {
158 reason: `Unexpected 'if' where the alternate is already scheduled`,
146 - loc: terminal.loc,
159 + description: null,
160 + details: [
161 + {
162 + kind: 'error',
163 + loc: terminal.loc,
164 + message: null,
165 + },
166 + ],
167 });
168 } else {
169 alternate = this.traverseBlock(this.cx.ir.blocks.get(alternateId)!);
@@ -196,7 +216,14 @@ class Driver {
216 if (this.cx.isScheduled(case_.block)) {
217 CompilerError.invariant(case_.block === terminal.fallthrough, {
218 reason: `Unexpected 'switch' where a case is already scheduled and block is not the fallthrough`,
199 - loc: terminal.loc,
219 + description: null,
220 + details: [
221 + {
222 + kind: 'error',
223 + loc: terminal.loc,
224 + message: null,
225 + },
226 + ],
227 });
228 return;
229 } else {
@@ -255,7 +282,14 @@ class Driver {
282 } else {
283 CompilerError.invariant(false, {
284 reason: `Unexpected 'do-while' where the loop is already scheduled`,
258 - loc: terminal.loc,
285 + description: null,
286 + details: [
287 + {
288 + kind: 'error',
289 + loc: terminal.loc,
290 + message: null,
291 + },
292 + ],
293 });
294 }
295
@@ -316,7 +350,14 @@ class Driver {
350 } else {
351 CompilerError.invariant(false, {
352 reason: `Unexpected 'while' where the loop is already scheduled`,
319 - loc: terminal.loc,
353 + description: null,
354 + details: [
355 + {
356 + kind: 'error',
357 + loc: terminal.loc,
358 + message: null,
359 + },
360 + ],
361 });
362 }
363
@@ -402,7 +443,14 @@ class Driver {
443 } else {
444 CompilerError.invariant(false, {
445 reason: `Unexpected 'for' where the loop is already scheduled`,
405 - loc: terminal.loc,
446 + description: null,
447 + details: [
448 + {
449 + kind: 'error',
450 + loc: terminal.loc,
451 + message: null,
452 + },
453 + ],
454 });
455 }
456
@@ -500,7 +548,14 @@ class Driver {
548 } else {
549 CompilerError.invariant(false, {
550 reason: `Unexpected 'for-of' where the loop is already scheduled`,
503 - loc: terminal.loc,
551 + description: null,
552 + details: [
553 + {
554 + kind: 'error',
555 + loc: terminal.loc,
556 + message: null,
557 + },
558 + ],
559 });
560 }
561
@@ -572,7 +627,14 @@ class Driver {
627 } else {
628 CompilerError.invariant(false, {
629 reason: `Unexpected 'for-in' where the loop is already scheduled`,
575 - loc: terminal.loc,
630 + description: null,
631 + details: [
632 + {
633 + kind: 'error',
634 + loc: terminal.loc,
635 + message: null,
636 + },
637 + ],
638 });
639 }
640
@@ -615,7 +677,14 @@ class Driver {
677 if (this.cx.isScheduled(terminal.alternate)) {
678 CompilerError.invariant(false, {
679 reason: `Unexpected 'branch' where the alternate is already scheduled`,
618 - loc: terminal.loc,
680 + description: null,
681 + details: [
682 + {
683 + kind: 'error',
684 + loc: terminal.loc,
685 + message: null,
686 + },
687 + ],
688 });
689 } else {
690 alternate = this.traverseBlock(
@@ -653,7 +722,14 @@ class Driver {
722 if (this.cx.isScheduled(terminal.block)) {
723 CompilerError.invariant(false, {
724 reason: `Unexpected 'label' where the block is already scheduled`,
656 - loc: terminal.loc,
725 + description: null,
726 + details: [
727 + {
728 + kind: 'error',
729 + loc: terminal.loc,
730 + message: null,
731 + },
732 + ],
733 });
734 } else {
735 block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block)!);
@@ -811,7 +887,14 @@ class Driver {
887 if (this.cx.isScheduled(terminal.block)) {
888 CompilerError.invariant(false, {
889 reason: `Unexpected 'scope' where the block is already scheduled`,
814 - loc: terminal.loc,
890 + description: null,
891 + details: [
892 + {
893 + kind: 'error',
894 + loc: terminal.loc,
895 + message: null,
896 + },
897 + ],
898 });
899 } else {
900 block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block)!);
@@ -837,7 +920,13 @@ class Driver {
920 CompilerError.invariant(false, {
921 reason: 'Unexpected unsupported terminal',
922 description: null,
840 - loc: terminal.loc,
923 + details: [
924 + {
925 + kind: 'error',
926 + loc: terminal.loc,
927 + message: null,
928 + },
929 + ],
930 suggestions: null,
931 });
932 }
@@ -874,7 +963,13 @@ class Driver {
963 reason:
964 'Expected branch block to end in an instruction that sets the test value',
965 description: null,
877 - loc: instr.lvalue.loc,
966 + details: [
967 + {
968 + kind: 'error',
969 + loc: instr.lvalue.loc,
970 + message: null,
971 + },
972 + ],
973 suggestions: null,
974 },
975 );
@@ -906,7 +1001,13 @@ class Driver {
1001 CompilerError.invariant(false, {
1002 reason: 'Expected goto value block to have at least one instruction',
1003 description: null,
909 - loc: null,
1004 + details: [
1005 + {
1006 + kind: 'error',
1007 + loc: null,
1008 + message: null,
1009 + },
1010 + ],
1011 suggestions: null,
1012 });
1013 } else if (defaultBlock.instructions.length === 1) {
@@ -1191,14 +1292,27 @@ class Driver {
1292 CompilerError.invariant(false, {
1293 reason: 'Expected a break target',
1294 description: null,
1194 - loc: null,
1295 + details: [
1296 + {
1297 + kind: 'error',
1298 + loc: null,
1299 + message: null,
1300 + },
1301 + ],
1302 suggestions: null,
1303 });
1304 }
1305 if (this.cx.scopeFallthroughs.has(target.block)) {
1306 CompilerError.invariant(target.type === 'implicit', {
1307 reason: 'Expected reactive scope to implicitly break to fallthrough',
1201 - loc,
1308 + description: null,
1309 + details: [
1310 + {
1311 + kind: 'error',
1312 + loc,
1313 + message: null,
1314 + },
1315 + ],
1316 });
1317 return null;
1318 }
@@ -1224,7 +1338,13 @@ class Driver {
1338 CompilerError.invariant(target !== null, {
1339 reason: `Expected continue target to be scheduled for bb${block}`,
1340 description: null,
1227 - loc: null,
1341 + details: [
1342 + {
1343 + kind: 'error',
1344 + loc: null,
1345 + message: null,
1346 + },
1347 + ],
1348 suggestions: null,
1349 });
1350
@@ -1299,7 +1419,13 @@ class Context {
1419 CompilerError.invariant(!this.#scheduled.has(block), {
1420 reason: `Break block is already scheduled: bb${block}`,
1421 description: null,
1302 - loc: null,
1422 + details: [
1423 + {
1424 + kind: 'error',
1425 + loc: null,
1426 + message: null,
1427 + },
1428 + ],
1429 suggestions: null,
1430 });
1431 this.#scheduled.add(block);
@@ -1318,7 +1444,13 @@ class Context {
1444 CompilerError.invariant(!this.#scheduled.has(continueBlock), {
1445 reason: `Continue block is already scheduled: bb${continueBlock}`,
1446 description: null,
1321 - loc: null,
1447 + details: [
1448 + {
1449 + kind: 'error',
1450 + loc: null,
1451 + message: null,
1452 + },
1453 + ],
1454 suggestions: null,
1455 });
1456 this.#scheduled.add(continueBlock);
@@ -1346,7 +1478,13 @@ class Context {
1478 CompilerError.invariant(last !== undefined && last.id === scheduleId, {
1479 reason: 'Can only unschedule the last target',
1480 description: null,
1349 - loc: null,
1481 + details: [
1482 + {
1483 + kind: 'error',
1484 + loc: null,
1485 + message: null,
1486 + },
1487 + ],
1488 suggestions: null,
1489 });
1490 if (last.type !== 'loop' || last.ownsBlock !== null) {
@@ -1421,7 +1559,13 @@ class Context {
1559 CompilerError.invariant(false, {
1560 reason: 'Expected a break target',
1561 description: null,
1424 - loc: null,
1562 + details: [
1563 + {
1564 + kind: 'error',
1565 + loc: null,
1566 + message: null,
1567 + },
1568 + ],
1569 suggestions: null,
1570 });
1571 }
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
+300 -44
@@ -296,7 +296,14 @@ export function codegenFunction(
296 CompilerError.invariant(globalGating != null, {
297 reason:
298 'Bad config not caught! Expected at least one of gating or globalGating',
299 - loc: null,
299 + description: null,
300 + details: [
301 + {
302 + kind: 'error',
303 + loc: null,
304 + message: null,
305 + },
306 + ],
307 suggestions: null,
308 });
309 ifTest = globalGating;
@@ -499,10 +506,16 @@ function codegenBlock(cx: Context, block: ReactiveBlock): t.BlockStatement {
506 continue;
507 }
508 CompilerError.invariant(temp.get(key)! === value, {
502 - loc: null,
509 reason: 'Expected temporary value to be unchanged',
510 description: null,
511 suggestions: null,
512 + details: [
513 + {
514 + kind: 'error',
515 + loc: null,
516 + message: null,
517 + },
518 + ],
519 });
520 }
521 cx.temp = temp;
@@ -670,7 +683,13 @@ function codegenReactiveScope(
683 description: `Declaration \`${printIdentifier(
684 identifier,
685 )}\` is unnamed in scope @${scope.id}`,
673 - loc: null,
686 + details: [
687 + {
688 + kind: 'error',
689 + loc: null,
690 + message: null,
691 + },
692 + ],
693 suggestions: null,
694 });
695
@@ -707,7 +726,13 @@ function codegenReactiveScope(
726 CompilerError.invariant(firstOutputIndex !== null, {
727 reason: `Expected scope to have at least one declaration`,
728 description: `Scope '@${scope.id}' has no declarations`,
710 - loc: null,
729 + details: [
730 + {
731 + kind: 'error',
732 + loc: null,
733 + message: null,
734 + },
735 + ],
736 suggestions: null,
737 });
738 testCondition = t.binaryExpression(
@@ -730,7 +755,13 @@ function codegenReactiveScope(
755 {
756 reason: `Expected to not have both change detection enabled and memoization disabled`,
757 description: `Incompatible config options`,
733 - loc: null,
758 + details: [
759 + {
760 + kind: 'error',
761 + loc: null,
762 + message: null,
763 + },
764 + ],
765 },
766 );
767 testCondition = t.logicalExpression(
@@ -914,8 +945,14 @@ function codegenReactiveScope(
945 earlyReturnValue.value.name.kind === 'named',
946 {
947 reason: `Expected early return value to be promoted to a named variable`,
917 - loc: earlyReturnValue.loc,
948 description: null,
949 + details: [
950 + {
951 + kind: 'error',
952 + loc: earlyReturnValue.loc,
953 + message: null,
954 + },
955 + ],
956 suggestions: null,
957 },
958 );
@@ -975,7 +1012,13 @@ function codegenTerminal(
1012 CompilerError.invariant(terminal.init.kind === 'SequenceExpression', {
1013 reason: `Expected a sequence expression init for for..in`,
1014 description: `Got \`${terminal.init.kind}\` expression instead`,
978 - loc: terminal.init.loc,
1015 + details: [
1016 + {
1017 + kind: 'error',
1018 + loc: terminal.init.loc,
1019 + message: null,
1020 + },
1021 + ],
1022 suggestions: null,
1023 });
1024 if (terminal.init.instructions.length !== 2) {
@@ -1010,7 +1053,13 @@ function codegenTerminal(
1053 CompilerError.invariant(false, {
1054 reason: `Expected a StoreLocal or Destructure to be assigned to the collection`,
1055 description: `Found ${iterableItem.value.kind}`,
1013 - loc: iterableItem.value.loc,
1056 + details: [
1057 + {
1058 + kind: 'error',
1059 + loc: iterableItem.value.loc,
1060 + message: null,
1061 + },
1062 + ],
1063 suggestions: null,
1064 });
1065 }
@@ -1027,7 +1076,13 @@ function codegenTerminal(
1076 reason:
1077 'Destructure should never be Reassign as it would be an Object/ArrayPattern',
1078 description: null,
1030 - loc: iterableItem.loc,
1079 + details: [
1080 + {
1081 + kind: 'error',
1082 + loc: iterableItem.loc,
1083 + message: null,
1084 + },
1085 + ],
1086 suggestions: null,
1087 });
1088 case InstructionKind.Catch:
@@ -1038,7 +1093,13 @@ function codegenTerminal(
1093 CompilerError.invariant(false, {
1094 reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..in collection`,
1095 description: null,
1041 - loc: iterableItem.loc,
1096 + details: [
1097 + {
1098 + kind: 'error',
1099 + loc: iterableItem.loc,
1100 + message: null,
1101 + },
1102 + ],
1103 suggestions: null,
1104 });
1105 default:
@@ -1067,7 +1128,13 @@ function codegenTerminal(
1128 {
1129 reason: `Expected a single-expression sequence expression init for for..of`,
1130 description: `Got \`${terminal.init.kind}\` expression instead`,
1070 - loc: terminal.init.loc,
1131 + details: [
1132 + {
1133 + kind: 'error',
1134 + loc: terminal.init.loc,
1135 + message: null,
1136 + },
1137 + ],
1138 suggestions: null,
1139 },
1140 );
@@ -1076,7 +1143,13 @@ function codegenTerminal(
1143 CompilerError.invariant(terminal.test.kind === 'SequenceExpression', {
1144 reason: `Expected a sequence expression test for for..of`,
1145 description: `Got \`${terminal.init.kind}\` expression instead`,
1079 - loc: terminal.test.loc,
1146 + details: [
1147 + {
1148 + kind: 'error',
1149 + loc: terminal.test.loc,
1150 + message: null,
1151 + },
1152 + ],
1153 suggestions: null,
1154 });
1155 if (terminal.test.instructions.length !== 2) {
@@ -1110,7 +1183,13 @@ function codegenTerminal(
1183 CompilerError.invariant(false, {
1184 reason: `Expected a StoreLocal or Destructure to be assigned to the collection`,
1185 description: `Found ${iterableItem.value.kind}`,
1113 - loc: iterableItem.value.loc,
1186 + details: [
1187 + {
1188 + kind: 'error',
1189 + loc: iterableItem.value.loc,
1190 + message: null,
1191 + },
1192 + ],
1193 suggestions: null,
1194 });
1195 }
@@ -1131,7 +1210,13 @@ function codegenTerminal(
1210 CompilerError.invariant(false, {
1211 reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..of collection`,
1212 description: null,
1134 - loc: iterableItem.loc,
1213 + details: [
1214 + {
1215 + kind: 'error',
1216 + loc: iterableItem.loc,
1217 + message: null,
1218 + },
1219 + ],
1220 suggestions: null,
1221 });
1222 default:
@@ -1272,7 +1357,13 @@ function codegenInstructionNullable(
1357 reason:
1358 'Encountered a destructuring operation where some identifiers are already declared (reassignments) but others are not (declarations)',
1359 description: null,
1275 - loc: instr.loc,
1360 + details: [
1361 + {
1362 + kind: 'error',
1363 + loc: instr.loc,
1364 + message: null,
1365 + },
1366 + ],
1367 suggestions: null,
1368 });
1369 } else if (hasReassign) {
@@ -1285,7 +1376,13 @@ function codegenInstructionNullable(
1376 CompilerError.invariant(instr.lvalue === null, {
1377 reason: `Const declaration cannot be referenced as an expression`,
1378 description: null,
1288 - loc: instr.value.loc,
1379 + details: [
1380 + {
1381 + kind: 'error',
1382 + loc: instr.value.loc,
1383 + message: `this is ${kind}`,
1384 + },
1385 + ],
1386 suggestions: null,
1387 });
1388 return createVariableDeclaration(instr.loc, 'const', [
@@ -1296,20 +1393,38 @@ function codegenInstructionNullable(
1393 CompilerError.invariant(instr.lvalue === null, {
1394 reason: `Function declaration cannot be referenced as an expression`,
1395 description: null,
1299 - loc: instr.value.loc,
1396 + details: [
1397 + {
1398 + kind: 'error',
1399 + loc: instr.value.loc,
1400 + message: `this is ${kind}`,
1401 + },
1402 + ],
1403 suggestions: null,
1404 });
1405 const genLvalue = codegenLValue(cx, lvalue);
1406 CompilerError.invariant(genLvalue.type === 'Identifier', {
1407 reason: 'Expected an identifier as a function declaration lvalue',
1408 description: null,
1306 - loc: instr.value.loc,
1409 + details: [
1410 + {
1411 + kind: 'error',
1412 + loc: instr.value.loc,
1413 + message: null,
1414 + },
1415 + ],
1416 suggestions: null,
1417 });
1418 CompilerError.invariant(value?.type === 'FunctionExpression', {
1419 reason: 'Expected a function as a function declaration value',
1420 description: `Got ${value == null ? String(value) : value.type} at ${printInstruction(instr)}`,
1312 - loc: instr.value.loc,
1421 + details: [
1422 + {
1423 + kind: 'error',
1424 + loc: instr.value.loc,
1425 + message: null,
1426 + },
1427 + ],
1428 suggestions: null,
1429 });
1430 return createFunctionDeclaration(
@@ -1325,7 +1440,13 @@ function codegenInstructionNullable(
1440 CompilerError.invariant(instr.lvalue === null, {
1441 reason: `Const declaration cannot be referenced as an expression`,
1442 description: null,
1328 - loc: instr.value.loc,
1443 + details: [
1444 + {
1445 + kind: 'error',
1446 + loc: instr.value.loc,
1447 + message: 'this is const',
1448 + },
1449 + ],
1450 suggestions: null,
1451 });
1452 return createVariableDeclaration(instr.loc, 'let', [
@@ -1336,7 +1457,13 @@ function codegenInstructionNullable(
1457 CompilerError.invariant(value !== null, {
1458 reason: 'Expected a value for reassignment',
1459 description: null,
1339 - loc: instr.value.loc,
1460 + details: [
1461 + {
1462 + kind: 'error',
1463 + loc: instr.value.loc,
1464 + message: null,
1465 + },
1466 + ],
1467 suggestions: null,
1468 });
1469 const expr = t.assignmentExpression(
@@ -1369,7 +1496,13 @@ function codegenInstructionNullable(
1496 CompilerError.invariant(false, {
1497 reason: `Expected ${kind} to have been pruned in PruneHoistedContexts`,
1498 description: null,
1372 - loc: instr.loc,
1499 + details: [
1500 + {
1501 + kind: 'error',
1502 + loc: instr.loc,
1503 + message: null,
1504 + },
1505 + ],
1506 suggestions: null,
1507 });
1508 }
@@ -1387,7 +1520,14 @@ function codegenInstructionNullable(
1520 } else if (instr.value.kind === 'ObjectMethod') {
1521 CompilerError.invariant(instr.lvalue, {
1522 reason: 'Expected object methods to have a temp lvalue',
1390 - loc: null,
1523 + description: null,
1524 + details: [
1525 + {
1526 + kind: 'error',
1527 + loc: null,
1528 + message: null,
1529 + },
1530 + ],
1531 suggestions: null,
1532 });
1533 cx.objectMethods.set(instr.lvalue.identifier.id, instr.value);
@@ -1434,7 +1574,13 @@ function codegenForInit(
1574 (instr.kind === 'let' || instr.kind === 'const'),
1575 {
1576 reason: 'Expected a variable declaration',
1437 - loc: init.loc,
1577 + details: [
1578 + {
1579 + kind: 'error',
1580 + loc: init.loc,
1581 + message: null,
1582 + },
1583 + ],
1584 description: `Got ${instr.type}`,
1585 suggestions: null,
1586 },
@@ -1447,7 +1593,13 @@ function codegenForInit(
1593 });
1594 CompilerError.invariant(declarators.length > 0, {
1595 reason: 'Expected a variable declaration',
1450 - loc: init.loc,
1596 + details: [
1597 + {
1598 + kind: 'error',
1599 + loc: init.loc,
1600 + message: null,
1601 + },
1602 + ],
1603 description: null,
1604 suggestions: null,
1605 });
@@ -1768,7 +1920,13 @@ function codegenInstructionValue(
1920 CompilerError.invariant(t.isExpression(optionalValue.callee), {
1921 reason: 'v8 intrinsics are validated during lowering',
1922 description: null,
1771 - loc: optionalValue.callee.loc ?? null,
1923 + details: [
1924 + {
1925 + kind: 'error',
1926 + loc: optionalValue.callee.loc ?? null,
1927 + message: null,
1928 + },
1929 + ],
1930 suggestions: null,
1931 });
1932 value = t.optionalCallExpression(
@@ -1784,7 +1942,13 @@ function codegenInstructionValue(
1942 CompilerError.invariant(t.isExpression(property), {
1943 reason: 'Private names are validated during lowering',
1944 description: null,
1787 - loc: property.loc ?? null,
1945 + details: [
1946 + {
1947 + kind: 'error',
1948 + loc: property.loc ?? null,
1949 + message: null,
1950 + },
1951 + ],
1952 suggestions: null,
1953 });
1954 value = t.optionalMemberExpression(
@@ -1800,7 +1964,13 @@ function codegenInstructionValue(
1964 reason:
1965 'Expected an optional value to resolve to a call expression or member expression',
1966 description: `Got a \`${optionalValue.type}\``,
1803 - loc: instrValue.loc,
1967 + details: [
1968 + {
1969 + kind: 'error',
1970 + loc: instrValue.loc,
1971 + message: null,
1972 + },
1973 + ],
1974 suggestions: null,
1975 });
1976 }
@@ -1816,10 +1986,15 @@ function codegenInstructionValue(
1986 t.isOptionalMemberExpression(memberExpr),
1987 {
1988 reason:
1819 - '[Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. ' +
1820 - `Got a \`${memberExpr.type}\``,
1989 + '[Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression',
1990 description: null,
1822 - loc: memberExpr.loc ?? null,
1991 + details: [
1992 + {
1993 + kind: 'error',
1994 + loc: memberExpr.loc ?? null,
1995 + message: `Got: '${memberExpr.type}'`,
1996 + },
1997 + ],
1998 suggestions: null,
1999 },
2000 );
@@ -1833,7 +2008,13 @@ function codegenInstructionValue(
2008 '[Codegen] Internal error: Forget should always generate MethodCall::property ' +
2009 'as a MemberExpression of MethodCall::receiver',
2010 description: null,
1836 - loc: memberExpr.loc ?? null,
2011 + details: [
2012 + {
2013 + kind: 'error',
2014 + loc: memberExpr.loc ?? null,
2015 + message: null,
2016 + },
2017 + ],
2018 suggestions: null,
2019 },
2020 );
@@ -1878,7 +2059,14 @@ function codegenInstructionValue(
2059 const method = cx.objectMethods.get(property.place.identifier.id);
2060 CompilerError.invariant(method, {
2061 reason: 'Expected ObjectMethod instruction',
1881 - loc: null,
2062 + description: null,
2063 + details: [
2064 + {
2065 + kind: 'error',
2066 + loc: null,
2067 + message: null,
2068 + },
2069 + ],
2070 suggestions: null,
2071 });
2072 const loweredFunc = method.loweredFunc;
@@ -1949,7 +2137,13 @@ function codegenInstructionValue(
2137 CompilerError.invariant(tagValue.type === 'StringLiteral', {
2138 reason: `Expected JSX tag to be an identifier or string, got \`${tagValue.type}\``,
2139 description: null,
1952 - loc: tagValue.loc ?? null,
2140 + details: [
2141 + {
2142 + kind: 'error',
2143 + loc: tagValue.loc ?? null,
2144 + message: null,
2145 + },
2146 + ],
2147 suggestions: null,
2148 });
2149 if (tagValue.value.indexOf(':') >= 0) {
@@ -1969,7 +2163,13 @@ function codegenInstructionValue(
2163 SINGLE_CHILD_FBT_TAGS.has(tagValue.value)
2164 ) {
2165 CompilerError.invariant(instrValue.children != null, {
1972 - loc: instrValue.loc,
2166 + details: [
2167 + {
2168 + kind: 'error',
2169 + loc: instrValue.loc,
2170 + message: null,
2171 + },
2172 + ],
2173 reason: 'Expected fbt element to have children',
2174 suggestions: null,
2175 description: null,
@@ -2271,7 +2471,13 @@ function codegenInstructionValue(
2471 {
2472 reason: `Unexpected StoreLocal in codegenInstructionValue`,
2473 description: null,
2274 - loc: instrValue.loc,
2474 + details: [
2475 + {
2476 + kind: 'error',
2477 + loc: instrValue.loc,
2478 + message: null,
2479 + },
2480 + ],
2481 suggestions: null,
2482 },
2483 );
@@ -2301,7 +2507,13 @@ function codegenInstructionValue(
2507 CompilerError.invariant(false, {
2508 reason: `Unexpected ${instrValue.kind} in codegenInstructionValue`,
2509 description: null,
2304 - loc: instrValue.loc,
2510 + details: [
2511 + {
2512 + kind: 'error',
2513 + loc: instrValue.loc,
2514 + message: null,
2515 + },
2516 + ],
2517 suggestions: null,
2518 });
2519 }
@@ -2447,7 +2659,13 @@ function convertMemberExpressionToJsx(
2659 CompilerError.invariant(expr.property.type === 'Identifier', {
2660 reason: 'Expected JSX member expression property to be a string',
2661 description: null,
2450 - loc: expr.loc ?? null,
2662 + details: [
2663 + {
2664 + kind: 'error',
2665 + loc: expr.loc ?? null,
2666 + message: null,
2667 + },
2668 + ],
2669 suggestions: null,
2670 });
2671 const property = t.jsxIdentifier(expr.property.name);
@@ -2458,7 +2676,13 @@ function convertMemberExpressionToJsx(
2676 reason:
2677 'Expected JSX member expression to be an identifier or nested member expression',
2678 description: null,
2461 - loc: expr.object.loc ?? null,
2679 + details: [
2680 + {
2681 + kind: 'error',
2682 + loc: expr.object.loc ?? null,
2683 + message: null,
2684 + },
2685 + ],
2686 suggestions: null,
2687 });
2688 const object = convertMemberExpressionToJsx(expr.object);
@@ -2482,7 +2706,13 @@ function codegenObjectPropertyKey(
2706 CompilerError.invariant(t.isExpression(expr), {
2707 reason: 'Expected object property key to be an expression',
2708 description: null,
2485 - loc: key.name.loc,
2709 + details: [
2710 + {
2711 + kind: 'error',
2712 + loc: key.name.loc,
2713 + message: null,
2714 + },
2715 + ],
2716 suggestions: null,
2717 });
2718 return expr;
@@ -2629,7 +2859,13 @@ function codegenPlace(cx: Context, place: Place): t.Expression | t.JSXText {
2859 description: `Value for '${printPlace(
2860 place,
2861 )}' was not set in the codegen context`,
2632 - loc: place.loc,
2862 + details: [
2863 + {
2864 + kind: 'error',
2865 + loc: place.loc,
2866 + message: null,
2867 + },
2868 + ],
2869 suggestions: null,
2870 });
2871 const identifier = convertIdentifier(place.identifier);
@@ -2642,7 +2878,13 @@ function convertIdentifier(identifier: Identifier): t.Identifier {
2878 identifier.name !== null && identifier.name.kind === 'named',
2879 {
2880 reason: `Expected temporaries to be promoted to named identifiers in an earlier pass`,
2645 - loc: GeneratedSource,
2881 + details: [
2882 + {
2883 + kind: 'error',
2884 + loc: GeneratedSource,
2885 + message: null,
2886 + },
2887 + ],
2888 description: `identifier ${identifier.id} is unnamed`,
2889 suggestions: null,
2890 },
@@ -2658,7 +2900,14 @@ function compareScopeDependency(
2900 a.identifier.name?.kind === 'named' && b.identifier.name?.kind === 'named',
2901 {
2902 reason: '[Codegen] Expected named identifier for dependency',
2661 - loc: a.identifier.loc,
2903 + description: null,
2904 + details: [
2905 + {
2906 + kind: 'error',
2907 + loc: a.identifier.loc,
2908 + message: null,
2909 + },
2910 + ],
2911 },
2912 );
2913 const aName = [
@@ -2682,7 +2931,14 @@ function compareScopeDeclaration(
2931 a.identifier.name?.kind === 'named' && b.identifier.name?.kind === 'named',
2932 {
2933 reason: '[Codegen] Expected named identifier for declaration',
2685 - loc: a.identifier.loc,
2934 + description: null,
2935 + details: [
2936 + {
2937 + kind: 'error',
2938 + loc: a.identifier.loc,
2939 + message: null,
2940 + },
2941 + ],
2942 },
2943 );
2944 const aName = a.identifier.name.value;
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenScopesWithHooksOrUseHIR.ts
+7 -1
@@ -75,7 +75,13 @@ export function flattenScopesWithHooksOrUseHIR(fn: HIRFunction): void {
75 CompilerError.invariant(terminal.kind === 'scope', {
76 reason: `Expected block to have a scope terminal`,
77 description: `Expected block bb${block.id} to end in a scope terminal`,
78 - loc: terminal.loc,
78 + details: [
79 + {
80 + kind: 'error',
81 + loc: terminal.loc,
82 + message: null,
83 + },
84 + ],
85 });
86 const body = fn.body.blocks.get(terminal.block)!;
87 if (
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts
+7 -1
@@ -162,7 +162,13 @@ export function inferReactiveScopeVariables(fn: HIRFunction): void {
162 });
163 CompilerError.invariant(false, {
164 reason: `Invalid mutable range for scope`,
165 - loc: GeneratedSource,
165 + details: [
166 + {
167 + kind: 'error',
168 + loc: GeneratedSource,
169 + message: null,
170 + },
171 + ],
172 description: `Scope @${scope.id} has range [${scope.range.start}:${
173 scope.range.end
174 }] but the valid range is [1:${maxInstruction + 1}]`,
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts
+15 -3
@@ -159,11 +159,17 @@ class Transform extends ReactiveFunctionTransform<ReactiveScopeDependencies | nu
159 const merged: Array<MergedScope> = [];
160 function reset(): void {
161 CompilerError.invariant(current !== null, {
162 - loc: null,
162 reason:
163 'MergeConsecutiveScopes: expected current scope to be non-null if reset()',
165 - suggestions: null,
164 description: null,
165 + details: [
166 + {
167 + kind: 'error',
168 + loc: null,
169 + message: null,
170 + },
171 + ],
172 + suggestions: null,
173 });
174 if (current.to > current.from + 1) {
175 merged.push(current);
@@ -375,10 +381,16 @@ class Transform extends ReactiveFunctionTransform<ReactiveScopeDependencies | nu
381 }
382 const mergedScope = block[entry.from]!;
383 CompilerError.invariant(mergedScope.kind === 'scope', {
378 - loc: null,
384 reason:
385 'MergeConsecutiveScopes: Expected scope starting index to be a scope',
386 description: null,
387 + details: [
388 + {
389 + kind: 'error',
390 + loc: null,
391 + message: null,
392 + },
393 + ],
394 suggestions: null,
395 });
396 nextInstructions.push(mergedScope);
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts
+7 -1
@@ -323,7 +323,13 @@ function writeTerminal(writer: Writer, terminal: ReactiveTerminal): void {
323 CompilerError.invariant(block != null, {
324 reason: 'Expected case to have a block',
325 description: null,
326 - loc: case_.test?.loc ?? null,
326 + details: [
327 + {
328 + kind: 'error',
329 + loc: case_.test?.loc ?? null,
330 + message: null,
331 + },
332 + ],
333 suggestions: null,
334 });
335 writeReactiveInstructions(writer, block);
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PromoteUsedTemporaries.ts
+15 -2
@@ -290,7 +290,14 @@ class PromoteInterposedTemporaries extends ReactiveFunctionVisitor<InterState> {
290 CompilerError.invariant(lval.identifier.name != null, {
291 reason:
292 'PromoteInterposedTemporaries: Assignment targets not expected to be temporaries',
293 - loc: instruction.loc,
293 + description: null,
294 + details: [
295 + {
296 + kind: 'error',
297 + loc: instruction.loc,
298 + message: null,
299 + },
300 + ],
301 });
302 }
303
@@ -454,7 +461,13 @@ function promoteIdentifier(identifier: Identifier, state: State): void {
461 reason:
462 'promoteTemporary: Expected to be called only for temporary variables',
463 description: null,
457 - loc: GeneratedSource,
464 + details: [
465 + {
466 + kind: 'error',
467 + loc: GeneratedSource,
468 + message: null,
469 + },
470 + ],
471 suggestions: null,
472 });
473 if (state.tags.has(identifier.declarationId)) {
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts
+8 -1
@@ -145,7 +145,14 @@ class Visitor extends ReactiveFunctionTransform<VisitorState> {
145 if (maybeHoistedFn != null) {
146 CompilerError.invariant(maybeHoistedFn.kind === 'func', {
147 reason: '[PruneHoistedContexts] Unexpected hoisted function',
148 - loc: instruction.loc,
148 + description: null,
149 + details: [
150 + {
151 + kind: 'error',
152 + loc: instruction.loc,
153 + message: null,
154 + },
155 + ],
156 });
157 maybeHoistedFn.definition = instruction.value.lvalue.place;
158 /**
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts
+8 -1
@@ -196,7 +196,14 @@ class Visitor extends ReactiveFunctionVisitor<CreateUpdate> {
196 ): void {
197 CompilerError.invariant(state !== 'Create', {
198 reason: "Visiting a terminal statement with state 'Create'",
199 - loc: stmt.terminal.loc,
199 + description: null,
200 + details: [
201 + {
202 + kind: 'error',
203 + loc: stmt.terminal.loc,
204 + message: null,
205 + },
206 + ],
207 });
208 super.visitTerminal(stmt, state);
209 }
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts
+35 -5
@@ -264,7 +264,13 @@ class State {
264 CompilerError.invariant(identifierNode !== undefined, {
265 reason: 'Expected identifier to be initialized',
266 description: `[${id}] operand=${printPlace(place)} for identifier declaration ${identifier}`,
267 - loc: place.loc,
267 + details: [
268 + {
269 + kind: 'error',
270 + loc: place.loc,
271 + message: null,
272 + },
273 + ],
274 suggestions: null,
275 });
276 identifierNode.scopes.add(scope.id);
@@ -286,7 +292,13 @@ function computeMemoizedIdentifiers(state: State): Set<DeclarationId> {
292 CompilerError.invariant(node !== undefined, {
293 reason: `Expected a node for all identifiers, none found for \`${id}\``,
294 description: null,
289 - loc: null,
295 + details: [
296 + {
297 + kind: 'error',
298 + loc: null,
299 + message: null,
300 + },
301 + ],
302 suggestions: null,
303 });
304 if (node.seen) {
@@ -328,7 +340,13 @@ function computeMemoizedIdentifiers(state: State): Set<DeclarationId> {
340 CompilerError.invariant(node !== undefined, {
341 reason: 'Expected a node for all scopes',
342 description: null,
331 - loc: null,
343 + details: [
344 + {
345 + kind: 'error',
346 + loc: null,
347 + message: null,
348 + },
349 + ],
350 suggestions: null,
351 });
352 if (node.seen) {
@@ -977,7 +995,13 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
995 CompilerError.invariant(identifierNode !== undefined, {
996 reason: 'Expected identifier to be initialized',
997 description: null,
980 - loc: stmt.terminal.loc,
998 + details: [
999 + {
1000 + kind: 'error',
1001 + loc: stmt.terminal.loc,
1002 + message: null,
1003 + },
1004 + ],
1005 suggestions: null,
1006 });
1007 for (const scope of scopes) {
@@ -1002,7 +1026,13 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
1026 CompilerError.invariant(identifierNode !== undefined, {
1027 reason: 'Expected identifier to be initialized',
1028 description: null,
1005 - loc: reassignment.loc,
1029 + details: [
1030 + {
1031 + kind: 'error',
1032 + loc: reassignment.loc,
1033 + message: null,
1034 + },
1035 + ],
1036 suggestions: null,
1037 });
1038 for (const scope of scopes) {
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/RenameVariables.ts
+7 -1
@@ -186,7 +186,13 @@ class Scopes {
186 CompilerError.invariant(last === next, {
187 reason: 'Mismatch push/pop calls',
188 description: null,
189 - loc: null,
189 + details: [
190 + {
191 + kind: 'error',
192 + loc: null,
193 + message: null,
194 + },
195 + ],
196 suggestions: null,
197 });
198 }
compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts
+23 -3
@@ -97,7 +97,13 @@ export function eliminateRedundantPhi(
97 CompilerError.invariant(same !== null, {
98 reason: 'Expected phis to be non-empty',
99 description: null,
100 - loc: null,
100 + details: [
101 + {
102 + kind: 'error',
103 + loc: null,
104 + message: null,
105 + },
106 + ],
107 suggestions: null,
108 });
109 rewrites.set(phi.place.identifier, same);
@@ -149,12 +155,26 @@ export function eliminateRedundantPhi(
155 for (const phi of block.phis) {
156 CompilerError.invariant(!rewrites.has(phi.place.identifier), {
157 reason: '[EliminateRedundantPhis]: rewrite not complete',
152 - loc: phi.place.loc,
158 + description: null,
159 + details: [
160 + {
161 + kind: 'error',
162 + loc: phi.place.loc,
163 + message: null,
164 + },
165 + ],
166 });
167 for (const [, operand] of phi.operands) {
168 CompilerError.invariant(!rewrites.has(operand.identifier), {
169 reason: '[EliminateRedundantPhis]: rewrite not complete',
157 - loc: phi.place.loc,
170 + description: null,
171 + details: [
172 + {
173 + kind: 'error',
174 + loc: phi.place.loc,
175 + message: null,
176 + },
177 + ],
178 });
179 }
180 }
compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts
+28 -4
@@ -70,7 +70,13 @@ class SSABuilder {
70 CompilerError.invariant(this.#current !== null, {
71 reason: 'we need to be in a block to access state!',
72 description: null,
73 - loc: null,
73 + details: [
74 + {
75 + kind: 'error',
76 + loc: null,
77 + message: null,
78 + },
79 + ],
80 suggestions: null,
81 });
82 return this.#states.get(this.#current)!;
@@ -253,7 +259,13 @@ function enterSSAImpl(
259 CompilerError.invariant(!visitedBlocks.has(block), {
260 reason: `found a cycle! visiting bb${block.id} again`,
261 description: null,
256 - loc: null,
262 + details: [
263 + {
264 + kind: 'error',
265 + loc: null,
266 + message: null,
267 + },
268 + ],
269 suggestions: null,
270 });
271
@@ -266,7 +278,13 @@ function enterSSAImpl(
278 CompilerError.invariant(func.context.length === 0, {
279 reason: `Expected function context to be empty for outer function declarations`,
280 description: null,
269 - loc: func.loc,
281 + details: [
282 + {
283 + kind: 'error',
284 + loc: func.loc,
285 + message: null,
286 + },
287 + ],
288 suggestions: null,
289 });
290 func.params = func.params.map(param => {
@@ -295,7 +313,13 @@ function enterSSAImpl(
313 reason:
314 'Expected function expression entry block to have zero predecessors',
315 description: null,
298 - loc: null,
316 + details: [
317 + {
318 + kind: 'error',
319 + loc: null,
320 + message: null,
321 + },
322 + ],
323 suggestions: null,
324 });
325 entry.preds.add(blockId);
compiler/packages/babel-plugin-react-compiler/src/SSA/RewriteInstructionKindsBasedOnReassignment.ts
+56 -8
@@ -59,7 +59,13 @@ export function rewriteInstructionKindsBasedOnReassignment(
59 {
60 reason: `Expected variable not to be defined prior to declaration`,
61 description: `${printPlace(lvalue.place)} was already defined`,
62 - loc: lvalue.place.loc,
62 + details: [
63 + {
64 + kind: 'error',
65 + loc: lvalue.place.loc,
66 + message: null,
67 + },
68 + ],
69 },
70 );
71 declarations.set(lvalue.place.identifier.declarationId, lvalue);
@@ -77,7 +83,13 @@ export function rewriteInstructionKindsBasedOnReassignment(
83 {
84 reason: `Expected variable not to be defined prior to declaration`,
85 description: `${printPlace(lvalue.place)} was already defined`,
80 - loc: lvalue.place.loc,
86 + details: [
87 + {
88 + kind: 'error',
89 + loc: lvalue.place.loc,
90 + message: null,
91 + },
92 + ],
93 },
94 );
95 declarations.set(lvalue.place.identifier.declarationId, lvalue);
@@ -101,7 +113,13 @@ export function rewriteInstructionKindsBasedOnReassignment(
113 description: `other places were \`${kind}\` but '${printPlace(
114 place,
115 )}' is const`,
104 - loc: place.loc,
116 + details: [
117 + {
118 + kind: 'error',
119 + loc: place.loc,
120 + message: 'Expected consistent kind for destructuring',
121 + },
122 + ],
123 suggestions: null,
124 },
125 );
@@ -114,7 +132,13 @@ export function rewriteInstructionKindsBasedOnReassignment(
132 CompilerError.invariant(block.kind !== 'value', {
133 reason: `TODO: Handle reassignment in a value block where the original declaration was removed by dead code elimination (DCE)`,
134 description: null,
117 - loc: place.loc,
135 + details: [
136 + {
137 + kind: 'error',
138 + loc: place.loc,
139 + message: null,
140 + },
141 + ],
142 suggestions: null,
143 });
144 declarations.set(place.identifier.declarationId, lvalue);
@@ -125,7 +149,13 @@ export function rewriteInstructionKindsBasedOnReassignment(
149 description: `Other places were \`${kind}\` but '${printPlace(
150 place,
151 )}' is const`,
128 - loc: place.loc,
152 + details: [
153 + {
154 + kind: 'error',
155 + loc: place.loc,
156 + message: 'Expected consistent kind for destructuring',
157 + },
158 + ],
159 suggestions: null,
160 },
161 );
@@ -138,7 +168,13 @@ export function rewriteInstructionKindsBasedOnReassignment(
168 description: `Other places were \`${kind}\` but '${printPlace(
169 place,
170 )}' is reassigned`,
141 - loc: place.loc,
171 + details: [
172 + {
173 + kind: 'error',
174 + loc: place.loc,
175 + message: 'Expected consistent kind for destructuring',
176 + },
177 + ],
178 suggestions: null,
179 },
180 );
@@ -150,7 +186,13 @@ export function rewriteInstructionKindsBasedOnReassignment(
186 CompilerError.invariant(kind !== null, {
187 reason: 'Expected at least one operand',
188 description: null,
153 - loc: null,
189 + details: [
190 + {
191 + kind: 'error',
192 + loc: null,
193 + message: null,
194 + },
195 + ],
196 suggestions: null,
197 });
198 lvalue.kind = kind;
@@ -163,7 +205,13 @@ export function rewriteInstructionKindsBasedOnReassignment(
205 CompilerError.invariant(declaration !== undefined, {
206 reason: `Expected variable to have been defined`,
207 description: `No declaration for ${printPlace(lvalue)}`,
166 - loc: lvalue.loc,
208 + details: [
209 + {
210 + kind: 'error',
211 + loc: lvalue.loc,
212 + message: null,
213 + },
214 + ],
215 });
216 declaration.kind = InstructionKind.Let;
217 break;
compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts
+7 -1
@@ -616,7 +616,13 @@ class Unifier {
616 CompilerError.invariant(type.operands.length > 0, {
617 reason: 'there should be at least one operand',
618 description: null,
619 - loc: null,
619 + details: [
620 + {
621 + kind: 'error',
622 + loc: null,
623 + message: null,
624 + },
625 + ],
626 suggestions: null,
627 });
628
compiler/packages/babel-plugin-react-compiler/src/Utils/DisjointSet.ts
+7 -1
@@ -21,7 +21,13 @@ export default class DisjointSet<T> {
21 CompilerError.invariant(first != null, {
22 reason: 'Expected set to be non-empty',
23 description: null,
24 - loc: null,
24 + details: [
25 + {
26 + kind: 'error',
27 + loc: null,
28 + message: null,
29 + },
30 + ],
31 suggestions: null,
32 });
33 /*
compiler/packages/babel-plugin-react-compiler/src/Utils/TestUtils.ts
+21 -3
@@ -164,7 +164,13 @@ function parseConfigPragmaEnvironmentForTest(
164 CompilerError.invariant(false, {
165 reason: 'Internal error, could not parse config from pragma string',
166 description: `${fromZodError(config.error)}`,
167 - loc: null,
167 + details: [
168 + {
169 + kind: 'error',
170 + loc: null,
171 + message: null,
172 + },
173 + ],
174 suggestions: null,
175 });
176 }
@@ -248,7 +254,13 @@ function parseConfigStringAsJS(
254 CompilerError.invariant(false, {
255 reason: 'Failed to parse config pragma as JavaScript object',
256 description: `Could not parse: ${configString}. Error: ${error}`,
251 - loc: null,
257 + details: [
258 + {
259 + kind: 'error',
260 + loc: null,
261 + message: null,
262 + },
263 + ],
264 suggestions: null,
265 });
266 }
@@ -279,7 +291,13 @@ function parseConfigStringAsJS(
291 CompilerError.invariant(false, {
292 reason: 'Invalid environment configuration in config pragma',
293 description: `${fromZodError(validatedEnvironment.error)}`,
282 - loc: null,
294 + details: [
295 + {
296 + kind: 'error',
297 + loc: null,
298 + message: null,
299 + },
300 + ],
301 suggestions: null,
302 });
303 }
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateContextVariableLValues.ts
+10 -3
@@ -106,12 +106,19 @@ function visit(
106 }
107
108 CompilerError.invariant(false, {
109 - reason: `Expected all references to a variable to be consistently local or context references`,
110 - loc: place.loc,
109 + reason:
110 + 'Expected all references to a variable to be consistently local or context references',
111 description: `Identifier ${printPlace(
112 place,
113 - )} is referenced as a ${kind} variable, but was previously referenced as a ${prev} variable`,
113 + )} is referenced as a ${kind} variable, but was previously referenced as a ${prev.kind} variable`,
114 suggestions: null,
115 + details: [
116 + {
117 + kind: 'error',
118 + loc: place.loc,
119 + message: `this is ${prev.kind}`,
120 + },
121 + ],
122 });
123 }
124 }
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts
+10 -3
@@ -40,7 +40,7 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void {
40 category: ErrorCategory.Immutability,
41 reason: 'Cannot reassign variable after render completes',
42 description: `Reassigning ${variable} after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead.`,
43 - }).withDetail({
43 + }).withDetails({
44 kind: 'error',
45 loc: reassignment.loc,
46 message: `Cannot reassign ${variable} after render completes`,
@@ -96,7 +96,7 @@ function getContextReassignment(
96 reason: 'Cannot reassign variable in async function',
97 description:
98 'Reassigning a variable in an async function can cause inconsistent behavior on subsequent renders. Consider using state instead',
99 - }).withDetail({
99 + }).withDetails({
100 kind: 'error',
101 loc: reassignment.loc,
102 message: `Cannot reassign ${variable}`,
@@ -191,7 +191,14 @@ function getContextReassignment(
191 for (const operand of operands) {
192 CompilerError.invariant(operand.effect !== Effect.Unknown, {
193 reason: `Expected effects to be inferred prior to ValidateLocalsNotReassignedAfterRender`,
194 - loc: operand.loc,
194 + description: null,
195 + details: [
196 + {
197 + kind: 'error',
198 + loc: operand.loc,
199 + message: '',
200 + },
201 + ],
202 });
203 const reassignment = reassigningFunctions.get(
204 operand.identifier.id,
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts
+8 -1
@@ -83,7 +83,14 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
83 const dependencies: Array<IdentifierId> = deps.elements.map(dep => {
84 CompilerError.invariant(dep.kind === 'Identifier', {
85 reason: `Dependency is checked as a place above`,
86 - loc: value.loc,
86 + description: null,
87 + details: [
88 + {
89 + kind: 'error',
90 + loc: value.loc,
91 + message: 'this is checked as a place above',
92 + },
93 + ],
94 });
95 return locals.get(dep.identifier.id) ?? dep.identifier.id;
96 });
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts
+2 -2
@@ -69,12 +69,12 @@ export function validateNoFreezingKnownMutableFunctions(
69 reason: 'Cannot modify local variables after render completes',
70 description: `This argument is a function which may reassign or mutate ${variable} after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead.`,
71 })
72 - .withDetail({
72 + .withDetails({
73 kind: 'error',
74 loc: operand.loc,
75 message: `This function may (indirectly) reassign or modify ${variable} after render`,
76 })
77 - .withDetail({
77 + .withDetails({
78 kind: 'error',
79 loc: effect.value.loc,
80 message: `This modifies ${variable}`,
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts
+1 -1
@@ -45,7 +45,7 @@ export function validateNoImpureFunctionsInRender(
45 : '') +
46 'Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)',
47 suggestions: null,
48 - }).withDetail({
48 + }).withDetails({
49 kind: 'error',
50 loc: callee.loc,
51 message: 'Cannot call impure function',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts
+1 -1
@@ -40,7 +40,7 @@ export function validateNoJSXInTryStatement(
40 category: ErrorCategory.ErrorBoundaries,
41 reason: 'Avoid constructing JSX within try/catch',
42 description: `React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)`,
43 - }).withDetail({
43 + }).withDetails({
44 kind: 'error',
45 loc: value.loc,
46 message: 'Avoid constructing JSX within try/catch',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts
+53 -12
@@ -57,8 +57,14 @@ function makeRefId(id: number): RefId {
57 CompilerError.invariant(id >= 0 && Number.isInteger(id), {
58 reason: 'Expected identifier id to be a non-negative integer',
59 description: null,
60 - loc: null,
60 suggestions: null,
61 + details: [
62 + {
63 + kind: 'error',
64 + loc: null,
65 + message: null,
66 + },
67 + ],
68 });
69 return id as RefId;
70 }
@@ -191,19 +197,40 @@ function tyEqual(a: RefAccessType, b: RefAccessType): boolean {
197 case 'Guard':
198 CompilerError.invariant(b.kind === 'Guard', {
199 reason: 'Expected ref value',
194 - loc: null,
200 + description: null,
201 + details: [
202 + {
203 + kind: 'error',
204 + loc: null,
205 + message: null,
206 + },
207 + ],
208 });
209 return a.refId === b.refId;
210 case 'RefValue':
211 CompilerError.invariant(b.kind === 'RefValue', {
212 reason: 'Expected ref value',
200 - loc: null,
213 + description: null,
214 + details: [
215 + {
216 + kind: 'error',
217 + loc: null,
218 + message: null,
219 + },
220 + ],
221 });
222 return a.loc == b.loc;
223 case 'Structure': {
224 CompilerError.invariant(b.kind === 'Structure', {
225 reason: 'Expected structure',
206 - loc: null,
226 + description: null,
227 + details: [
228 + {
229 + kind: 'error',
230 + loc: null,
231 + message: null,
232 + },
233 + ],
234 });
235 const fnTypesEqual =
236 (a.fn === null && b.fn === null) ||
@@ -242,7 +269,14 @@ function joinRefAccessTypes(...types: Array<RefAccessType>): RefAccessType {
269 a.kind === 'Structure' && b.kind === 'Structure',
270 {
271 reason: 'Expected structure',
245 - loc: null,
272 + description: null,
273 + details: [
274 + {
275 + kind: 'error',
276 + loc: null,
277 + message: null,
278 + },
279 + ],
280 },
281 );
282 const fn =
@@ -471,7 +505,7 @@ function validateNoRefAccessInRenderImpl(
505 category: ErrorCategory.Refs,
506 reason: 'Cannot access refs during render',
507 description: ERROR_DESCRIPTION,
474 - }).withDetail({
508 + }).withDetails({
509 kind: 'error',
510 loc: callee.loc,
511 message: `This function accesses a ref value`,
@@ -708,7 +742,14 @@ function validateNoRefAccessInRenderImpl(
742
743 CompilerError.invariant(!env.hasChanged(), {
744 reason: 'Ref type environment did not converge',
711 - loc: null,
745 + description: null,
746 + details: [
747 + {
748 + kind: 'error',
749 + loc: null,
750 + message: null,
751 + },
752 + ],
753 });
754
755 return Ok(
@@ -734,7 +775,7 @@ function guardCheck(errors: CompilerError, operand: Place, env: Env): void {
775 category: ErrorCategory.Refs,
776 reason: 'Cannot access refs during render',
777 description: ERROR_DESCRIPTION,
737 - }).withDetail({
778 + }).withDetails({
779 kind: 'error',
780 loc: operand.loc,
781 message: `Cannot access ref value during render`,
@@ -758,7 +799,7 @@ function validateNoRefValueAccess(
799 category: ErrorCategory.Refs,
800 reason: 'Cannot access refs during render',
801 description: ERROR_DESCRIPTION,
761 - }).withDetail({
802 + }).withDetails({
803 kind: 'error',
804 loc: (type.kind === 'RefValue' && type.loc) || operand.loc,
805 message: `Cannot access ref value during render`,
@@ -784,7 +825,7 @@ function validateNoRefPassedToFunction(
825 category: ErrorCategory.Refs,
826 reason: 'Cannot access refs during render',
827 description: ERROR_DESCRIPTION,
787 - }).withDetail({
828 + }).withDetails({
829 kind: 'error',
830 loc: (type.kind === 'RefValue' && type.loc) || loc,
831 message: `Passing a ref to a function may read its value during render`,
@@ -806,7 +847,7 @@ function validateNoRefUpdate(
847 category: ErrorCategory.Refs,
848 reason: 'Cannot access refs during render',
849 description: ERROR_DESCRIPTION,
809 - }).withDetail({
850 + }).withDetails({
851 kind: 'error',
852 loc: (type.kind === 'RefValue' && type.loc) || loc,
853 message: `Cannot update ref during render`,
@@ -827,7 +868,7 @@ function validateNoDirectRefValueAccess(
868 category: ErrorCategory.Refs,
869 reason: 'Cannot access refs during render',
870 description: ERROR_DESCRIPTION,
830 - }).withDetail({
871 + }).withDetails({
872 kind: 'error',
873 loc: type.loc ?? operand.loc,
874 message: `Cannot access ref value during render`,
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts
+1 -1
@@ -107,7 +107,7 @@ export function validateNoSetStateInEffects(
107 'Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. ' +
108 '(https://react.dev/learn/you-might-not-need-an-effect)',
109 suggestions: null,
110 - }).withDetail({
110 + }).withDetails({
111 kind: 'error',
112 loc: setState.loc,
113 message:
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts
+18 -4
@@ -102,7 +102,14 @@ function validateNoSetStateInRenderImpl(
102 case 'StartMemoize': {
103 CompilerError.invariant(activeManualMemoId === null, {
104 reason: 'Unexpected nested StartMemoize instructions',
105 - loc: instr.value.loc,
105 + description: null,
106 + details: [
107 + {
108 + kind: 'error',
109 + loc: instr.value.loc,
110 + message: null,
111 + },
112 + ],
113 });
114 activeManualMemoId = instr.value.manualMemoId;
115 break;
@@ -113,7 +120,14 @@ function validateNoSetStateInRenderImpl(
120 {
121 reason:
122 'Expected FinishMemoize to align with previous StartMemoize instruction',
116 - loc: instr.value.loc,
123 + description: null,
124 + details: [
125 + {
126 + kind: 'error',
127 + loc: instr.value.loc,
128 + message: null,
129 + },
130 + ],
131 },
132 );
133 activeManualMemoId = null;
@@ -134,7 +148,7 @@ function validateNoSetStateInRenderImpl(
148 description:
149 'Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)',
150 suggestions: null,
137 - }).withDetail({
151 + }).withDetails({
152 kind: 'error',
153 loc: callee.loc,
154 message: 'Found setState() within useMemo()',
@@ -149,7 +163,7 @@ function validateNoSetStateInRenderImpl(
163 description:
164 'Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)',
165 suggestions: null,
152 - }).withDetail({
166 + }).withDetails({
167 kind: 'error',
168 loc: callee.loc,
169 message: 'Found setState() in render',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts
+25 -6
@@ -245,7 +245,14 @@ function validateInferredDep(
245 CompilerError.invariant(dep.identifier.name?.kind === 'named', {
246 reason:
247 'ValidatePreservedManualMemoization: expected scope dependency to be named',
248 - loc: GeneratedSource,
248 + description: null,
249 + details: [
250 + {
251 + kind: 'error',
252 + loc: GeneratedSource,
253 + message: null,
254 + },
255 + ],
256 suggestions: null,
257 });
258 normalizedDep = {
@@ -303,7 +310,7 @@ function validateInferredDep(
310 .join('')
311 .trim(),
312 suggestions: null,
306 - }).withDetail({
313 + }).withDetails({
314 kind: 'error',
315 loc: memoLocation,
316 message: 'Could not preserve existing manual memoization',
@@ -495,7 +502,13 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
502 CompilerError.invariant(state.manualMemoState == null, {
503 reason: 'Unexpected nested StartMemoize instructions',
504 description: `Bad manual memoization ids: ${state.manualMemoState?.manualMemoId}, ${value.manualMemoId}`,
498 - loc: value.loc,
505 + details: [
506 + {
507 + kind: 'error',
508 + loc: value.loc,
509 + message: null,
510 + },
511 + ],
512 suggestions: null,
513 });
514
@@ -540,7 +553,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
553 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. ',
554 'This dependency may be mutated later, which could cause the value to change unexpectedly.',
555 ].join(''),
543 - }).withDetail({
556 + }).withDetails({
557 kind: 'error',
558 loc,
559 message: 'This dependency may be modified later',
@@ -556,7 +569,13 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
569 {
570 reason: 'Unexpected mismatch between StartMemoize and FinishMemoize',
571 description: `Encountered StartMemoize id=${state.manualMemoState?.manualMemoId} followed by FinishMemoize id=${value.manualMemoId}`,
559 - loc: value.loc,
572 + details: [
573 + {
574 + kind: 'error',
575 + loc: value.loc,
576 + message: null,
577 + },
578 + ],
579 suggestions: null,
580 },
581 );
@@ -591,7 +610,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
610 ]
611 .join('')
612 .trim(),
594 - }).withDetail({
613 + }).withDetails({
614 kind: 'error',
615 loc,
616 message: 'Could not preserve existing memoization',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts
+2 -2
@@ -69,12 +69,12 @@ export function validateStaticComponents(
69 reason: 'Cannot create components during render',
70 description: `Components created during render will reset their state each time they are created. Declare components outside of render. `,
71 })
72 - .withDetail({
72 + .withDetails({
73 kind: 'error',
74 loc: value.tag.loc,
75 message: 'This component is created during render',
76 })
77 - .withDetail({
77 + .withDetails({
78 kind: 'error',
79 loc: location,
80 message: 'The component is created during render here',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts
+2 -2
@@ -79,7 +79,7 @@ export function validateUseMemo(fn: HIRFunction): Result<void, CompilerError> {
79 description:
80 'useMemo() callbacks are called by React to cache calculations across re-renders. They should not take parameters. Instead, directly reference the props, state, or local variables needed for the computation.',
81 suggestions: null,
82 - }).withDetail({
82 + }).withDetails({
83 kind: 'error',
84 loc,
85 message: 'Callbacks with parameters are not supported',
@@ -96,7 +96,7 @@ export function validateUseMemo(fn: HIRFunction): Result<void, CompilerError> {
96 description:
97 'useMemo() callbacks are called once and must synchronously return a value.',
98 suggestions: null,
99 - }).withDetail({
99 + }).withDetails({
100 kind: 'error',
101 loc: body.loc,
102 message: 'Async and generator functions are not supported',
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.expect.md
+2 -2
@@ -31,13 +31,13 @@ Found 1 error:
31
32 Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized
33
34 -<unknown> thunk$14.
34 +<unknown> thunk$14
35
36 error.bug-infer-mutation-aliasing-effects.ts:10:22
37 8 | function thunk(action) {
38 9 | if (typeof action === 'function') {
39 > 10 | return action(thunk, () => stateRef.current, extraArg);
40 - | ^^^^^ [InferMutationAliasingEffects] Expected value kind to be initialized
40 + | ^^^^^ this is uninitialized
41 11 | } else {
42 12 | dispatch(action);
43 13 | return undefined;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.expect.md
+4 -2
@@ -16,13 +16,15 @@ const YearsAndMonthsSince = () => {
16 ```
17 Found 1 error:
18
19 -Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier`
19 +Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression
20 +
21 +
22
23 error.bug-invariant-codegen-methodcall.ts:3:17
24 1 | const YearsAndMonthsSince = () => {
25 2 | const diff = foo();
26 > 3 | const months = Math.floor(diff.bar());
25 - | ^^^^^^^^^^ [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier`
27 + | ^^^^^^^^^^ Got: 'Identifier'
28 4 | return <>{months}</>;
29 5 | };
30 6 |
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-consistent-destructuring.expect.md
+1 -1
@@ -29,7 +29,7 @@ Found 1 error:
29
30 Invariant: Expected consistent kind for destructuring
31
32 -Other places were `Reassign` but 'mutate? #t8$46[7:9]{reactive}' is const.
32 +Other places were `Reassign` but 'mutate? #t8$46[7:9]{reactive}' is const
33
34 error.bug-invariant-expected-consistent-destructuring.ts:9:9
35 7 |
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.expect.md
+2 -2
@@ -31,13 +31,13 @@ Found 1 error:
31
32 Invariant: Expected all references to a variable to be consistently local or context references
33
34 -Identifier <unknown> err$7 is referenced as a context variable, but was previously referenced as a [object Object] variable.
34 +Identifier <unknown> err$7 is referenced as a context variable, but was previously referenced as a local variable
35
36 error.bug-invariant-local-or-context-references.ts:15:13
37 13 | setState(_prevState => ({
38 14 | loading: false,
39 > 15 | error: err,
40 - | ^^^ Expected all references to a variable to be consistently local or context references
40 + | ^^^ this is local
41 16 | }));
42 17 | }
43 18 | };
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md
+3 -1
@@ -21,11 +21,13 @@ Found 1 error:
21
22 Invariant: Unexpected terminal in optional
23
24 +
25 +
26 error.bug-invariant-unexpected-terminal-in-optional.ts:3:16
27 1 | const Foo = ({json}) => {
28 2 | try {
29 > 3 | const foo = JSON.parse(json)?.foo;
28 - | ^^^^ Unexpected terminal in optional
30 + | ^^^^ Unexpected maybe-throw in optional
31 4 | return <span>{foo}</span>;
32 5 | } catch {
33 6 | return null;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unnamed-temporary.expect.md
+1 -1
@@ -24,7 +24,7 @@ Found 1 error:
24
25 Invariant: Expected temporaries to be promoted to named identifiers in an earlier pass
26
27 -identifier 15 is unnamed.
27 +identifier 15 is unnamed
28 ```
29
30
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.call-args-destructuring-asignment-complex.expect.md
+3 -1
@@ -18,11 +18,13 @@ Found 1 error:
18
19 Invariant: Const declaration cannot be referenced as an expression
20
21 +
22 +
23 error.call-args-destructuring-asignment-complex.ts:3:9
24 1 | function Component(props) {
25 2 | let x = makeObject();
26 > 3 | x.foo(([[x]] = makeObject()));
25 - | ^^^^^ Const declaration cannot be referenced as an expression
27 + | ^^^^^ this is Const
28 4 | return x;
29 5 | }
30 6 |
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-nested-method-calls-lower-property-load-into-temporary.expect.md
+4 -2
@@ -24,13 +24,15 @@ export const FIXTURE_ENTRYPOINT = {
24 ```
25 Found 1 error:
26
27 -Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier`
27 +Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression
28 +
29 +
30
31 error.todo-nested-method-calls-lower-property-load-into-temporary.ts:6:14
32 4 | function Component({}) {
33 5 | const items = makeArray(0, 1, 2, null, 4, false, 6);
34 > 6 | const max = Math.max(2, items.push(5), ...other);
33 - | ^^^^^^^^ [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier`
35 + | ^^^^^^^^ Got: 'Identifier'
36 7 | return max;
37 8 | }
38 9 |
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md
+2 -2
@@ -23,13 +23,13 @@ Found 1 error:
23
24 Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized
25
26 -<unknown> hasErrors_0$15:TFunction.
26 +<unknown> hasErrors_0$15:TFunction
27
28 error.todo-repro-named-function-with-shadowed-local-same-name.ts:9:9
29 7 | return hasErrors;
30 8 | }
31 > 9 | return hasErrors();
32 - | ^^^^^^^^^ [InferMutationAliasingEffects] Expected value kind to be initialized
32 + | ^^^^^^^^^ this is uninitialized
33 10 | }
34 11 |
35 ```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md
+2 -2
@@ -24,13 +24,13 @@ Found 1 error:
24
25 Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized
26
27 -<unknown> hasErrors_0$15:TFunction.
27 +<unknown> hasErrors_0$15:TFunction
28
29 error.todo-repro-named-function-with-shadowed-local-same-name.ts:10:9
30 8 | return hasErrors;
31 9 | }
32 > 10 | return hasErrors();
33 - | ^^^^^^^^^ [InferMutationAliasingEffects] Expected value kind to be initialized
33 + | ^^^^^^^^^ this is uninitialized
34 11 | }
35 12 |
36 ```