[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
```