tsc-ts 0.0.8 → 0.0.10
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.
- package/README.md +1 -1
- package/dist/api/compiler/ast.d.ts +2 -0
- package/dist/api/compiler/ast.js +3 -0
- package/dist/api/compiler/checker-calls.js +5 -1
- package/dist/api/compiler/checker-grammar.js +3 -2
- package/dist/api/compiler/checker-inference.js +8 -2
- package/dist/api/compiler/checker-members.js +8 -3
- package/dist/api/compiler/checker-source-file.d.ts +12 -0
- package/dist/api/compiler/checker-source-file.js +35 -0
- package/dist/api/compiler/checker-symbols.js +2 -1
- package/dist/api/compiler/checker-type-factory.js +8 -2
- package/dist/api/compiler/checker.d.ts +17 -1
- package/dist/api/compiler/checker.js +49 -1
- package/dist/api/compiler/compile-program.d.ts +26 -2
- package/dist/api/compiler/compile-program.js +100 -7
- package/dist/api/compiler/diagnostics.d.ts +22 -0
- package/dist/api/compiler/diagnostics.js +86 -4
- package/dist/api/compiler/file-loader.d.ts +13 -3
- package/dist/api/compiler/file-loader.js +106 -30
- package/dist/api/compiler/link-tables.d.ts +7 -0
- package/dist/api/compiler/link-tables.js +22 -0
- package/dist/api/compiler/parallel-parse.d.ts +3 -2
- package/dist/api/compiler/parallel-parse.js +17 -5
- package/dist/api/compiler/parser.js +15 -14
- package/dist/api/compiler/printer/emit-context.d.ts +2 -0
- package/dist/api/compiler/printer/emit-context.js +4 -0
- package/dist/api/compiler/printer/printer.d.ts +48 -2
- package/dist/api/compiler/printer/printer.js +238 -14
- package/dist/api/compiler/program-checker.d.ts +22 -0
- package/dist/api/compiler/program-checker.js +39 -2
- package/dist/api/compiler/program.d.ts +2 -6
- package/dist/api/compiler/program.js +5 -30
- package/dist/api/compiler/relations.js +10 -0
- package/dist/api/compiler/symbol.d.ts +1 -1
- package/dist/api/compiler/symbol.js +8 -10
- package/dist/api/library/diagnostics.d.ts +10 -0
- package/dist/api/library/diagnostics.js +20 -0
- package/package.json +9 -9
- package/src/compiler/ast.ts +3 -0
- package/src/compiler/checker-calls.ts +3 -1
- package/src/compiler/checker-grammar.ts +3 -2
- package/src/compiler/checker-inference.ts +7 -2
- package/src/compiler/checker-members.ts +9 -3
- package/src/compiler/checker-source-file.ts +34 -0
- package/src/compiler/checker-symbols.ts +2 -1
- package/src/compiler/checker-type-factory.ts +4 -2
- package/src/compiler/checker.ts +45 -1
- package/src/compiler/compile-program.ts +121 -7
- package/src/compiler/diagnostics.ts +84 -3
- package/src/compiler/file-loader.ts +106 -29
- package/src/compiler/incremental.ts +80 -13
- package/src/compiler/link-tables.ts +32 -0
- package/src/compiler/parallel-check.ts +326 -62
- package/src/compiler/parallel-emit.ts +320 -0
- package/src/compiler/parallel-parse.ts +16 -5
- package/src/compiler/parse-thread.ts +3 -0
- package/src/compiler/parser.ts +15 -16
- package/src/compiler/printer/emit-context.ts +5 -0
- package/src/compiler/printer/printer.ts +231 -16
- package/src/compiler/program-checker.ts +40 -2
- package/src/compiler/program.ts +5 -25
- package/src/compiler/relations.ts +7 -0
- package/src/compiler/symbol.ts +15 -10
- package/src/compiler/thread-entry.ts +61 -3
- package/src/compiler/tsc-build.ts +63 -9
- package/src/compiler/tsc-cli.ts +5 -0
- package/src/compiler/tsc-compile.ts +278 -3
- package/src/library/diagnostics.ts +23 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* ```
|
|
8
8
|
*/
|
|
9
9
|
import { ArrayLiteralExpression, Decorator, getText, NodeVisitor, ObjectLiteralExpression, ParameterDeclaration, } from './ast.js';
|
|
10
|
-
import { compareDiagnostics, createCompilerDiagnostic, Diagnostic, equalDiagnostics, equalDiagnosticsNoRelatedInfo, useThreadTextCaches, } from './diagnostics.js';
|
|
10
|
+
import { compareDiagnostics, createCompilerDiagnostic, Diagnostic, equalDiagnostics, equalDiagnosticsNoRelatedInfo, sortDiagnostics, useThreadTextCaches, } from './diagnostics.js';
|
|
11
11
|
import { canReplaceFile, FileLoader, jsxRuntimeImportOf, modeAwareKey, needsImportHelpersImportSpecifier, withReplacedFile, } from './file-loader.js';
|
|
12
12
|
import { PackageJsonLookup } from './package-json.js';
|
|
13
13
|
import { ProcessingDiagnostic } from './file-include.js';
|
|
@@ -325,34 +325,9 @@ export class Program {
|
|
|
325
325
|
getResolvedModule(file, moduleName, mode) {
|
|
326
326
|
return this.processed.resolvedModules.get(file.path)?.get(modeAwareKey(moduleName, mode));
|
|
327
327
|
}
|
|
328
|
-
/** The
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
* files by file name, finds a file without computing its path when it is resolved by that name.
|
|
332
|
-
*/
|
|
333
|
-
getResolvedFilesOf(file, byFileName) {
|
|
334
|
-
const result = [];
|
|
335
|
-
const modules = this.processed.resolvedModules.get(file.path);
|
|
336
|
-
if (modules !== undefined)
|
|
337
|
-
for (const resolved of modules.values()) {
|
|
338
|
-
const name = resolved.resolvedFileName;
|
|
339
|
-
if (name === '')
|
|
340
|
-
continue;
|
|
341
|
-
const target = byFileName?.get(name) ?? this.getSourceFileForResolvedModule(name);
|
|
342
|
-
if (target !== undefined)
|
|
343
|
-
result.push(target);
|
|
344
|
-
}
|
|
345
|
-
const types = this.processed.typeResolutionsInFile.get(file.path);
|
|
346
|
-
if (types !== undefined)
|
|
347
|
-
for (const resolved of types.values()) {
|
|
348
|
-
const name = resolved.resolvedFileName;
|
|
349
|
-
if (name === '')
|
|
350
|
-
continue;
|
|
351
|
-
const target = byFileName?.get(name) ?? this.getSourceFile(name);
|
|
352
|
-
if (target !== undefined)
|
|
353
|
-
result.push(target);
|
|
354
|
-
}
|
|
355
|
-
return result;
|
|
328
|
+
/** The files each file added to the program (`ProcessedFiles.addedFiles`), as indices of `getSourceFiles`. */
|
|
329
|
+
addedFiles() {
|
|
330
|
+
return this.processed.addedFiles;
|
|
356
331
|
}
|
|
357
332
|
/** The specifier of the implicit JSX runtime import of `file`, if any. */
|
|
358
333
|
jsxRuntimeImportSpecifier(path) {
|
|
@@ -986,7 +961,7 @@ class NodeCollector extends NodeVisitor {
|
|
|
986
961
|
}
|
|
987
962
|
/** Sorts diagnostics and merges duplicates, combining their related information. */
|
|
988
963
|
export function sortAndDeduplicateDiagnostics(diagnostics) {
|
|
989
|
-
const sorted =
|
|
964
|
+
const sorted = sortDiagnostics(diagnostics);
|
|
990
965
|
if (sorted.length < 2)
|
|
991
966
|
return sorted;
|
|
992
967
|
const result = [];
|
|
@@ -232,6 +232,16 @@ export function isTypeRelatedTo(c, source, target, relation) {
|
|
|
232
232
|
if ((source.flags & 394239 /* TypeFlags.Singleton */) !== 0)
|
|
233
233
|
return true;
|
|
234
234
|
}
|
|
235
|
+
else {
|
|
236
|
+
// What the relater decides first for types that may simplify (Relater.isRelatedToEx): their normal forms are
|
|
237
|
+
// one type, or can be identical only with identical flags.
|
|
238
|
+
const s = getNormalizedType(c, source, false);
|
|
239
|
+
const t = getNormalizedType(c, target, true);
|
|
240
|
+
if (s === t)
|
|
241
|
+
return true;
|
|
242
|
+
if (s.flags !== t.flags)
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
235
245
|
if ((source.flags & 1048576 /* TypeFlags.Object */) !== 0 && (target.flags & 1048576 /* TypeFlags.Object */) !== 0) {
|
|
236
246
|
const related = relation.get(getRelationKey(c, source, target, 0 /* IntersectionState.None */, relation === c.identityRelation, false).key);
|
|
237
247
|
if (related !== 0 /* RelationComparisonResult.None */)
|
|
@@ -139,7 +139,7 @@ export declare class SymbolRareFields implements ProgramLifetime {
|
|
|
139
139
|
}
|
|
140
140
|
export declare class Symbol implements ProgramLifetime {
|
|
141
141
|
flags: SymbolFlags;
|
|
142
|
-
/** The check flags, and `
|
|
142
|
+
/** The check flags, and `SymbolBits.ValueDeclarationIsFirst`. */
|
|
143
143
|
private bits;
|
|
144
144
|
readonly name: string;
|
|
145
145
|
/**
|
|
@@ -8,11 +8,9 @@ export class SymbolRareFields {
|
|
|
8
8
|
/** The value declaration where it is not the first declaration (`Symbol.valueDeclaration`). */
|
|
9
9
|
valueDeclaration = undefined;
|
|
10
10
|
}
|
|
11
|
-
/** In `Symbol.bits`, above the check flags: the value declaration is the first declaration. */
|
|
12
|
-
const valueDeclarationIsFirst = 1 << 30;
|
|
13
11
|
export class Symbol {
|
|
14
12
|
flags;
|
|
15
|
-
/** The check flags, and `
|
|
13
|
+
/** The check flags, and `SymbolBits.ValueDeclarationIsFirst`. */
|
|
16
14
|
bits;
|
|
17
15
|
name;
|
|
18
16
|
/**
|
|
@@ -35,17 +33,17 @@ export class Symbol {
|
|
|
35
33
|
this.id = idsAtCreation ? takeSymbolId() : 0;
|
|
36
34
|
}
|
|
37
35
|
get checkFlags() {
|
|
38
|
-
return (this.bits & ~
|
|
36
|
+
return (this.bits & ~1073741824 /* SymbolBits.ValueDeclarationIsFirst */);
|
|
39
37
|
}
|
|
40
38
|
set checkFlags(flags) {
|
|
41
|
-
this.bits = (this.bits &
|
|
39
|
+
this.bits = (this.bits & 1073741824 /* SymbolBits.ValueDeclarationIsFirst */) | flags;
|
|
42
40
|
}
|
|
43
41
|
/** Makes `node` the first declaration, keeping the value declaration. */
|
|
44
42
|
setFirst(node) {
|
|
45
|
-
if ((this.bits &
|
|
43
|
+
if ((this.bits & 1073741824 /* SymbolBits.ValueDeclarationIsFirst */) !== 0 && node !== this.declaration) {
|
|
46
44
|
// The value declaration stays what it was.
|
|
47
45
|
this.rareFieldsOrNew().valueDeclaration = this.declaration;
|
|
48
|
-
this.bits &= ~
|
|
46
|
+
this.bits &= ~1073741824 /* SymbolBits.ValueDeclarationIsFirst */;
|
|
49
47
|
}
|
|
50
48
|
this.declaration = node;
|
|
51
49
|
}
|
|
@@ -54,7 +52,7 @@ export class Symbol {
|
|
|
54
52
|
* says; any other is kept in the rare fields.
|
|
55
53
|
*/
|
|
56
54
|
get valueDeclaration() {
|
|
57
|
-
if ((this.bits &
|
|
55
|
+
if ((this.bits & 1073741824 /* SymbolBits.ValueDeclarationIsFirst */) !== 0)
|
|
58
56
|
return this.declaration;
|
|
59
57
|
const group = this.rareFields;
|
|
60
58
|
return group === undefined ? undefined : group.valueDeclaration;
|
|
@@ -62,12 +60,12 @@ export class Symbol {
|
|
|
62
60
|
set valueDeclaration(node) {
|
|
63
61
|
const group = this.rareFields;
|
|
64
62
|
if (node !== undefined && node === this.declaration) {
|
|
65
|
-
this.bits |=
|
|
63
|
+
this.bits |= 1073741824 /* SymbolBits.ValueDeclarationIsFirst */;
|
|
66
64
|
if (group !== undefined)
|
|
67
65
|
group.valueDeclaration = undefined;
|
|
68
66
|
return;
|
|
69
67
|
}
|
|
70
|
-
this.bits &= ~
|
|
68
|
+
this.bits &= ~1073741824 /* SymbolBits.ValueDeclarationIsFirst */;
|
|
71
69
|
if (node !== undefined || group !== undefined)
|
|
72
70
|
this.rareFieldsOrNew().valueDeclaration = node;
|
|
73
71
|
}
|
|
@@ -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.
|
|
3
|
+
"version": "0.0.10",
|
|
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.
|
|
32
|
+
"@scriptc/threads": "0.4.5"
|
|
33
33
|
},
|
|
34
34
|
"engines": {
|
|
35
35
|
"node": ">=20"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@tsc-ts/darwin-arm64": "0.0.
|
|
39
|
-
"@tsc-ts/darwin-x64": "0.0.
|
|
40
|
-
"@tsc-ts/linux-arm64-gnu": "0.0.
|
|
41
|
-
"@tsc-ts/linux-arm64-musl": "0.0.
|
|
42
|
-
"@tsc-ts/linux-x64-gnu": "0.0.
|
|
43
|
-
"@tsc-ts/linux-x64-musl": "0.0.
|
|
44
|
-
"@tsc-ts/win32-x64-msvc": "0.0.
|
|
38
|
+
"@tsc-ts/darwin-arm64": "0.0.10",
|
|
39
|
+
"@tsc-ts/darwin-x64": "0.0.10",
|
|
40
|
+
"@tsc-ts/linux-arm64-gnu": "0.0.10",
|
|
41
|
+
"@tsc-ts/linux-arm64-musl": "0.0.10",
|
|
42
|
+
"@tsc-ts/linux-x64-gnu": "0.0.10",
|
|
43
|
+
"@tsc-ts/linux-x64-musl": "0.0.10",
|
|
44
|
+
"@tsc-ts/win32-x64-msvc": "0.0.10"
|
|
45
45
|
}
|
|
46
46
|
}
|
package/src/compiler/ast.ts
CHANGED
|
@@ -8258,6 +8258,8 @@ export class SourceFile extends Node {
|
|
|
8258
8258
|
identifierCount: number;
|
|
8259
8259
|
nodeCount: number;
|
|
8260
8260
|
textCount: number;
|
|
8261
|
+
/** The API's binary encoding of this file, when an API server keeps it (`keptEncodingOf`). */
|
|
8262
|
+
apiEncoding: Uint8Array | undefined;
|
|
8261
8263
|
/** Module specifiers of imports, exports, `require` calls and `import()` types, in source order. */
|
|
8262
8264
|
imports: Node[];
|
|
8263
8265
|
/** Names of `declare module "x"` augmentations and `declare global` blocks in modules. */
|
|
@@ -8325,6 +8327,7 @@ export class SourceFile extends Node {
|
|
|
8325
8327
|
this.identifierCount = 0;
|
|
8326
8328
|
this.nodeCount = 0;
|
|
8327
8329
|
this.textCount = 0;
|
|
8330
|
+
this.apiEncoding = undefined;
|
|
8328
8331
|
this.imports = [];
|
|
8329
8332
|
this.moduleAugmentations = emptyNodes;
|
|
8330
8333
|
this.ambientModuleNames = emptyStrings;
|
|
@@ -975,7 +975,9 @@ export function reorderCandidates(c: Checker, signatures: Signature[], callChain
|
|
|
975
975
|
cutoffIndex++;
|
|
976
976
|
} else spliceIndex = index;
|
|
977
977
|
if (callChainFlags !== 0) signature = getOptionalCallSignature(c, signature, callChainFlags);
|
|
978
|
-
|
|
978
|
+
// Most signatures go at the end, where a push is cheaper than an inserting splice.
|
|
979
|
+
if (spliceIndex === result.length) result.push(signature);
|
|
980
|
+
else result.splice(spliceIndex, 0, signature);
|
|
979
981
|
}
|
|
980
982
|
return result;
|
|
981
983
|
}
|
|
@@ -3143,7 +3143,8 @@ function checkGrammarObjectLiteralExpression(
|
|
|
3143
3143
|
node: ObjectLiteralExpression,
|
|
3144
3144
|
inDestructuring: boolean,
|
|
3145
3145
|
): boolean {
|
|
3146
|
-
|
|
3146
|
+
// An object literal with one property can't repeat a name, so it needs no table of names.
|
|
3147
|
+
const seen = node.properties.nodes.length > 1 ? new Map<string, DeclarationMeaning>() : undefined;
|
|
3147
3148
|
for (const property of node.properties.nodes) {
|
|
3148
3149
|
if (property.kind === SyntaxKind.SpreadAssignment) {
|
|
3149
3150
|
if (inDestructuring) {
|
|
@@ -3222,7 +3223,7 @@ function checkGrammarObjectLiteralExpression(
|
|
|
3222
3223
|
}
|
|
3223
3224
|
if (inDestructuring) continue;
|
|
3224
3225
|
const effectiveName = getEffectivePropertyNameForPropertyNameNode(g.c, name);
|
|
3225
|
-
if (effectiveName === undefined) continue;
|
|
3226
|
+
if (effectiveName === undefined || seen === undefined) continue;
|
|
3226
3227
|
const existingKind = seen.get(effectiveName);
|
|
3227
3228
|
if (existingKind === undefined) {
|
|
3228
3229
|
seen.set(effectiveName, currentKind);
|
|
@@ -733,8 +733,13 @@ class InferenceState {
|
|
|
733
733
|
// Keep candidates with the highest depth first.
|
|
734
734
|
index = 0;
|
|
735
735
|
while (index < inference.candidateDepths.length && inference.candidateDepths[index] >= this.depth) index++;
|
|
736
|
-
inference.candidates.
|
|
737
|
-
|
|
736
|
+
if (index === inference.candidates.length) {
|
|
737
|
+
inference.candidates.push(candidate);
|
|
738
|
+
inference.candidateDepths.push(this.depth);
|
|
739
|
+
} else {
|
|
740
|
+
inference.candidates.splice(index, 0, candidate);
|
|
741
|
+
inference.candidateDepths.splice(index, 0, this.depth);
|
|
742
|
+
}
|
|
738
743
|
clearCachedInferences(this.inferences);
|
|
739
744
|
}
|
|
740
745
|
}
|
|
@@ -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
|
-
|
|
927
|
-
|
|
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;
|
|
@@ -1570,7 +1574,9 @@ export function getPropertyOfTypeEx(
|
|
|
1570
1574
|
): Symbol | undefined {
|
|
1571
1575
|
if (!isOwnReducedApparentType(t)) t = getReducedApparentTypeWorker(c, t);
|
|
1572
1576
|
if ((t.flags & TypeFlags.Object) !== 0) {
|
|
1573
|
-
|
|
1577
|
+
// The first test of resolveStructuredTypeMembers, here where most lookups find the members resolved.
|
|
1578
|
+
const resolved =
|
|
1579
|
+
(t.objectFlags & ObjectFlags.MembersResolved) !== 0 ? (t as StructuredType) : resolveStructuredTypeMembers(c, t);
|
|
1574
1580
|
const symbol = getResolvedMember(resolved, name);
|
|
1575
1581
|
if (symbol !== undefined && includeTypeOnlyMembers) return symbol;
|
|
1576
1582
|
if (symbol !== undefined) {
|
|
@@ -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;
|
|
@@ -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
|
}
|
|
@@ -998,7 +998,8 @@ export function unionContainsSortedTypes(c: Checker, union: UnionType, types: re
|
|
|
998
998
|
export function insertType(c: Checker, types: Type[], t: Type): boolean {
|
|
999
999
|
const index = binarySearchTypes(c, types, t);
|
|
1000
1000
|
if (index >= 0) return false;
|
|
1001
|
-
|
|
1001
|
+
if (~index === types.length) types.push(t);
|
|
1002
|
+
else types.splice(~index, 0, t);
|
|
1002
1003
|
return true;
|
|
1003
1004
|
}
|
|
1004
1005
|
|
|
@@ -1214,7 +1215,8 @@ function insertTypeNearLast(c: Checker, set: TypeSet, t: Type): void {
|
|
|
1214
1215
|
if (r < 0) low = middle + 1;
|
|
1215
1216
|
else high = middle - 1;
|
|
1216
1217
|
}
|
|
1217
|
-
|
|
1218
|
+
if (low === types.length) types.push(t);
|
|
1219
|
+
else types.splice(low, 0, t);
|
|
1218
1220
|
set.last = low;
|
|
1219
1221
|
}
|
|
1220
1222
|
|
package/src/compiler/checker.ts
CHANGED
|
@@ -33,7 +33,7 @@ import type { DeferredCollisionCheck } from './checker-generated-code.js';
|
|
|
33
33
|
import type { EmitHelperFileLinks } from './checker-emit-helpers.js';
|
|
34
34
|
import { sideOf } from './side-state.js';
|
|
35
35
|
import type { Node, PatternAmbientModule, SourceFile } from './ast.js';
|
|
36
|
-
import { CompactSymbolLinkTable, IntLinkTable, LinkTable, SparseLinkTable } from './link-tables.js';
|
|
36
|
+
import { CompactSymbolLinkTable, IntLinkTable, LinkTable, PagedIdSet, SparseLinkTable } from './link-tables.js';
|
|
37
37
|
import { getErrorRangeForNode, getSourceFileOfNode } from './binder-utilities.js';
|
|
38
38
|
import { Diagnostic, type DiagnosticMessage, Diagnostics, compareDiagnostics } from './diagnostics.js';
|
|
39
39
|
import {
|
|
@@ -245,6 +245,30 @@ class DiagnosticCollection {
|
|
|
245
245
|
return this.global.slice();
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
/** The global diagnostics `withoutNewGlobals` removed. */
|
|
249
|
+
removedGlobals = 0;
|
|
250
|
+
|
|
251
|
+
/** Runs `run`, then removes the global diagnostics it added. */
|
|
252
|
+
withoutNewGlobals<T>(run: () => T): T {
|
|
253
|
+
const outer = this.log;
|
|
254
|
+
const added: Diagnostic[] = [];
|
|
255
|
+
this.log = added;
|
|
256
|
+
try {
|
|
257
|
+
return run();
|
|
258
|
+
} finally {
|
|
259
|
+
this.log = outer;
|
|
260
|
+
if (outer !== undefined) for (const d of added) outer.push(d);
|
|
261
|
+
const globals = new Set<Diagnostic>();
|
|
262
|
+
for (const d of added) if (d.file === undefined) globals.add(d);
|
|
263
|
+
if (globals.size > 0) {
|
|
264
|
+
this.removedGlobals += globals.size;
|
|
265
|
+
let kept = 0;
|
|
266
|
+
for (const d of this.global) if (!globals.has(d)) this.global[kept++] = d;
|
|
267
|
+
this.global.length = kept;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
248
272
|
/** Records the diagnostics added from now on. */
|
|
249
273
|
startLog(): void {
|
|
250
274
|
this.log = [];
|
|
@@ -402,6 +426,11 @@ export class Checker implements TypeChecking {
|
|
|
402
426
|
readonly resolvedSignatures = new SparseLinkTable<Signature>();
|
|
403
427
|
/** Merged symbols, indexed by the id of the symbol merged into them. */
|
|
404
428
|
readonly mergedSymbols: Map<number, Symbol>;
|
|
429
|
+
/**
|
|
430
|
+
* The ids that `mergedSymbols` has, or had: most symbols are merged into none, and `getMergedSymbol`
|
|
431
|
+
* finds that here without probing the map.
|
|
432
|
+
*/
|
|
433
|
+
readonly mergedSymbolIds = new PagedIdSet();
|
|
405
434
|
/** Globals merged from the default libraries, shared with other checkers. */
|
|
406
435
|
libGlobals: LibGlobals | undefined;
|
|
407
436
|
/** The program's globals and module augmentations as another checker merged them, shared with it. */
|
|
@@ -746,6 +775,7 @@ export class Checker implements TypeChecking {
|
|
|
746
775
|
this.globals = libs.copyGlobals();
|
|
747
776
|
this.mergedSymbols = libs.copyMergedSymbols();
|
|
748
777
|
}
|
|
778
|
+
for (const id of this.mergedSymbols.keys()) this.mergedSymbolIds.add(id);
|
|
749
779
|
this.globalThisSymbol = this.newSymbol(SymbolFlags.Module, 'globalThis');
|
|
750
780
|
this.globalThisSymbol.checkFlags = CheckFlags.Readonly;
|
|
751
781
|
this.globalThisSymbol.exports = this.globals;
|
|
@@ -934,6 +964,19 @@ export class Checker implements TypeChecking {
|
|
|
934
964
|
return this.diagnostics.globals();
|
|
935
965
|
}
|
|
936
966
|
|
|
967
|
+
/**
|
|
968
|
+
* Runs `run` (such as emitting declarations), then forgets the global diagnostics it reported:
|
|
969
|
+
* the program collects global diagnostics before it emits.
|
|
970
|
+
*/
|
|
971
|
+
withoutGlobalDiagnostics<T>(run: () => T): T {
|
|
972
|
+
return this.diagnostics.withoutNewGlobals(run);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
/** The global diagnostics `withoutGlobalDiagnostics` forgot so far. */
|
|
976
|
+
forgottenGlobalDiagnostics(): number {
|
|
977
|
+
return this.diagnostics.removedGlobals;
|
|
978
|
+
}
|
|
979
|
+
|
|
937
980
|
// ---- Links
|
|
938
981
|
|
|
939
982
|
/** The rarely used links of `symbol`, created on first use. */
|
|
@@ -1087,6 +1130,7 @@ export function disposeChecker(c: Checker): void {
|
|
|
1087
1130
|
c.mergedSymbols.clear();
|
|
1088
1131
|
c.globals.clear();
|
|
1089
1132
|
}
|
|
1133
|
+
c.mergedSymbolIds.clear();
|
|
1090
1134
|
c.sharedSymbolCopies.clear();
|
|
1091
1135
|
c.memberPositionsInLists.clear();
|
|
1092
1136
|
c.memberNamesOfLists.clear();
|
|
@@ -13,7 +13,11 @@ import { CheckerDeclarationEmitResolver, CheckerEmitResolver } from './checker-e
|
|
|
13
13
|
import { getEmitModuleFormatOfFile } from './program-utilities.js';
|
|
14
14
|
import { DeclarationGlobals, SyntacticDeclarationEmitResolver } from './transformers/declarations-syntactic.js';
|
|
15
15
|
import { mark } from './timeline.js';
|
|
16
|
-
import
|
|
16
|
+
import { DecoratorMetadata } from './transformers/decorator-metadata.js';
|
|
17
|
+
import { SyntaxFacts } from './transformers/syntax-facts.js';
|
|
18
|
+
import type { TypeReferenceSerializationKind } from './transformers/type-serialization.js';
|
|
19
|
+
import { EmitContext } from './printer/emit-context.js';
|
|
20
|
+
import { type EmitResolver, SyntacticEmitResolver } from './transformers/emit-resolver.js';
|
|
17
21
|
import { ModuleFormatHost } from './transformers/module.js';
|
|
18
22
|
import { type MergedGlobals, ModuleLookup, ReferenceResolver } from './transformers/reference-resolver.js';
|
|
19
23
|
|
|
@@ -193,6 +197,100 @@ export class EmitIndexes {
|
|
|
193
197
|
}
|
|
194
198
|
}
|
|
195
199
|
|
|
200
|
+
/**
|
|
201
|
+
* The JavaScript emit of a program's files without a checker, for emit threads (parallel-emit.ts).
|
|
202
|
+
* JavaScript emit asks the checker only how decorator metadata serializes a type
|
|
203
|
+
* (`CheckerEmitResolver`): with `kinds`, the answers the main thread's checker gave
|
|
204
|
+
* (`recordMetadataKinds`), else files with decorator metadata are emitted by a `ProgramEmitter`.
|
|
205
|
+
*/
|
|
206
|
+
export class JavaScriptEmitter {
|
|
207
|
+
private readonly host: ProgramEmitHost;
|
|
208
|
+
private readonly recorded: RecordedKindsEmitResolver | undefined;
|
|
209
|
+
|
|
210
|
+
constructor(program: Program, kinds: readonly number[] = []) {
|
|
211
|
+
const options = program.options;
|
|
212
|
+
const indexes = program.emitIndexes;
|
|
213
|
+
const references = new ReferenceResolver(
|
|
214
|
+
options,
|
|
215
|
+
program.getSourceFiles(),
|
|
216
|
+
new ProgramModules(program),
|
|
217
|
+
indexes !== undefined ? indexes.globals : undefined,
|
|
218
|
+
);
|
|
219
|
+
this.recorded = kinds.length > 0 ? new RecordedKindsEmitResolver(options, references, kinds) : undefined;
|
|
220
|
+
this.host = new ProgramEmitHost(program, this.recorded ?? new SyntacticEmitResolver(options, references));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Emits `file`, or returns undefined if its decorator metadata asked for a kind that wasn't recorded: what
|
|
225
|
+
* was written is then not the file's emit, and it must be emitted with the checker.
|
|
226
|
+
*/
|
|
227
|
+
emit(file: SourceFile, writer: OutputWriter): EmitResult | undefined {
|
|
228
|
+
const host = this.host;
|
|
229
|
+
const recorded = this.recorded;
|
|
230
|
+
if (recorded !== undefined) recorded.missed = false;
|
|
231
|
+
host.writer = writer;
|
|
232
|
+
const result = emitFiles(host, [file], EmitOnly.Js);
|
|
233
|
+
host.writer = undefined;
|
|
234
|
+
return recorded !== undefined && recorded.missed ? undefined : result;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* The serialization kinds of decorator metadata that the checker of `checked` gives the type references of
|
|
240
|
+
* `files`, in the order JavaScript emit asks for them: the type name's node id, the location's node id (-1 for
|
|
241
|
+
* none) and the kind, for each. Only the decorator metadata transform runs, as the first transform of emit.
|
|
242
|
+
*/
|
|
243
|
+
export function recordMetadataKinds(checked: CheckedProgram, files: readonly SourceFile[]): number[] {
|
|
244
|
+
const program = checked.program;
|
|
245
|
+
const options = program.options;
|
|
246
|
+
const indexes = program.emitIndexes;
|
|
247
|
+
const references = new ReferenceResolver(
|
|
248
|
+
options,
|
|
249
|
+
program.getSourceFiles(),
|
|
250
|
+
new ProgramModules(program),
|
|
251
|
+
indexes !== undefined ? indexes.globals : undefined,
|
|
252
|
+
);
|
|
253
|
+
const resolver = new RecordingEmitResolver(options, references, checked.checker);
|
|
254
|
+
for (const file of files)
|
|
255
|
+
new DecoratorMetadata(new EmitContext(), options, resolver, new SyntaxFacts()).transformSourceFile(file);
|
|
256
|
+
return resolver.kinds;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** A `CheckerEmitResolver` that records the serialization kinds it gives (`recordMetadataKinds`). */
|
|
260
|
+
class RecordingEmitResolver extends CheckerEmitResolver {
|
|
261
|
+
readonly kinds: number[] = [];
|
|
262
|
+
|
|
263
|
+
getTypeReferenceSerializationKind(typeName: Node, location: Node | undefined): TypeReferenceSerializationKind {
|
|
264
|
+
const kind = super.getTypeReferenceSerializationKind(typeName, location);
|
|
265
|
+
this.kinds.push(typeName.id, location === undefined ? -1 : location.id, kind);
|
|
266
|
+
return kind;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** Answers serialization kinds from those recorded on the main thread; `missed` once one wasn't. */
|
|
271
|
+
class RecordedKindsEmitResolver extends SyntacticEmitResolver {
|
|
272
|
+
/** The kind and location of each type name, by the type name's node id. */
|
|
273
|
+
private readonly byName = new Map<number, number>();
|
|
274
|
+
missed = false;
|
|
275
|
+
|
|
276
|
+
constructor(
|
|
277
|
+
options: CompilerOptions,
|
|
278
|
+
referenceResolver: ReferenceResolver,
|
|
279
|
+
private readonly kinds: readonly number[],
|
|
280
|
+
) {
|
|
281
|
+
super(options, referenceResolver);
|
|
282
|
+
for (let i = 0; i < kinds.length; i += 3) if (!this.byName.has(kinds[i]!)) this.byName.set(kinds[i]!, i);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
getTypeReferenceSerializationKind(typeName: Node, location: Node | undefined): TypeReferenceSerializationKind {
|
|
286
|
+
const at = this.byName.get(typeName.id);
|
|
287
|
+
if (at !== undefined && this.kinds[at + 1] === (location === undefined ? -1 : location.id))
|
|
288
|
+
return this.kinds[at + 2]! as TypeReferenceSerializationKind;
|
|
289
|
+
this.missed = true;
|
|
290
|
+
return super.getTypeReferenceSerializationKind(typeName, location);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
196
294
|
/** A checked program and the emit of its files. */
|
|
197
295
|
export class ProgramEmitter {
|
|
198
296
|
private host: ProgramEmitHost | undefined = undefined;
|
|
@@ -354,16 +452,25 @@ export class PlainProgram extends CompilerProgram {
|
|
|
354
452
|
const program = this.program;
|
|
355
453
|
const files = program.getSourceFiles();
|
|
356
454
|
const parallel = this.checked.emittedInParallel;
|
|
357
|
-
// Checker threads emitted the files they checked (parallel-check.ts)
|
|
455
|
+
// Checker threads emitted the files they checked (parallel-check.ts), or emit threads their JavaScript
|
|
456
|
+
// (parallel-emit.ts); the rest is emitted here, in order.
|
|
358
457
|
const result =
|
|
359
458
|
parallel === undefined
|
|
360
459
|
? this.emitter.emit(files, EmitOnly.All, writer)
|
|
361
460
|
: combineEmitResults(
|
|
362
461
|
files.map((file, i) => {
|
|
363
462
|
const emitted = parallel[i];
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
463
|
+
// The declaration thread emitted the declarations of the files it could (parallel-emit.ts).
|
|
464
|
+
const ahead = this.checked.declarationsEmittedAhead;
|
|
465
|
+
const declarations = (): EmitResult => ahead?.[i] ?? this.emitter.emit([file], EmitOnly.Dts, writer);
|
|
466
|
+
if (emitted === undefined)
|
|
467
|
+
return ahead !== undefined
|
|
468
|
+
? combineEmitResults([this.emitter.emit([file], EmitOnly.Js, writer), declarations()])
|
|
469
|
+
: this.emitter.emit([file], EmitOnly.All, writer);
|
|
470
|
+
const written = writeHeldOutputs(emitted, writer);
|
|
471
|
+
// Emit threads emit JavaScript only.
|
|
472
|
+
if (!this.checked.javaScriptEmittedOnThreads || !getEmitDeclarations(options)) return written;
|
|
473
|
+
return combineEmitResults([written, declarations()]);
|
|
367
474
|
}),
|
|
368
475
|
);
|
|
369
476
|
if (options.noEmit === true) {
|
|
@@ -390,9 +497,15 @@ export function handleNoEmitOnError(program: CompilerProgram): EmitResult | unde
|
|
|
390
497
|
|
|
391
498
|
/**
|
|
392
499
|
* Config and syntax errors; without syntax errors, program, global and semantic errors too, and
|
|
393
|
-
* declaration errors under `noEmit` (or `withDeclarationDiagnostics`).
|
|
500
|
+
* declaration errors under `noEmit` (or `withDeclarationDiagnostics`). With `declarationsLater`, the
|
|
501
|
+
* declaration errors are left to `program.emit`, which reports them under `noEmit` (without
|
|
502
|
+
* `noEmitOnError`) whether or not other errors were found.
|
|
394
503
|
*/
|
|
395
|
-
export function getDiagnosticsOfProgram(
|
|
504
|
+
export function getDiagnosticsOfProgram(
|
|
505
|
+
program: CompilerProgram,
|
|
506
|
+
withDeclarationDiagnostics: boolean,
|
|
507
|
+
declarationsLater: boolean = false,
|
|
508
|
+
): Diagnostic[] {
|
|
396
509
|
const result: Diagnostic[] = [...program.getConfigFileParsingDiagnostics()];
|
|
397
510
|
const configCount = result.length;
|
|
398
511
|
for (const d of program.getSyntacticDiagnostics()) result.push(d);
|
|
@@ -414,6 +527,7 @@ export function getDiagnosticsOfProgram(program: CompilerProgram, withDeclaratio
|
|
|
414
527
|
mark('semantic diagnostics');
|
|
415
528
|
}
|
|
416
529
|
if (
|
|
530
|
+
!declarationsLater &&
|
|
417
531
|
(withDeclarationDiagnostics || options.noEmit === true) &&
|
|
418
532
|
getEmitDeclarations(options) &&
|
|
419
533
|
result.length === configCount
|