tsc-ts 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +7 -1
  2. package/dist/api/compiler/ast.d.ts +6 -0
  3. package/dist/api/compiler/ast.js +19 -3
  4. package/dist/api/compiler/checker-functions.js +5 -1
  5. package/dist/api/compiler/checker-grammar.d.ts +39 -4
  6. package/dist/api/compiler/checker-grammar.js +239 -75
  7. package/dist/api/compiler/checker-heritage.js +20 -14
  8. package/dist/api/compiler/checker-modules.js +4 -2
  9. package/dist/api/compiler/checker-narrowing.d.ts +7 -0
  10. package/dist/api/compiler/checker-narrowing.js +31 -4
  11. package/dist/api/compiler/checker-source-file.js +16 -1
  12. package/dist/api/compiler/checker-statements.js +11 -2
  13. package/dist/api/compiler/checker-type-factory.js +17 -7
  14. package/dist/api/compiler/checker-type-nodes.d.ts +1 -1
  15. package/dist/api/compiler/checker-type-nodes.js +5 -5
  16. package/dist/api/compiler/checker-unused.js +15 -10
  17. package/dist/api/compiler/checker.d.ts +4 -0
  18. package/dist/api/compiler/checker.js +6 -0
  19. package/dist/api/compiler/file-loader.d.ts +5 -0
  20. package/dist/api/compiler/file-loader.js +7 -0
  21. package/dist/api/compiler/program-checker.d.ts +18 -0
  22. package/dist/api/compiler/program-checker.js +27 -0
  23. package/package.json +14 -9
  24. package/src/compiler/ast.ts +20 -3
  25. package/src/compiler/checker-functions.ts +5 -0
  26. package/src/compiler/checker-grammar.ts +247 -88
  27. package/src/compiler/checker-heritage.ts +31 -17
  28. package/src/compiler/checker-modules.ts +4 -2
  29. package/src/compiler/checker-narrowing.ts +30 -4
  30. package/src/compiler/checker-source-file.ts +16 -1
  31. package/src/compiler/checker-statements.ts +10 -2
  32. package/src/compiler/checker-type-factory.ts +14 -7
  33. package/src/compiler/checker-type-nodes.ts +5 -5
  34. package/src/compiler/checker-unused.ts +13 -8
  35. package/src/compiler/checker.ts +6 -0
  36. package/src/compiler/file-loader.ts +8 -0
  37. package/src/compiler/parallel-check.ts +13 -1
  38. package/src/compiler/parse-thread.ts +24 -2
  39. package/src/compiler/program-checker.ts +28 -0
  40. package/src/compiler/run-records.ts +12 -5
  41. package/src/compiler/tsc-compile.ts +10 -1
@@ -136,9 +136,11 @@ import { getSymbolOfDeclaration, resolveAlias } from './checker-symbols.js';
136
136
  import { Diagnostics } from './diagnostic-messages.js';
137
137
  import { Diagnostic, DiagnosticCategory, type DiagnosticMessage, messageCategory } from './diagnostics.js';
138
138
  import {
139
+ type CompilerOptions,
139
140
  ModuleKind,
140
141
  ScriptTarget,
141
142
  getEmitModuleKind,
143
+ getEmitScriptTarget,
142
144
  supportsDeferredImports,
143
145
  supportsSourcePhaseImports,
144
146
  } from './options.js';
@@ -159,11 +161,40 @@ import { getDeclarations, SymbolFlags } from './symbol.js';
159
161
 
160
162
  /** Runs the grammar checks of every node of `file`. */
161
163
  export function checkGrammarSourceFile(c: Checker, file: SourceFile): void {
164
+ const diagnostics = file.grammarDiagnostics;
165
+ const residualNodes = file.grammarResidualNodes;
166
+ // A parse thread walked the file: it reported the checks that don't need the checker, and left the
167
+ // nodes of the checks that do (checkGrammarSourceFileInParseThread).
168
+ if (diagnostics !== undefined && residualNodes !== undefined) {
169
+ for (const diagnostic of diagnostics) c.addDiagnostic(diagnostic);
170
+ if (residualNodes.length === 0) return;
171
+ const g = new GrammarChecker(c, file, undefined, undefined, file.grammarAmbientReports);
172
+ for (const node of residualNodes) g.visitNode(node);
173
+ return;
174
+ }
162
175
  const g = new GrammarChecker(c, file);
163
176
  if ((file.flags & NodeFlags.Ambient) !== 0) checkGrammarTopLevelElementsForRequiredDeclareModifier(g, file);
164
177
  file.forEachChild(g);
165
178
  }
166
179
 
180
+ /**
181
+ * Runs the grammar checks of `file` in a parse thread, before the file is published: the checks that
182
+ * don't need the checker report now, and the nodes of those that do are kept for the checker, which
183
+ * runs them in the same tree order (`checkGrammarSourceFile`).
184
+ */
185
+ export function checkGrammarSourceFileInParseThread(
186
+ file: SourceFile,
187
+ options: CompilerOptions,
188
+ metadata: SourceFileMetadata,
189
+ ): void {
190
+ const g = new GrammarChecker(undefined, file, options, metadata);
191
+ if ((file.flags & NodeFlags.Ambient) !== 0) checkGrammarTopLevelElementsForRequiredDeclareModifier(g, file);
192
+ file.forEachChild(g);
193
+ file.grammarDiagnostics = g.diagnostics!;
194
+ file.grammarResidualNodes = g.residualNodes!;
195
+ file.grammarAmbientReports = [...g.reportedAmbientStatements];
196
+ }
197
+
167
198
  /** The grammar checker of the file of `node`, for grammar checks run while checking expressions. */
