tsc-ts 0.0.7 → 0.0.9

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 (39) hide show
  1. package/README.md +1 -1
  2. package/dist/api/compiler/checker-declaration-order.js +3 -2
  3. package/dist/api/compiler/checker-declared-types.js +6 -3
  4. package/dist/api/compiler/checker-deprecation.js +14 -13
  5. package/dist/api/compiler/checker-destructuring.js +3 -2
  6. package/dist/api/compiler/checker-members.js +6 -2
  7. package/dist/api/compiler/checker-source-file.d.ts +12 -0
  8. package/dist/api/compiler/checker-source-file.js +35 -0
  9. package/dist/api/compiler/checker-symbol-types.js +5 -5
  10. package/dist/api/compiler/checker-symbols.js +5 -2
  11. package/dist/api/compiler/checker.d.ts +6 -1
  12. package/dist/api/compiler/checker.js +9 -1
  13. package/dist/api/compiler/file-loader.d.ts +2 -2
  14. package/dist/api/compiler/file-loader.js +43 -23
  15. package/dist/api/compiler/link-tables.d.ts +7 -0
  16. package/dist/api/compiler/link-tables.js +22 -0
  17. package/dist/api/compiler/parser.d.ts +7 -0
  18. package/dist/api/compiler/parser.js +55 -32
  19. package/dist/api/compiler/program-checker.d.ts +18 -0
  20. package/dist/api/compiler/program-checker.js +35 -2
  21. package/dist/api/library/diagnostics.d.ts +10 -0
  22. package/dist/api/library/diagnostics.js +20 -0
  23. package/package.json +9 -9
  24. package/src/compiler/checker-declaration-order.ts +3 -2
  25. package/src/compiler/checker-declared-types.ts +6 -3
  26. package/src/compiler/checker-deprecation.ts +13 -11
  27. package/src/compiler/checker-destructuring.ts +11 -2
  28. package/src/compiler/checker-members.ts +6 -2
  29. package/src/compiler/checker-source-file.ts +34 -0
  30. package/src/compiler/checker-symbol-types.ts +14 -4
  31. package/src/compiler/checker-symbols.ts +6 -2
  32. package/src/compiler/checker.ts +8 -1
  33. package/src/compiler/file-loader.ts +49 -24
  34. package/src/compiler/link-tables.ts +32 -0
  35. package/src/compiler/parallel-check.ts +199 -20
  36. package/src/compiler/parser.ts +55 -32
  37. package/src/compiler/program-checker.ts +36 -2
  38. package/src/compiler/thread-entry.ts +16 -1
  39. package/src/library/diagnostics.ts +23 -0
