tsc-ts 0.1.0 → 0.1.2
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 +7 -1
- package/dist/api/compiler/ast.d.ts +15 -3
- package/dist/api/compiler/ast.js +36 -15
- package/dist/api/compiler/checker-classes.js +2 -1
- package/dist/api/compiler/checker-contextual.d.ts +20 -0
- package/dist/api/compiler/checker-contextual.js +111 -1
- package/dist/api/compiler/checker-expressions.js +14 -1
- package/dist/api/compiler/checker-grammar.d.ts +39 -4
- package/dist/api/compiler/checker-grammar.js +239 -75
- package/dist/api/compiler/checker-heritage.js +20 -14
- package/dist/api/compiler/checker-jsx.js +2 -1
- package/dist/api/compiler/checker-modules.js +4 -2
- package/dist/api/compiler/checker-source-file.js +1 -1
- package/dist/api/compiler/checker-type-factory.js +70 -19
- package/dist/api/compiler/checker-type-nodes.d.ts +1 -1
- package/dist/api/compiler/checker-type-nodes.js +5 -5
- package/dist/api/compiler/checker-unused.js +15 -10
- package/dist/api/compiler/checker.d.ts +7 -1
- package/dist/api/compiler/checker.js +14 -4
- package/dist/api/compiler/compile-program.d.ts +5 -0
- package/dist/api/compiler/compile-program.js +8 -0
- package/dist/api/compiler/expr-record.d.ts +11 -0
- package/dist/api/compiler/expr-record.js +53 -0
- package/dist/api/compiler/file-loader.d.ts +5 -0
- package/dist/api/compiler/file-loader.js +7 -0
- package/dist/api/compiler/identifier-name.d.ts +9 -0
- package/dist/api/compiler/identifier-name.js +10 -0
- package/dist/api/compiler/jsdoc.js +4 -2
- package/dist/api/compiler/parser.d.ts +2 -1
- package/dist/api/compiler/parser.js +10 -8
- package/dist/api/compiler/printer/factory.js +3 -2
- package/dist/api/compiler/printer/printer.js +3 -2
- package/dist/api/compiler/program-checker.d.ts +18 -0
- package/dist/api/compiler/program-checker.js +27 -0
- package/dist/api/compiler/reparser.js +4 -3
- package/dist/api/compiler/scanner.d.ts +8 -0
- package/dist/api/compiler/scanner.js +58 -42
- package/dist/api/compiler/shared-results.d.ts +376 -143
- package/dist/api/compiler/shared-results.js +1550 -773
- package/dist/api/compiler/transformers/declarations.js +2 -1
- package/package.json +15 -10
- package/src/compiler/ast.ts +39 -15
- package/src/compiler/cgroup.ts +157 -0
- package/src/compiler/checker-classes.ts +2 -1
- package/src/compiler/checker-contextual.ts +104 -0
- package/src/compiler/checker-expressions.ts +16 -1
- package/src/compiler/checker-grammar.ts +247 -88
- package/src/compiler/checker-heritage.ts +31 -17
- package/src/compiler/checker-jsx.ts +2 -1
- package/src/compiler/checker-modules.ts +4 -2
- package/src/compiler/checker-source-file.ts +1 -1
- package/src/compiler/checker-type-factory.ts +67 -21
- package/src/compiler/checker-type-nodes.ts +5 -5
- package/src/compiler/checker-unused.ts +13 -8
- package/src/compiler/checker.ts +15 -4
- package/src/compiler/compile-program.ts +8 -0
- package/src/compiler/decoder.ts +2 -1
- package/src/compiler/doctor-report.ts +133 -0
- package/src/compiler/expr-record.ts +59 -0
- package/src/compiler/file-loader.ts +8 -0
- package/src/compiler/identifier-name.ts +13 -0
- package/src/compiler/jsdoc.ts +4 -2
- package/src/compiler/parallel-check.ts +364 -146
- package/src/compiler/parallel-emit.ts +3 -3
- package/src/compiler/parse-thread.ts +24 -2
- package/src/compiler/parser.ts +10 -8
- package/src/compiler/printer/factory.ts +3 -2
- package/src/compiler/printer/printer.ts +4 -2
- package/src/compiler/program-checker.ts +28 -0
- package/src/compiler/reparser.ts +7 -3
- package/src/compiler/run-config.ts +1383 -0
- package/src/compiler/run-record-read.ts +87 -0
- package/src/compiler/run-records.ts +575 -0
- package/src/compiler/scanner.ts +57 -41
- package/src/compiler/shared-results.ts +1626 -896
- package/src/compiler/thread-entry.ts +3 -1
- package/src/compiler/transformers/declarations.ts +2 -1
- package/src/compiler/tsc-build.ts +64 -6
- package/src/compiler/tsc-cli.ts +33 -4
- package/src/compiler/tsc-compile.ts +223 -9
- package/src/compiler/tsc-watch.ts +25 -4
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ npx tsc-ts --noEmit src/index.ts
|
|
|
33
33
|
|
|
34
34
|
`tsc-ts --api` serves the TypeScript API over stdin and stdout, like `tsc --api`. On Windows, `--api --pipe \\.\pipe\<name>` serves it over a named pipe it creates, as `tsc --api --pipe` does, for clients that connect to the pipe (such as scriptc under Node.js); only the native executable supports `--pipe`. On macOS and Linux, `--api --listen <path>` serves it on a Unix socket it creates, with mode 0600, to one client of the same user at a time, each until the client closes its end. Each client gets the answers a new `tsc-ts --api` process would give, except that symbol ids continue from earlier clients, and the server reads every file through the client again, but it keeps parsed files between clients and reuses those whose text is unchanged, along with the encoding `getSourceFile` sends for each, so a client that opens the same project again loads it faster. The server exits when no client connects for 60 seconds (`--idle-exit <seconds>` sets the time), or after a client when its resident memory is above 2.5 times what it held after its first client (`TSC_TS_LISTEN_MEMORY` sets the limit in megabytes). To stop, it removes the socket file, serves the clients that had connected, and exits. It replaces a socket file that no server answers on, such as one left by a server that was killed. Only the native executable supports `--listen`. With `--default-libraries-from-disk`, the server reads the files in its default library directory (`TSC_TS_LIB_DIR`, or the executable's directory) from the disk itself, even when the client handles file system calls (`--callbacks`), which saves a round trip to the client for each library file.
|
|
35
35
|
|
|
36
|
-
`--checkers N` checks the program on N threads. Unless `--checkers` or `--singleThreaded` is given, the native executable uses one checker per CPU it may run on (up to 16), and at least tsgo's four; it uses fewer than the CPUs, but never fewer than four, when the estimated peak memory of more checkers would not fit 85% of the machine's memory (`TSC_TS_CHECKERS=fixed` keeps tsgo's four), and checkers beyond the fourth stop taking files, one at a time, when the process's memory reaches that share; it shares one program between its threads and also parses and binds the program's files on them. Unless `--singleThreaded` is given, the program's files are parsed and bound on threads also with `--checkers 1` and in the first build of `--watch`, with or without build info, as tsgo does. Files that share costly declarations, such as a large generated schema and the few files importing it, are checked together on one checker. Under Node.js, where every thread builds its own copy of the program, tsc-ts checks on one thread unless `--checkers` is given. `--incremental`, `--watch` and `--build` always check on one thread. The diagnostics are the same as with one checker.
|
|
36
|
+
`--checkers N` checks the program on N threads. Unless `--checkers` or `--singleThreaded` is given, the native executable uses one checker per CPU it may run on (up to 16), and at least tsgo's four; it uses fewer than the CPUs, but never fewer than four, when the estimated peak memory of more checkers would not fit 85% of the machine's memory (`TSC_TS_CHECKERS=fixed` keeps tsgo's four), and checkers beyond the fourth stop taking files, one at a time, when the process's memory reaches that share; it shares one program between its threads and also parses and binds the program's files on them. Unless `--singleThreaded` is given, the program's files are parsed and bound on threads also with `--checkers 1` and in the first build of `--watch`, with or without build info, as tsgo does. Files that share costly declarations, such as a large generated schema and the few files importing it, are checked together on one checker. The checker threads share the results they compute where the run expects that to pay: at 12 or more checkers, when 40% of the program's files are declarations or come from `node_modules` and the checkers' ranges mostly resolve the same large libraries. `TSC_TS_SHARE=1` turns sharing on for any program and `TSC_TS_SHARE=0` keeps it off, and a run whose sharing stops paying stops sharing its results as it goes. A sharing run may also bound how many results it posts at a time, which costs a few percent on a project that does not gain by it and saves more on one that does: the learned choice among a project's runs, off until its record shows it faster, and `TSC_TS_SHARE_BOUNDED=1` turns it on for any program while `TSC_TS_SHARE_BOUNDED=0` keeps it off. `TSC_TS_AUTO=0` keeps the choices of a run before automatic selection (fewer checkers where the ranges resolve large libraries, no sharing), and `TSC_TS_AUTO=static` keeps the rules and the in-run switches but reads and writes no records, and `TSC_TS_AUTO=explore` adds the experimental exploration described below. Unless `--singleThreaded` is given, the files are parsed on the CPUs the process may run on, but one, whatever the checker count, and `TSC_TS_PARSE_THREADS` sets how many. `--extendedDiagnostics` prints the checker threads, the sharing and the parse threads after the statistics table, under `Suggestions:`, with where each value came from (`pinned: --checkers`, `default`, `automatic: ...`, `learned: check 14% faster over 3 runs`, `exploring`, `control`) and how to pin it; `--build` prints one section per project it builds. The section also names the run's record under `Records:`. Each run that checks a program writes what it measured to `~/.cache/tsc-ts/runs-v1/` (`TSC_TS_CACHE_DIR` sets the directory, `TSC_TS_CACHE=0` turns records off), for later runs of the same project on the same machine to read. A later run chooses from that record where the rules left a setting open: a configuration the samples show faster than the static choice — by 3% or twice the standard error of the gains each of its samples makes against the nearest run of the other arm, on three samples of each taken while the machine was not busy — is adopted, every sixteenth run (and the first after two weeks) re-measures the static choice as a control run, and an adopted configuration whose last three samples all fall behind the control runs reverts at once. A run never tries a configuration that could make itself slower: it adopts only what the samples already show faster, from `tsc-ts doctor`, from a pinned run or from a run that already used it. `TSC_TS_AUTO=explore` turns on an experimental alternative in which a run also tries a setting the signals leave uncertain: one run in eight tries three quarters of the count where the library text puts it near the cut, sharing at eight checkers near the rule's limits, or half the parse threads, and such a run is slower than the configuration it would have used. A program whose shape changed by more than 15% discards the record's samples. Watch mode, a `--build` of several projects at once, `--singleThreaded`, Node builds and `TSC_TS_AUTO=0` or `static` keep no record, and the section says why; a run with `CI` set reads and adopts but never explores. `tsc-ts doctor [-p <tsconfig>] [--runs N] [--budget SECONDS] [--emit] [--json] [--no-save]` measures these settings on this machine: it runs the project's check under the default configuration, with sharing on, with up to 16 checkers, with both, and with half the parse threads, compares the phase times by the same rule automatic selection uses, and prints what it recommends with the evidence for it. Each measured run is a child process, so it runs as a user's run would, and it writes what it measured to the file named by `TSC_TS_DOCTOR_REPORT`; runs without the variable are unaffected. Doctor stores its samples in the record with role `doctor`, unless `--no-save` is given. The command is experimental: the configurations it compares and what it recommends may change. Under Node.js, where every thread builds its own copy of the program, tsc-ts checks on one thread unless `--checkers` is given. `--incremental`, `--watch` and `--build` always check on one thread. The diagnostics are the same as with one checker.
|
|
37
37
|
|
|
38
38
|
The native executable never frees syntax trees, types, signatures or symbols: it keeps them until it exits, which saves the cost of tracking them during a build. A one-shot build is unaffected, but a long-running process grows with each rebuild or project update. Native `--watch` (also with `--build`) runs in a child process, and when a change arrives while that process holds more than 2.5 times the memory it held after its first build, a new process replaces it and builds the change, reporting what the old process would have. `TSC_TS_WATCH_MEMORY` sets that limit in megabytes, and `TSC_TS_WATCH_MEMORY=0` turns the replacement off. A `--api` process grows with each project update; restart it to reclaim the memory.
|
|
39
39
|
|
|
@@ -84,3 +84,9 @@ The program's diagnostics, with their text and positions, are those `tsc --api`
|
|
|
84
84
|
An exception the compiler throws while answering a call reaches the caller as an `InternalCompilerError`, with the exception as its `cause`; the program's checker may be inconsistent after one, so dispose of the program. `program.dispose()` frees the program's checkers; calls on the program or its checker after it throw a `DisposedProgramError`.
|
|
85
85
|
|
|
86
86
|
The package has a JavaScript build with declaration files for Node.js, and the TypeScript sources of the API and the compiler (the `source` export condition) for compilers that build it from source. The sources compile with scriptc: a test builds a program on `tsc-ts/api` natively and checks that it answers as the Node build.
|
|
87
|
+
|
|
88
|
+
The API imports `@scriptc/threads`, an optional peer dependency that the command line doesn't use. Install it next to `tsc-ts` to use `tsc-ts/api`:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm install -D tsc-ts @scriptc/threads
|
|
92
|
+
```
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ProgramLifetime } from '@scriptc/types';
|
|
2
|
+
import { IdentifierName } from './identifier-name.js';
|
|
2
3
|
import { SyntaxKind } from './syntax-kind.js';
|
|
3
4
|
import { type CommentDirective, type CommentRange, type LanguageVariant, TokenFlags } from './types.js';
|
|
4
5
|
import { type Diagnostic, DiagnosticFile } from './diagnostics.js';
|
|
@@ -242,8 +243,9 @@ export declare class Token extends Node {
|
|
|
242
243
|
copy(): Token;
|
|
243
244
|
}
|
|
244
245
|
export declare class Identifier extends Node {
|
|
245
|
-
|
|
246
|
-
constructor(
|
|
246
|
+
readonly identifierName: IdentifierName;
|
|
247
|
+
constructor(name: IdentifierName);
|
|
248
|
+
get text(): string;
|
|
247
249
|
forEachChild(_v: NodeVisitor): boolean;
|
|
248
250
|
setParentOfChildren(): void;
|
|
249
251
|
deepClone(): Node;
|
|
@@ -256,7 +258,7 @@ export declare class Identifier extends Node {
|
|
|
256
258
|
*/
|
|
257
259
|
export declare class ReferenceIdentifier extends Identifier {
|
|
258
260
|
flowNode: FlowNode | undefined;
|
|
259
|
-
constructor(
|
|
261
|
+
constructor(name: IdentifierName);
|
|
260
262
|
copy(): Identifier;
|
|
261
263
|
}
|
|
262
264
|
export declare class PrivateIdentifier extends Node {
|
|
@@ -2325,6 +2327,12 @@ export declare class SourceFile extends Node {
|
|
|
2325
2327
|
patternAmbientModules: readonly PatternAmbientModule[];
|
|
2326
2328
|
/** UMD exports from `export as namespace N`. */
|
|
2327
2329
|
globalExports: SymbolTable | undefined;
|
|
2330
|
+
/** The diagnostics the parse thread's grammar walk reported for this file. */
|
|
2331
|
+
grammarDiagnostics: Diagnostic[] | undefined;
|
|
2332
|
+
/** The nodes of this file whose grammar check needs the checker, in tree order. */
|
|
2333
|
+
grammarResidualNodes: Node[] | undefined;
|
|
2334
|
+
/** The blocks and statements that reported a statement in an ambient context. */
|
|
2335
|
+
grammarAmbientReports: readonly number[];
|
|
2328
2336
|
constructor(fileName: string, path: string, text: string, externalModuleIndicatorOptions: ExternalModuleIndicatorOptions, statements: NodeList, endOfFileToken: Token);
|
|
2329
2337
|
forEachChild(v: NodeVisitor): boolean;
|
|
2330
2338
|
setParentOfChildren(): void;
|
|
@@ -2346,6 +2354,10 @@ export declare class PatternAmbientModule {
|
|
|
2346
2354
|
readonly text: string;
|
|
2347
2355
|
readonly starIndex: number;
|
|
2348
2356
|
readonly symbol: Symbol;
|
|
2357
|
+
/** The part of `text` before `starIndex`, kept so a match does not copy it. */
|
|
2358
|
+
readonly prefix: string;
|
|
2359
|
+
/** The part of `text` after `starIndex`, kept so a match does not copy it. */
|
|
2360
|
+
readonly suffix: string;
|
|
2349
2361
|
constructor(text: string, starIndex: number, symbol: Symbol);
|
|
2350
2362
|
matches(candidate: string): boolean;
|
|
2351
2363
|
}
|
package/dist/api/compiler/ast.js
CHANGED
|
@@ -52,9 +52,14 @@ export class NodeVisitor {
|
|
|
52
52
|
return this.visitList(list);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
// Native builds store `pos`, `end` and `id` as 32-bit integers when every write provably stores
|
|
56
|
-
// int32, so writes of values the compiler can't bound (parameters, the id counter) are
|
|
57
|
-
// with `| 0`; the values are always int32.
|
|
55
|
+
// Native builds store `pos`, `end` and `id` as 32-bit integers when every write provably stores
|
|
56
|
+
// an int32, so writes of values the compiler can't bound (parameters, the id counter) are
|
|
57
|
+
// coerced with `| 0`; the values are always int32.
|
|
58
|
+
//
|
|
59
|
+
// The fields of a node that the public API's node types declare are stored fields, not values
|
|
60
|
+
// computed from or packed into another field: a native build copies the stored fields of a node
|
|
61
|
+
// into a record when API code narrows one (`node as StringLiteralLike`), and a field behind an
|
|
62
|
+
// accessor is not copied.
|
|
58
63
|
export class Node {
|
|
59
64
|
kind;
|
|
60
65
|
flags;
|
|
@@ -221,10 +226,13 @@ export class Token extends Node {
|
|
|
221
226
|
}
|
|
222
227
|
}
|
|
223
228
|
export class Identifier extends Node {
|
|
224
|
-
|
|
225
|
-
constructor(
|
|
229
|
+
identifierName;
|
|
230
|
+
constructor(name) {
|
|
226
231
|
super(79 /* SyntaxKind.Identifier */);
|
|
227
|
-
this.
|
|
232
|
+
this.identifierName = name;
|
|
233
|
+
}
|
|
234
|
+
get text() {
|
|
235
|
+
return this.identifierName.text;
|
|
228
236
|
}
|
|
229
237
|
forEachChild(_v) {
|
|
230
238
|
return false;
|
|
@@ -234,7 +242,7 @@ export class Identifier extends Node {
|
|
|
234
242
|
return this.copy();
|
|
235
243
|
}
|
|
236
244
|
copy() {
|
|
237
|
-
const node = new Identifier(this.
|
|
245
|
+
const node = new Identifier(this.identifierName);
|
|
238
246
|
node.flags = this.flags;
|
|
239
247
|
node.pos = this.pos;
|
|
240
248
|
node.end = this.end;
|
|
@@ -249,12 +257,12 @@ export class Identifier extends Node {
|
|
|
249
257
|
export class ReferenceIdentifier extends Identifier {
|
|
250
258
|
// Set by the binder.
|
|
251
259
|
flowNode;
|
|
252
|
-
constructor(
|
|
253
|
-
super(
|
|
260
|
+
constructor(name) {
|
|
261
|
+
super(name);
|
|
254
262
|
this.flowNode = undefined;
|
|
255
263
|
}
|
|
256
264
|
copy() {
|
|
257
|
-
const node = new ReferenceIdentifier(this.
|
|
265
|
+
const node = new ReferenceIdentifier(this.identifierName);
|
|
258
266
|
node.flags = this.flags;
|
|
259
267
|
node.pos = this.pos;
|
|
260
268
|
node.end = this.end;
|
|
@@ -6623,6 +6631,7 @@ export const emptyCommentDirectives = [];
|
|
|
6623
6631
|
export const emptyPragmas = [];
|
|
6624
6632
|
export const emptyFileReferences = [];
|
|
6625
6633
|
export const emptyPatternAmbientModules = [];
|
|
6634
|
+
const emptyNumbers = [];
|
|
6626
6635
|
/** `list` with `item` appended: a new array when `list` is empty (it may be shared), else `list` itself. */
|
|
6627
6636
|
export function appendToList(list, item) {
|
|
6628
6637
|
if (list.length === 0)
|
|
@@ -6695,6 +6704,13 @@ export class SourceFile extends Node {
|
|
|
6695
6704
|
patternAmbientModules;
|
|
6696
6705
|
/** UMD exports from `export as namespace N`. */
|
|
6697
6706
|
globalExports;
|
|
6707
|
+
// Set by the grammar checks of a parse thread (checker-grammar.ts).
|
|
6708
|
+
/** The diagnostics the parse thread's grammar walk reported for this file. */
|
|
6709
|
+
grammarDiagnostics;
|
|
6710
|
+
/** The nodes of this file whose grammar check needs the checker, in tree order. */
|
|
6711
|
+
grammarResidualNodes;
|
|
6712
|
+
/** The blocks and statements that reported a statement in an ambient context. */
|
|
6713
|
+
grammarAmbientReports;
|
|
6698
6714
|
constructor(fileName, path, text, externalModuleIndicatorOptions, statements, endOfFileToken) {
|
|
6699
6715
|
super(308 /* SyntaxKind.SourceFile */);
|
|
6700
6716
|
this.fileName = fileName;
|
|
@@ -6741,6 +6757,9 @@ export class SourceFile extends Node {
|
|
|
6741
6757
|
this.symbolCount = 0;
|
|
6742
6758
|
this.patternAmbientModules = emptyPatternAmbientModules;
|
|
6743
6759
|
this.globalExports = undefined;
|
|
6760
|
+
this.grammarDiagnostics = undefined;
|
|
6761
|
+
this.grammarResidualNodes = undefined;
|
|
6762
|
+
this.grammarAmbientReports = emptyNumbers;
|
|
6744
6763
|
}
|
|
6745
6764
|
forEachChild(v) {
|
|
6746
6765
|
return v.visitList(this.statements) || v.visitNode(this.endOfFileToken);
|
|
@@ -6782,17 +6801,19 @@ export class PatternAmbientModule {
|
|
|
6782
6801
|
text;
|
|
6783
6802
|
starIndex;
|
|
6784
6803
|
symbol;
|
|
6804
|
+
/** The part of `text` before `starIndex`, kept so a match does not copy it. */
|
|
6805
|
+
prefix;
|
|
6806
|
+
/** The part of `text` after `starIndex`, kept so a match does not copy it. */
|
|
6807
|
+
suffix;
|
|
6785
6808
|
constructor(text, starIndex, symbol) {
|
|
6786
6809
|
this.text = text;
|
|
6787
6810
|
this.starIndex = starIndex;
|
|
6788
6811
|
this.symbol = symbol;
|
|
6812
|
+
this.prefix = text.substring(0, starIndex);
|
|
6813
|
+
this.suffix = text.substring(starIndex + 1);
|
|
6789
6814
|
}
|
|
6790
6815
|
matches(candidate) {
|
|
6791
|
-
|
|
6792
|
-
const star = this.starIndex;
|
|
6793
|
-
return (candidate.length >= text.length - 1 &&
|
|
6794
|
-
candidate.startsWith(text.substring(0, star)) &&
|
|
6795
|
-
candidate.endsWith(text.substring(star + 1)));
|
|
6816
|
+
return (candidate.length >= this.text.length - 1 && candidate.startsWith(this.prefix) && candidate.endsWith(this.suffix));
|
|
6796
6817
|
}
|
|
6797
6818
|
}
|
|
6798
6819
|
function containsNonASCII(text) {
|
|
@@ -28,6 +28,7 @@ import { checkFunctionOrConstructorSymbol, checkFunctionOrMethodSymbols } from '
|
|
|
28
28
|
import { checkClassHeritage, checkClassOrInterfaceForDuplicateIndexSignatures, checkInterfaceHeritage, } from './checker-heritage.js';
|
|
29
29
|
import { checkDecorators, getFirstTransformableStaticClassElement } from './checker-decorators.js';
|
|
30
30
|
import { getTypeOfNode } from './checker-services.js';
|
|
31
|
+
import { IdentifierName } from './identifier-name.js';
|
|
31
32
|
export function checkClassDeclaration(c, node) {
|
|
32
33
|
checkClassLikeDeclaration(c, node);
|
|
33
34
|
checkClassMembers(c, node);
|
|
@@ -464,7 +465,7 @@ function newThisPropertyReference(symbol, container, flowNode) {
|
|
|
464
465
|
if (name.startsWith('\ufffe#'))
|
|
465
466
|
accessName = new PrivateIdentifier(name.substring(name.indexOf('@') + 1));
|
|
466
467
|
else
|
|
467
|
-
accessName = new Identifier(name);
|
|
468
|
+
accessName = new Identifier(new IdentifierName(name));
|
|
468
469
|
const thisExpression = new KeywordExpression(109 /* SyntaxKind.ThisKeyword */);
|
|
469
470
|
const reference = new PropertyAccessExpression(thisExpression, undefined, accessName, 0 /* NodeFlags.None */);
|
|
470
471
|
thisExpression.parent = reference;
|
|
@@ -18,6 +18,26 @@ export declare function pushCachedContextualType(c: Checker, node: Node): void;
|
|
|
18
18
|
export declare function popContextualType(c: Checker): void;
|
|
19
19
|
/** The index of the contextual type pushed onto `node`, or -1. */
|
|
20
20
|
export declare function findContextualNode(c: Checker, node: Node, includeCaches: boolean): number;
|
|
21
|
+
/**
|
|
22
|
+
* The id of the contextual type in force for `node`, or -1 if the node's contextual type is not on
|
|
23
|
+
* the stack. A key built from -1 can't tell a check under a contextual type that was not pushed from
|
|
24
|
+
* a check with no contextual type, so callers record nothing under -1.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getContextualTypeId(c: Checker, node: Node): number;
|
|
27
|
+
/**
|
|
28
|
+
* Whether a check of `node` has no contextual type and no inference context, so its type is a
|
|
29
|
+
* function of the node and the check mode alone: the node is not on the contextual stack, no
|
|
30
|
+
* inference context contains it, and its parent gives it no contextual type. The parents answered
|
|
31
|
+
* here are the ones `getContextualTypeEx` returns `undefined` for without computing anything; a
|
|
32
|
+
* parent it computes a type for is not answered, so the result is never "yes" for a check that
|
|
33
|
+
* could have a contextual type.
|
|
34
|
+
*
|
|
35
|
+
* Types computed inside a flow loop are provisional (the checker does not cache them either), so a
|
|
36
|
+
* check in a loop is not context-free. The same holds while a reduce label is in force, as when
|
|
37
|
+
* flow analysis revisits a `finally` block with the antecedents of one outgoing path: the flow
|
|
38
|
+
* state differs from the one the earlier check of the block saw.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isCheckedWithoutContextualType(c: Checker, node: Node): boolean;
|
|
21
41
|
export declare function pushInferenceContext(c: Checker, node: Node, context: InferenceContext | undefined): void;
|
|
22
42
|
export declare function popInferenceContext(c: Checker): void;
|
|
23
43
|
/** The inference context of the innermost call argument containing `node`. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Contextual typing: the type an expression's position implies, and contextual signatures.
|
|
2
2
|
import { resolvedReturnTypeOf } from './side-state.js';
|
|
3
|
-
import { getInitializer, getName, getParameters, getType, getText, getSymbol, getTypeParameters, JsxAttribute, JsxElement, } from './ast.js';
|
|
3
|
+
import { getArguments, getInitializer, getName, getParameters, getType, getText, getSymbol, getTypeParameters, JsxAttribute, JsxElement, } from './ast.js';
|
|
4
4
|
import { getImmediatelyInvokedFunctionExpression, isFunctionExpressionOrArrowFunction, isObjectLiteralMethod, isStatic, } from './binder-utilities.js';
|
|
5
5
|
import { filterType, getIntersectionType, getNumberLiteralType, getRegularTypeOfLiteralType, getUnionType, getUnionTypeEx, getWidenedLiteralType, getEndElementCount, getStringLiteralType, getTypeArguments, getTypeReferenceArity, mapType, mapTypeEx, isTupleType, tupleTargetOf, typesOf, } from './checker-type-factory.js';
|
|
6
6
|
import { combineUnionOrIntersectionMemberSignatures, compareTypeParametersIdentical, findApplicableIndexInfo, getApparentType, getBaseConstraintOrType, getIndexInfosOfStructuredType, getPropertiesOfType, getPropertyOfType, getReducedType, getSignaturesOfType, } from './checker-members.js';
|
|
@@ -68,6 +68,116 @@ export function findContextualNode(c, node, includeCaches) {
|
|
|
68
68
|
return i;
|
|
69
69
|
return -1;
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* The id of the contextual type in force for `node`, or -1 if the node's contextual type is not on
|
|
73
|
+
* the stack. A key built from -1 can't tell a check under a contextual type that was not pushed from
|
|
74
|
+
* a check with no contextual type, so callers record nothing under -1.
|
|
75
|
+
*/
|
|
76
|
+
export function getContextualTypeId(c, node) {
|
|
77
|
+
const index = findContextualNode(c, node, true);
|
|
78
|
+
if (index < 0)
|
|
79
|
+
return -1;
|
|
80
|
+
const t = c.inferenceCaches.contextualTypes[index];
|
|
81
|
+
return t === undefined ? -1 : t.id;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Whether a check of `node` has no contextual type and no inference context, so its type is a
|
|
85
|
+
* function of the node and the check mode alone: the node is not on the contextual stack, no
|
|
86
|
+
* inference context contains it, and its parent gives it no contextual type. The parents answered
|
|
87
|
+
* here are the ones `getContextualTypeEx` returns `undefined` for without computing anything; a
|
|
88
|
+
* parent it computes a type for is not answered, so the result is never "yes" for a check that
|
|
89
|
+
* could have a contextual type.
|
|
90
|
+
*
|
|
91
|
+
* Types computed inside a flow loop are provisional (the checker does not cache them either), so a
|
|
92
|
+
* check in a loop is not context-free. The same holds while a reduce label is in force, as when
|
|
93
|
+
* flow analysis revisits a `finally` block with the antecedents of one outgoing path: the flow
|
|
94
|
+
* state differs from the one the earlier check of the block saw.
|
|
95
|
+
*/
|
|
96
|
+
export function isCheckedWithoutContextualType(c, node) {
|
|
97
|
+
if (c.flowLoopStack.length !== 0)
|
|
98
|
+
return false;
|
|
99
|
+
if (c.flowReduceLabels.length !== 0)
|
|
100
|
+
return false;
|
|
101
|
+
if (findContextualNode(c, node, true) >= 0)
|
|
102
|
+
return false;
|
|
103
|
+
if (getInferenceContext(c, node) !== undefined)
|
|
104
|
+
return false;
|
|
105
|
+
const parent = node.parent;
|
|
106
|
+
if (parent === undefined)
|
|
107
|
+
return true;
|
|
108
|
+
switch (parent.kind) {
|
|
109
|
+
case 262 /* SyntaxKind.VariableDeclaration */:
|
|
110
|
+
case 171 /* SyntaxKind.Parameter */:
|
|
111
|
+
case 174 /* SyntaxKind.PropertyDeclaration */:
|
|
112
|
+
case 173 /* SyntaxKind.PropertySignature */:
|
|
113
|
+
case 210 /* SyntaxKind.BindingElement */:
|
|
114
|
+
// Only the initializer is contextually typed by the declaration.
|
|
115
|
+
return getInitializer(parent) !== node;
|
|
116
|
+
case 215 /* SyntaxKind.CallExpression */:
|
|
117
|
+
case 216 /* SyntaxKind.NewExpression */: {
|
|
118
|
+
// Only the arguments are contextually typed by the parameters; the callee is not.
|
|
119
|
+
const args = getArguments(parent);
|
|
120
|
+
if (args !== undefined) {
|
|
121
|
+
for (const arg of args.nodes)
|
|
122
|
+
if (arg === node)
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
case 212 /* SyntaxKind.ObjectLiteralExpression */:
|
|
128
|
+
// Only a method takes the property's contextual type.
|
|
129
|
+
return node.kind !== 176 /* SyntaxKind.MethodDeclaration */;
|
|
130
|
+
case 228 /* SyntaxKind.BinaryExpression */: {
|
|
131
|
+
const binary = parent;
|
|
132
|
+
if (binary.type !== undefined)
|
|
133
|
+
return false;
|
|
134
|
+
switch (binary.operatorToken.kind) {
|
|
135
|
+
case 63 /* SyntaxKind.EqualsToken */:
|
|
136
|
+
case 76 /* SyntaxKind.AmpersandAmpersandEqualsToken */:
|
|
137
|
+
case 75 /* SyntaxKind.BarBarEqualsToken */:
|
|
138
|
+
case 77 /* SyntaxKind.QuestionQuestionEqualsToken */:
|
|
139
|
+
return node !== binary.right;
|
|
140
|
+
case 56 /* SyntaxKind.BarBarToken */:
|
|
141
|
+
case 60 /* SyntaxKind.QuestionQuestionToken */:
|
|
142
|
+
case 55 /* SyntaxKind.AmpersandAmpersandToken */:
|
|
143
|
+
case 27 /* SyntaxKind.CommaToken */:
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
case 229 /* SyntaxKind.ConditionalExpression */: {
|
|
149
|
+
const conditional = parent;
|
|
150
|
+
return node !== conditional.whenTrue && node !== conditional.whenFalse;
|
|
151
|
+
}
|
|
152
|
+
case 241 /* SyntaxKind.TemplateSpan */: {
|
|
153
|
+
// Only a tagged template types its spans.
|
|
154
|
+
const template = parent.parent;
|
|
155
|
+
return template.parent === undefined || template.parent.kind !== 217 /* SyntaxKind.TaggedTemplateExpression */;
|
|
156
|
+
}
|
|
157
|
+
case 221 /* SyntaxKind.ArrowFunction */:
|
|
158
|
+
case 255 /* SyntaxKind.ReturnStatement */:
|
|
159
|
+
case 231 /* SyntaxKind.YieldExpression */:
|
|
160
|
+
case 225 /* SyntaxKind.AwaitExpression */:
|
|
161
|
+
case 172 /* SyntaxKind.Decorator */:
|
|
162
|
+
case 236 /* SyntaxKind.AsExpression */:
|
|
163
|
+
case 218 /* SyntaxKind.TypeAssertionExpression */:
|
|
164
|
+
case 240 /* SyntaxKind.SatisfiesExpression */:
|
|
165
|
+
case 279 /* SyntaxKind.ExportAssignment */:
|
|
166
|
+
case 304 /* SyntaxKind.PropertyAssignment */:
|
|
167
|
+
case 305 /* SyntaxKind.ShorthandPropertyAssignment */:
|
|
168
|
+
case 306 /* SyntaxKind.SpreadAssignment */:
|
|
169
|
+
case 211 /* SyntaxKind.ArrayLiteralExpression */:
|
|
170
|
+
case 219 /* SyntaxKind.ParenthesizedExpression */:
|
|
171
|
+
case 237 /* SyntaxKind.NonNullExpression */:
|
|
172
|
+
case 296 /* SyntaxKind.JsxExpression */:
|
|
173
|
+
case 293 /* SyntaxKind.JsxAttribute */:
|
|
174
|
+
case 295 /* SyntaxKind.JsxSpreadAttribute */:
|
|
175
|
+
case 288 /* SyntaxKind.JsxOpeningElement */:
|
|
176
|
+
case 287 /* SyntaxKind.JsxSelfClosingElement */:
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
71
181
|
export function pushInferenceContext(c, node, context) {
|
|
72
182
|
const caches = c.inferenceCaches;
|
|
73
183
|
const depth = caches.inferenceDepth;
|
|
@@ -43,7 +43,7 @@ import { isFunctionLike, isImportCall, isInJSFile, isRequireCall } from './ast-u
|
|
|
43
43
|
import { isLiteralKind } from './printer/utilities.js';
|
|
44
44
|
import { convertAutoToAny, isEvolvingArrayOperationTarget, getAssignmentTargetKind, getControlFlowContainer, isConstantVariable, isInCompoundLikeAssignment, isMutableLocalVariableDeclaration, isParameterOrMutableLocalVariable, isPastLastAssignment, isSymbolAssignedDefinitely, getFlowTypeOfReference, getNarrowedTypeOfSymbol, } from './checker-narrowing.js';
|
|
45
45
|
import { getFlowTypeOfAutoTypedProperty, getThisTypeOfAssignedFunction } from './checker-javascript.js';
|
|
46
|
-
import { checkExpressionWithContextualType, getThisTypeOfObjectLiteralMember } from './checker-contextual.js';
|
|
46
|
+
import { checkExpressionWithContextualType, getThisTypeOfObjectLiteralMember, isCheckedWithoutContextualType, } from './checker-contextual.js';
|
|
47
47
|
import { getInferenceContext, instantiateContextualType, popContextualType, pushCachedContextualType, } from './checker-contextual.js';
|
|
48
48
|
import { addIntraExpressionInferenceSite, isConstTypeVariable } from './checker-inference.js';
|
|
49
49
|
import { isContextSensitiveFunctionOrObjectLiteralMethod } from './checker-contextual.js';
|
|
@@ -56,6 +56,17 @@ export function checkExpression(c, node) {
|
|
|
56
56
|
return checkExpressionEx(c, node, 0 /* CheckMode.Normal */);
|
|
57
57
|
}
|
|
58
58
|
export function checkExpressionEx(c, node, checkMode) {
|
|
59
|
+
// A completed check of this node under this mode answers this one when the check has no
|
|
60
|
+
// contextual type and no inference context: the checker's state only grew since, so this check
|
|
61
|
+
// would produce the type the completed one produced, report the diagnostics it reported and
|
|
62
|
+
// defer the nodes it deferred. Those diagnostics are equal to ones already reported and a node
|
|
63
|
+
// is deferred at most once, so serving the completed type changes neither.
|
|
64
|
+
const recordable = isCheckedWithoutContextualType(c, node);
|
|
65
|
+
if (recordable) {
|
|
66
|
+
const recorded = c.exprCheckRecord.get(node.id, checkMode);
|
|
67
|
+
if (recorded !== undefined)
|
|
68
|
+
return recorded;
|
|
69
|
+
}
|
|
59
70
|
const saveCurrentNode = c.currentNode;
|
|
60
71
|
c.currentNode = node;
|
|
61
72
|
c.instantiationCount = 0;
|
|
@@ -63,6 +74,8 @@ export function checkExpressionEx(c, node, checkMode) {
|
|
|
63
74
|
if (isConstEnumObjectTypeLocal(t))
|
|
64
75
|
checkConstEnumAccess(c, node, t);
|
|
65
76
|
c.currentNode = saveCurrentNode;
|
|
77
|
+
if (recordable)
|
|
78
|
+
c.exprCheckRecord.set(node.id, checkMode, t);
|
|
66
79
|
return t;
|
|
67
80
|
}
|
|
68
81
|
/**
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { type Node, type NodeList, NodeVisitor, type ObjectLiteralExpression, type SourceFile } from './ast.js';
|
|
2
2
|
import { type Checker } from './checker.js';
|
|
3
|
-
import {
|
|
3
|
+
import { Diagnostic, type DiagnosticMessage } from './diagnostics.js';
|
|
4
|
+
import { type CompilerOptions, ModuleKind } from './options.js';
|
|
4
5
|
import { SourceFileMetadata } from './program-utilities.js';
|
|
5
6
|
import { Scanner } from './scanner.js';
|
|
6
7
|
/** Runs the grammar checks of every node of `file`. */
|
|
7
8
|
export declare function checkGrammarSourceFile(c: Checker, file: SourceFile): void;
|
|
9
|
+
/**
|
|
10
|
+
* Runs the grammar checks of `file` in a parse thread, before the file is published: the checks that
|
|
11
|
+
* don't need the checker report now, and the nodes of those that do are kept for the checker, which
|
|
12
|
+
* runs them in the same tree order (`checkGrammarSourceFile`).
|
|
13
|
+
*/
|
|
14
|
+
export declare function checkGrammarSourceFileInParseThread(file: SourceFile, options: CompilerOptions, metadata: SourceFileMetadata): void;
|
|
8
15
|
/** Checks the grammar of an object literal each time it is checked, as tsgo does. */
|
|
9
16
|
export declare function checkGrammarObjectLiteralOfExpression(c: Checker, node: ObjectLiteralExpression, inDestructuring: boolean): void;
|
|
10
17
|
/** Reports a trailing comma after the rest element of a destructuring assignment. */
|
|
@@ -17,7 +24,10 @@ export declare function checkGrammarAwaitExpression(c: Checker, node: Node): voi
|
|
|
17
24
|
export declare function checkGrammarYieldOfExpression(c: Checker, node: Node): void;
|
|
18
25
|
/** Per-file state of the grammar walk. */
|
|
19
26
|
export declare class GrammarChecker extends NodeVisitor {
|
|
20
|
-
|
|
27
|
+
/** The checker of a walk in the checker thread; undefined for a walk in a parse thread. */
|
|
28
|
+
readonly c: Checker | undefined;
|
|
29
|
+
readonly compilerOptions: CompilerOptions;
|
|
30
|
+
readonly languageVersion: number;
|
|
21
31
|
readonly file: SourceFile;
|
|
22
32
|
/** Grammar errors are only reported in files without parse errors. */
|
|
23
33
|
readonly hasParseErrors: boolean;
|
|
@@ -25,10 +35,35 @@ export declare class GrammarChecker extends NodeVisitor {
|
|
|
25
35
|
readonly metadata: SourceFileMetadata;
|
|
26
36
|
readonly legacyDecorators: boolean;
|
|
27
37
|
/** Blocks and statements that already reported a statement in an ambient context. */
|
|
28
|
-
|
|
38
|
+
reportedAmbientStatements: Set<number>;
|
|
39
|
+
/**
|
|
40
|
+
* The IDs `reportedAmbientStatements` gained in a parse thread's walk, in the order it gained them, so
|
|
41
|
+
* that the reports of a node whose check the checker runs are undone without copying the set.
|
|
42
|
+
* Undefined in the checker thread, where no check is undone.
|
|
43
|
+
*/
|
|
44
|
+
private readonly ambientReportLog;
|
|
45
|
+
/**
|
|
46
|
+
* The diagnostics of a walk in a parse thread, which has no checker, for the checker to add to its
|
|
47
|
+
* collection; undefined in the checker thread, where they are reported as they are found.
|
|
48
|
+
*/
|
|
49
|
+
readonly diagnostics: Diagnostic[] | undefined;
|
|
50
|
+
/** The nodes of a parse thread's walk whose check needs the checker, in tree order. */
|
|
51
|
+
readonly residualNodes: Node[] | undefined;
|
|
52
|
+
/** Set when the check of a parse thread's walk needs the checker: the checker runs that node. */
|
|
53
|
+
needsChecker: boolean;
|
|
29
54
|
private scanner;
|
|
30
|
-
constructor(c: Checker, file: SourceFile
|
|
55
|
+
constructor(c: Checker | undefined, file: SourceFile, options?: CompilerOptions, metadata?: SourceFileMetadata,
|
|
56
|
+
/** `file.grammarAmbientReports`: what a parse thread's walk already reported. */
|
|
57
|
+
ambientReports?: readonly number[]);
|
|
31
58
|
visitNode(node: Node): boolean;
|
|
59
|
+
/** Records that `id` reported a statement in an ambient context. */
|
|
60
|
+
reportAmbientStatement(id: number): void;
|
|
61
|
+
/** Undoes the ambient-context reports added since the log had `mark` entries. */
|
|
62
|
+
private undoAmbientReports;
|
|
63
|
+
/** Reports an error at `node`, as `Checker.error`; returns the diagnostic. */
|
|
64
|
+
error(node: Node | undefined, message: DiagnosticMessage, ...args: string[]): Diagnostic;
|
|
65
|
+
/** Reports `diagnostic`, as `Checker.addDiagnostic`. */
|
|
66
|
+
report(diagnostic: Diagnostic): void;
|
|
32
67
|
/** A scanner over the file's text, for rescanning tokens. */
|
|
33
68
|
getScanner(): Scanner;
|
|
34
69
|
}
|