168
199
  function grammarCheckerOf(c: Checker, node: Node): GrammarChecker {
169
200
  const file = getSourceFileOfNode(node);
@@ -211,7 +242,10 @@ export function checkGrammarYieldOfExpression(c: Checker, node: Node): void {
211
242
 
212
243
  /** Per-file state of the grammar walk. */
213
244
  export class GrammarChecker extends NodeVisitor {
214
- readonly c: Checker;
245
+ /** The checker of a walk in the checker thread; undefined for a walk in a parse thread. */
246
+ readonly c: Checker | undefined;
247
+ readonly compilerOptions: CompilerOptions;
248
+ readonly languageVersion: number;
215
249
  readonly file: SourceFile;
216
250
  /** Grammar errors are only reported in files without parse errors. */
217
251
  readonly hasParseErrors: boolean;
@@ -219,24 +253,100 @@ export class GrammarChecker extends NodeVisitor {
219
253
  readonly metadata: SourceFileMetadata;
220
254
  readonly legacyDecorators: boolean;
221
255
  /** Blocks and statements that already reported a statement in an ambient context. */
222
- readonly reportedAmbientStatements = new Set<number>();
256
+ reportedAmbientStatements: Set<number>;
257
+ /**
258
+ * The IDs `reportedAmbientStatements` gained in a parse thread's walk, in the order it gained them, so
259
+ * that the reports of a node whose check the checker runs are undone without copying the set.
260
+ * Undefined in the checker thread, where no check is undone.
261
+ */
262
+ private readonly ambientReportLog: number[] | undefined;
263
+ /**
264
+ * The diagnostics of a walk in a parse thread, which has no checker, for the checker to add to its
265
+ * collection; undefined in the checker thread, where they are reported as they are found.
266
+ */
267
+ readonly diagnostics: Diagnostic[] | undefined;
268
+ /** The nodes of a parse thread's walk whose check needs the checker, in tree order. */
269
+ readonly residualNodes: Node[] | undefined;
270
+ /** Set when the check of a parse thread's walk needs the checker: the checker runs that node. */
271
+ needsChecker = false;
223
272
  private scanner: Scanner | undefined = undefined;
224
273
 
225
- constructor(c: Checker, file: SourceFile) {
274
+ constructor(
275
+ c: Checker | undefined,
276
+ file: SourceFile,
277
+ options: CompilerOptions = c!.compilerOptions,
278
+ metadata?: SourceFileMetadata,
279
+ /** `file.grammarAmbientReports`: what a parse thread's walk already reported. */
280
+ ambientReports?: readonly number[],
281
+ ) {
226
282
  super();
227
283
  this.c = c;
284
+ this.compilerOptions = options;
285
+ this.languageVersion = getEmitScriptTarget(options);
228
286
  this.file = file;
229
287
  this.hasParseErrors = file.diagnostics.length > 0;
230
- this.moduleKind = getEmitModuleKind(c.compilerOptions);
231
- this.metadata = c.host.getSourceFileMetadata(file) ?? new SourceFileMetadata('', '', ModuleKind.None);
232
- this.legacyDecorators = c.compilerOptions.experimentalDecorators === true;
288
+ this.moduleKind = getEmitModuleKind(options);
289
+ this.metadata = metadata ?? c!.host.getSourceFileMetadata(file) ?? new SourceFileMetadata('', '', ModuleKind.None);
290
+ this.legacyDecorators = options.experimentalDecorators === true;
291
+ this.reportedAmbientStatements = new Set(ambientReports);
292
+ this.ambientReportLog = c === undefined ? [] : undefined;
293
+ this.diagnostics = c === undefined ? [] : undefined;
294
+ this.residualNodes = c === undefined ? [] : undefined;
233
295
  }
234
296
 
235
297
  visitNode(node: Node): boolean {
236
- if (checkGrammarNode(this, node)) node.forEachChild(this);
298
+ const diagnostics = this.diagnostics;
299
+ if (diagnostics === undefined) {
300
+ if (checkGrammarNode(this, node)) node.forEachChild(this);
301
+ return false;
302
+ }
303
+ // A parse thread has no checker: a node whose check needs it is recorded for the checker, with the
304
+ // diagnostics and the ambient-context reports it made undone, and its children are left to the
305
+ // checker as well.
306
+ const start = diagnostics.length;
307
+ const reportsMark = this.ambientReportLog!.length;
308
+ const descend = checkGrammarNode(this, node);
309
+ if (this.needsChecker) {
310
+ this.needsChecker = false;
311
+ diagnostics.length = start;
312
+ this.undoAmbientReports(reportsMark);
313
+ this.residualNodes!.push(node);
314
+ return false;
315
+ }
316
+ if (descend) node.forEachChild(this);
237
317
  return false;
238
318
  }
239
319
 
320
+ /** Records that `id` reported a statement in an ambient context. */
321
+ reportAmbientStatement(id: number): void {
322
+ if (this.reportedAmbientStatements.has(id)) return;
323
+ this.reportedAmbientStatements.add(id);
324
+ this.ambientReportLog?.push(id);
325
+ }
326
+
327
+ /** Undoes the ambient-context reports added since the log had `mark` entries. */
328
+ private undoAmbientReports(mark: number): void {
329
+ const log = this.ambientReportLog!;
330
+ for (let i = mark; i < log.length; i++) this.reportedAmbientStatements.delete(log[i]!);
331
+ log.length = mark;
332
+ }
333
+
334
+ /** Reports an error at `node`, as `Checker.error`; returns the diagnostic. */
335
+ error(node: Node | undefined, message: DiagnosticMessage, ...args: string[]): Diagnostic {
336
+ const c = this.c;
337
+ if (c !== undefined) return c.error(node, message, ...args);
338
+ const diagnostic = createDiagnosticForNode(node, message, args);
339
+ this.diagnostics!.push(diagnostic);
340
+ return diagnostic;
341
+ }
342
+
343
+ /** Reports `diagnostic`, as `Checker.addDiagnostic`. */
344
+ report(diagnostic: Diagnostic): void {
345
+ const c = this.c;
346
+ if (c !== undefined) c.addDiagnostic(diagnostic);
347
+ else this.diagnostics!.push(diagnostic);
348
+ }
349
+
240
350
  /** A scanner over the file's text, for rescanning tokens. */
241
351
  getScanner(): Scanner {
242
352
  let scanner = this.scanner;
@@ -244,7 +354,7 @@ export class GrammarChecker extends NodeVisitor {
244
354
  scanner = new Scanner(this.file.text);
245
355
  scanner.setLanguageVariant(this.file.languageVariant);
246
356
  // The scanner's target enum has the same values as the option's.
247
- scanner.setScriptTarget(this.c.languageVersion as number as LanguageTarget);
357
+ scanner.setScriptTarget(this.languageVersion as number as LanguageTarget);
248
358
  this.scanner = scanner;
249
359
  }
250
360
  return scanner;
@@ -255,7 +365,7 @@ export class GrammarChecker extends NodeVisitor {
255
365
 
256
366
  function grammarErrorOnNode(g: GrammarChecker, node: Node, message: DiagnosticMessage, ...args: string[]): boolean {
257
367
  if (g.hasParseErrors) return false;
258
- g.c.error(node, message, ...args);
368
+ g.error(node, message, ...args);
259
369
  return true;
260
370
  }
261
371
 
@@ -267,7 +377,7 @@ function grammarErrorOnFirstToken(
267
377
  ): boolean {
268
378
  if (g.hasParseErrors) return false;
269
379
  const range = getRangeOfTokenAtPosition(g.file, node.pos);
270
- g.c.addDiagnostic(new Diagnostic(g.file.diagnosticFile(), range.pos, range.end, message, args));
380
+ g.report(new Diagnostic(g.file.diagnosticFile(), range.pos, range.end, message, args));
271
381
  return true;
272
382
  }
273
383
 
@@ -279,7 +389,7 @@ function grammarErrorAtPos(
279
389
  ...args: string[]
280
390
  ): boolean {
281
391
  if (g.hasParseErrors) return false;
282
- g.c.addDiagnostic(new Diagnostic(g.file.diagnosticFile(), start, start + length, message, args));
392
+ g.report(new Diagnostic(g.file.diagnosticFile(), start, start + length, message, args));
283
393
  return true;
284
394
  }
285
395
 
@@ -572,20 +682,25 @@ function checkGrammarModifiers(g: GrammarChecker, node: Node): boolean {
572
682
  );
573
683
  return grammarErrorOnFirstToken(g, node, Diagnostics.Decorators_are_not_valid_here);
574
684
  } else if (g.legacyDecorators && (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor)) {
575
- const first = getFirstAccessorOfPair(g.c, node);
576
- if (first !== node && hasDecorators(first))
577
- return grammarErrorOnFirstToken(
578
- g,
579
- node,
580
- Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name,
581
- );
685
+ const c = g.c;
686
+ // Which accessor comes first is a symbol question; a parse thread leaves the node to the checker.
687
+ if (c === undefined) g.needsChecker = true;
688
+ else {
689
+ const first = getFirstAccessorOfPair(c, node);
690
+ if (first !== node && hasDecorators(first))
691
+ return grammarErrorOnFirstToken(
692
+ g,
693
+ node,
694
+ Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name,
695
+ );
696
+ }
582
697
  }
583
698
  // Decorators can only follow `export` and `default`.
584
699
  if ((flags & ~(ModifierFlags.ExportDefault | ModifierFlags.Decorator)) !== 0)
585
700
  return grammarErrorOnNode(g, modifier, Diagnostics.Decorators_are_not_valid_here);
586
701
  if (hasLeadingDecorators && (flags & ModifierFlags.Modifier) !== 0) {
587
702
  if (g.hasParseErrors) return false;
588
- const diagnostic = g.c.error(
703
+ const diagnostic = g.error(
589
704
  modifier,
590
705
  Diagnostics.Decorators_may_not_appear_after_export_or_export_default_if_they_also_appear_before_export,
591
706
  );
@@ -819,7 +934,7 @@ function checkGrammarModifiers(g: GrammarChecker, node: Node): boolean {
819
934
  break;
820
935
  case SyntaxKind.ExportKeyword:
821
936
  if (
822
- g.c.compilerOptions.verbatimModuleSyntax === true &&
937
+ g.compilerOptions.verbatimModuleSyntax === true &&
823
938
  (node.flags & NodeFlags.Ambient) === 0 &&
824
939
  node.kind !== SyntaxKind.TypeAliasDeclaration &&
825
940
  node.kind !== SyntaxKind.InterfaceDeclaration &&
@@ -1335,7 +1450,7 @@ function checkGrammarDecorator(g: GrammarChecker, decorator: Decorator): boolean
1335
1450
  break;
1336
1451
  }
1337
1452
  if (errorNode === undefined) return false;
1338
- const diagnostic = g.c.error(
1453
+ const diagnostic = g.error(
1339
1454
  decorator.expression,
1340
1455
  Diagnostics.Expression_must_be_enclosed_in_parentheses_to_be_used_as_a_decorator,
1341
1456
  );
@@ -1410,7 +1525,7 @@ function checkGrammarParameterList(g: GrammarChecker, parameters: NodeList): boo
1410
1525
  }
1411
1526
 
1412
1527
  function checkGrammarForUseStrictSimpleParameterList(g: GrammarChecker, node: Node): boolean {
1413
- if (g.c.languageVersion < ScriptTarget.ES2016) return false;
1528
+ if (g.languageVersion < ScriptTarget.ES2016) return false;
1414
1529
  const body = getBody(node);
1415
1530
  if (body === undefined || body.kind !== SyntaxKind.Block) return false;
1416
1531
  const useStrictDirective = findUseStrictPrologue(g.file, getStatements(body)!.nodes);
@@ -1423,10 +1538,10 @@ function checkGrammarForUseStrictSimpleParameterList(g: GrammarChecker, node: No
1423
1538
  }
1424
1539
  if (nonSimpleParameters.length === 0) return false;
1425
1540
  for (const parameter of nonSimpleParameters) {
1426
- const diagnostic = g.c.error(parameter, Diagnostics.This_parameter_is_not_allowed_with_use_strict_directive);
1541
+ const diagnostic = g.error(parameter, Diagnostics.This_parameter_is_not_allowed_with_use_strict_directive);
1427
1542
  addRelated(diagnostic, useStrictDirective, Diagnostics.X_use_strict_directive_used_here);
1428
1543
  }
1429
- const diagnostic = g.c.error(
1544
+ const diagnostic = g.error(
1430
1545
  useStrictDirective,
1431
1546
  Diagnostics.X_use_strict_directive_cannot_be_used_with_non_simple_parameter_list,
1432
1547
  );
@@ -1539,14 +1654,20 @@ function checkGrammarIndexSignatureParameters(g: GrammarChecker, node: IndexSign
1539
1654
  return grammarErrorOnNode(g, parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_initializer);
1540
1655
  if (parameter.type === undefined)
1541
1656
  return grammarErrorOnNode(g, parameter.name, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation);
1542
- const t = getTypeFromTypeNode(g.c, parameter.type);
1543
- if (someTypeHasFlags(t, TypeFlags.StringOrNumberLiteralOrUnique) || isGenericType(g.c, t))
1657
+ const c = g.c;
1658
+ if (c === undefined) {
1659
+ // The parameter's type decides; a parse thread leaves the node to the checker.
1660
+ g.needsChecker = true;
1661
+ return false;
1662
+ }
1663
+ const t = getTypeFromTypeNode(c, parameter.type);
1664
+ if (someTypeHasFlags(t, TypeFlags.StringOrNumberLiteralOrUnique) || isGenericType(c, t))
1544
1665
  return grammarErrorOnNode(
1545
1666
  g,
1546
1667
  parameter.name,
1547
1668
  Diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead,
1548
1669
  );
1549
- if (!everyTypeIsValidIndexKey(g.c, t))
1670
+ if (!everyTypeIsValidIndexKey(c, t))
1550
1671
  return grammarErrorOnNode(
1551
1672
  g,
1552
1673
  parameter.name,
@@ -1724,12 +1845,18 @@ function checkGrammarForInvalidExclamationToken(
1724
1845
  }
1725
1846
 
1726
1847
  /** Whether a name is dynamic and can't be late bound: its type isn't a literal or unique symbol. */
1727
- function isNonBindableDynamicName(c: Checker, node: Node): boolean {
1848
+ function isNonBindableDynamicName(g: GrammarChecker, node: Node): boolean {
1728
1849
  if (!isDynamicName(node)) return false;
1729
1850
  let expression: Node | undefined;
1730
1851
  if (node.kind === SyntaxKind.ComputedPropertyName) expression = getExpression(node);
1731
1852
  else if (node instanceof ElementAccessExpression) expression = node.argumentExpression;
1732
1853
  if (expression === undefined || !isEntityNameExpression(expression, false)) return true;
1854
+ const c = g.c;
1855
+ if (c === undefined) {
1856
+ // The name's type decides; a parse thread leaves the node to the checker.
1857
+ g.needsChecker = true;
1858
+ return false;
1859
+ }
1733
1860
  const t =
1734
1861
  node.kind === SyntaxKind.ComputedPropertyName
1735
1862
  ? checkComputedPropertyName(c, node)
@@ -1738,7 +1865,7 @@ function isNonBindableDynamicName(c: Checker, node: Node): boolean {
1738
1865
  }
1739
1866
 
1740
1867
  function checkGrammarForInvalidDynamicName(g: GrammarChecker, node: Node, message: DiagnosticMessage): boolean {
1741
- if (!isNonBindableDynamicName(g.c, node)) return false;
1868
+ if (!isNonBindableDynamicName(g, node)) return false;
1742
1869
  const expression =
1743
1870
  node instanceof ElementAccessExpression ? skipParentheses(node.argumentExpression) : getExpression(node)!;
1744
1871
  return !isEntityNameExpression(expression, false) && grammarErrorOnNode(g, node, message);
@@ -1755,11 +1882,11 @@ function checkGrammarMethodDeclaration(g: GrammarChecker, node: Node): void {
1755
1882
  if (!checkGrammarMethod(g, node)) {
1756
1883
  checkGrammarComputedPropertyName(g, name);
1757
1884
  if (getAsteriskToken(node) !== undefined && name instanceof Identifier && name.text === 'constructor')
1758
- g.c.error(name, Diagnostics.Class_constructor_may_not_be_a_generator);
1885
+ g.error(name, Diagnostics.Class_constructor_may_not_be_a_generator);
1759
1886
  }
1760
1887
  checkGrammarDecorators(g, node);
1761
1888
  if (name.kind === SyntaxKind.PrivateIdentifier && getContainingClass(node) === undefined)
1762
- g.c.error(node, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies);
1889
+ g.error(node, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies);
1763
1890
  }
1764
1891
 
1765
1892
  function checkGrammarMethod(g: GrammarChecker, node: Node): boolean {
@@ -1989,7 +2116,7 @@ function checkAmbientInitializer(g: GrammarChecker, node: Node): boolean {
1989
2116
  if (initializer === undefined) return false;
1990
2117
  const isInvalidInitializer = !(
1991
2118
  isInitializerStringOrNumberLiteralExpression(initializer) ||
1992
- isInitializerSimpleLiteralEnumReference(g.c, initializer) ||
2119
+ isInitializerSimpleLiteralEnumReference(g, initializer) ||
1993
2120
  initializer.kind === SyntaxKind.TrueKeyword ||
1994
2121
  initializer.kind === SyntaxKind.FalseKeyword ||
1995
2122
  isInitializerBigIntLiteralExpression(initializer)
@@ -2042,16 +2169,22 @@ function isInitializerBigIntLiteralExpression(expression: Node): boolean {
2042
2169
  return unary.operator === SyntaxKind.MinusToken && unary.operand.kind === SyntaxKind.BigIntLiteral;
2043
2170
  }
2044
2171
 
2045
- function isInitializerSimpleLiteralEnumReference(c: Checker, expression: Node): boolean {
2046
- if (expression.kind === SyntaxKind.PropertyAccessExpression)
2047
- return (checkExpressionCached(c, expression).flags & TypeFlags.EnumLike) !== 0;
2048
- if (expression instanceof ElementAccessExpression)
2049
- return (
2172
+ function isInitializerSimpleLiteralEnumReference(g: GrammarChecker, expression: Node): boolean {
2173
+ let accessesEnum: boolean;
2174
+ if (expression.kind === SyntaxKind.PropertyAccessExpression) accessesEnum = true;
2175
+ else if (expression instanceof ElementAccessExpression)
2176
+ accessesEnum =
2050
2177
  isInitializerStringOrNumberLiteralExpression(expression.argumentExpression) &&
2051
- isEntityNameExpression(expression.expression, false) &&
2052
- (checkExpressionCached(c, expression).flags & TypeFlags.EnumLike) !== 0
2053
- );
2054
- return false;
2178
+ isEntityNameExpression(expression.expression, false);
2179
+ else return false;
2180
+ if (!accessesEnum) return false;
2181
+ // Whether the reference is to an enum is a type question.
2182
+ const c = g.c;
2183
+ if (c === undefined) {
2184
+ g.needsChecker = true;
2185
+ return false;
2186
+ }
2187
+ return (checkExpressionCached(c, expression).flags & TypeFlags.EnumLike) !== 0;
2055
2188
  }
2056
2189
 
2057
2190
  // ---- Statements
@@ -2066,7 +2199,7 @@ function checkGrammarStatementInAmbientContext(g: GrammarChecker, node: Node): b
2066
2199
  node,
2067
2200
  Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts,
2068
2201
  );
2069
- if (reported) g.reportedAmbientStatements.add(id);
2202
+ if (reported) g.reportAmbientStatement(id);
2070
2203
  return reported;
2071
2204
  }
2072
2205
  // Report once per block; statements nested in other statements are covered by their parent.
@@ -2078,7 +2211,7 @@ function checkGrammarStatementInAmbientContext(g: GrammarChecker, node: Node): b
2078
2211
  const parentId = getNodeId(parent);
2079
2212
  if (!g.reportedAmbientStatements.has(parentId)) {
2080
2213
  const reported = grammarErrorOnFirstToken(g, node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts);
2081
- if (reported) g.reportedAmbientStatements.add(parentId);
2214
+ if (reported) g.reportAmbientStatement(parentId);
2082
2215
  return reported;
2083
2216
  }
2084
2217
  }
@@ -2103,7 +2236,7 @@ function checkGrammarForDisallowedBlockScopedVariableStatement(g: GrammarChecker
2103
2236
  else if (blockScopeKind === NodeFlags.Const) keyword = 'const';
2104
2237
  else if (blockScopeKind === NodeFlags.Using) keyword = 'using';
2105
2238
  else keyword = 'await using';
2106
- g.c.error(node, Diagnostics.X_0_declarations_can_only_be_declared_inside_a_block, keyword);
2239
+ g.error(node, Diagnostics.X_0_declarations_can_only_be_declared_inside_a_block, keyword);
2107
2240
  }
2108
2241
 
2109
2242
  function containerAllowsBlockScopedVariable(parent: Node): boolean {
@@ -2295,7 +2428,7 @@ function checkGrammarForInOrForOfStatementWorker(g: GrammarChecker, node: ForInO
2295
2428
  if (isInTopLevelContext(node)) {
2296
2429
  if (!g.hasParseErrors) {
2297
2430
  if (!isEffectiveExternalModule(g))
2298
- g.c.addDiagnostic(
2431
+ g.report(
2299
2432
  createDiagnosticForNode(
2300
2433
  awaitModifier,
2301
2434
  Diagnostics.X_for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module,
@@ -2304,7 +2437,7 @@ function checkGrammarForInOrForOfStatementWorker(g: GrammarChecker, node: ForInO
2304
2437
  );
2305
2438
  const kind = checkTopLevelAwaitModule(g);
2306
2439
  if (kind === TopLevelAwaitSupport.CommonJS)
2307
- g.c.addDiagnostic(
2440
+ g.report(
2308
2441
  createDiagnosticForNode(
2309
2442
  awaitModifier,
2310
2443
  Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level,
@@ -2312,7 +2445,7 @@ function checkGrammarForInOrForOfStatementWorker(g: GrammarChecker, node: ForInO
2312
2445
  ),
2313
2446
  );
2314
2447
  else if (kind === TopLevelAwaitSupport.Unsupported)
2315
- g.c.addDiagnostic(
2448
+ g.report(
2316
2449
  createDiagnosticForNode(
2317
2450
  awaitModifier,
2318
2451
  Diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_node20_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher,
@@ -2330,7 +2463,7 @@ function checkGrammarForInOrForOfStatementWorker(g: GrammarChecker, node: ForInO
2330
2463
  const containingFunction = getContainingFunction(node);
2331
2464
  if (containingFunction !== undefined && containingFunction.kind !== SyntaxKind.Constructor)
2332
2465
  addRelated(diagnostic, containingFunction, Diagnostics.Did_you_mean_to_mark_this_function_as_async);
2333
- g.c.addDiagnostic(diagnostic);
2466
+ g.report(diagnostic);
2334
2467
  return true;
2335
2468
  }
2336
2469
  }
@@ -2397,7 +2530,7 @@ function checkTopLevelAwaitModule(g: GrammarChecker): TopLevelAwaitSupport {
2397
2530
  moduleKind !== ModuleKind.System
2398
2531
  )
2399
2532
  return TopLevelAwaitSupport.Unsupported;
2400
- return g.c.languageVersion >= ScriptTarget.ES2017 ? TopLevelAwaitSupport.Supported : TopLevelAwaitSupport.Unsupported;
2533
+ return g.languageVersion >= ScriptTarget.ES2017 ? TopLevelAwaitSupport.Supported : TopLevelAwaitSupport.Unsupported;
2401
2534
  }
2402
2535
 
2403
2536
  function checkGrammarBreakOrContinueStatement(g: GrammarChecker, node: Node): boolean {
@@ -2512,7 +2645,13 @@ function checkGrammarCatchClause(g: GrammarChecker, node: CatchClause): void {
2512
2645
  if (declaration === undefined) return;
2513
2646
  const typeNode = declaration.type;
2514
2647
  if (typeNode !== undefined) {
2515
- const t = getTypeFromTypeNode(g.c, typeNode);
2648
+ // The annotation's type decides; a parse thread leaves the node to the checker.
2649
+ const c = g.c;
2650
+ if (c === undefined) {
2651
+ g.needsChecker = true;
2652
+ return;
2653
+ }
2654
+ const t = getTypeFromTypeNode(c, typeNode);
2516
2655
  if ((t.flags & TypeFlags.AnyOrUnknown) === 0)
2517
2656
  grammarErrorOnFirstToken(
2518
2657
  g,
@@ -2659,13 +2798,13 @@ function checkExternalImportOrExportDeclaration(g: GrammarChecker, node: Node):
2659
2798
  // A missing name is a parse error.
2660
2799
  if (moduleName === undefined || moduleName.pos === moduleName.end) return false;
2661
2800
  if (moduleName.kind !== SyntaxKind.StringLiteral) {
2662
- g.c.error(moduleName, Diagnostics.String_literal_expected);
2801
+ g.error(moduleName, Diagnostics.String_literal_expected);
2663
2802
  return false;
2664
2803
  }
2665
2804
  const parent = node.parent!;
2666
2805
  const inAmbientExternalModule = parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(parent.parent!);
2667
2806
  if (parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule) {
2668
- g.c.error(
2807
+ g.error(
2669
2808
  moduleName,
2670
2809
  node.kind === SyntaxKind.ExportDeclaration
2671
2810
  ? Diagnostics.Export_declarations_are_not_permitted_in_a_namespace
@@ -2679,7 +2818,7 @@ function checkExternalImportOrExportDeclaration(g: GrammarChecker, node: Node):
2679
2818
  !isModuleAugmentationExternal(parent.parent!)
2680
2819
  ) {
2681
2820
  // Module augmentations report relative names when checking the augmentation.
2682
- g.c.error(
2821
+ g.error(
2683
2822
  node,
2684
2823
  Diagnostics.Import_or_export_declaration_in_an_ambient_module_declaration_cannot_reference_module_through_relative_module_name,
2685
2824
  );
@@ -2697,7 +2836,7 @@ function checkGrammarImportAttributeValues(g: GrammarChecker, node: ImportAttrib
2697
2836
  const value = (attribute as ImportAttribute).value;
2698
2837
  if (value.kind !== SyntaxKind.StringLiteral) {
2699
2838
  hasError = true;
2700
- g.c.error(value, Diagnostics.Import_attribute_values_must_be_string_literal_expressions);
2839
+ g.error(value, Diagnostics.Import_attribute_values_must_be_string_literal_expressions);
2701
2840
  }
2702
2841
  }
2703
2842
  return hasError;
@@ -2769,12 +2908,16 @@ function checkGrammarImportClause(g: GrammarChecker, node: ImportClause): boolea
2769
2908
  Diagnostics.Source_phase_imports_are_only_supported_when_the_module_option_is_set_to_esnext_nodenext_or_preserve,
2770
2909
  );
2771
2910
  const moduleSpecifier = (node.parent as ImportDeclaration).moduleSpecifier;
2772
- if (getEmitSyntaxForModuleSpecifierExpression(g.c, moduleSpecifier) === ModuleKind.CommonJS)
2773
- return grammarErrorOnNode(
2774
- g,
2775
- node,
2776
- Diagnostics.Source_phase_imports_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls,
2777
- );
2911
+ const c = g.c;
2912
+ // The specifier's emit syntax comes from the module resolution; a parse thread leaves it to the checker.
2913
+ if (c !== undefined) {
2914
+ if (getEmitSyntaxForModuleSpecifierExpression(c, moduleSpecifier) === ModuleKind.CommonJS)
2915
+ return grammarErrorOnNode(
2916
+ g,
2917
+ node,
2918
+ Diagnostics.Source_phase_imports_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls,
2919
+ );
2920
+ } else g.needsChecker = true;
2778
2921
  }
2779
2922
  return false;
2780
2923
  }
@@ -2808,9 +2951,14 @@ function checkGrammarImportEqualsDeclaration(g: GrammarChecker, node: ImportEqua
2808
2951
  const isExternal = node.moduleReference.kind === SyntaxKind.ExternalModuleReference;
2809
2952
  if (!isExternal) {
2810
2953
  if (node.isTypeOnly) {
2811
- const symbol = getSymbolOfDeclaration(g.c, node);
2812
- if (symbol !== undefined && resolveAlias(g.c, symbol) !== g.c.unknownSymbol)
2813
- grammarErrorOnNode(g, node, Diagnostics.An_import_alias_cannot_use_import_type);
2954
+ const c = g.c;
2955
+ // Whether the alias resolves is a symbol question; a parse thread leaves the node to the checker.
2956
+ if (c === undefined) g.needsChecker = true;
2957
+ else {
2958
+ const symbol = getSymbolOfDeclaration(c, node);
2959
+ if (symbol !== undefined && resolveAlias(c, symbol) !== c.unknownSymbol)
2960
+ grammarErrorOnNode(g, node, Diagnostics.An_import_alias_cannot_use_import_type);
2961
+ }
2814
2962
  }
2815
2963
  return;
2816
2964
  }
@@ -2861,7 +3009,7 @@ function checkGrammarExportDeclaration(g: GrammarChecker, node: ExportDeclaratio
2861
3009
  !hasModuleSpecifier &&
2862
3010
  (node.flags & NodeFlags.Ambient) !== 0;
2863
3011
  if (parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule && !inAmbientNamespaceDeclaration)
2864
- g.c.error(node, Diagnostics.Export_declarations_are_not_permitted_in_a_namespace);
3012
+ g.error(node, Diagnostics.Export_declarations_are_not_permitted_in_a_namespace);
2865
3013
  }
2866
3014
  checkGrammarImportAttributes(g, node);
2867
3015
  }
@@ -2893,7 +3041,7 @@ function checkGrammarExportAssignment(g: GrammarChecker, node: ExportAssignment)
2893
3041
  const parent = node.parent!;
2894
3042
  const container = parent.kind === SyntaxKind.SourceFile ? parent : parent.parent!;
2895
3043
  if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) {
2896
- g.c.error(
3044
+ g.error(
2897
3045
  node,
2898
3046
  isExportEquals
2899
3047
  ? Diagnostics.An_export_assignment_cannot_be_used_in_a_namespace
@@ -2930,7 +3078,7 @@ function checkGrammarExportAssignment(g: GrammarChecker, node: ExportAssignment)
2930
3078
  }
2931
3079
 
2932
3080
  function getEmitModuleFormat(g: GrammarChecker): ModuleKind {
2933
- return getEmitModuleFormatOfFile(g.file.fileName, g.c.compilerOptions, g.metadata);
3081
+ return getEmitModuleFormatOfFile(g.file.fileName, g.compilerOptions, g.metadata);
2934
3082
  }
2935
3083
 
2936
3084
  function isEffectiveExternalModule(g: GrammarChecker): boolean {
@@ -3051,12 +3199,18 @@ function checkGrammarTupleType(g: GrammarChecker, node: TupleTypeNode): void {
3051
3199
  let seenOptionalElement = false;
3052
3200
  let seenRestElement = false;
3053
3201
  for (const element of node.elements.nodes) {
3054
- let flags = getTupleElementFlags(g.c, element);
3202
+ let flags = getTupleElementFlags(element);
3055
3203
  if ((flags & ElementFlags.Variadic) !== 0) {
3056
- const t = getTypeFromTypeNode(g.c, getType(element)!);
3204
+ const c = g.c;
3205
+ // The element type decides whether a variadic element is a rest element.
3206
+ if (c === undefined) {
3207
+ g.needsChecker = true;
3208
+ return;
3209
+ }
3210
+ const t = getTypeFromTypeNode(c, getType(element)!);
3057
3211
  // `checkTupleType` reports non-array rest types and stops.
3058
- if (!isArrayLikeType(g.c, t)) break;
3059
- if (isArrayType(g.c, t) || (isTupleType(t) && (tupleTargetOf(t).combinedFlags & ElementFlags.Rest) !== 0))
3212
+ if (!isArrayLikeType(c, t)) break;
3213
+ if (isArrayType(c, t) || (isTupleType(t) && (tupleTargetOf(t).combinedFlags & ElementFlags.Rest) !== 0))
3060
3214
  flags |= ElementFlags.Rest;
3061
3215
  }
3062
3216
  if ((flags & ElementFlags.Rest) !== 0) {
@@ -3105,9 +3259,15 @@ function checkGrammarJSDocTypeInTypeScript(g: GrammarChecker, node: Node): void
3105
3259
  const isNullable = node.kind === SyntaxKind.JSDocNullableType;
3106
3260
  const typeNode = getType(node)!;
3107
3261
  const postfix = node.pos === typeNode.pos;
3108
- let t = getTypeFromTypeNode(g.c, typeNode);
3109
- if (isNullable && t !== g.c.neverType && t !== g.c.voidType)
3110
- t = getNullableType(g.c, t, postfix ? TypeFlags.Undefined : TypeFlags.Nullable);
3262
+ const c = g.c;
3263
+ // The error names the type's printed form; a parse thread leaves the node to the checker.
3264
+ if (c === undefined) {
3265
+ g.needsChecker = true;
3266
+ return;
3267
+ }
3268
+ let t = getTypeFromTypeNode(c, typeNode);
3269
+ if (isNullable && t !== c.neverType && t !== c.voidType)
3270
+ t = getNullableType(c, t, postfix ? TypeFlags.Undefined : TypeFlags.Nullable);
3111
3271
  grammarErrorOnNode(
3112
3272
  g,
3113
3273
  node,
@@ -3115,7 +3275,7 @@ function checkGrammarJSDocTypeInTypeScript(g: GrammarChecker, node: Node): void
3115
3275
  ? Diagnostics.X_0_at_the_end_of_a_type_is_not_valid_TypeScript_syntax_Did_you_mean_to_write_1
3116
3276
  : Diagnostics.X_0_at_the_start_of_a_type_is_not_valid_TypeScript_syntax_Did_you_mean_to_write_1,
3117
3277
  isNullable ? '?' : '!',
3118
- typeToString(g.c, t),
3278
+ typeToString(c, t),
3119
3279
  );
3120
3280
  }
3121
3281
 
@@ -3265,9 +3425,7 @@ function checkGrammarObjectLiteralExpression(
3265
3425
  );
3266
3426
  checkGrammarForInvalidQuestionMark(g, postfixToken, Diagnostics.An_object_member_cannot_be_declared_optional);
3267
3427
  if (name.kind === SyntaxKind.BigIntLiteral)
3268
- g.c.addDiagnostic(
3269
- createDiagnosticForNode(name, Diagnostics.A_bigint_literal_cannot_be_used_as_a_property_name, []),
3270
- );
3428
+ g.report(createDiagnosticForNode(name, Diagnostics.A_bigint_literal_cannot_be_used_as_a_property_name, []));
3271
3429
  currentKind = DeclarationMeaning.PropertyAssignment;
3272
3430
  break;
3273
3431
  }
@@ -3282,7 +3440,8 @@ function checkGrammarObjectLiteralExpression(
3282
3440
  break;
3283
3441
  }
3284
3442
  if (inDestructuring) continue;
3285
- const effectiveName = getEffectivePropertyNameForPropertyNameNode(g.c, name);
3443
+ // Object literals are checked with the checker, when the expression is checked.
3444
+ const effectiveName = getEffectivePropertyNameForPropertyNameNode(g.c!, name);
3286
3445
  if (effectiveName === undefined || seen === undefined) continue;
3287
3446
  const existingKind = seen.get(effectiveName);
3288
3447
  if (existingKind === undefined) {
@@ -3369,7 +3528,7 @@ function checkGrammarCallExpression(g: GrammarChecker, node: CallExpression): vo
3369
3528
 
3370
3529
  function checkGrammarImportCallExpression(g: GrammarChecker, node: CallExpression): boolean {
3371
3530
  const moduleKind = g.moduleKind;
3372
- if (g.c.compilerOptions.verbatimModuleSyntax === true && moduleKind === ModuleKind.CommonJS)
3531
+ if (g.compilerOptions.verbatimModuleSyntax === true && moduleKind === ModuleKind.CommonJS)
3373
3532
  return grammarErrorOnNode(
3374
3533
  g,
3375
3534
  node,
@@ -3489,7 +3648,7 @@ function checkGrammarAwaitOrAwaitUsing(g: GrammarChecker, node: Node): boolean {
3489
3648
  const container = getContainingFunctionOrClassStaticBlock(node);
3490
3649
  if (container !== undefined && container.kind === SyntaxKind.ClassStaticBlockDeclaration) {
3491
3650
  // Reported even with parse errors.
3492
- g.c.error(
3651
+ g.error(
3493
3652
  node,
3494
3653
  isAwaitExpression
3495
3654
  ? Diagnostics.X_await_expression_cannot_be_used_inside_a_class_static_block
@@ -3500,7 +3659,7 @@ function checkGrammarAwaitOrAwaitUsing(g: GrammarChecker, node: Node): boolean {
3500
3659
  if (isInTopLevelContext(node)) {
3501
3660
  if (!g.hasParseErrors) {
3502
3661
  if (!isEffectiveExternalModule(g)) {
3503
- g.c.addDiagnostic(
3662
+ g.report(
3504
3663
  diagnosticAtFirstToken(
3505
3664
  g,
3506
3665
  node,
@@ -3513,7 +3672,7 @@ function checkGrammarAwaitOrAwaitUsing(g: GrammarChecker, node: Node): boolean {
3513
3672
  }
3514
3673
  const support = checkTopLevelAwaitModule(g);
3515
3674
  if (support === TopLevelAwaitSupport.CommonJS) {
3516
- g.c.addDiagnostic(
3675
+ g.report(
3517
3676
  diagnosticAtFirstToken(
3518
3677
  g,
3519
3678
  node,
@@ -3522,7 +3681,7 @@ function checkGrammarAwaitOrAwaitUsing(g: GrammarChecker, node: Node): boolean {
3522
3681
  );
3523
3682
  hasError = true;
3524
3683
  } else if (support === TopLevelAwaitSupport.Unsupported) {
3525
- g.c.addDiagnostic(
3684
+ g.report(
3526
3685
  diagnosticAtFirstToken(
3527
3686
  g,
3528
3687
  node,
@@ -3549,13 +3708,13 @@ function checkGrammarAwaitOrAwaitUsing(g: GrammarChecker, node: Node): boolean {
3549
3708
  !hasSyntacticModifier(container, ModifierFlags.Async)
3550
3709
  )
3551
3710
  addRelated(diagnostic, container, Diagnostics.Did_you_mean_to_mark_this_function_as_async);
3552
- g.c.addDiagnostic(diagnostic);
3711
+ g.report(diagnostic);
3553
3712
  hasError = true;
3554
3713
  }
3555
3714
  }
3556
3715
  if (isAwaitExpression && isInParameterInitializerBeforeContainingFunction(node)) {
3557
3716
  // Reported even with parse errors.
3558
- g.c.error(node, Diagnostics.X_await_expressions_cannot_be_used_in_a_parameter_initializer);
3717
+ g.error(node, Diagnostics.X_await_expressions_cannot_be_used_in_a_parameter_initializer);
3559
3718
  hasError = true;
3560
3719
  }
3561
3720
  return hasError;
@@ -3568,7 +3727,7 @@ function checkGrammarYieldExpression(g: GrammarChecker, node: Node): boolean {
3568
3727
  hasError = true;
3569
3728
  }
3570
3729
  if (isInParameterInitializerBeforeContainingFunction(node)) {
3571
- g.c.error(node, Diagnostics.X_yield_expressions_cannot_be_used_in_a_parameter_initializer);
3730
+ g.error(node, Diagnostics.X_yield_expressions_cannot_be_used_in_a_parameter_initializer);
3572
3731
  hasError = true;
3573
3732
  }
3574
3733
  return hasError;
@@ -3627,7 +3786,7 @@ function checkGrammarBigIntLiteral(g: GrammarChecker, node: Node): boolean {
3627
3786
  return (
3628
3787
  !isLiteralType &&
3629
3788
  (node.flags & NodeFlags.Ambient) === 0 &&
3630
- g.c.languageVersion < ScriptTarget.ES2020 &&
3789
+ g.languageVersion < ScriptTarget.ES2020 &&
3631
3790
  grammarErrorOnNode(g, node, Diagnostics.BigInt_literals_are_not_available_when_targeting_lower_than_ES2020)
3632
3791
  );
3633
3792
  }
@@ -3654,7 +3813,7 @@ class RegularExpressionErrorReporter extends ScannerErrorReporter {
3654
3813
  } else if (lastError === undefined || start !== lastError.pos) {
3655
3814
  const diagnostic = new Diagnostic(this.g.file.diagnosticFile(), start, start + length, message, args);
3656
3815
  this.lastError = diagnostic;
3657
- this.g.c.addDiagnostic(diagnostic);
3816
+ this.g.report(diagnostic);
3658
3817
  }
3659
3818
  }
3660
3819
  }