@@ -147,6 +147,10 @@ export class Parser extends ScannerErrorReporter {
147
147
  // receives reparsed nodes, and a fresh array per parsed list would be one more allocation each.
148
148
  reparseLists;
149
149
  reparseDepth;
150
+ // One scratch array per nesting depth of the lists being parsed. A list collects its elements in
151
+ // its depth's array and is copied out at its exact length, so the tree keeps no spare capacity.
152
+ listScratch;
153
+ listDepth;
150
154
  reparsedClones;
151
155
  /** Nodes with eagerly parsed JSDoc, for rewinding. */
152
156
  jsDocInfos;
@@ -200,6 +204,8 @@ export class Parser extends ScannerErrorReporter {
200
204
  this.reparseList = [];
201
205
  this.reparseLists = [this.reparseList];
202
206
  this.reparseDepth = 0;
207
+ this.listScratch = [];
208
+ this.listDepth = -1;
203
209
  this.reparsedClones = [];
204
210
  this.jsDocInfos = [];
205
211
  this.jsDocTable = undefined;
@@ -610,7 +616,7 @@ export class Parser extends ScannerErrorReporter {
610
616
  this.reparseLists.push([]);
611
617
  const reparseList = this.reparseLists[depth];
612
618
  this.reparseList = reparseList;
613
- const list = [];
619
+ const list = this.openList();
614
620
  while (!this.isListTerminator(kind)) {
615
621
  if (this.isListElement(kind, false)) {
616
622
  const elt = this.parseListElement(element, list.length);
@@ -636,7 +642,7 @@ export class Parser extends ScannerErrorReporter {
636
642
  this.reparseDepth = depth - 1;
637
643
  this.reparseList = outerReparseList;
638
644
  this.parsingContexts = saveParsingContexts;
639
- return list;
645
+ return this.closeList(list);
640
646
  }
641
647
  parseList(kind, element) {
642
648
  const pos = this.nodePos();
@@ -648,12 +654,13 @@ export class Parser extends ScannerErrorReporter {
648
654
  const pos = this.nodePos();
649
655
  const saveParsingContexts = this.parsingContexts;
650
656
  this.parsingContexts |= 1 << kind;
651
- const list = [];
657
+ const list = this.openList();
652
658
  for (;;) {
653
659
  if (this.isListElement(kind, false)) {
654
660
  const startPos = this.nodePos();
655
661
  const result = this.parseListElement(element, list.length);
656
662
  if (result === this.noElement) {
663
+ this.closeList(list);
657
664
  this.parsingContexts = saveParsingContexts;
658
665
  return undefined;
659
666
  }
@@ -683,7 +690,24 @@ export class Parser extends ScannerErrorReporter {
683
690
  break;
684
691
  }
685
692
  this.parsingContexts = saveParsingContexts;
686
- return this.newNodeList(pos, this.nodePos(), list);
693
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
694
+ }
695
+ /** The scratch array for a list at the next nesting depth, empty. */
696
+ openList() {
697
+ const depth = ++this.listDepth;
698
+ if (depth === this.listScratch.length)
699
+ this.listScratch.push([]);
700
+ return this.listScratch[depth];
701
+ }
702
+ /** The elements collected in `list` (the scratch array from `openList`) as an array of their exact
703
+ * length, or the shared empty array; empties the scratch array for the next list at its depth. */
704
+ closeList(list) {
705
+ this.listDepth--;
706
+ if (list.length === 0)
707
+ return emptyListNodes;
708
+ const nodes = list.slice();
709
+ list.length = 0;
710
+ return nodes;
687
711
  }
688
712
  /** The list; a missing list if `opening` is absent; undefined if an element parser returned undefined. */
689
713
  parseBracketedList(kind, element, opening, closing) {
@@ -2373,10 +2397,11 @@ export class Parser extends ScannerErrorReporter {
2373
2397
  ? this.parseFunctionOrConstructorTypeToError(isUnionType)
2374
2398
  : this.parseConstituentType(isUnionType);
2375
2399
  if (this.token() === operator || hasLeadingOperator) {
2376
- const types = [type];
2400
+ const types = this.openList();
2401
+ types.push(type);
2377
2402
  while (this.parseOptional(operator))
2378
2403
  types.push(this.parseFunctionOrConstructorTypeToError(isUnionType));
2379
- const list = this.newNodeList(pos, this.nodePos(), types);
2404
+ const list = this.newNodeList(pos, this.nodePos(), this.closeList(types));
2380
2405
  type = isUnionType ? new UnionTypeNode(list) : new IntersectionTypeNode(list);
2381
2406
  this.finishNode(type, pos);
2382
2407
  }
@@ -2985,17 +3010,12 @@ export class Parser extends ScannerErrorReporter {
2985
3010
  return false;
2986
3011
  }
2987
3012
  parseTypeOrTypePredicate() {
2988
- if (this.isIdentifier()) {
2989
- const state = this.beginSpeculation();
3013
+ // `x is T`: the identifier is parsed only once `is` is known to follow it.
3014
+ if (this.isIdentifier() && this.lookAhead(nextTokenIsIsKeywordOnSameLine)) {
2990
3015
  const pos = this.nodePos();
2991
3016
  const id = this.parseIdentifier(1 /* IdentifierUse.Name */);
2992
- if (this.token() === 142 /* SyntaxKind.IsKeyword */ && !this.hasPrecedingLineBreak()) {
2993
- this.endSpeculation(state);
2994
- this.nextToken();
2995
- return this.finishNode(new TypePredicateNode(undefined, id, this.parseType()), pos);
2996
- }
2997
- this.rewind(state);
2998
- this.endSpeculation(state);
3017
+ this.nextToken();
3018
+ return this.finishNode(new TypePredicateNode(undefined, id, this.parseType()), pos);
2999
3019
  }
3000
3020
  return this.parseType();
3001
3021
  }
@@ -3175,14 +3195,14 @@ export class Parser extends ScannerErrorReporter {
3175
3195
  }
3176
3196
  parseTemplateTypeSpans() {
3177
3197
  const pos = this.nodePos();
3178
- const list = [];
3198
+ const list = this.openList();
3179
3199
  for (;;) {
3180
3200
  const span = this.parseTemplateTypeSpan();
3181
3201
  list.push(span);
3182
3202
  if (span.literal.kind !== 16 /* SyntaxKind.TemplateMiddle */)
3183
3203
  break;
3184
3204
  }
3185
- return this.newNodeList(pos, this.nodePos(), list);
3205
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
3186
3206
  }
3187
3207
  parseTemplateTypeSpan() {
3188
3208
  const pos = this.nodePos();
@@ -3282,12 +3302,10 @@ export class Parser extends ScannerErrorReporter {
3282
3302
  let hasTrailingModifier = false;
3283
3303
  let hasStaticModifier = false;
3284
3304
  const pos = this.nodePos();
3285
- let list;
3305
+ const list = this.openList();
3286
3306
  for (;;) {
3287
3307
  if (allowDecorators && this.token() === 59 /* SyntaxKind.AtToken */ && !hasTrailingModifier) {
3288
3308
  const decorator = this.parseDecorator();
3289
- if (list === undefined)
3290
- list = [];
3291
3309
  list.push(decorator);
3292
3310
  if (hasLeadingModifier)
3293
3311
  hasTrailingDecorator = true;
@@ -3298,8 +3316,6 @@ export class Parser extends ScannerErrorReporter {
3298
3316
  break;
3299
3317
  if (modifier.kind === 125 /* SyntaxKind.StaticKeyword */)
3300
3318
  hasStaticModifier = true;
3301
- if (list === undefined)
3302
- list = [];
3303
3319
  list.push(modifier);
3304
3320
  if (hasTrailingDecorator)
3305
3321
  hasTrailingModifier = true;
@@ -3307,7 +3323,8 @@ export class Parser extends ScannerErrorReporter {
3307
3323
  hasLeadingModifier = true;
3308
3324
  }
3309
3325
  }
3310
- return list === undefined ? undefined : this.newModifierList(pos, this.nodePos(), list);
3326
+ const nodes = this.closeList(list);
3327
+ return nodes.length === 0 ? undefined : this.newModifierList(pos, this.nodePos(), nodes);
3311
3328
  }
3312
3329
  parseDecorator() {
3313
3330
  const pos = this.nodePos();
@@ -3941,7 +3958,7 @@ export class Parser extends ScannerErrorReporter {
3941
3958
  const pos = this.nodePos();
3942
3959
  const saveParsingContexts = this.parsingContexts;
3943
3960
  this.parsingContexts |= 1 << 14 /* ParsingContext.JsxChildren */;
3944
- const list = [];
3961
+ const list = this.openList();
3945
3962
  for (;;) {
3946
3963
  // Like tsgo, this leaves the parser's current token unchanged.
3947
3964
  const currentToken = this.scanner.reScanJsxToken(true);
@@ -3957,7 +3974,7 @@ export class Parser extends ScannerErrorReporter {
3957
3974
  break;
3958
3975
  }
3959
3976
  this.parsingContexts = saveParsingContexts;
3960
- return this.newNodeList(pos, this.nodePos(), list);
3977
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
3961
3978
  }
3962
3979
  parseJsxChild(openingTag, token) {
3963
3980
  switch (token) {
@@ -4519,14 +4536,14 @@ export class Parser extends ScannerErrorReporter {
4519
4536
  }
4520
4537
  parseTemplateSpans(isTaggedTemplate) {
4521
4538
  const pos = this.nodePos();
4522
- const list = [];
4539
+ const list = this.openList();
4523
4540
  for (;;) {
4524
4541
  const span = this.parseTemplateSpan(isTaggedTemplate);
4525
4542
  list.push(span);
4526
4543
  if (span.literal.kind !== 16 /* SyntaxKind.TemplateMiddle */)
4527
4544
  break;
4528
4545
  }
4529
- return this.newNodeList(pos, this.nodePos(), list);
4546
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
4530
4547
  }
4531
4548
  parseTemplateSpan(isTaggedTemplate) {
4532
4549
  const pos = this.nodePos();
@@ -5960,6 +5977,9 @@ function nextTokenCanFollowExportModifier(p) {
5960
5977
  function nextTokenIsClassKeywordOnSameLine(p) {
5961
5978
  return p.nextToken() === 85 /* SyntaxKind.ClassKeyword */ && !p.hasPrecedingLineBreak();
5962
5979
  }
5980
+ function nextTokenIsIsKeywordOnSameLine(p) {
5981
+ return p.nextToken() === 142 /* SyntaxKind.IsKeyword */ && !p.hasPrecedingLineBreak();
5982
+ }
5963
5983
  function nextTokenIsFunctionKeywordOnSameLine(p) {
5964
5984
  return p.nextToken() === 99 /* SyntaxKind.FunctionKeyword */ && !p.hasPrecedingLineBreak();
5965
5985
  }
@@ -6012,11 +6032,14 @@ function nextIsUnParenthesizedAsyncArrowFunction(p) {
6012
6032
  // `async =>` is a simple arrow function with a parameter named `async`.
6013
6033
  if (p.hasPrecedingLineBreak() || p.token() === 38 /* SyntaxKind.EqualsGreaterThanToken */)
6014
6034
  return false;
6015
- const expr = p.parseBinaryExpressionOrHigher(0 /* OperatorPrecedence.Lowest */);
6016
- if (!p.hasPrecedingLineBreak() &&
6017
- expr.kind === 79 /* SyntaxKind.Identifier */ &&
6018
- p.token() === 38 /* SyntaxKind.EqualsGreaterThanToken */)
6019
- return true;
6035
+ // The binary expression after `async` is a lone identifier followed by `=>` only when an identifier
6036
+ // token is followed by `=>`. Any other first token starts another kind of expression or none, and any
6037
+ // other token after the identifier continues the expression or ends it before `=>`. Checking the
6038
+ // tokens gives the same answer as parsing the expression, whose nodes would be discarded.
6039
+ if (!p.isIdentifier())
6040
+ return false;
6041
+ p.nextToken();
6042
+ return !p.hasPrecedingLineBreak() && p.token() === 38 /* SyntaxKind.EqualsGreaterThanToken */;
6020
6043
  }
6021
6044
  return false;
6022
6045
  }
@@ -134,6 +134,23 @@ export declare class CheckedProgram {
134
134
  * incremental program keeps them unfiltered under `noEmit` too.
135
135
  */
136
136
  unfilteredDiagnosticsOfFile(file: SourceFile): Diagnostic[];
137
+ /**
138
+ * Checks the statements `start` to `end` of the declaration file `file` with this checker, one of the
139
+ * ranges that several checkers check it in (`checkSourceFileRange`, parallel-check.ts), and returns
140
+ * whether the checker then has diagnostics in the file.
141
+ */
142
+ checkRange(file: SourceFile, start: number, end: number): boolean;
143
+ /**
144
+ * The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, where checkers checked it in
145
+ * ranges and found no diagnostics in it (`checkRange`).
146
+ */
147
+ unfilteredDiagnosticsOfCleanRanges(file: SourceFile): Diagnostic[];
148
+ /**
149
+ * The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, from a new checker that checks it
150
+ * whole: for a file checked in ranges that found diagnostics in it (parallel-check.ts), part of which this
151
+ * thread's checker may have checked.
152
+ */
153
+ unfilteredDiagnosticsOfFileOnNewChecker(file: SourceFile): Diagnostic[];
137
154
  /**
138
155
  * The bind and check diagnostics of `file` before `noEmit` filtering and without include errors.
139
156
  * Once checker threads checked the program, they come from the threads' diagnostics of the file,
@@ -156,6 +173,7 @@ export declare class CheckedProgram {
156
173
  skipTypeChecking(file: SourceFile): boolean;
157
174
  private collect;
158
175
  private collectChecked;
176
+ /** `checks` are the checker's diagnostics of `file`. */
159
177
  private getBindAndCheckDiagnostics;
160
178
  getIncludeProcessorDiagnostics(file: SourceFile): Diagnostic[];
161
179
  }
@@ -4,6 +4,7 @@ import { ModuleSpecifierHost } from './module-specifiers.js';
4
4
  import { sortAndDeduplicateDiagnostics } from './program.js';
5
5
  import { getEmitModuleFormatOfFile, getEmitSyntaxForUsageLocation, isCheckJsEnabledForFile, } from './program-utilities.js';
6
6
  import { bindSourceFile } from './binder.js';
7
+ import { checkSourceFileRange } from './checker-source-file.js';
7
8
  import { computeLineOfPosition } from './scanner.js';
8
9
  /** What the checker needs, answered by a program. */
9
10
  export class ProgramCheckerHost extends CheckerHost {
@@ -250,6 +251,37 @@ export class CheckedProgram {
250
251
  result.push(d);
251
252
  return result;
252
253
  }
254
+ /**
255
+ * Checks the statements `start` to `end` of the declaration file `file` with this checker, one of the
256
+ * ranges that several checkers check it in (`checkSourceFileRange`, parallel-check.ts), and returns
257
+ * whether the checker then has diagnostics in the file.
258
+ */
259
+ checkRange(file, start, end) {
260
+ return checkSourceFileRange(this.checker, file, start, end);
261
+ }
262
+ /**
263
+ * The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, where checkers checked it in
264
+ * ranges and found no diagnostics in it (`checkRange`).
265
+ */
266
+ unfilteredDiagnosticsOfCleanRanges(file) {
267
+ const result = this.getBindAndCheckDiagnostics(file, []);
268
+ for (const d of this.getIncludeProcessorDiagnostics(file))
269
+ result.push(d);
270
+ return result;
271
+ }
272
+ /**
273
+ * The diagnostics of `file`, as `unfilteredDiagnosticsOfFile` gives them, from a new checker that checks it
274
+ * whole: for a file checked in ranges that found diagnostics in it (parallel-check.ts), part of which this
275
+ * thread's checker may have checked.
276
+ */
277
+ unfilteredDiagnosticsOfFileOnNewChecker(file) {
278
+ const checker = this.createChecker();
279
+ const result = this.getBindAndCheckDiagnostics(file, checker.getDiagnostics(file));
280
+ disposeChecker(checker);
281
+ for (const d of this.getIncludeProcessorDiagnostics(file))
282
+ result.push(d);
283
+ return result;
284
+ }
253
285
  /**
254
286
  * The bind and check diagnostics of `file` before `noEmit` filtering and without include errors.
255
287
  * Once checker threads checked the program, they come from the threads' diagnostics of the file,
@@ -331,10 +363,11 @@ export class CheckedProgram {
331
363
  }
332
364
  return sortAndDeduplicateDiagnostics(result);
333
365
  }
334
- getBindAndCheckDiagnostics(file) {
366
+ /** `checks` are the checker's diagnostics of `file`. */
367
+ getBindAndCheckDiagnostics(file, checks) {
335
368
  const options = this.program.options;
336
369
  const diagnostics = file.bindDiagnostics.slice();
337
- for (const d of this.checker.getDiagnostics(file))
370
+ for (const d of checks ?? this.checker.getDiagnostics(file))
338
371
  diagnostics.push(d);
339
372
  if (isPlainJSFile(file, options)) {
340
373
  const result = [];
@@ -11,3 +11,13 @@ export declare function diagnosticOf(d: CompilerDiagnostic): Diagnostic;
11
11
  * them. Declaration diagnostics are empty, as tsgo's API returns them.
12
12
  */
13
13
  export declare function programDiagnostics(checked: CheckedProgram, kind: DiagnosticKind, file: SourceFile | undefined): readonly CompilerDiagnostic[];
14
+ /**
15
+ * What `semantic` answers for each of `files` and what `global` answers, after checking `files` and
16
+ * no other file. Checking one file can add diagnostics located in another, so every file is checked
17
+ * before any file's diagnostics are collected. With every file of the program listed, the answers are
18
+ * those of the full check.
19
+ */
20
+ export declare function checkedFileDiagnostics(checked: CheckedProgram, files: readonly SourceFile[]): {
21
+ files: (readonly CompilerDiagnostic[])[];
22
+ global: readonly CompilerDiagnostic[];
23
+ };
@@ -48,3 +48,23 @@ export function programDiagnostics(checked, kind, file) {
48
48
  return [];
49
49
  }
50
50
  }
51
+ /**
52
+ * What `semantic` answers for each of `files` and what `global` answers, after checking `files` and
53
+ * no other file. Checking one file can add diagnostics located in another, so every file is checked
54
+ * before any file's diagnostics are collected. With every file of the program listed, the answers are
55
+ * those of the full check.
56
+ */
57
+ export function checkedFileDiagnostics(checked, files) {
58
+ for (const file of files)
59
+ checked.getSemanticDiagnostics(file);
60
+ const program = checked.program;
61
+ const global = [
62
+ ...program.getConfigFileParsingDiagnostics(),
63
+ ...program.getProgramDiagnostics(),
64
+ ...checked.getGlobalDiagnostics(),
65
+ ];
66
+ return {
67
+ files: files.map((file) => checked.getSemanticDiagnostics(file)),
68
+ global: sortAndDeduplicateDiagnostics(global).filter((d) => d.file === undefined),
69
+ };
70
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsc-ts",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "The TypeScript 7 compiler, ported to TypeScript and compiled to a native executable.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -29,18 +29,18 @@
29
29
  "./package.json": "./package.json"
30
30
  },
31
31
  "dependencies": {
32
- "@scriptc/threads": "0.4.1"
32
+ "@scriptc/threads": "0.4.2"
33
33
  },
34
34
  "engines": {
35
35
  "node": ">=20"
36
36
  },
37
37
  "optionalDependencies": {
38
- "@tsc-ts/darwin-arm64": "0.0.7",
39
- "@tsc-ts/darwin-x64": "0.0.7",
40
- "@tsc-ts/linux-arm64-gnu": "0.0.7",
41
- "@tsc-ts/linux-arm64-musl": "0.0.7",
42
- "@tsc-ts/linux-x64-gnu": "0.0.7",
43
- "@tsc-ts/linux-x64-musl": "0.0.7",
44
- "@tsc-ts/win32-x64-msvc": "0.0.7"
38
+ "@tsc-ts/darwin-arm64": "0.0.9",
39
+ "@tsc-ts/darwin-x64": "0.0.9",
40
+ "@tsc-ts/linux-arm64-gnu": "0.0.9",
41
+ "@tsc-ts/linux-arm64-musl": "0.0.9",
42
+ "@tsc-ts/linux-x64-gnu": "0.0.9",
43
+ "@tsc-ts/linux-x64-musl": "0.0.9",
44
+ "@tsc-ts/win32-x64-msvc": "0.0.9"
45
45
  }
46
46
  }
@@ -37,7 +37,7 @@ import { getExportSymbolOfValueSymbolIfExported } from './checker-symbols.js';
37
37
  import { getBaseTypes, getDeclaredTypeOfSymbol } from './checker-declared-types.js';
38
38
  import { getPropertyOfType } from './checker-members.js';
39
39
  import { FunctionFlags, getFunctionFlags } from './checker-utilities.js';
40
- import { getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
40
+ import { declarationAt, declarationCount, type Symbol, SymbolFlags } from './symbol.js';
41
41
 
42
42
  /** Reports a block-scoped variable, class or enum resolved at `errorLocation` before its declaration. */
43
43
  export function checkResolvedBlockScopedVariable(c: Checker, resolved: Symbol, errorLocation: Node): void {
@@ -50,7 +50,8 @@ export function checkResolvedBlockScopedVariable(c: Checker, resolved: Symbol, e
50
50
  )
51
51
  return;
52
52
  let declaration: Node | undefined;
53
- for (const d of getDeclarations(result)) {
53
+ for (let i = 0; i < declarationCount(result); i++) {
54
+ const d = declarationAt(result, i);
54
55
  if (isBlockOrCatchScoped(d) || isClassLike(d) || d.kind === SyntaxKind.EnumDeclaration) {
55
56
  declaration = d;
56
57
  break;
@@ -87,7 +87,7 @@ import { getIndexedAccessType, isGenericMappedType } from './checker-type-operat
87
87
  import { getSignatureInstantiation } from './checker-signatures.js';
88
88
  import { evaluateEnumMember, EvaluatedFlags, EvaluatedKind } from './checker-evaluator.js';
89
89
  import { checkTypeAssignableTo, isTypeIdenticalTo } from './relations.js';
90
- import { getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
90
+ import { declarationAt, declarationCount, getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
91
91
 
92
92
  export { getParentOfSymbol };
93
93
 
@@ -877,9 +877,12 @@ export function getMinTypeArgumentCount(c: Checker, typeParameters: readonly Typ
877
877
 
878
878
  /** Whether a type parameter is declared with a default, without resolving it. */
879
879
  function hasTypeParameterDefault(t: Type): boolean {
880
- if (t.symbol === undefined) return false;
881
- for (const d of getDeclarations(t.symbol))
880
+ const symbol = t.symbol;
881
+ if (symbol === undefined) return false;
882
+ for (let i = 0; i < declarationCount(symbol); i++) {
883
+ const d = declarationAt(symbol, i);
882
884
  if (d.kind === SyntaxKind.TypeParameter && (d as TypeParameterDeclaration).defaultType !== undefined) return true;
885
+ }
883
886
  return false;
884
887
  }
885
888
 
@@ -32,7 +32,7 @@ import { entityNameToString } from './checker-expressions.js';
32
32
  import { isErrorType } from './checker-type-factory.js';
33
33
  import { getPropertyOfType } from './checker-members.js';
34
34
  import { signatureToString } from './type-printer.js';
35
- import { declarationCount, getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
35
+ import { declarationAt, declarationCount, getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
36
36
 
37
37
  /** Whether `declaration`, or the statement it belongs to, has a `@deprecated` JSDoc tag. */
38
38
  export function isDeprecatedDeclaration(declaration: Node): boolean {
@@ -56,25 +56,26 @@ function getJSDocDeprecatedTag(node: Node): Node | undefined {
56
56
  * members when all are.
57
57
  */
58
58
  export function isDeprecatedSymbol(c: Checker, symbol: Symbol): boolean {
59
- const declarations = getDeclarations(symbol);
59
+ const count = declarationCount(symbol);
60
60
  const parentSymbol = getParentOfSymbol(c, symbol);
61
- if (parentSymbol !== undefined && declarations.length > 1)
61
+ if (parentSymbol !== undefined && count > 1)
62
62
  return (parentSymbol.flags & SymbolFlags.Interface) !== 0
63
- ? someDeprecatedDeclaration(declarations)
64
- : everyDeprecatedDeclaration(declarations);
63
+ ? someDeprecatedDeclaration(symbol)
64
+ : everyDeprecatedDeclaration(symbol);
65
65
  return (
66
66
  (symbol.valueDeclaration !== undefined && isDeprecatedDeclaration(symbol.valueDeclaration)) ||
67
- (declarations.length !== 0 && everyDeprecatedDeclaration(declarations))
67
+ (count !== 0 && everyDeprecatedDeclaration(symbol))
68
68
  );
69
69
  }
70
70
 
71
- function someDeprecatedDeclaration(declarations: readonly Node[]): boolean {
72
- for (const d of declarations) if (isDeprecatedDeclaration(d)) return true;
71
+ function someDeprecatedDeclaration(symbol: Symbol): boolean {
72
+ for (let i = 0; i < declarationCount(symbol); i++) if (isDeprecatedDeclaration(declarationAt(symbol, i))) return true;
73
73
  return false;
74
74
  }
75
75
 
76
- function everyDeprecatedDeclaration(declarations: readonly Node[]): boolean {
77
- for (const d of declarations) if (!isDeprecatedDeclaration(d)) return false;
76
+ function everyDeprecatedDeclaration(symbol: Symbol): boolean {
77
+ for (let i = 0; i < declarationCount(symbol); i++)
78
+ if (!isDeprecatedDeclaration(declarationAt(symbol, i))) return false;
78
79
  return true;
79
80
  }
80
81
 
@@ -330,7 +331,8 @@ export function checkDeprecatedTypeReference(c: Checker, node: Node, type: Type)
330
331
  if (isErrorType(c, type)) return;
331
332
  const symbol = c.resolvedSymbols.get(node.id);
332
333
  if (symbol === undefined) return;
333
- for (const d of getDeclarations(symbol)) {
334
+ for (let i = 0; i < declarationCount(symbol); i++) {
335
+ const d = declarationAt(symbol, i);
334
336
  if (isTypeDeclaration(d) && isDeprecatedDeclaration(d)) {
335
337
  addDeprecatedSuggestion(c, getDeprecatedSuggestionNode(node), getDeclarations(symbol), symbol.name);
336
338
  return;
@@ -115,7 +115,15 @@ import { TypeFacts, getNonNullableType, getTypeWithFacts, hasTypeFacts } from '.
115
115
  import { sliceTupleType } from './checker-signatures.js';
116
116
  import { getPropertyNameFromType, isTypeUsableAsPropertyName, maybeTypeOfKind } from './checker-utilities.js';
117
117
  import { checkPropertyAccessibility } from './checker-property-access.js';
118
- import { CheckFlags, copyDeclarations, getDeclarations, getSymbolId, type Symbol, SymbolFlags } from './symbol.js';
118
+ import {
119
+ CheckFlags,
120
+ copyDeclarations,
121
+ declarationAt,
122
+ declarationCount,
123
+ getSymbolId,
124
+ type Symbol,
125
+ SymbolFlags,
126
+ } from './symbol.js';
119
127
 
120
128
  function isBindingPatternNode(node: Node | undefined): boolean {
121
129
  return (
@@ -766,7 +774,8 @@ export function isSpreadableProperty(prop: Symbol): boolean {
766
774
  (prop.flags & (SymbolFlags.Method | SymbolFlags.GetAccessor | SymbolFlags.SetAccessor)) === 0;
767
775
  let hasPrivateName = false;
768
776
  let inClass = false;
769
- for (const d of getDeclarations(prop)) {
777
+ for (let i = 0; i < declarationCount(prop); i++) {
778
+ const d = declarationAt(prop, i);
770
779
  if (isPrivateIdentifierClassElementDeclaration(d)) hasPrivateName = true;
771
780
  if (d.parent !== undefined && isClassLike(d.parent)) inClass = true;
772
781
  }
@@ -923,8 +923,12 @@ export function resolveDeclaredMembers(c: Checker, t: InterfaceType): InterfaceT
923
923
  const members = getMembersOfSymbol(c, t.symbol!);
924
924
  declared.declaredMembersResolved = true;
925
925
  declared.declaredMembers = members;
926
- declared.declaredCallSignatures = getSignaturesOfSymbol(c, members.get(InternalSymbolName.Call));
927
- declared.declaredConstructSignatures = getSignaturesOfSymbol(c, members.get(InternalSymbolName.New));
926
+ // Most interfaces declare neither, and share one empty list.
927
+ const call = members.get(InternalSymbolName.Call);
928
+ const construct = members.get(InternalSymbolName.New);
929
+ declared.declaredCallSignatures = call !== undefined ? getSignaturesOfSymbol(c, call) : emptySignatures;
930
+ declared.declaredConstructSignatures =
931
+ construct !== undefined ? getSignaturesOfSymbol(c, construct) : emptySignatures;
928
932
  declared.declaredIndexInfos = getIndexInfosOfSymbol(c, t.symbol!);
929
933
  }
930
934
  return declared;
@@ -161,6 +161,40 @@ function checkSourceFileWorker(c: Checker, file: SourceFile): void {
161
161
  links.deferredNodes = undefined;
162
162
  }
163
163
 
164
+ /**
165
+ * Checks the statements `start` to `end` of the declaration file `file`, one of the ranges that several
166
+ * checkers check it in (parallel-check.ts), and returns whether the checker then has diagnostics in the
167
+ * file. The range ending the file also runs the checks of the whole file. The file is not marked checked.
168
+ *
169
+ * When no range finds a diagnostic in the file, checking it whole would find none either: each statement
170
+ * is checked by the checker of its range. Otherwise the file is checked whole (`startParallelCheck`): the
171
+ * diagnostics of the ranges can differ from the file's, where they depend on the order the file's
172
+ * declarations are resolved in. A union type prints its members in the order the checker created them,
173
+ * and a check that a symbol's first declaration runs reports on all its declarations.
174
+ */
175
+ export function checkSourceFileRange(c: Checker, file: SourceFile, start: number, end: number): boolean {
176
+ const statements = getStatements(file)!.nodes;
177
+ c.fileBeingChecked = file;
178
+ c.saveDeferredDiagnostics = true;
179
+ for (let i = start; i < end; i++) checkSourceElement(c, statements[i]!);
180
+ checkDeferredNodes(c, file);
181
+ const whole = end === statements.length;
182
+ if (whole && isExternalOrCommonJSModule(file)) checkExternalModuleExports(c, file);
183
+ c.renamedBindingElementsInTypes.length = 0;
184
+ if (whole) {
185
+ checkGrammarSourceFile(c, file);
186
+ checkDeferredNodes(c, file);
187
+ checkPendingExternalEmitHelpers(c, file);
188
+ }
189
+ c.fileBeingChecked = undefined;
190
+ c.saveDeferredDiagnostics = false;
191
+ produceDeferredIterationErrors(c);
192
+ produceDeferredCollisionChecks(c);
193
+ // Deferred nodes of a later range are queued again (checkNodeDeferred).
194
+ c.nodeLinks(file).deferredNodes = undefined;
195
+ return c.diagnostics.forFile(file.fileName).length > 0;
196
+ }
197
+
164
198
  /** Checks a statement, declaration, class member or type node. */
165
199
  export function checkSourceElement(c: Checker, node: Node | undefined): void {
166
200
  if (node === undefined) return;
@@ -129,7 +129,16 @@ import { getTypeForBindingElement, getTypeFromBindingPattern } from './checker-d
129
129
  import { checkRightHandSideOfForOf } from './checker-statements.js';
130
130
  import { getTypeWithFacts, TypeFacts, hasTypeFacts, getNonNullableType } from './checker-flow.js';
131
131
  import { getTypeOfModuleExportsSymbol, getWidenedTypeForAssignmentDeclaration } from './checker-javascript.js';
132
- import { CheckFlags, copyDeclarations, getDeclarations, getSymbolId, type Symbol, SymbolFlags } from './symbol.js';
132
+ import {
133
+ CheckFlags,
134
+ copyDeclarations,
135
+ declarationAt,
136
+ declarationCount,
137
+ getDeclarations,
138
+ getSymbolId,
139
+ type Symbol,
140
+ SymbolFlags,
141
+ } from './symbol.js';
133
142
 
134
143
  export function getTypeOfSymbol(c: Checker, symbol: Symbol): Type {
135
144
  const checkFlags = symbol.checkFlags;
@@ -932,12 +941,13 @@ export function isReadonlySymbol(c: Checker, symbol: Symbol): boolean {
932
941
  (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Constant) !== 0) ||
933
942
  ((symbol.flags & SymbolFlags.Accessor) !== 0 && (symbol.flags & SymbolFlags.SetAccessor) === 0) ||
934
943
  (symbol.flags & SymbolFlags.EnumMember) !== 0 ||
935
- someReadonlyAssignmentDeclaration(c, getDeclarations(symbol))
944
+ someReadonlyAssignmentDeclaration(c, symbol)
936
945
  );
937
946
  }
938
947
 
939
- function someReadonlyAssignmentDeclaration(c: Checker, declarations: readonly Node[]): boolean {
940
- for (const d of declarations) if (isReadonlyAssignmentDeclaration(c, d)) return true;
948
+ function someReadonlyAssignmentDeclaration(c: Checker, symbol: Symbol): boolean {
949
+ for (let i = 0; i < declarationCount(symbol); i++)
950
+ if (isReadonlyAssignmentDeclaration(c, declarationAt(symbol, i))) return true;
941
951
  return false;
942
952
  }
943
953
 
@@ -957,6 +957,7 @@ export function setGlobal(c: Checker, name: string, symbol: Symbol): void {
957
957
  function setMergedSymbol(c: Checker, id: number, target: Symbol): void {
958
958
  if (c.mergedSymbolChanges !== undefined) c.mergedSymbolChanges.set(c.mergedSymbols, id, target);
959
959
  else c.mergedSymbols.set(id, target);
960
+ c.mergedSymbolIds.add(id);
960
961
  }
961
962
 
962
963
  /** Merges script locals into globals; ambient modules and augmentations wait for global types. */
@@ -1298,7 +1299,7 @@ function recordMergedSymbol(c: Checker, target: Symbol, source: Symbol): void {
1298
1299
 
1299
1300
  export function getMergedSymbol(c: Checker, symbol: Symbol): Symbol {
1300
1301
  const id = symbol.id;
1301
- if (id !== 0) {
1302
+ if (id !== 0 && c.mergedSymbolIds.has(id)) {
1302
1303
  const merged = c.mergedSymbols.get(id);
1303
1304
  if (merged !== undefined) return merged;
1304
1305
  }
@@ -1761,7 +1762,10 @@ export function symbolIsValue(c: Checker, symbol: Symbol): boolean {
1761
1762
  function isDeclarationContainedBy(symbol: Symbol, container: Symbol): boolean {
1762
1763
  const declaration = symbol.valueDeclaration;
1763
1764
  if (declaration !== undefined)
1764
- for (const d of getDeclarations(container)) if (declaration.pos >= d.pos && declaration.end <= d.end) return true;
1765
+ for (let i = 0; i < declarationCount(container); i++) {
1766
+ const d = declarationAt(container, i);
1767
+ if (declaration.pos >= d.pos && declaration.end <= d.end) return true;
1768
+ }
1765
1769
  return false;
1766
1770
  }
1767
1771