tsc-ts 0.0.10 → 0.1.1
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/bin/tsc-ts.js +70 -1
- package/dist/api/compiler/ast-utilities.d.ts +19 -1
- package/dist/api/compiler/ast-utilities.js +180 -95
- package/dist/api/compiler/ast.d.ts +29 -18
- package/dist/api/compiler/ast.js +1040 -1007
- package/dist/api/compiler/astnav.js +15 -15
- package/dist/api/compiler/binder-utilities.js +186 -186
- package/dist/api/compiler/binder.js +290 -263
- package/dist/api/compiler/character-codes.js +2 -2
- package/dist/api/compiler/checker-calls.js +173 -123
- package/dist/api/compiler/checker-classes.d.ts +14 -3
- package/dist/api/compiler/checker-classes.js +136 -91
- package/dist/api/compiler/checker-contextual.d.ts +20 -0
- package/dist/api/compiler/checker-contextual.js +175 -62
- package/dist/api/compiler/checker-declaration-order.js +79 -79
- package/dist/api/compiler/checker-declarations.d.ts +1 -0
- package/dist/api/compiler/checker-declarations.js +160 -136
- package/dist/api/compiler/checker-declared-types.js +67 -65
- package/dist/api/compiler/checker-decorators.js +77 -77
- package/dist/api/compiler/checker-deprecation.d.ts +8 -3
- package/dist/api/compiler/checker-deprecation.js +76 -55
- package/dist/api/compiler/checker-destructuring.js +47 -45
- package/dist/api/compiler/checker-elaboration.js +24 -24
- package/dist/api/compiler/checker-emit-helpers.js +4 -4
- package/dist/api/compiler/checker-emit-resolver.d.ts +4 -2
- package/dist/api/compiler/checker-emit-resolver.js +25 -13
- package/dist/api/compiler/checker-evaluator.js +9 -9
- package/dist/api/compiler/checker-expressions.js +258 -212
- package/dist/api/compiler/checker-functions.js +113 -107
- package/dist/api/compiler/checker-generated-code.d.ts +0 -11
- package/dist/api/compiler/checker-generated-code.js +28 -52
- package/dist/api/compiler/checker-grammar.d.ts +1 -0
- package/dist/api/compiler/checker-grammar.js +469 -438
- package/dist/api/compiler/checker-heritage.js +91 -93
- package/dist/api/compiler/checker-inference.d.ts +77 -5
- package/dist/api/compiler/checker-inference.js +487 -113
- package/dist/api/compiler/checker-iteration.d.ts +0 -10
- package/dist/api/compiler/checker-iteration.js +35 -52
- package/dist/api/compiler/checker-javascript.js +14 -14
- package/dist/api/compiler/checker-jsdoc.d.ts +8 -10
- package/dist/api/compiler/checker-jsdoc.js +67 -58
- package/dist/api/compiler/checker-jsx.js +107 -89
- package/dist/api/compiler/checker-members.d.ts +9 -2
- package/dist/api/compiler/checker-members.js +210 -74
- package/dist/api/compiler/checker-modules.d.ts +15 -6
- package/dist/api/compiler/checker-modules.js +469 -309
- package/dist/api/compiler/checker-narrowing.js +273 -189
- package/dist/api/compiler/checker-object-literals.js +25 -22
- package/dist/api/compiler/checker-operators.js +126 -118
- package/dist/api/compiler/checker-overloads.js +27 -27
- package/dist/api/compiler/checker-property-access.js +59 -55
- package/dist/api/compiler/checker-services.d.ts +1 -0
- package/dist/api/compiler/checker-services.js +222 -210
- package/dist/api/compiler/checker-signatures.js +65 -49
- package/dist/api/compiler/checker-source-file.d.ts +5 -0
- package/dist/api/compiler/checker-source-file.js +154 -130
- package/dist/api/compiler/checker-statements.js +33 -32
- package/dist/api/compiler/checker-super.js +50 -50
- package/dist/api/compiler/checker-symbol-types.js +109 -93
- package/dist/api/compiler/checker-symbols.d.ts +13 -1
- package/dist/api/compiler/checker-symbols.js +264 -149
- package/dist/api/compiler/checker-type-factory.d.ts +5 -0
- package/dist/api/compiler/checker-type-factory.js +190 -46
- package/dist/api/compiler/checker-type-nodes.d.ts +1 -0
- package/dist/api/compiler/checker-type-nodes.js +179 -141
- package/dist/api/compiler/checker-type-operators.d.ts +2 -0
- package/dist/api/compiler/checker-type-operators.js +110 -63
- package/dist/api/compiler/checker-types.d.ts +80 -3
- package/dist/api/compiler/checker-types.js +121 -2
- package/dist/api/compiler/checker-unused.js +114 -118
- package/dist/api/compiler/checker-utilities.js +11 -11
- package/dist/api/compiler/checker.d.ts +97 -31
- package/dist/api/compiler/checker.js +149 -35
- package/dist/api/compiler/command-line.d.ts +1 -3
- package/dist/api/compiler/command-line.js +47 -44
- package/dist/api/compiler/compile-program.d.ts +24 -4
- package/dist/api/compiler/compile-program.js +53 -26
- package/dist/api/compiler/diagnostic-messages.d.ts +1849 -1774
- package/dist/api/compiler/diagnostic-messages.js +128 -122
- package/dist/api/compiler/diagnostics.js +7 -7
- package/dist/api/compiler/emitter.d.ts +7 -1
- package/dist/api/compiler/emitter.js +53 -11
- package/dist/api/compiler/expr-record.d.ts +11 -0
- package/dist/api/compiler/expr-record.js +53 -0
- package/dist/api/compiler/file-include.d.ts +2 -1
- package/dist/api/compiler/file-include.js +11 -7
- package/dist/api/compiler/file-loader.d.ts +10 -0
- package/dist/api/compiler/file-loader.js +138 -41
- package/dist/api/compiler/identifier-name.d.ts +9 -0
- package/dist/api/compiler/identifier-name.js +10 -0
- package/dist/api/compiler/instantiation.d.ts +7 -0
- package/dist/api/compiler/instantiation.js +101 -49
- package/dist/api/compiler/jsdoc.js +27 -25
- package/dist/api/compiler/link-tables.d.ts +48 -18
- package/dist/api/compiler/link-tables.js +80 -37
- package/dist/api/compiler/locales/cs-CZ.d.ts +1 -1
- package/dist/api/compiler/locales/cs-CZ.js +1 -1
- package/dist/api/compiler/locales/de-DE.d.ts +1 -1
- package/dist/api/compiler/locales/de-DE.js +1 -1
- package/dist/api/compiler/locales/es-ES.d.ts +1 -1
- package/dist/api/compiler/locales/es-ES.js +1 -1
- package/dist/api/compiler/locales/fr-FR.d.ts +1 -1
- package/dist/api/compiler/locales/fr-FR.js +1 -1
- package/dist/api/compiler/locales/it-IT.d.ts +1 -1
- package/dist/api/compiler/locales/it-IT.js +1 -1
- package/dist/api/compiler/locales/ja-JP.d.ts +1 -1
- package/dist/api/compiler/locales/ja-JP.js +1 -1
- package/dist/api/compiler/locales/ko-KR.d.ts +1 -1
- package/dist/api/compiler/locales/ko-KR.js +1 -1
- package/dist/api/compiler/locales/pl-PL.d.ts +1 -1
- package/dist/api/compiler/locales/pl-PL.js +1 -1
- package/dist/api/compiler/locales/pt-BR.d.ts +1 -1
- package/dist/api/compiler/locales/pt-BR.js +1 -1
- package/dist/api/compiler/locales/ru-RU.d.ts +1 -1
- package/dist/api/compiler/locales/ru-RU.js +1 -1
- package/dist/api/compiler/locales/tr-TR.d.ts +1 -1
- package/dist/api/compiler/locales/tr-TR.js +1 -1
- package/dist/api/compiler/locales/zh-CN.d.ts +1 -1
- package/dist/api/compiler/locales/zh-CN.js +1 -1
- package/dist/api/compiler/locales/zh-TW.d.ts +1 -1
- package/dist/api/compiler/locales/zh-TW.js +1 -1
- package/dist/api/compiler/module-resolution-types.js +6 -6
- package/dist/api/compiler/module-resolution.d.ts +10 -1
- package/dist/api/compiler/module-resolution.js +115 -84
- package/dist/api/compiler/module-specifiers.d.ts +15 -0
- package/dist/api/compiler/module-specifiers.js +24 -18
- package/dist/api/compiler/name-resolver.js +74 -65
- package/dist/api/compiler/node-builder-names.d.ts +11 -3
- package/dist/api/compiler/node-builder-names.js +210 -90
- package/dist/api/compiler/node-builder-pseudo.js +29 -31
- package/dist/api/compiler/node-builder-reuse.js +23 -22
- package/dist/api/compiler/node-builder.d.ts +18 -1
- package/dist/api/compiler/node-builder.js +191 -102
- package/dist/api/compiler/option-declarations.d.ts +2 -6
- package/dist/api/compiler/option-declarations.js +315 -375
- package/dist/api/compiler/options.d.ts +15 -33
- package/dist/api/compiler/options.js +21 -54
- package/dist/api/compiler/output-paths.d.ts +4 -1
- package/dist/api/compiler/output-paths.js +6 -11
- package/dist/api/compiler/package-json.d.ts +3 -3
- package/dist/api/compiler/package-json.js +11 -10
- package/dist/api/compiler/parser.d.ts +42 -20
- package/dist/api/compiler/parser.js +318 -224
- package/dist/api/compiler/path.d.ts +9 -0
- package/dist/api/compiler/path.js +20 -3
- package/dist/api/compiler/printer/emit-context.d.ts +3 -1
- package/dist/api/compiler/printer/emit-context.js +16 -1
- package/dist/api/compiler/printer/factory-base.d.ts +2 -2
- package/dist/api/compiler/printer/factory-base.js +7 -3
- package/dist/api/compiler/printer/factory.js +6 -3
- package/dist/api/compiler/printer/helpers.js +10 -1
- package/dist/api/compiler/printer/name-generator.d.ts +1 -1
- package/dist/api/compiler/printer/name-generator.js +35 -16
- package/dist/api/compiler/printer/printer.d.ts +1 -0
- package/dist/api/compiler/printer/printer.js +306 -283
- package/dist/api/compiler/printer/utilities.js +149 -147
- package/dist/api/compiler/program-checker.d.ts +8 -2
- package/dist/api/compiler/program-checker.js +84 -34
- package/dist/api/compiler/program-utilities.d.ts +3 -1
- package/dist/api/compiler/program-utilities.js +28 -15
- package/dist/api/compiler/program.d.ts +2 -0
- package/dist/api/compiler/program.js +69 -57
- package/dist/api/compiler/pseudo-bigint.d.ts +2 -0
- package/dist/api/compiler/pseudo-bigint.js +18 -0
- package/dist/api/compiler/regexp-checker.d.ts +1 -1
- package/dist/api/compiler/regexp-checker.js +93 -76
- package/dist/api/compiler/relations.d.ts +27 -4
- package/dist/api/compiler/relations.js +337 -180
- package/dist/api/compiler/reparser.js +64 -59
- package/dist/api/compiler/scanner.d.ts +27 -2
- package/dist/api/compiler/scanner.js +181 -150
- package/dist/api/compiler/shared-results.d.ts +696 -0
- package/dist/api/compiler/shared-results.js +2905 -0
- package/dist/api/compiler/sourcemap.js +2 -2
- package/dist/api/compiler/symbol-accessibility.js +87 -74
- package/dist/api/compiler/symbol.d.ts +22 -13
- package/dist/api/compiler/symbol.js +15 -1
- package/dist/api/compiler/syntax-kind.d.ts +198 -197
- package/dist/api/compiler/transformers/alias-references.js +247 -139
- package/dist/api/compiler/transformers/async-utilities.js +25 -25
- package/dist/api/compiler/transformers/async.d.ts +0 -1
- package/dist/api/compiler/transformers/async.js +64 -77
- package/dist/api/compiler/transformers/class-fields.d.ts +1 -0
- package/dist/api/compiler/transformers/class-fields.js +81 -78
- package/dist/api/compiler/transformers/commonjs-module.js +18 -15
- package/dist/api/compiler/transformers/const-enum-inliner.js +1 -1
- package/dist/api/compiler/transformers/declarations-diagnostics.js +247 -244
- package/dist/api/compiler/transformers/declarations-pseudo.js +100 -100
- package/dist/api/compiler/transformers/declarations-resolver.d.ts +0 -3
- package/dist/api/compiler/transformers/declarations-syntactic.d.ts +1 -2
- package/dist/api/compiler/transformers/declarations-syntactic.js +134 -156
- package/dist/api/compiler/transformers/declarations-tracker.js +18 -18
- package/dist/api/compiler/transformers/declarations.d.ts +4 -1
- package/dist/api/compiler/transformers/declarations.js +307 -239
- package/dist/api/compiler/transformers/decorator-metadata.d.ts +1 -1
- package/dist/api/compiler/transformers/decorator-metadata.js +53 -45
- package/dist/api/compiler/transformers/decorator-utilities.js +24 -24
- package/dist/api/compiler/transformers/destructuring.js +19 -18
- package/dist/api/compiler/transformers/emit-resolver.js +1 -1
- package/dist/api/compiler/transformers/es-decorators.js +55 -55
- package/dist/api/compiler/transformers/external-module-info.js +3 -3
- package/dist/api/compiler/transformers/for-await.js +25 -25
- package/dist/api/compiler/transformers/import-elision.js +14 -14
- package/dist/api/compiler/transformers/jsx.js +12 -12
- package/dist/api/compiler/transformers/legacy-decorators.js +17 -17
- package/dist/api/compiler/transformers/module.js +8 -8
- package/dist/api/compiler/transformers/named-evaluation.js +4 -4
- package/dist/api/compiler/transformers/object-rest-spread.js +20 -20
- package/dist/api/compiler/transformers/optional-chain.js +10 -10
- package/dist/api/compiler/transformers/reference-resolver.d.ts +12 -1
- package/dist/api/compiler/transformers/reference-resolver.js +131 -69
- package/dist/api/compiler/transformers/runtime-syntax.js +35 -31
- package/dist/api/compiler/transformers/subtree-facts.js +47 -47
- package/dist/api/compiler/transformers/syntax-facts.js +56 -58
- package/dist/api/compiler/transformers/type-eraser.js +73 -66
- package/dist/api/compiler/transformers/type-serialization.js +24 -24
- package/dist/api/compiler/transformers/using.js +12 -12
- package/dist/api/compiler/transformers/utilities.js +77 -77
- package/dist/api/compiler/transformers/visitor-base.js +172 -172
- package/dist/api/compiler/transformers/visitor-hooks.js +6 -2
- package/dist/api/compiler/tsconfig.d.ts +10 -2
- package/dist/api/compiler/tsconfig.js +136 -48
- package/dist/api/compiler/type-printer.js +40 -3
- package/dist/api/compiler/types.d.ts +2 -1
- package/dist/api/library/ast.generated.d.ts +42 -39
- package/dist/api/library/ast.generated.js +1 -1
- package/dist/api/library/compiler-options.generated.d.ts +111 -100
- package/dist/api/library/compiler-options.generated.js +1 -1
- package/dist/api/library/disk.js +12 -1
- package/dist/api/library/enums.generated.d.ts +206 -206
- package/dist/api/library/enums.generated.js +206 -206
- package/dist/api/library/nodes.js +26 -26
- package/package.json +9 -9
- package/src/compiler/ast-utilities.ts +99 -7
- package/src/compiler/ast.ts +74 -38
- package/src/compiler/binder.ts +39 -4
- package/src/compiler/cgroup.ts +157 -0
- package/src/compiler/character-codes.ts +2 -2
- package/src/compiler/checker-calls.ts +76 -8
- package/src/compiler/checker-classes.ts +80 -25
- package/src/compiler/checker-contextual.ts +110 -1
- package/src/compiler/checker-declarations.ts +31 -4
- package/src/compiler/checker-declared-types.ts +8 -5
- package/src/compiler/checker-decorators.ts +1 -1
- package/src/compiler/checker-deprecation.ts +29 -8
- package/src/compiler/checker-destructuring.ts +10 -3
- package/src/compiler/checker-emit-helpers.ts +1 -0
- package/src/compiler/checker-emit-resolver.ts +16 -6
- package/src/compiler/checker-expressions.ts +95 -47
- package/src/compiler/checker-functions.ts +21 -6
- package/src/compiler/checker-generated-code.ts +2 -22
- package/src/compiler/checker-grammar.ts +133 -60
- package/src/compiler/checker-heritage.ts +22 -21
- package/src/compiler/checker-inference.ts +514 -87
- package/src/compiler/checker-iteration.ts +18 -31
- package/src/compiler/checker-javascript.ts +1 -1
- package/src/compiler/checker-jsdoc.ts +50 -27
- package/src/compiler/checker-jsx.ts +28 -5
- package/src/compiler/checker-members.ts +197 -55
- package/src/compiler/checker-modules.ts +332 -65
- package/src/compiler/checker-narrowing.ts +98 -19
- package/src/compiler/checker-object-literals.ts +3 -0
- package/src/compiler/checker-operators.ts +11 -4
- package/src/compiler/checker-property-access.ts +7 -2
- package/src/compiler/checker-services.ts +39 -12
- package/src/compiler/checker-signatures.ts +15 -1
- package/src/compiler/checker-source-file.ts +39 -13
- package/src/compiler/checker-statements.ts +3 -2
- package/src/compiler/checker-symbol-types.ts +29 -6
- package/src/compiler/checker-symbols.ts +158 -15
- package/src/compiler/checker-type-factory.ts +173 -35
- package/src/compiler/checker-type-nodes.ts +46 -3
- package/src/compiler/checker-type-operators.ts +83 -26
- package/src/compiler/checker-types.ts +147 -4
- package/src/compiler/checker-unused.ts +9 -14
- package/src/compiler/checker.ts +175 -41
- package/src/compiler/command-line.ts +28 -28
- package/src/compiler/compile-program.ts +59 -25
- package/src/compiler/decoder.ts +15 -5
- package/src/compiler/diagnostic-messages.ts +1973 -1892
- package/src/compiler/doctor-report.ts +133 -0
- package/src/compiler/emitter.ts +57 -8
- package/src/compiler/encoder.ts +23 -8
- package/src/compiler/expr-record.ts +59 -0
- package/src/compiler/file-include.ts +9 -3
- package/src/compiler/file-loader.ts +139 -32
- package/src/compiler/help.ts +10 -14
- package/src/compiler/identifier-name.ts +13 -0
- package/src/compiler/incremental.ts +86 -18
- package/src/compiler/init.ts +2 -7
- package/src/compiler/instantiation.ts +77 -22
- package/src/compiler/jsdoc.ts +7 -3
- package/src/compiler/link-tables.ts +82 -37
- package/src/compiler/locales/cs-CZ.ts +1 -1
- package/src/compiler/locales/de-DE.ts +1 -1
- package/src/compiler/locales/es-ES.ts +1 -1
- package/src/compiler/locales/fr-FR.ts +1 -1
- package/src/compiler/locales/it-IT.ts +1 -1
- package/src/compiler/locales/ja-JP.ts +1 -1
- package/src/compiler/locales/ko-KR.ts +1 -1
- package/src/compiler/locales/pl-PL.ts +1 -1
- package/src/compiler/locales/pt-BR.ts +1 -1
- package/src/compiler/locales/ru-RU.ts +1 -1
- package/src/compiler/locales/tr-TR.ts +1 -1
- package/src/compiler/locales/zh-CN.ts +1 -1
- package/src/compiler/locales/zh-TW.ts +1 -1
- package/src/compiler/module-resolution.ts +44 -8
- package/src/compiler/module-specifiers.ts +62 -20
- package/src/compiler/name-resolver.ts +9 -1
- package/src/compiler/node-builder-names.ts +236 -54
- package/src/compiler/node-builder-pseudo.ts +4 -7
- package/src/compiler/node-builder-reuse.ts +5 -4
- package/src/compiler/node-builder.ts +130 -31
- package/src/compiler/option-declarations.ts +33 -103
- package/src/compiler/options.ts +23 -62
- package/src/compiler/output-paths.ts +5 -18
- package/src/compiler/package-entrypoints.ts +345 -0
- package/src/compiler/package-json.ts +4 -4
- package/src/compiler/parallel-check.ts +543 -147
- package/src/compiler/parallel-emit.ts +4 -4
- package/src/compiler/parser.ts +166 -47
- package/src/compiler/path.ts +22 -2
- package/src/compiler/printer/emit-context.ts +16 -0
- package/src/compiler/printer/factory-base.ts +10 -3
- package/src/compiler/printer/factory.ts +7 -3
- package/src/compiler/printer/helpers.ts +10 -1
- package/src/compiler/printer/name-generator.ts +24 -2
- package/src/compiler/printer/printer.ts +39 -16
- package/src/compiler/printer/utilities.ts +8 -2
- package/src/compiler/program-checker.ts +53 -5
- package/src/compiler/program-utilities.ts +23 -10
- package/src/compiler/program.ts +13 -1
- package/src/compiler/pseudo-bigint.ts +17 -0
- package/src/compiler/regexp-checker.ts +63 -30
- package/src/compiler/relations.ts +233 -77
- package/src/compiler/reparser.ts +14 -5
- 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 +166 -120
- package/src/compiler/shared-results.ts +3144 -0
- package/src/compiler/show-config.ts +18 -1
- package/src/compiler/sourcemap.ts +2 -2
- package/src/compiler/symbol-accessibility.ts +26 -3
- package/src/compiler/symbol.ts +31 -14
- package/src/compiler/syntax-kind.ts +188 -187
- package/src/compiler/thread-entry.ts +22 -3
- package/src/compiler/transformers/alias-references.ts +123 -4
- package/src/compiler/transformers/async.ts +2 -17
- package/src/compiler/transformers/class-fields.ts +13 -12
- package/src/compiler/transformers/commonjs-module.ts +11 -7
- package/src/compiler/transformers/declarations-diagnostics.ts +5 -3
- package/src/compiler/transformers/declarations-pseudo.ts +2 -4
- package/src/compiler/transformers/declarations-resolver.ts +0 -3
- package/src/compiler/transformers/declarations-syntactic.ts +1 -21
- package/src/compiler/transformers/declarations.ts +136 -49
- package/src/compiler/transformers/decorator-metadata.ts +9 -1
- package/src/compiler/transformers/destructuring.ts +4 -3
- package/src/compiler/transformers/external-module-info.ts +1 -1
- package/src/compiler/transformers/jsx.ts +2 -1
- package/src/compiler/transformers/reference-resolver.ts +83 -19
- package/src/compiler/transformers/runtime-syntax.ts +6 -1
- package/src/compiler/transformers/syntax-facts.ts +2 -7
- package/src/compiler/transformers/type-eraser.ts +10 -1
- package/src/compiler/transformers/type-serialization.ts +3 -2
- package/src/compiler/transformers/visitor-base.ts +2 -1
- package/src/compiler/transformers/visitor-hooks.ts +9 -4
- package/src/compiler/tsc-build.ts +67 -6
- package/src/compiler/tsc-cli.ts +35 -4
- package/src/compiler/tsc-compile.ts +220 -10
- package/src/compiler/tsc-watch.ts +97 -47
- package/src/compiler/tsconfig.ts +176 -19
- package/src/compiler/type-printer.ts +36 -2
- package/src/compiler/types.ts +2 -1
- package/src/library/ast.generated.ts +57 -41
- package/src/library/compiler-options.generated.ts +117 -103
- package/src/library/disk.ts +10 -1
- package/src/library/enums.generated.ts +196 -196
|
@@ -0,0 +1,2905 @@
|
|
|
1
|
+
// Results one checker thread computed, as records in its number log that other checker threads translate into their
|
|
2
|
+
// own types (TSC_TS_SHARE=1).
|
|
3
|
+
//
|
|
4
|
+
// A checker exports the result of a declaration-level computation (the value type of a variable or property, or the
|
|
5
|
+
// return type of a declared signature) as records: each type the result reaches through its identity (constituents,
|
|
6
|
+
// type arguments, alias arguments, instantiation arguments, and the parts of index, indexed access, conditional,
|
|
7
|
+
// template, string mapping and substitution types), down to types every checker can get by itself (intrinsic types,
|
|
8
|
+
// declared types of symbols, types of declarations and type nodes). Another checker translates the records through
|
|
9
|
+
// its own interning caches, so each type still has one object in it.
|
|
10
|
+
import { getSymbol, getType, NodeVisitor } from './ast.js';
|
|
11
|
+
import { getSourceFileOfNode } from './binder-utilities.js';
|
|
12
|
+
import { getDeclaredTypeOfSymbol } from './checker-declared-types.js';
|
|
13
|
+
import { TupleElementInfo, TypeAlias, getMappedType, IndexInfo, newTypeMapper, } from './checker-types.js';
|
|
14
|
+
import { createTypeReference, getBigIntLiteralType, getFreshTypeOfLiteralType, getNumberLiteralType, getStringLiteralType, getTemplateLiteralType, getTupleTargetType, getUnionTypeFromSortedList, newIntersectionType, newObjectType, newUnionType, setStructuredTypeMembers, getPropagatingFlagsOfTypes, typeListHash, } from './checker-type-factory.js';
|
|
15
|
+
import { distributedKey, getConditionalTypeInstantiation, getIndexTypeEx, getIndexedAccessTypeEx, getNoInferType, getStringMappingType, getSubstitutionType, isNoInferType, } from './checker-type-operators.js';
|
|
16
|
+
import { getESSymbolLikeTypeForNode, getTypeFromTypeNode } from './checker-type-nodes.js';
|
|
17
|
+
import { instantiateTypeWithAlias } from './instantiation.js';
|
|
18
|
+
import { resolvedReturnTypeOf, sideOf } from './side-state.js';
|
|
19
|
+
import { getDeclarations, getSymbolId, setDeclarations } from './symbol.js';
|
|
20
|
+
import { keepPropertiesOnly, scannedLiteralPropertiesLimit } from './checker-members.js';
|
|
21
|
+
import { findResolutionCycleStartIndex } from './checker-symbols.js';
|
|
22
|
+
import { typeToString } from './type-printer.js';
|
|
23
|
+
import { getTypeOfSymbol } from './checker-symbol-types.js';
|
|
24
|
+
import { getReturnTypeOfSignature } from './checker-signatures.js';
|
|
25
|
+
import { LinkTable } from './link-tables.js';
|
|
26
|
+
// Functions, classes, enums and modules have anonymous types that are cheap to create; their members are not. (A
|
|
27
|
+
// function: a top-level constant computed from an enum member of a module in an import cycle doesn't compile natively.)
|
|
28
|
+
function sharedValueFlags() {
|
|
29
|
+
return 3 /* SymbolFlags.Variable */ | 4 /* SymbolFlags.Property */;
|
|
30
|
+
}
|
|
31
|
+
const noRefs = [];
|
|
32
|
+
/**
|
|
33
|
+
* Writes records into a checker's store: int32 words at a cursor, strings into its string log, and each record's
|
|
34
|
+
* offset in its record table. The cursor is the writer's alone until it publishes a result.
|
|
35
|
+
*/
|
|
36
|
+
export class StoreWriter {
|
|
37
|
+
numbers;
|
|
38
|
+
strings;
|
|
39
|
+
table;
|
|
40
|
+
fileIndex;
|
|
41
|
+
/** The cursor in the number log, and in the string log. */
|
|
42
|
+
at = 0;
|
|
43
|
+
unitAt = 0;
|
|
44
|
+
/** Set when a record or a field didn't fit the store's configured capacity. */
|
|
45
|
+
full = false;
|
|
46
|
+
constructor(numbers, strings, table, fileIndex) {
|
|
47
|
+
this.numbers = numbers;
|
|
48
|
+
this.strings = strings;
|
|
49
|
+
this.table = table;
|
|
50
|
+
this.fileIndex = fileIndex;
|
|
51
|
+
}
|
|
52
|
+
/** Returns to the cursors `at` and `unitAt`. */
|
|
53
|
+
reset(at, unitAt) {
|
|
54
|
+
this.at = at;
|
|
55
|
+
this.unitAt = unitAt;
|
|
56
|
+
this.full = false;
|
|
57
|
+
}
|
|
58
|
+
/** Starts record `index` at the cursor: its header, and its offset in the record table. */
|
|
59
|
+
beginRecord(index, header) {
|
|
60
|
+
if (index < this.table.length)
|
|
61
|
+
this.table[index] = this.at + 1;
|
|
62
|
+
else
|
|
63
|
+
this.full = true;
|
|
64
|
+
this.word(header);
|
|
65
|
+
}
|
|
66
|
+
word(value) {
|
|
67
|
+
if (this.at < this.numbers.length)
|
|
68
|
+
this.numbers[this.at] = value;
|
|
69
|
+
else
|
|
70
|
+
this.full = true;
|
|
71
|
+
this.at++;
|
|
72
|
+
}
|
|
73
|
+
/** A double as the two int32 halves of its bits. */
|
|
74
|
+
double(value) {
|
|
75
|
+
const words = doubleWords();
|
|
76
|
+
words.f[0] = value;
|
|
77
|
+
this.word(words.i[0]);
|
|
78
|
+
this.word(words.i[1]);
|
|
79
|
+
}
|
|
80
|
+
/** A string as its offset and length in the string log. */
|
|
81
|
+
text(value) {
|
|
82
|
+
const length = value.length;
|
|
83
|
+
if (this.unitAt + length <= this.strings.length) {
|
|
84
|
+
this.word(this.unitAt);
|
|
85
|
+
this.word(length);
|
|
86
|
+
for (let j = 0; j < length; j++)
|
|
87
|
+
this.strings[this.unitAt++] = value.charCodeAt(j);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
this.full = true;
|
|
91
|
+
this.word(0);
|
|
92
|
+
this.word(0);
|
|
93
|
+
}
|
|
94
|
+
/** A node as its file, range and id, or -1 for none. The file must be one `fileIndex` has. */
|
|
95
|
+
node(node) {
|
|
96
|
+
if (node === undefined) {
|
|
97
|
+
this.word(-1);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
this.word(this.fileIndex.get(getSourceFileOfNode(node)));
|
|
101
|
+
this.word(node.pos);
|
|
102
|
+
this.word(node.end);
|
|
103
|
+
this.word(node.id);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** The types every checker creates when it starts, in the same order; marker types are left out. */
|
|
107
|
+
export function initialTypes(c) {
|
|
108
|
+
return [
|
|
109
|
+
c.anyType,
|
|
110
|
+
c.autoType,
|
|
111
|
+
c.wildcardType,
|
|
112
|
+
c.blockedStringType,
|
|
113
|
+
c.errorType,
|
|
114
|
+
c.unresolvedType,
|
|
115
|
+
c.nonInferrableAnyType,
|
|
116
|
+
c.intrinsicMarkerType,
|
|
117
|
+
c.unknownType,
|
|
118
|
+
c.undefinedType,
|
|
119
|
+
c.undefinedWideningType,
|
|
120
|
+
c.missingType,
|
|
121
|
+
c.undefinedOrMissingType,
|
|
122
|
+
c.optionalType,
|
|
123
|
+
c.nullType,
|
|
124
|
+
c.nullWideningType,
|
|
125
|
+
c.stringType,
|
|
126
|
+
c.numberType,
|
|
127
|
+
c.bigintType,
|
|
128
|
+
c.regularFalseType,
|
|
129
|
+
c.falseType,
|
|
130
|
+
c.regularTrueType,
|
|
131
|
+
c.trueType,
|
|
132
|
+
c.booleanType,
|
|
133
|
+
c.esSymbolType,
|
|
134
|
+
c.voidType,
|
|
135
|
+
c.neverType,
|
|
136
|
+
c.silentNeverType,
|
|
137
|
+
c.implicitNeverType,
|
|
138
|
+
c.unreachableNeverType,
|
|
139
|
+
c.nonPrimitiveType,
|
|
140
|
+
c.stringOrNumberType,
|
|
141
|
+
c.stringNumberSymbolType,
|
|
142
|
+
c.numberOrBigIntType,
|
|
143
|
+
c.numericStringType,
|
|
144
|
+
c.templateConstraintType,
|
|
145
|
+
c.uniqueLiteralType,
|
|
146
|
+
c.emptyObjectType,
|
|
147
|
+
c.emptyJsxObjectType,
|
|
148
|
+
c.emptyFreshJsxObjectType,
|
|
149
|
+
c.emptyTypeLiteralType,
|
|
150
|
+
c.unknownEmptyObjectType,
|
|
151
|
+
c.unknownUnionType,
|
|
152
|
+
c.emptyGenericType,
|
|
153
|
+
c.anyFunctionType,
|
|
154
|
+
c.noConstraintType,
|
|
155
|
+
c.circularConstraintType,
|
|
156
|
+
c.resolvingDefaultType,
|
|
157
|
+
c.emptyStringType,
|
|
158
|
+
c.zeroType,
|
|
159
|
+
c.zeroBigIntType,
|
|
160
|
+
c.typeofType,
|
|
161
|
+
];
|
|
162
|
+
}
|
|
163
|
+
/** The reason an export stops at its budget (`Exporter.limit`), which `post` returns: the result is not posted. */
|
|
164
|
+
export const budgetFailure = 'export budget';
|
|
165
|
+
/** A checker's `Exporter.mergedOrigins`, kept while its merged symbols stay the same. */
|
|
166
|
+
export class MergedOrigins {
|
|
167
|
+
origins = new Map();
|
|
168
|
+
size = -1;
|
|
169
|
+
}
|
|
170
|
+
/** An index signature of an `AnonymousObject` record, waiting for the words of its `CompleteObject`. */
|
|
171
|
+
class IndexInfoWords {
|
|
172
|
+
keyType;
|
|
173
|
+
valueType;
|
|
174
|
+
isReadonly;
|
|
175
|
+
declaration;
|
|
176
|
+
components;
|
|
177
|
+
constructor(keyType, valueType, isReadonly, declaration, components) {
|
|
178
|
+
this.keyType = keyType;
|
|
179
|
+
this.valueType = valueType;
|
|
180
|
+
this.isReadonly = isReadonly;
|
|
181
|
+
this.declaration = declaration;
|
|
182
|
+
this.components = components;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Writes a result as records; `failure` names the first part that has no record kind. */
|
|
186
|
+
export class Exporter {
|
|
187
|
+
c;
|
|
188
|
+
writer;
|
|
189
|
+
/**
|
|
190
|
+
* The index of the first record of the export in progress. A checker's exporter keeps the records of the types it
|
|
191
|
+
* exported before (`ThreadSharing.post`): its store has them already, and a result's records are only the new ones.
|
|
192
|
+
*/
|
|
193
|
+
base = 0;
|
|
194
|
+
/** The number of records the export in progress wrote. */
|
|
195
|
+
count = 0;
|
|
196
|
+
/** The record of each type, by type id, and of each property symbol, by symbol id. */
|
|
197
|
+
indexes = new Map();
|
|
198
|
+
properties = new Map();
|
|
199
|
+
/** The types and properties the export in progress gave indexes, which a failed export forgets again. */
|
|
200
|
+
addedTypes = [];
|
|
201
|
+
addedProperties = [];
|
|
202
|
+
/**
|
|
203
|
+
* The most records the export in progress may add (`ThreadSharing.post` prices it with `kappa`); past it the export
|
|
204
|
+
* fails and the result is not posted.
|
|
205
|
+
*/
|
|
206
|
+
limit = Number.POSITIVE_INFINITY;
|
|
207
|
+
initial;
|
|
208
|
+
failure = undefined;
|
|
209
|
+
/** The ids above which nodes and symbols are the checker thread's own (lazily parsed JSDoc), or Infinity. */
|
|
210
|
+
nodeLimit = Infinity;
|
|
211
|
+
symbolLimit = Infinity;
|
|
212
|
+
/** The ids of the symbols each merged symbol merged (`getMergedSymbol`), built on first use. */
|
|
213
|
+
mergedOrigins = undefined;
|
|
214
|
+
/** Where the checker keeps `mergedOrigins` between exports. */
|
|
215
|
+
originsCache = undefined;
|
|
216
|
+
/** How the record in progress names its symbol and its alias, and the node it carries. */
|
|
217
|
+
naming = 0 /* SymbolNaming.None */;
|
|
218
|
+
namingMerged = -1;
|
|
219
|
+
namingNode = undefined;
|
|
220
|
+
aliasNaming = 0 /* SymbolNaming.None */;
|
|
221
|
+
aliasMerged = -1;
|
|
222
|
+
aliasNode = undefined;
|
|
223
|
+
aliasRefs = noRefs;
|
|
224
|
+
node = undefined;
|
|
225
|
+
constructor(c, initial, writer) {
|
|
226
|
+
this.c = c;
|
|
227
|
+
this.initial = initial;
|
|
228
|
+
this.writer = writer;
|
|
229
|
+
}
|
|
230
|
+
fail(reason) {
|
|
231
|
+
if (this.failure === undefined)
|
|
232
|
+
this.failure = reason;
|
|
233
|
+
return -1;
|
|
234
|
+
}
|
|
235
|
+
/** Whether `node` is one every checker shares, and can name; fails if not. */
|
|
236
|
+
sharedNode(node) {
|
|
237
|
+
if (node === undefined)
|
|
238
|
+
return true;
|
|
239
|
+
if (node.id > this.nodeLimit) {
|
|
240
|
+
this.fail('node of the thread');
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
if (!this.writer.fileIndex.has(getSourceFileOfNode(node))) {
|
|
244
|
+
this.fail('node outside the program');
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* The index of the next record of the store, or -1 if the result is over its export budget; the store's table must
|
|
251
|
+
* have room for it.
|
|
252
|
+
*/
|
|
253
|
+
nextIndex() {
|
|
254
|
+
const index = this.base + this.count;
|
|
255
|
+
if (index >= this.limit)
|
|
256
|
+
return this.fail(budgetFailure);
|
|
257
|
+
this.count++;
|
|
258
|
+
if (index >= this.writer.table.length)
|
|
259
|
+
this.writer.full = true;
|
|
260
|
+
return index;
|
|
261
|
+
}
|
|
262
|
+
/** Records the type `t` at `index`. */
|
|
263
|
+
memo(t, index) {
|
|
264
|
+
// A consumer's memo is by record index, so a type has one record: VERIFY runs check that it does.
|
|
265
|
+
if (shareVerifyValue !== undefined && this.indexes.has(t.id))
|
|
266
|
+
process.stderr.write('share-verify: type ' + t.id + ' has a record already\n');
|
|
267
|
+
this.indexes.set(t.id, index);
|
|
268
|
+
this.addedTypes.push(t.id);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Sets how the record in progress names `symbol`: a symbol of the program by the node it is the symbol of, or a
|
|
272
|
+
* symbol the checker merged by the id of a symbol it merged. Fails for a symbol of the thread.
|
|
273
|
+
*/
|
|
274
|
+
nameSymbol(symbol, alias) {
|
|
275
|
+
let naming = 0 /* SymbolNaming.None */;
|
|
276
|
+
let merged = -1;
|
|
277
|
+
let node = undefined;
|
|
278
|
+
if (symbol !== undefined) {
|
|
279
|
+
if ((symbol.flags & 33554432 /* SymbolFlags.Transient */) === 0) {
|
|
280
|
+
if (getSymbolId(symbol) > this.symbolLimit) {
|
|
281
|
+
this.fail('symbol of the thread');
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
const declaration = symbol.declaration;
|
|
285
|
+
if (declaration === undefined) {
|
|
286
|
+
this.fail('symbol without a declaration');
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
const local = getSymbol(declaration);
|
|
290
|
+
if (local === symbol)
|
|
291
|
+
naming = 1 /* SymbolNaming.Node */;
|
|
292
|
+
else if (local !== undefined && local.exportSymbol === symbol)
|
|
293
|
+
naming = 2 /* SymbolNaming.Export */;
|
|
294
|
+
else {
|
|
295
|
+
this.fail('symbol not named by its declaration');
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
node = declaration;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
let origins = this.mergedOrigins;
|
|
302
|
+
if (origins === undefined)
|
|
303
|
+
origins = this.buildOrigins();
|
|
304
|
+
const origin = origins.get(symbol);
|
|
305
|
+
if (origin === undefined) {
|
|
306
|
+
this.fail('checker symbol ' + symbol.name);
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
naming = 3 /* SymbolNaming.Merged */;
|
|
310
|
+
merged = origin;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (alias) {
|
|
314
|
+
this.aliasNaming = naming;
|
|
315
|
+
this.aliasMerged = merged;
|
|
316
|
+
this.aliasNode = node;
|
|
317
|
+
// The alias's type arguments are recorded after it is named (`aliasBits`). A record that names an alias which
|
|
318
|
+
// has none, such as a property naming its parent, keeps none of the last alias's.
|
|
319
|
+
this.aliasRefs = noRefs;
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
this.naming = naming;
|
|
323
|
+
this.namingMerged = merged;
|
|
324
|
+
this.namingNode = node;
|
|
325
|
+
}
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
/** The ids of the symbols each merged symbol merged, from the checker's `mergedSymbols`. */
|
|
329
|
+
buildOrigins() {
|
|
330
|
+
const cache = this.originsCache;
|
|
331
|
+
let origins;
|
|
332
|
+
if (cache !== undefined && cache.size === this.c.mergedSymbols.size)
|
|
333
|
+
origins = cache.origins;
|
|
334
|
+
else {
|
|
335
|
+
origins = new Map();
|
|
336
|
+
for (const [id, target] of this.c.mergedSymbols)
|
|
337
|
+
if (!origins.has(target))
|
|
338
|
+
origins.set(target, id);
|
|
339
|
+
if (cache !== undefined) {
|
|
340
|
+
cache.origins = origins;
|
|
341
|
+
cache.size = this.c.mergedSymbols.size;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
this.mergedOrigins = origins;
|
|
345
|
+
return origins;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Names the alias of the record in progress, after its type arguments are exported, and returns the header bits that
|
|
349
|
+
* name it; -1 if it can't be named.
|
|
350
|
+
*/
|
|
351
|
+
aliasBits(alias, refs) {
|
|
352
|
+
if (alias === undefined)
|
|
353
|
+
return 0;
|
|
354
|
+
if (!this.nameSymbol(alias.symbol, true))
|
|
355
|
+
return -1;
|
|
356
|
+
this.aliasRefs = refs;
|
|
357
|
+
return 32 /* RecordHeader.HasAlias */ | (this.aliasNaming === 3 /* SymbolNaming.Merged */ ? 1024 /* RecordHeader.AliasMerged */ : 0);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Starts the record at `index`: its header, its refs, its alias, its symbol and its node, all decided by `bits` and
|
|
361
|
+
* the fields set just before. A kind's own fields follow.
|
|
362
|
+
*/
|
|
363
|
+
begin(kind, index, refs, bits) {
|
|
364
|
+
const w = this.writer;
|
|
365
|
+
const n = refs.length;
|
|
366
|
+
w.beginRecord(index, kind | bits | (n < 65535 /* RecordHeader.RefEscape */ ? n << 16 : 65535 /* RecordHeader.RefEscape */ << 16));
|
|
367
|
+
if (n >= 65535 /* RecordHeader.RefEscape */)
|
|
368
|
+
w.word(n);
|
|
369
|
+
for (let i = 0; i < n; i++)
|
|
370
|
+
w.word(refs[i]);
|
|
371
|
+
if ((bits & 32 /* RecordHeader.HasAlias */) !== 0) {
|
|
372
|
+
if ((bits & 1024 /* RecordHeader.AliasMerged */) !== 0)
|
|
373
|
+
w.word(this.aliasMerged);
|
|
374
|
+
else {
|
|
375
|
+
w.word(this.aliasNaming === 2 /* SymbolNaming.Export */ ? 1 : 0);
|
|
376
|
+
w.node(this.aliasNode);
|
|
377
|
+
}
|
|
378
|
+
const aliasRefs = this.aliasRefs;
|
|
379
|
+
w.word(aliasRefs.length);
|
|
380
|
+
for (let i = 0; i < aliasRefs.length; i++)
|
|
381
|
+
w.word(aliasRefs[i]);
|
|
382
|
+
}
|
|
383
|
+
const naming = bits & 192 /* RecordHeader.NamingMask */;
|
|
384
|
+
if (naming === 3 /* SymbolNaming.Merged */ << 6 /* RecordHeader.NamingShift */)
|
|
385
|
+
w.word(this.namingMerged);
|
|
386
|
+
else if (naming !== 0)
|
|
387
|
+
w.node(this.namingNode);
|
|
388
|
+
if ((bits & 256 /* RecordHeader.HasNode */) !== 0)
|
|
389
|
+
w.node(this.node);
|
|
390
|
+
}
|
|
391
|
+
/** The record of `t` of `kind`, with `refs` and no fields of its own; its index. */
|
|
392
|
+
plain(kind, t, refs) {
|
|
393
|
+
const index = this.nextIndex();
|
|
394
|
+
this.memo(t, index);
|
|
395
|
+
this.begin(kind, index, refs, 0);
|
|
396
|
+
return index;
|
|
397
|
+
}
|
|
398
|
+
/** The record of the initial type `t`, which is `num`th in `initialTypes`. */
|
|
399
|
+
initialType(t, num) {
|
|
400
|
+
const index = this.nextIndex();
|
|
401
|
+
this.memo(t, index);
|
|
402
|
+
this.begin(0 /* RecordKind.Initial */, index, noRefs, 0);
|
|
403
|
+
this.writer.word(num);
|
|
404
|
+
return index;
|
|
405
|
+
}
|
|
406
|
+
/** The record of the type `t` of `kind` named by `symbol`, with `refs`; its index. */
|
|
407
|
+
symbolType(kind, t, symbol, refs) {
|
|
408
|
+
if (!this.nameSymbol(symbol, false))
|
|
409
|
+
return -1;
|
|
410
|
+
const index = this.nextIndex();
|
|
411
|
+
this.memo(t, index);
|
|
412
|
+
this.begin(kind, index, refs, this.naming << 6 /* RecordHeader.NamingShift */);
|
|
413
|
+
return index;
|
|
414
|
+
}
|
|
415
|
+
/** The record of the type `t` of the type node `node`; its index. */
|
|
416
|
+
nodeType(t, node) {
|
|
417
|
+
if (!this.sharedNode(node))
|
|
418
|
+
return -1;
|
|
419
|
+
this.node = node;
|
|
420
|
+
const index = this.nextIndex();
|
|
421
|
+
this.memo(t, index);
|
|
422
|
+
this.begin(8 /* RecordKind.NodeType */, index, noRefs, 256 /* RecordHeader.HasNode */);
|
|
423
|
+
return index;
|
|
424
|
+
}
|
|
425
|
+
types(list) {
|
|
426
|
+
const refs = [];
|
|
427
|
+
for (const t of list) {
|
|
428
|
+
refs.push(this.type(t));
|
|
429
|
+
if (this.failure !== undefined)
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
return refs;
|
|
433
|
+
}
|
|
434
|
+
type(t) {
|
|
435
|
+
if (this.failure !== undefined)
|
|
436
|
+
return -1;
|
|
437
|
+
const known = this.indexes.get(t.id);
|
|
438
|
+
if (known !== undefined)
|
|
439
|
+
return known;
|
|
440
|
+
const initial = this.initial.get(t.id);
|
|
441
|
+
if (initial !== undefined)
|
|
442
|
+
return this.initialType(t, initial);
|
|
443
|
+
const c = this.c;
|
|
444
|
+
const flags = t.flags;
|
|
445
|
+
if ((flags & 15360 /* TypeFlags.Literal */) !== 0 && (flags & 256 /* TypeFlags.Boolean */) === 0)
|
|
446
|
+
return this.literal(t);
|
|
447
|
+
if ((flags & 16384 /* TypeFlags.UniqueESSymbol */) !== 0) {
|
|
448
|
+
if (c.uniqueESSymbolTypes.get(t.symbol) !== t)
|
|
449
|
+
return this.fail('unique symbol');
|
|
450
|
+
return this.symbolType(4 /* RecordKind.UniqueSymbol */, t, t.symbol, noRefs);
|
|
451
|
+
}
|
|
452
|
+
if ((flags & 524288 /* TypeFlags.TypeParameter */) !== 0) {
|
|
453
|
+
const symbol = t.symbol;
|
|
454
|
+
if (symbol === undefined)
|
|
455
|
+
return this.fail('type parameter without a symbol');
|
|
456
|
+
const declared = getDeclaredTypeOfSymbol(c, symbol);
|
|
457
|
+
if (declared === t)
|
|
458
|
+
return this.symbolType(5 /* RecordKind.Declared */, t, symbol, noRefs);
|
|
459
|
+
if ((declared.objectFlags & 3 /* ObjectFlags.ClassOrInterface */) !== 0 && declared.thisType === t)
|
|
460
|
+
return this.symbolType(6 /* RecordKind.ThisType */, t, symbol, noRefs);
|
|
461
|
+
return this.fail('fresh type parameter');
|
|
462
|
+
}
|
|
463
|
+
if (t.symbol !== undefined && (flags & (134217728 /* TypeFlags.Union */ | 65536 /* TypeFlags.Enum */)) !== 0) {
|
|
464
|
+
// An enum type: the declared type of its symbol.
|
|
465
|
+
if (getDeclaredTypeOfSymbol(c, t.symbol) !== t)
|
|
466
|
+
return this.fail('enum type');
|
|
467
|
+
return this.symbolType(5 /* RecordKind.Declared */, t, t.symbol, noRefs);
|
|
468
|
+
}
|
|
469
|
+
if ((flags & 134217728 /* TypeFlags.Union */) !== 0)
|
|
470
|
+
return this.union(t);
|
|
471
|
+
if ((flags & 268435456 /* TypeFlags.Intersection */) !== 0)
|
|
472
|
+
return this.intersection(t);
|
|
473
|
+
if ((flags & 1048576 /* TypeFlags.Object */) !== 0)
|
|
474
|
+
return this.object(t);
|
|
475
|
+
if ((flags & 2097152 /* TypeFlags.Index */) !== 0) {
|
|
476
|
+
const target = this.type(t.target);
|
|
477
|
+
if (this.failure !== undefined)
|
|
478
|
+
return -1;
|
|
479
|
+
const index = this.nextIndex();
|
|
480
|
+
this.memo(t, index);
|
|
481
|
+
this.begin(14 /* RecordKind.Index */, index, [target], 0);
|
|
482
|
+
this.writer.word(t.indexFlags);
|
|
483
|
+
return index;
|
|
484
|
+
}
|
|
485
|
+
if ((flags & 33554432 /* TypeFlags.IndexedAccess */) !== 0) {
|
|
486
|
+
const access = t;
|
|
487
|
+
const refs = this.types([access.objectType, access.indexType]);
|
|
488
|
+
if (this.failure !== undefined)
|
|
489
|
+
return -1;
|
|
490
|
+
const alias = t.alias;
|
|
491
|
+
const aliasRefs = alias === undefined ? noRefs : this.types(alias.typeArguments);
|
|
492
|
+
if (this.failure !== undefined)
|
|
493
|
+
return -1;
|
|
494
|
+
const bits = this.aliasBits(alias, aliasRefs);
|
|
495
|
+
if (bits < 0)
|
|
496
|
+
return -1;
|
|
497
|
+
const index = this.nextIndex();
|
|
498
|
+
this.memo(t, index);
|
|
499
|
+
this.begin(15 /* RecordKind.IndexedAccess */, index, refs, bits);
|
|
500
|
+
this.writer.word(this.c.indexedAccessKeyFlags.get(t) ?? access.accessFlags);
|
|
501
|
+
return index;
|
|
502
|
+
}
|
|
503
|
+
if ((flags & 67108864 /* TypeFlags.Conditional */) !== 0)
|
|
504
|
+
return this.conditional(t);
|
|
505
|
+
if ((flags & 4194304 /* TypeFlags.TemplateLiteral */) !== 0) {
|
|
506
|
+
const template = t;
|
|
507
|
+
const refs = this.types(template.types);
|
|
508
|
+
if (this.failure !== undefined)
|
|
509
|
+
return -1;
|
|
510
|
+
const index = this.nextIndex();
|
|
511
|
+
this.memo(t, index);
|
|
512
|
+
this.begin(17 /* RecordKind.Template */, index, refs, 0);
|
|
513
|
+
const texts = template.texts;
|
|
514
|
+
this.writer.word(texts.length);
|
|
515
|
+
for (let i = 0; i < texts.length; i++)
|
|
516
|
+
this.writer.text(texts[i]);
|
|
517
|
+
return index;
|
|
518
|
+
}
|
|
519
|
+
if ((flags & 8388608 /* TypeFlags.StringMapping */) !== 0) {
|
|
520
|
+
const target = this.type(t.target);
|
|
521
|
+
if (this.failure !== undefined)
|
|
522
|
+
return -1;
|
|
523
|
+
return this.symbolType(18 /* RecordKind.StringMapping */, t, t.symbol, [target]);
|
|
524
|
+
}
|
|
525
|
+
if ((flags & 16777216 /* TypeFlags.Substitution */) !== 0) {
|
|
526
|
+
const substitution = t;
|
|
527
|
+
if (isNoInferType(c, t)) {
|
|
528
|
+
const base = this.type(substitution.baseType);
|
|
529
|
+
if (this.failure !== undefined)
|
|
530
|
+
return -1;
|
|
531
|
+
return this.plain(20 /* RecordKind.NoInfer */, t, [base]);
|
|
532
|
+
}
|
|
533
|
+
const refs = this.types([substitution.baseType, substitution.constraint]);
|
|
534
|
+
if (this.failure !== undefined)
|
|
535
|
+
return -1;
|
|
536
|
+
return this.plain(19 /* RecordKind.Substitution */, t, refs);
|
|
537
|
+
}
|
|
538
|
+
return this.fail('type flags ' + flags);
|
|
539
|
+
}
|
|
540
|
+
literal(t) {
|
|
541
|
+
const regular = t.regularType;
|
|
542
|
+
if (regular !== t) {
|
|
543
|
+
if (regular.freshType !== t)
|
|
544
|
+
return this.fail('literal');
|
|
545
|
+
const index = this.type(regular);
|
|
546
|
+
if (this.failure !== undefined)
|
|
547
|
+
return -1;
|
|
548
|
+
return this.plain(2 /* RecordKind.FreshLiteral */, t, [index]);
|
|
549
|
+
}
|
|
550
|
+
if (t.symbol !== undefined) {
|
|
551
|
+
if (getDeclaredTypeOfSymbol(this.c, t.symbol) !== t)
|
|
552
|
+
return this.fail('enum literal');
|
|
553
|
+
return this.symbolType(3 /* RecordKind.EnumLiteral */, t, t.symbol, noRefs);
|
|
554
|
+
}
|
|
555
|
+
const index = this.nextIndex();
|
|
556
|
+
this.memo(t, index);
|
|
557
|
+
this.begin(1 /* RecordKind.Literal */, index, noRefs, 0);
|
|
558
|
+
const w = this.writer;
|
|
559
|
+
w.word(t.flags);
|
|
560
|
+
if ((t.flags & 2048 /* TypeFlags.NumberLiteral */) !== 0)
|
|
561
|
+
w.double(t.numberValue);
|
|
562
|
+
else
|
|
563
|
+
w.text(t.stringValue);
|
|
564
|
+
return index;
|
|
565
|
+
}
|
|
566
|
+
/** The record of the constituents of a union's or intersection's origin, which is not a type: it has no alias. */
|
|
567
|
+
originRecord(kind, flags, refs) {
|
|
568
|
+
const index = this.nextIndex();
|
|
569
|
+
this.begin(kind, index, refs, 2048 /* RecordHeader.Constituent */);
|
|
570
|
+
this.writer.word(flags);
|
|
571
|
+
// A union's origin field is -1 here, as it is for a union with no origin: the constituents are refs, and the
|
|
572
|
+
// reader scans the field for records this record depends on.
|
|
573
|
+
if (kind === 12 /* RecordKind.Union */)
|
|
574
|
+
this.writer.word(-1);
|
|
575
|
+
return index;
|
|
576
|
+
}
|
|
577
|
+
union(t) {
|
|
578
|
+
const refs = this.types(t.types);
|
|
579
|
+
if (this.failure !== undefined)
|
|
580
|
+
return -1;
|
|
581
|
+
let origin = -1;
|
|
582
|
+
const o = t.origin;
|
|
583
|
+
if (o !== undefined) {
|
|
584
|
+
if ((o.flags & 402653184 /* TypeFlags.UnionOrIntersection */) !== 0) {
|
|
585
|
+
// Origins are not interned: a union key spells their constituents.
|
|
586
|
+
const parts = this.types(o.types);
|
|
587
|
+
if (this.failure !== undefined)
|
|
588
|
+
return -1;
|
|
589
|
+
const kind = (o.flags & 134217728 /* TypeFlags.Union */) !== 0 ? 12 /* RecordKind.Union */ : 13 /* RecordKind.Intersection */;
|
|
590
|
+
origin = this.originRecord(kind, o.objectFlags, parts);
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
origin = this.type(o);
|
|
594
|
+
if (this.failure !== undefined)
|
|
595
|
+
return -1;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
const alias = t.alias;
|
|
599
|
+
const aliasRefs = alias === undefined ? noRefs : this.types(alias.typeArguments);
|
|
600
|
+
if (this.failure !== undefined)
|
|
601
|
+
return -1;
|
|
602
|
+
const bits = this.aliasBits(alias, aliasRefs);
|
|
603
|
+
if (bits < 0)
|
|
604
|
+
return -1;
|
|
605
|
+
const index = this.nextIndex();
|
|
606
|
+
this.memo(t, index);
|
|
607
|
+
this.begin(12 /* RecordKind.Union */, index, refs, bits);
|
|
608
|
+
this.writer.word(t.objectFlags);
|
|
609
|
+
this.writer.word(origin);
|
|
610
|
+
return index;
|
|
611
|
+
}
|
|
612
|
+
intersection(t) {
|
|
613
|
+
const refs = this.types(t.types);
|
|
614
|
+
if (this.failure !== undefined)
|
|
615
|
+
return -1;
|
|
616
|
+
const alias = t.alias;
|
|
617
|
+
const aliasRefs = alias === undefined ? noRefs : this.types(alias.typeArguments);
|
|
618
|
+
if (this.failure !== undefined)
|
|
619
|
+
return -1;
|
|
620
|
+
const bits = this.aliasBits(alias, aliasRefs);
|
|
621
|
+
if (bits < 0)
|
|
622
|
+
return -1;
|
|
623
|
+
const index = this.nextIndex();
|
|
624
|
+
this.memo(t, index);
|
|
625
|
+
this.begin(13 /* RecordKind.Intersection */, index, refs, bits);
|
|
626
|
+
this.writer.word(t.objectFlags);
|
|
627
|
+
return index;
|
|
628
|
+
}
|
|
629
|
+
object(t) {
|
|
630
|
+
const c = this.c;
|
|
631
|
+
const objectFlags = t.objectFlags;
|
|
632
|
+
const symbol = t.symbol;
|
|
633
|
+
if ((objectFlags & 4 /* ObjectFlags.Reference */) !== 0) {
|
|
634
|
+
const reference = t;
|
|
635
|
+
if (reference.node !== undefined)
|
|
636
|
+
return this.instantiation(t);
|
|
637
|
+
const target = reference.target;
|
|
638
|
+
if (target === t) {
|
|
639
|
+
if ((objectFlags & 8 /* ObjectFlags.Tuple */) !== 0)
|
|
640
|
+
return this.tupleTarget(t);
|
|
641
|
+
if (symbol === undefined || getDeclaredTypeOfSymbol(c, symbol) !== t)
|
|
642
|
+
return this.fail('generic target');
|
|
643
|
+
return this.symbolType(5 /* RecordKind.Declared */, t, symbol, noRefs);
|
|
644
|
+
}
|
|
645
|
+
const refs = [this.type(target), ...this.types(reference.resolvedTypeArguments ?? [])];
|
|
646
|
+
if (this.failure !== undefined)
|
|
647
|
+
return -1;
|
|
648
|
+
return this.plain(9 /* RecordKind.Reference */, t, refs);
|
|
649
|
+
}
|
|
650
|
+
if ((objectFlags & 3 /* ObjectFlags.ClassOrInterface */) !== 0) {
|
|
651
|
+
if (symbol === undefined || getDeclaredTypeOfSymbol(c, symbol) !== t)
|
|
652
|
+
return this.fail('declared type');
|
|
653
|
+
return this.symbolType(5 /* RecordKind.Declared */, t, symbol, noRefs);
|
|
654
|
+
}
|
|
655
|
+
if ((objectFlags & (1024 /* ObjectFlags.ReverseMapped */ | 256 /* ObjectFlags.EvolvingArray */)) !== 0)
|
|
656
|
+
return this.fail('object kind');
|
|
657
|
+
if ((objectFlags & 64 /* ObjectFlags.Instantiated */) !== 0)
|
|
658
|
+
return this.instantiation(t);
|
|
659
|
+
if ((objectFlags & (16 /* ObjectFlags.Anonymous */ | 32 /* ObjectFlags.Mapped */)) === 0 || symbol === undefined)
|
|
660
|
+
return this.fail('object without a declaration, object flags ' + objectFlags);
|
|
661
|
+
// The anonymous type of a function, class, enum or module; a variable's own type is what is being shared.
|
|
662
|
+
if ((symbol.flags & sharedValueFlags()) === 0 && c.symbolTypes.get(getSymbolId(symbol)) === t)
|
|
663
|
+
return this.symbolType(7 /* RecordKind.SymbolType */, t, symbol, noRefs);
|
|
664
|
+
const declaration = (objectFlags & 32 /* ObjectFlags.Mapped */) !== 0 ? t.declaration : symbol.declaration;
|
|
665
|
+
if (declaration !== undefined && c.resolvedTypes.get(declaration.id) === t)
|
|
666
|
+
return this.nodeType(t, declaration);
|
|
667
|
+
if ((symbol.flags & 4096 /* SymbolFlags.ObjectLiteral */) !== 0 &&
|
|
668
|
+
(objectFlags & (16 /* ObjectFlags.Anonymous */ | 2097152 /* ObjectFlags.MembersResolved */)) ===
|
|
669
|
+
(16 /* ObjectFlags.Anonymous */ | 2097152 /* ObjectFlags.MembersResolved */))
|
|
670
|
+
return this.anonymousObject(t);
|
|
671
|
+
return this.fail('anonymous type ' +
|
|
672
|
+
((objectFlags & 128 /* ObjectFlags.ObjectLiteral */) !== 0 ? 'object literal ' : '') +
|
|
673
|
+
'symbol flags ' +
|
|
674
|
+
symbol.flags +
|
|
675
|
+
' declaration kind ' +
|
|
676
|
+
(symbol.declaration?.kind ?? -1) +
|
|
677
|
+
' object flags ' +
|
|
678
|
+
objectFlags);
|
|
679
|
+
}
|
|
680
|
+
/** An object literal type, or one made from one, with its properties and index infos. */
|
|
681
|
+
anonymousObject(t) {
|
|
682
|
+
const c = this.c;
|
|
683
|
+
if ((t.objectFlags & -2147483648 /* ObjectFlags.SideState */) !== 0 || c.patternForType.has(t))
|
|
684
|
+
return this.fail('object literal state');
|
|
685
|
+
const resolved = t;
|
|
686
|
+
if (resolved.callSignatures.length !== 0 || resolved.constructSignatures.length !== 0)
|
|
687
|
+
return this.fail('object literal signatures');
|
|
688
|
+
const shell = this.nextIndex();
|
|
689
|
+
this.memo(t, shell);
|
|
690
|
+
const members = [];
|
|
691
|
+
for (const prop of resolved.properties) {
|
|
692
|
+
members.push(this.property(prop));
|
|
693
|
+
if (this.failure !== undefined)
|
|
694
|
+
return -1;
|
|
695
|
+
}
|
|
696
|
+
const infos = [];
|
|
697
|
+
for (const info of resolved.indexInfos) {
|
|
698
|
+
const key = this.type(info.keyType);
|
|
699
|
+
const value = this.type(info.valueType);
|
|
700
|
+
if (this.failure !== undefined)
|
|
701
|
+
return -1;
|
|
702
|
+
if (!this.sharedNode(info.declaration))
|
|
703
|
+
return -1;
|
|
704
|
+
for (const node of info.components)
|
|
705
|
+
if (!this.sharedNode(node))
|
|
706
|
+
return -1;
|
|
707
|
+
infos.push(new IndexInfoWords(key, value, info.isReadonly, info.declaration, info.components));
|
|
708
|
+
}
|
|
709
|
+
const complete = this.nextIndex();
|
|
710
|
+
if (!this.nameSymbol(t.symbol, false))
|
|
711
|
+
return -1;
|
|
712
|
+
this.begin(22 /* RecordKind.AnonymousObject */, shell, noRefs, this.naming << 6 /* RecordHeader.NamingShift */);
|
|
713
|
+
const w = this.writer;
|
|
714
|
+
w.word(t.objectFlags & ~lazyObjectFlags());
|
|
715
|
+
w.word(complete);
|
|
716
|
+
this.begin(23 /* RecordKind.CompleteObject */, complete, members, 0);
|
|
717
|
+
w.word(shell);
|
|
718
|
+
w.word(infos.length);
|
|
719
|
+
for (const info of infos) {
|
|
720
|
+
w.word(info.keyType);
|
|
721
|
+
w.word(info.valueType);
|
|
722
|
+
w.word(info.isReadonly ? 1 : 0);
|
|
723
|
+
w.node(info.declaration);
|
|
724
|
+
w.word(info.components.length);
|
|
725
|
+
for (const node of info.components)
|
|
726
|
+
w.node(node);
|
|
727
|
+
}
|
|
728
|
+
return shell;
|
|
729
|
+
}
|
|
730
|
+
/** A property symbol of an object literal type: a checker's own, made from one of the program or from another. */
|
|
731
|
+
property(prop) {
|
|
732
|
+
const id = getSymbolId(prop);
|
|
733
|
+
const known = this.properties.get(id);
|
|
734
|
+
if (known !== undefined)
|
|
735
|
+
return known;
|
|
736
|
+
const c = this.c;
|
|
737
|
+
if ((prop.flags & 33554432 /* SymbolFlags.Transient */) === 0)
|
|
738
|
+
return this.fail('property of the program');
|
|
739
|
+
if ((prop.checkFlags & ~(8 /* CheckFlags.Readonly */ | 32768 /* CheckFlags.Late */)) !== 0)
|
|
740
|
+
return this.fail('property check flags ' + prop.checkFlags);
|
|
741
|
+
const t = c.symbolTypes.get(id);
|
|
742
|
+
if (t === undefined)
|
|
743
|
+
return this.fail('property without a type');
|
|
744
|
+
const type = this.type(t);
|
|
745
|
+
const nameType = c.symbolNameTypes.get(id);
|
|
746
|
+
const name = nameType === undefined ? -1 : this.type(nameType);
|
|
747
|
+
if (this.failure !== undefined)
|
|
748
|
+
return -1;
|
|
749
|
+
const source = c.symbolTargets.get(id);
|
|
750
|
+
let target = -1;
|
|
751
|
+
let program = undefined;
|
|
752
|
+
if (source !== undefined) {
|
|
753
|
+
if ((source.flags & 33554432 /* SymbolFlags.Transient */) !== 0) {
|
|
754
|
+
target = this.property(source);
|
|
755
|
+
if (this.failure !== undefined)
|
|
756
|
+
return -1;
|
|
757
|
+
}
|
|
758
|
+
else
|
|
759
|
+
program = source;
|
|
760
|
+
}
|
|
761
|
+
const declarations = getDeclarations(prop);
|
|
762
|
+
if (!this.sharedNode(prop.valueDeclaration))
|
|
763
|
+
return -1;
|
|
764
|
+
for (const node of declarations)
|
|
765
|
+
if (!this.sharedNode(node))
|
|
766
|
+
return -1;
|
|
767
|
+
const index = this.nextIndex();
|
|
768
|
+
this.properties.set(id, index);
|
|
769
|
+
this.addedProperties.push(id);
|
|
770
|
+
if (!this.nameSymbol(program, false))
|
|
771
|
+
return -1;
|
|
772
|
+
const value = prop.valueDeclaration;
|
|
773
|
+
const valueIsFirst = value !== undefined && declarations.length !== 0 && declarations[0] === value;
|
|
774
|
+
this.node = value;
|
|
775
|
+
let bits = (this.naming << 6 /* RecordHeader.NamingShift */) |
|
|
776
|
+
(valueIsFirst ? 512 /* RecordHeader.ValueIsFirst */ : value !== undefined ? 256 /* RecordHeader.HasNode */ : 0);
|
|
777
|
+
if (prop.parent !== undefined) {
|
|
778
|
+
if (!this.nameSymbol(prop.parent, true))
|
|
779
|
+
return -1;
|
|
780
|
+
bits |= 32 /* RecordHeader.HasAlias */ | (this.aliasMerged >= 0 ? 1024 /* RecordHeader.AliasMerged */ : 0);
|
|
781
|
+
}
|
|
782
|
+
this.begin(24 /* RecordKind.Property */, index, [type, name, target], bits);
|
|
783
|
+
const w = this.writer;
|
|
784
|
+
w.word(prop.flags);
|
|
785
|
+
w.word(prop.checkFlags);
|
|
786
|
+
w.text(prop.name);
|
|
787
|
+
w.word(declarations.length);
|
|
788
|
+
for (const node of declarations)
|
|
789
|
+
w.node(node);
|
|
790
|
+
return index;
|
|
791
|
+
}
|
|
792
|
+
tupleTarget(t) {
|
|
793
|
+
const index = this.nextIndex();
|
|
794
|
+
this.memo(t, index);
|
|
795
|
+
this.begin(10 /* RecordKind.TupleTarget */, index, noRefs, 0);
|
|
796
|
+
const w = this.writer;
|
|
797
|
+
w.word(t.readonly ? 1 : 0);
|
|
798
|
+
const infos = t.elementInfos;
|
|
799
|
+
w.word(infos.length);
|
|
800
|
+
for (const info of infos) {
|
|
801
|
+
if (!this.sharedNode(info.labeledDeclaration))
|
|
802
|
+
return -1;
|
|
803
|
+
w.word(info.flags);
|
|
804
|
+
w.node(info.labeledDeclaration);
|
|
805
|
+
}
|
|
806
|
+
return index;
|
|
807
|
+
}
|
|
808
|
+
/** An instantiated anonymous or mapped type, or a deferred type reference: its target and outer type arguments. */
|
|
809
|
+
instantiation(t) {
|
|
810
|
+
const c = this.c;
|
|
811
|
+
const objectFlags = t.objectFlags;
|
|
812
|
+
if ((objectFlags & 33554432 /* ObjectFlags.SingleSignatureType */) !== 0)
|
|
813
|
+
return this.fail('single signature type');
|
|
814
|
+
let declaration;
|
|
815
|
+
let target;
|
|
816
|
+
if ((objectFlags & 4 /* ObjectFlags.Reference */) !== 0) {
|
|
817
|
+
declaration = t.node;
|
|
818
|
+
target = c.resolvedTypes.get(declaration.id);
|
|
819
|
+
if (target === undefined)
|
|
820
|
+
return this.fail('deferred reference');
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
if ((objectFlags & 16777216 /* ObjectFlags.InstantiationExpressionType */) !== 0)
|
|
824
|
+
return this.fail('instantiation expression');
|
|
825
|
+
declaration = t.symbol?.declaration;
|
|
826
|
+
target = t.target;
|
|
827
|
+
}
|
|
828
|
+
if (declaration !== undefined && t.mapper === undefined && c.resolvedTypes.get(declaration.id) === t)
|
|
829
|
+
return this.nodeType(t, declaration);
|
|
830
|
+
if (declaration === undefined || target === undefined || t.mapper === undefined)
|
|
831
|
+
return this.fail('instantiation, declaration ' + (declaration?.kind ?? -1) + ' target ' + (target !== undefined));
|
|
832
|
+
const typeParameters = c.nodeLinks(declaration).outerTypeParameters;
|
|
833
|
+
if (typeParameters === undefined)
|
|
834
|
+
return this.fail('instantiation without type parameters');
|
|
835
|
+
const args = [];
|
|
836
|
+
for (const tp of typeParameters)
|
|
837
|
+
args.push(getMappedType(tp, t.mapper));
|
|
838
|
+
const generic = sideOf(c, target);
|
|
839
|
+
if (generic.instantiations?.get(typeListHash(args, t.alias, 0), args, t.alias, 0) !== t)
|
|
840
|
+
return this.fail('instantiation not found');
|
|
841
|
+
const refs = [this.type(target), ...this.types(args)];
|
|
842
|
+
if (this.failure !== undefined)
|
|
843
|
+
return -1;
|
|
844
|
+
// The alias and its type arguments are exported before the record, as the record names them: a consumer builds
|
|
845
|
+
// records in index order, and would find them unbuilt after it.
|
|
846
|
+
const alias = t.alias;
|
|
847
|
+
const aliasRefs = alias === undefined ? noRefs : this.types(alias.typeArguments);
|
|
848
|
+
if (this.failure !== undefined)
|
|
849
|
+
return -1;
|
|
850
|
+
if (!this.sharedNode(declaration))
|
|
851
|
+
return -1;
|
|
852
|
+
// The record is written after the return types of its signatures, which are built right after it: its index is
|
|
853
|
+
// lower than theirs.
|
|
854
|
+
const index = this.nextIndex();
|
|
855
|
+
this.memo(t, index);
|
|
856
|
+
// Only for an export that hasn't failed (its alias may have): optionalType would forget that failure.
|
|
857
|
+
if (this.failure === undefined)
|
|
858
|
+
this.resolvedReturnTypes(t, refs);
|
|
859
|
+
if (this.failure !== undefined)
|
|
860
|
+
return -1;
|
|
861
|
+
const bits = this.aliasBits(alias, aliasRefs);
|
|
862
|
+
if (bits < 0)
|
|
863
|
+
return -1;
|
|
864
|
+
this.node = declaration;
|
|
865
|
+
this.begin(11 /* RecordKind.Instantiation */, index, refs, bits | 256 /* RecordHeader.HasNode */);
|
|
866
|
+
this.writer.word(args.length);
|
|
867
|
+
return index;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Adds to `refs` the return types the checker resolved for the signatures of the instantiation `t`, exported after
|
|
871
|
+
* it. The consumer then creates them right after `t` and before the types that contain it, as this checker did:
|
|
872
|
+
* inference stops at references whose type ids grow along its stack (`isDeeplyNestedType`), so a consumer that
|
|
873
|
+
* created them later, when it resolved them, could stop an inference this checker made.
|
|
874
|
+
*/
|
|
875
|
+
resolvedReturnTypes(t, refs) {
|
|
876
|
+
if ((t.objectFlags & 2097152 /* ObjectFlags.MembersResolved */) === 0)
|
|
877
|
+
return;
|
|
878
|
+
for (const signatures of [t.callSignatures, t.constructSignatures])
|
|
879
|
+
for (const signature of signatures) {
|
|
880
|
+
const returnType = resolvedReturnTypeOf(this.c, signature);
|
|
881
|
+
if (returnType === undefined)
|
|
882
|
+
continue;
|
|
883
|
+
const index = this.optionalType(returnType);
|
|
884
|
+
if (index >= 0)
|
|
885
|
+
refs.push(index);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* The record of `t`, or -1 if it can't be exported; that leaves the export in progress as it was. An export that
|
|
890
|
+
* failed before stays failed.
|
|
891
|
+
*/
|
|
892
|
+
optionalType(t) {
|
|
893
|
+
if (this.failure !== undefined)
|
|
894
|
+
return -1;
|
|
895
|
+
const w = this.writer;
|
|
896
|
+
const at = w.at;
|
|
897
|
+
const unitAt = w.unitAt;
|
|
898
|
+
const count = this.count;
|
|
899
|
+
const types = this.addedTypes.length;
|
|
900
|
+
const properties = this.addedProperties.length;
|
|
901
|
+
const index = this.type(t);
|
|
902
|
+
if (this.failure === undefined)
|
|
903
|
+
return index;
|
|
904
|
+
for (let i = types; i < this.addedTypes.length; i++)
|
|
905
|
+
this.indexes.delete(this.addedTypes[i]);
|
|
906
|
+
for (let i = properties; i < this.addedProperties.length; i++)
|
|
907
|
+
this.properties.delete(this.addedProperties[i]);
|
|
908
|
+
this.addedTypes.length = types;
|
|
909
|
+
this.addedProperties.length = properties;
|
|
910
|
+
this.count = count;
|
|
911
|
+
w.at = at;
|
|
912
|
+
w.unitAt = unitAt;
|
|
913
|
+
// A store that ran out stays out: the export can't be posted.
|
|
914
|
+
this.failure = undefined;
|
|
915
|
+
return -1;
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* The record of the conditional type `t`: the conditional type of a type node, or the instantiation of one with
|
|
919
|
+
* outer type arguments; -1 if it can't be exported.
|
|
920
|
+
*/
|
|
921
|
+
conditional(t) {
|
|
922
|
+
const root = t.root;
|
|
923
|
+
if (t.mapper === undefined) {
|
|
924
|
+
if (this.c.resolvedTypes.get(root.node.id) !== t)
|
|
925
|
+
return this.fail('conditional type');
|
|
926
|
+
return this.nodeType(t, root.node);
|
|
927
|
+
}
|
|
928
|
+
const args = [];
|
|
929
|
+
for (const tp of root.outerTypeParameters)
|
|
930
|
+
args.push(getMappedType(tp, t.mapper));
|
|
931
|
+
let tag = -1;
|
|
932
|
+
for (let k = 0; k < 2 && tag < 0; k++)
|
|
933
|
+
if (root.instantiations.get(typeListHash(args, t.alias, k), args, t.alias, k) === t)
|
|
934
|
+
tag = k;
|
|
935
|
+
if (tag < 0) {
|
|
936
|
+
const keyed = this.c.conditionalResults?.get(t);
|
|
937
|
+
if (keyed !== undefined) {
|
|
938
|
+
const refs = this.types(keyed.typeArguments);
|
|
939
|
+
if (this.failure !== undefined)
|
|
940
|
+
return -1;
|
|
941
|
+
const alias = keyed.alias;
|
|
942
|
+
const aliasRefs = alias === undefined ? noRefs : this.types(alias.typeArguments);
|
|
943
|
+
if (this.failure !== undefined)
|
|
944
|
+
return -1;
|
|
945
|
+
const bits = this.aliasBits(alias, aliasRefs);
|
|
946
|
+
if (bits < 0)
|
|
947
|
+
return -1;
|
|
948
|
+
if (!this.sharedNode(keyed.root.node))
|
|
949
|
+
return -1;
|
|
950
|
+
this.node = keyed.root.node;
|
|
951
|
+
const index = this.nextIndex();
|
|
952
|
+
this.memo(t, index);
|
|
953
|
+
this.begin(16 /* RecordKind.Conditional */, index, refs, bits | 256 /* RecordHeader.HasNode */);
|
|
954
|
+
this.writer.word(keyed.tag);
|
|
955
|
+
return index;
|
|
956
|
+
}
|
|
957
|
+
const distributed = this.c.distributedConditionals?.get(t);
|
|
958
|
+
if (distributed === undefined)
|
|
959
|
+
return this.fail('conditional instantiation not found');
|
|
960
|
+
const refs = this.types([...distributed.typeArguments, distributed.constituent]);
|
|
961
|
+
if (this.failure !== undefined)
|
|
962
|
+
return -1;
|
|
963
|
+
const alias = distributed.alias;
|
|
964
|
+
const aliasRefs = alias === undefined ? noRefs : this.types(alias.typeArguments);
|
|
965
|
+
if (this.failure !== undefined)
|
|
966
|
+
return -1;
|
|
967
|
+
const bits = this.aliasBits(alias, aliasRefs);
|
|
968
|
+
if (bits < 0)
|
|
969
|
+
return -1;
|
|
970
|
+
if (!this.sharedNode(root.node))
|
|
971
|
+
return -1;
|
|
972
|
+
this.node = root.node;
|
|
973
|
+
const index = this.nextIndex();
|
|
974
|
+
this.memo(t, index);
|
|
975
|
+
this.begin(21 /* RecordKind.DistributedConditional */, index, refs, bits | 256 /* RecordHeader.HasNode */);
|
|
976
|
+
this.writer.word(distributed.tag);
|
|
977
|
+
return index;
|
|
978
|
+
}
|
|
979
|
+
const refs = this.types(args);
|
|
980
|
+
if (this.failure !== undefined)
|
|
981
|
+
return -1;
|
|
982
|
+
const alias = t.alias;
|
|
983
|
+
const aliasRefs = alias === undefined ? noRefs : this.types(alias.typeArguments);
|
|
984
|
+
if (this.failure !== undefined)
|
|
985
|
+
return -1;
|
|
986
|
+
const bits = this.aliasBits(alias, aliasRefs);
|
|
987
|
+
if (bits < 0)
|
|
988
|
+
return -1;
|
|
989
|
+
if (!this.sharedNode(root.node))
|
|
990
|
+
return -1;
|
|
991
|
+
this.node = root.node;
|
|
992
|
+
const index = this.nextIndex();
|
|
993
|
+
this.memo(t, index);
|
|
994
|
+
this.begin(16 /* RecordKind.Conditional */, index, refs, bits | 256 /* RecordHeader.HasNode */);
|
|
995
|
+
this.writer.word(tag);
|
|
996
|
+
return index;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
/** Object flags that checkers compute after creating a type (a function: see `sharedValueFlags`). */
|
|
1000
|
+
function lazyObjectFlags() {
|
|
1001
|
+
return (524288 /* ObjectFlags.CouldContainTypeVariablesComputed */ |
|
|
1002
|
+
1048576 /* ObjectFlags.CouldContainTypeVariables */ |
|
|
1003
|
+
2097152 /* ObjectFlags.MembersResolved */ |
|
|
1004
|
+
-2147483648 /* ObjectFlags.SideState */ |
|
|
1005
|
+
134217728 /* ObjectFlags.IdenticalBaseTypeCalculated */ |
|
|
1006
|
+
268435456 /* ObjectFlags.IdenticalBaseTypeExists */);
|
|
1007
|
+
}
|
|
1008
|
+
/** Translates records into a checker's own types; one translation per producer type. */
|
|
1009
|
+
const noTypes = [];
|
|
1010
|
+
/** A type alias whose symbol and type arguments are read: its declared type first, as instantiating it does. */
|
|
1011
|
+
function typeAliasOf(c, symbol, refs) {
|
|
1012
|
+
// An instantiation of an alias follows its declared type, which records the alias's type parameters.
|
|
1013
|
+
getDeclaredTypeOfSymbol(c, symbol);
|
|
1014
|
+
return new TypeAlias(symbol, refs);
|
|
1015
|
+
}
|
|
1016
|
+
/** Translates the records of another checker's store into this checker's types, reading them where they are. */
|
|
1017
|
+
export class Translator {
|
|
1018
|
+
c;
|
|
1019
|
+
store;
|
|
1020
|
+
initial;
|
|
1021
|
+
/** Set when a record has no counterpart here; the translation is then abandoned. */
|
|
1022
|
+
failed = false;
|
|
1023
|
+
constructor(c, store) {
|
|
1024
|
+
this.c = c;
|
|
1025
|
+
this.store = store;
|
|
1026
|
+
this.initial = initialTypes(c);
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* The symbol of `node`, named by `how`: the symbol of the node itself, or its export symbol. The record names
|
|
1030
|
+
* symbols of the program this way, and a consumer that hasn't the symbol fails the translation.
|
|
1031
|
+
*/
|
|
1032
|
+
namedSymbol(node, how) {
|
|
1033
|
+
const local = getSymbol(node);
|
|
1034
|
+
return how === 2 /* SymbolNaming.Export */ ? local?.exportSymbol : local;
|
|
1035
|
+
}
|
|
1036
|
+
/** Abandons the record being read: the translation fails, and a later one starts afresh. */
|
|
1037
|
+
abandon() {
|
|
1038
|
+
this.failed = true;
|
|
1039
|
+
return undefined;
|
|
1040
|
+
}
|
|
1041
|
+
/** A property symbol made as the producer made it; undefined if its record can't be read here. */
|
|
1042
|
+
property(index) {
|
|
1043
|
+
const c = this.c;
|
|
1044
|
+
const store = this.store;
|
|
1045
|
+
const reader = store.reader;
|
|
1046
|
+
if (!reader.begin(index))
|
|
1047
|
+
return this.abandon();
|
|
1048
|
+
const f = reader.numbers;
|
|
1049
|
+
const type = store.types.get(f[reader.refAt]);
|
|
1050
|
+
if (type === undefined)
|
|
1051
|
+
return this.abandon();
|
|
1052
|
+
const nameAt = f[reader.refAt + 1];
|
|
1053
|
+
const targetAt = f[reader.refAt + 2];
|
|
1054
|
+
let parent = undefined;
|
|
1055
|
+
if (reader.aliasNaming >= 0) {
|
|
1056
|
+
if (reader.aliasNaming === 3 /* SymbolNaming.Merged */)
|
|
1057
|
+
parent = c.mergedSymbols.get(reader.aliasMergedId);
|
|
1058
|
+
else {
|
|
1059
|
+
const node = reader.readNode(reader.aliasNodeStart);
|
|
1060
|
+
if (node === undefined)
|
|
1061
|
+
return this.abandon();
|
|
1062
|
+
parent = this.namedSymbol(node, reader.aliasNaming);
|
|
1063
|
+
}
|
|
1064
|
+
if (parent === undefined)
|
|
1065
|
+
return this.abandon();
|
|
1066
|
+
}
|
|
1067
|
+
let source = undefined;
|
|
1068
|
+
if (reader.symbolNaming === 3 /* SymbolNaming.Merged */)
|
|
1069
|
+
source = c.mergedSymbols.get(reader.symbolMergedId);
|
|
1070
|
+
else if (reader.symbolNaming !== 0 /* SymbolNaming.None */) {
|
|
1071
|
+
const node = reader.readNode(reader.symbolNodeStart);
|
|
1072
|
+
if (node === undefined)
|
|
1073
|
+
return this.abandon();
|
|
1074
|
+
source = this.namedSymbol(node, reader.symbolNaming);
|
|
1075
|
+
}
|
|
1076
|
+
if (reader.symbolNaming !== 0 /* SymbolNaming.None */ && source === undefined)
|
|
1077
|
+
return this.abandon();
|
|
1078
|
+
let value = undefined;
|
|
1079
|
+
if (reader.nodeStart >= 0) {
|
|
1080
|
+
value = reader.readNode(reader.nodeStart);
|
|
1081
|
+
if (value === undefined)
|
|
1082
|
+
return this.abandon();
|
|
1083
|
+
}
|
|
1084
|
+
let p = reader.fields;
|
|
1085
|
+
const flags = f[p++];
|
|
1086
|
+
const checkFlags = f[p++];
|
|
1087
|
+
const text = reader.textAt(p);
|
|
1088
|
+
p += 2;
|
|
1089
|
+
const count = f[p++];
|
|
1090
|
+
const declarations = [];
|
|
1091
|
+
for (let i = 0; i < count; i++) {
|
|
1092
|
+
const node = reader.readNode(p);
|
|
1093
|
+
p += reader.nodeWords(p);
|
|
1094
|
+
if (node === undefined)
|
|
1095
|
+
return this.abandon();
|
|
1096
|
+
declarations.push(node);
|
|
1097
|
+
}
|
|
1098
|
+
if ((reader.header & 512 /* RecordHeader.ValueIsFirst */) !== 0)
|
|
1099
|
+
value = declarations[0];
|
|
1100
|
+
const prop = c.newSymbolWithCheckFlags(flags & ~33554432 /* SymbolFlags.Transient */, text, checkFlags);
|
|
1101
|
+
setDeclarations(prop, declarations);
|
|
1102
|
+
prop.valueDeclaration = value;
|
|
1103
|
+
if (parent !== undefined)
|
|
1104
|
+
prop.parent = parent;
|
|
1105
|
+
const id = getSymbolId(prop);
|
|
1106
|
+
c.symbolTypes.set(id, type);
|
|
1107
|
+
if (nameAt >= 0) {
|
|
1108
|
+
const nameType = store.types.get(nameAt);
|
|
1109
|
+
if (nameType === undefined)
|
|
1110
|
+
return this.abandon();
|
|
1111
|
+
c.symbolNameTypes.set(id, nameType);
|
|
1112
|
+
}
|
|
1113
|
+
const target = targetAt >= 0 ? store.symbols.get(targetAt) : source;
|
|
1114
|
+
if (target !== undefined)
|
|
1115
|
+
c.symbolTargets.set(id, target);
|
|
1116
|
+
return prop;
|
|
1117
|
+
}
|
|
1118
|
+
/** Sets the members of the `AnonymousObject` record a `CompleteObject` record completes; false if it can't read it. */
|
|
1119
|
+
complete(index) {
|
|
1120
|
+
const c = this.c;
|
|
1121
|
+
const store = this.store;
|
|
1122
|
+
const reader = store.reader;
|
|
1123
|
+
if (!reader.begin(index))
|
|
1124
|
+
return false;
|
|
1125
|
+
const f = reader.numbers;
|
|
1126
|
+
const refAt = reader.refAt;
|
|
1127
|
+
let p = reader.fields;
|
|
1128
|
+
const shell = store.types.get(f[p++]);
|
|
1129
|
+
if (shell === undefined)
|
|
1130
|
+
return false;
|
|
1131
|
+
if ((shell.objectFlags & 2097152 /* ObjectFlags.MembersResolved */) !== 0)
|
|
1132
|
+
return true;
|
|
1133
|
+
const members = new Map();
|
|
1134
|
+
for (let i = 0; i < reader.refCount; i++) {
|
|
1135
|
+
const prop = store.symbols.get(f[refAt + i]);
|
|
1136
|
+
if (prop === undefined)
|
|
1137
|
+
return false;
|
|
1138
|
+
members.set(prop.name, prop);
|
|
1139
|
+
}
|
|
1140
|
+
const count = f[p++];
|
|
1141
|
+
const infos = [];
|
|
1142
|
+
for (let i = 0; i < count; i++) {
|
|
1143
|
+
const keyType = store.types.get(f[p]);
|
|
1144
|
+
const valueType = store.types.get(f[p + 1]);
|
|
1145
|
+
const isReadonly = f[p + 2] === 1;
|
|
1146
|
+
p += 3;
|
|
1147
|
+
const declaration = reader.readNode(p);
|
|
1148
|
+
p += reader.nodeWords(p);
|
|
1149
|
+
const components = [];
|
|
1150
|
+
const componentCount = f[p++];
|
|
1151
|
+
for (let j = 0; j < componentCount; j++) {
|
|
1152
|
+
const node = reader.readNode(p);
|
|
1153
|
+
p += reader.nodeWords(p);
|
|
1154
|
+
if (node === undefined)
|
|
1155
|
+
return false;
|
|
1156
|
+
components.push(node);
|
|
1157
|
+
}
|
|
1158
|
+
if (keyType === undefined || valueType === undefined)
|
|
1159
|
+
return false;
|
|
1160
|
+
infos.push(new IndexInfo(keyType, valueType, isReadonly, declaration, components));
|
|
1161
|
+
}
|
|
1162
|
+
setStructuredTypeMembers(c, shell, members, [], [], infos);
|
|
1163
|
+
keepPropertiesOnly(c, shell, members, scannedLiteralPropertiesLimit);
|
|
1164
|
+
return true;
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Resolves the declared type of the type alias whose declaration contains the type node `node`, as resolving its
|
|
1168
|
+
* nodes through the alias does: that records the alias's type parameters, which its variances are measured with.
|
|
1169
|
+
* Sets `failed` if the alias's declared type is being resolved here.
|
|
1170
|
+
*/
|
|
1171
|
+
aliasOfNode(node) {
|
|
1172
|
+
const c = this.c;
|
|
1173
|
+
for (let n = node; n !== undefined; n = n.parent) {
|
|
1174
|
+
if (n.kind !== 267 /* SyntaxKind.TypeAliasDeclaration */ && n.kind !== 346 /* SyntaxKind.JSTypeAliasDeclaration */)
|
|
1175
|
+
continue;
|
|
1176
|
+
const symbol = getSymbol(n);
|
|
1177
|
+
if (symbol === undefined || c.symbolLinks(symbol).declaredType !== undefined)
|
|
1178
|
+
return;
|
|
1179
|
+
if (findResolutionCycleStartIndex(c, symbol, 2 /* TypeSystemPropertyName.DeclaredType */) >= 0)
|
|
1180
|
+
this.failed = true;
|
|
1181
|
+
else
|
|
1182
|
+
getDeclaredTypeOfSymbol(c, symbol);
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
/** The type record `index`; undefined if it or a record it needs can't be translated here. */
|
|
1187
|
+
record(index) {
|
|
1188
|
+
const c = this.c;
|
|
1189
|
+
const store = this.store;
|
|
1190
|
+
const reader = store.reader;
|
|
1191
|
+
if (!reader.begin(index))
|
|
1192
|
+
return this.abandon();
|
|
1193
|
+
const f = reader.numbers;
|
|
1194
|
+
const header = reader.header;
|
|
1195
|
+
const kind = reader.kind;
|
|
1196
|
+
const n = reader.refCount;
|
|
1197
|
+
// An instantiation's refs end with the return types of its signatures, which are built after it.
|
|
1198
|
+
const count = kind === 11 /* RecordKind.Instantiation */ ? Math.min(n, 1 + f[reader.fields]) : n;
|
|
1199
|
+
const refs = new Array(count);
|
|
1200
|
+
for (let i = 0; i < count; i++) {
|
|
1201
|
+
const t = store.types.get(f[reader.refAt + i]);
|
|
1202
|
+
if (t === undefined)
|
|
1203
|
+
return this.abandon();
|
|
1204
|
+
refs[i] = t;
|
|
1205
|
+
}
|
|
1206
|
+
let aliasSymbol = undefined;
|
|
1207
|
+
let aliasRefs = noTypes;
|
|
1208
|
+
if (reader.aliasNaming >= 0) {
|
|
1209
|
+
if (reader.aliasNaming === 3 /* SymbolNaming.Merged */) {
|
|
1210
|
+
aliasSymbol = c.mergedSymbols.get(reader.aliasMergedId);
|
|
1211
|
+
if (aliasSymbol === undefined)
|
|
1212
|
+
return this.abandon();
|
|
1213
|
+
}
|
|
1214
|
+
else {
|
|
1215
|
+
const aliasNode = reader.readNode(reader.aliasNodeStart);
|
|
1216
|
+
if (aliasNode === undefined)
|
|
1217
|
+
return this.abandon();
|
|
1218
|
+
aliasSymbol = this.namedSymbol(aliasNode, reader.aliasNaming);
|
|
1219
|
+
if (aliasSymbol === undefined)
|
|
1220
|
+
return this.abandon();
|
|
1221
|
+
}
|
|
1222
|
+
const aliasCount = reader.aliasRefCount;
|
|
1223
|
+
const types = new Array(aliasCount);
|
|
1224
|
+
for (let i = 0; i < aliasCount; i++) {
|
|
1225
|
+
const t = store.types.get(f[reader.aliasRefAt + i]);
|
|
1226
|
+
if (t === undefined)
|
|
1227
|
+
return this.abandon();
|
|
1228
|
+
types[i] = t;
|
|
1229
|
+
}
|
|
1230
|
+
aliasRefs = types;
|
|
1231
|
+
}
|
|
1232
|
+
let symbol = undefined;
|
|
1233
|
+
if (reader.symbolNaming === 3 /* SymbolNaming.Merged */) {
|
|
1234
|
+
symbol = c.mergedSymbols.get(reader.symbolMergedId);
|
|
1235
|
+
if (symbol === undefined)
|
|
1236
|
+
return this.abandon();
|
|
1237
|
+
}
|
|
1238
|
+
else if (reader.symbolNaming !== 0 /* SymbolNaming.None */) {
|
|
1239
|
+
const symbolNode = reader.readNode(reader.symbolNodeStart);
|
|
1240
|
+
if (symbolNode === undefined)
|
|
1241
|
+
return this.abandon();
|
|
1242
|
+
symbol = this.namedSymbol(symbolNode, reader.symbolNaming);
|
|
1243
|
+
if (symbol === undefined)
|
|
1244
|
+
return this.abandon();
|
|
1245
|
+
}
|
|
1246
|
+
let node = undefined;
|
|
1247
|
+
if (reader.nodeStart >= 0) {
|
|
1248
|
+
node = reader.readNode(reader.nodeStart);
|
|
1249
|
+
if (node === undefined)
|
|
1250
|
+
return this.abandon();
|
|
1251
|
+
}
|
|
1252
|
+
let p = reader.fields;
|
|
1253
|
+
switch (kind) {
|
|
1254
|
+
case 0 /* RecordKind.Initial */:
|
|
1255
|
+
return this.initial[f[p]];
|
|
1256
|
+
case 1 /* RecordKind.Literal */: {
|
|
1257
|
+
const flags = f[p++];
|
|
1258
|
+
if ((flags & 2048 /* TypeFlags.NumberLiteral */) !== 0)
|
|
1259
|
+
return getNumberLiteralType(c, reader.doubleAt(p));
|
|
1260
|
+
const text = reader.textAt(p);
|
|
1261
|
+
return (flags & 1024 /* TypeFlags.StringLiteral */) !== 0 ? getStringLiteralType(c, text) : getBigIntLiteralType(c, text);
|
|
1262
|
+
}
|
|
1263
|
+
case 2 /* RecordKind.FreshLiteral */:
|
|
1264
|
+
return getFreshTypeOfLiteralType(c, refs[0]);
|
|
1265
|
+
case 3 /* RecordKind.EnumLiteral */:
|
|
1266
|
+
case 5 /* RecordKind.Declared */:
|
|
1267
|
+
return getDeclaredTypeOfSymbol(c, symbol);
|
|
1268
|
+
case 6 /* RecordKind.ThisType */:
|
|
1269
|
+
return getDeclaredTypeOfSymbol(c, symbol).thisType;
|
|
1270
|
+
case 4 /* RecordKind.UniqueSymbol */:
|
|
1271
|
+
return getESSymbolLikeTypeForNode(c, symbol.valueDeclaration);
|
|
1272
|
+
case 7 /* RecordKind.SymbolType */:
|
|
1273
|
+
return getTypeOfSymbol(c, symbol);
|
|
1274
|
+
case 8 /* RecordKind.NodeType */: {
|
|
1275
|
+
const cached = c.resolvedTypes.get(node.id);
|
|
1276
|
+
if (cached !== undefined)
|
|
1277
|
+
return cached;
|
|
1278
|
+
this.aliasOfNode(node);
|
|
1279
|
+
if (this.failed)
|
|
1280
|
+
return undefined;
|
|
1281
|
+
const t = getTypeFromTypeNode(c, node);
|
|
1282
|
+
return c.resolvedTypes.get(node.id) ?? t;
|
|
1283
|
+
}
|
|
1284
|
+
case 9 /* RecordKind.Reference */:
|
|
1285
|
+
return createTypeReference(c, refs[0], refs.slice(1));
|
|
1286
|
+
case 10 /* RecordKind.TupleTarget */: {
|
|
1287
|
+
const readonly = f[p++] === 1;
|
|
1288
|
+
const infosCount = f[p++];
|
|
1289
|
+
const infos = [];
|
|
1290
|
+
for (let i = 0; i < infosCount; i++) {
|
|
1291
|
+
const flags = f[p++];
|
|
1292
|
+
const label = reader.readNode(p);
|
|
1293
|
+
p += reader.nodeWords(p);
|
|
1294
|
+
infos.push(new TupleElementInfo(flags, label));
|
|
1295
|
+
}
|
|
1296
|
+
return getTupleTargetType(c, infos, readonly);
|
|
1297
|
+
}
|
|
1298
|
+
case 11 /* RecordKind.Instantiation */: {
|
|
1299
|
+
const args = f[p++];
|
|
1300
|
+
const target = refs[0];
|
|
1301
|
+
const typeParameters = outerTypeParametersOf(c, node, target);
|
|
1302
|
+
return instantiateTypeWithAlias(c, target, newTypeMapper(typeParameters, refs.slice(1, 1 + args)), aliasSymbol === undefined ? undefined : typeAliasOf(c, aliasSymbol, aliasRefs));
|
|
1303
|
+
}
|
|
1304
|
+
case 12 /* RecordKind.Union */: {
|
|
1305
|
+
const flags = f[p++];
|
|
1306
|
+
const originAt = f[p++];
|
|
1307
|
+
if ((header & 2048 /* RecordHeader.Constituent */) !== 0)
|
|
1308
|
+
return newUnionType(c, flags & 0 /* ObjectFlags.None */, refs);
|
|
1309
|
+
return getUnionTypeFromSortedList(c, refs, flags & (32768 /* ObjectFlags.PrimitiveUnion */ | 33554432 /* ObjectFlags.ContainsIntersections */), aliasSymbol === undefined ? undefined : typeAliasOf(c, aliasSymbol, aliasRefs), originAt >= 0 ? store.types.get(originAt) : undefined);
|
|
1310
|
+
}
|
|
1311
|
+
case 13 /* RecordKind.Intersection */: {
|
|
1312
|
+
const flags = f[p++];
|
|
1313
|
+
if ((header & 2048 /* RecordHeader.Constituent */) !== 0)
|
|
1314
|
+
return newIntersectionType(c, 0 /* ObjectFlags.None */, refs);
|
|
1315
|
+
const alias = aliasSymbol === undefined ? undefined : typeAliasOf(c, aliasSymbol, aliasRefs);
|
|
1316
|
+
const hash = typeListHash(refs, alias, 0);
|
|
1317
|
+
const existing = c.intersectionTypes.get(hash, refs, alias, 0);
|
|
1318
|
+
if (existing !== undefined)
|
|
1319
|
+
return existing;
|
|
1320
|
+
const result = newIntersectionType(c, (flags & 134217728 /* ObjectFlags.IsConstrainedTypeVariable */) | getPropagatingFlagsOfTypes(refs, 12 /* TypeFlags.Nullable */), refs);
|
|
1321
|
+
result.alias = alias;
|
|
1322
|
+
c.intersectionTypes.set(hash, refs, alias, 0, result);
|
|
1323
|
+
return result;
|
|
1324
|
+
}
|
|
1325
|
+
case 14 /* RecordKind.Index */:
|
|
1326
|
+
return getIndexTypeEx(c, refs[0], f[p]);
|
|
1327
|
+
case 15 /* RecordKind.IndexedAccess */:
|
|
1328
|
+
return getIndexedAccessTypeEx(c, refs[0], refs[1], f[p], undefined, aliasSymbol === undefined ? undefined : typeAliasOf(c, aliasSymbol, aliasRefs));
|
|
1329
|
+
case 16 /* RecordKind.Conditional */: {
|
|
1330
|
+
const tag = f[p++];
|
|
1331
|
+
this.aliasOfNode(node);
|
|
1332
|
+
if (this.failed)
|
|
1333
|
+
return undefined;
|
|
1334
|
+
const declared = c.resolvedTypes.get(node.id) ?? getTypeFromTypeNode(c, node);
|
|
1335
|
+
const root = declared.root;
|
|
1336
|
+
return getConditionalTypeInstantiation(c, declared, newTypeMapper(root.outerTypeParameters, refs), tag === 1, aliasSymbol === undefined ? undefined : typeAliasOf(c, aliasSymbol, aliasRefs));
|
|
1337
|
+
}
|
|
1338
|
+
case 21 /* RecordKind.DistributedConditional */: {
|
|
1339
|
+
const tag = f[p++];
|
|
1340
|
+
this.aliasOfNode(node);
|
|
1341
|
+
if (this.failed)
|
|
1342
|
+
return undefined;
|
|
1343
|
+
const declared = (c.resolvedTypes.get(node.id) ?? getTypeFromTypeNode(c, node));
|
|
1344
|
+
const root = declared.root;
|
|
1345
|
+
const args = refs.slice(0, refs.length - 1);
|
|
1346
|
+
const alias = aliasSymbol === undefined ? undefined : typeAliasOf(c, aliasSymbol, aliasRefs);
|
|
1347
|
+
getConditionalTypeInstantiation(c, declared, newTypeMapper(root.outerTypeParameters, args), tag === 1, alias);
|
|
1348
|
+
const member = c.distributedByKey?.get(distributedKey(root.node.id, args, alias, tag, refs[refs.length - 1]));
|
|
1349
|
+
if (member === undefined)
|
|
1350
|
+
return this.abandon();
|
|
1351
|
+
return member;
|
|
1352
|
+
}
|
|
1353
|
+
case 17 /* RecordKind.Template */: {
|
|
1354
|
+
const textsCount = f[p++];
|
|
1355
|
+
const texts = [];
|
|
1356
|
+
for (let i = 0; i < textsCount; i++) {
|
|
1357
|
+
texts.push(reader.textAt(p));
|
|
1358
|
+
p += 2;
|
|
1359
|
+
}
|
|
1360
|
+
return getTemplateLiteralType(c, texts, refs);
|
|
1361
|
+
}
|
|
1362
|
+
case 18 /* RecordKind.StringMapping */:
|
|
1363
|
+
return getStringMappingType(c, symbol, refs[0]);
|
|
1364
|
+
case 19 /* RecordKind.Substitution */:
|
|
1365
|
+
return getSubstitutionType(c, refs[0], refs[1]);
|
|
1366
|
+
case 20 /* RecordKind.NoInfer */:
|
|
1367
|
+
return getNoInferType(c, refs[0]);
|
|
1368
|
+
case 22 /* RecordKind.AnonymousObject */: {
|
|
1369
|
+
// A translation that failed after this record opened the type still made it, and a record built then may name
|
|
1370
|
+
// it: the completion must fill that type, not a new one beside it.
|
|
1371
|
+
const known = store.types.get(index);
|
|
1372
|
+
if (known !== undefined)
|
|
1373
|
+
return known;
|
|
1374
|
+
return newObjectType(c, f[p] | 16 /* ObjectFlags.Anonymous */, symbol);
|
|
1375
|
+
}
|
|
1376
|
+
case 23 /* RecordKind.CompleteObject */:
|
|
1377
|
+
case 24 /* RecordKind.Property */:
|
|
1378
|
+
return this.abandon();
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
function outerTypeParametersOf(c, declaration, target) {
|
|
1383
|
+
const known = c.nodeLinks(declaration).outerTypeParameters;
|
|
1384
|
+
if (known !== undefined)
|
|
1385
|
+
return known;
|
|
1386
|
+
// The first instantiation records them; an identity instantiation computes them without creating a type.
|
|
1387
|
+
const probe = c.nodeLinks(declaration);
|
|
1388
|
+
instantiateTypeWithAlias(c, target, newTypeMapper([c.anyType], [c.anyType]), undefined);
|
|
1389
|
+
return probe.outerTypeParameters ?? [];
|
|
1390
|
+
}
|
|
1391
|
+
/** Whether the type of `symbol` is shared: a variable or property declared in the program, other than parameters. */
|
|
1392
|
+
export function isSharedValueSymbol(symbol) {
|
|
1393
|
+
if (symbol.checkFlags !== 0 || (symbol.flags & 33554432 /* SymbolFlags.Transient */) !== 0)
|
|
1394
|
+
return false;
|
|
1395
|
+
if ((symbol.flags & sharedValueFlags()) === 0)
|
|
1396
|
+
return false;
|
|
1397
|
+
const declaration = symbol.valueDeclaration;
|
|
1398
|
+
return (declaration !== undefined &&
|
|
1399
|
+
declaration.kind !== 171 /* SyntaxKind.Parameter */ &&
|
|
1400
|
+
declaration.kind !== 210 /* SyntaxKind.BindingElement */);
|
|
1401
|
+
}
|
|
1402
|
+
/** Whether the return type of `sig` is shared: the signature of a declaration, as `getSignatureFromDeclaration` makes it. */
|
|
1403
|
+
export function isSharedReturnSignature(c, sig) {
|
|
1404
|
+
const declaration = sig.declaration;
|
|
1405
|
+
return (declaration !== undefined &&
|
|
1406
|
+
sig.target === undefined &&
|
|
1407
|
+
sig.composite === undefined &&
|
|
1408
|
+
(sig.flags & (16 /* SignatureFlags.IsInnerCallChain */ | 32 /* SignatureFlags.IsOuterCallChain */)) === 0 &&
|
|
1409
|
+
c.resolvedSignatures.get(declaration.id) === sig);
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* The columns of a checker's row of `ThreadSharingData.stats`: the milliseconds of its outermost
|
|
1413
|
+
* computations by kind (0 owned, 1 computed here for a file another checker took, 2 translated, 3
|
|
1414
|
+
* other), of exporting, translating and unpacking results, the results it posted and translated, and
|
|
1415
|
+
* the milliseconds it saved by translating a result instead of computing it.
|
|
1416
|
+
*/
|
|
1417
|
+
export const shareStatColumns = 10;
|
|
1418
|
+
export const shareStatKinds = 4;
|
|
1419
|
+
export const shareStatExport = 4;
|
|
1420
|
+
export const shareStatTranslation = 5;
|
|
1421
|
+
export const shareStatUnpack = 6;
|
|
1422
|
+
export const shareStatPosted = 7;
|
|
1423
|
+
export const shareStatTranslated = 8;
|
|
1424
|
+
export const shareStatSaved = 9;
|
|
1425
|
+
/**
|
|
1426
|
+
* The size of each checker's logs: numbers (int32s) and string code units (2 bytes each), 8 MB and 2 MB. Only the
|
|
1427
|
+
* pages a checker writes take memory.
|
|
1428
|
+
*/
|
|
1429
|
+
export const numberLogSize = 1 << 21;
|
|
1430
|
+
export const stringLogSize = 1 << 20;
|
|
1431
|
+
/** The number of records each checker's store can hold. */
|
|
1432
|
+
export const recordTableSize = 1 << 20;
|
|
1433
|
+
/** The int32s each checker gets in `ThreadSharingData.used`, a cache line each, for two counters. */
|
|
1434
|
+
export const usedStride = 16;
|
|
1435
|
+
/** The number of entries of each result table: a power of two. */
|
|
1436
|
+
export const resultTableSize = 1 << 20;
|
|
1437
|
+
/**
|
|
1438
|
+
* The most checker threads that share results: a result's state (`postedState`) holds the checker and an offset in
|
|
1439
|
+
* its number log, below `numberLogSize` (2^21), in one int32, so the count times 2^21 stays below 2^31 - 2.
|
|
1440
|
+
*/
|
|
1441
|
+
export const maxSharingCheckers = 1023;
|
|
1442
|
+
/** The state of the result checker `producer` of `count` posted at `offset` of its number log. */
|
|
1443
|
+
export function postedState(count, producer, offset) {
|
|
1444
|
+
return -2 - (producer + count * offset);
|
|
1445
|
+
}
|
|
1446
|
+
/** The checker that posted the result of `state`, of `count` checkers. */
|
|
1447
|
+
export function postedProducer(count, state) {
|
|
1448
|
+
return (-2 - state) % count;
|
|
1449
|
+
}
|
|
1450
|
+
/** The offset in its producer's number log of the result of `state`, of `count` checkers. */
|
|
1451
|
+
export function postedOffset(count, state) {
|
|
1452
|
+
return Math.floor((-2 - state) / count);
|
|
1453
|
+
}
|
|
1454
|
+
/** The int32 words of each file's forbidden bits (`ThreadSharingData.forbidden`): a bit for each of `count` checkers. */
|
|
1455
|
+
export function forbiddenWords(count) {
|
|
1456
|
+
return (count + 31) >>> 5;
|
|
1457
|
+
}
|
|
1458
|
+
/** Whether checker `index` of `count` took results for declarations of file `file` before any checker took it. */
|
|
1459
|
+
export function isForbidden(forbidden, count, file, index) {
|
|
1460
|
+
return (Atomics.load(forbidden, file * forbiddenWords(count) + (index >>> 5)) & (1 << (index & 31))) !== 0;
|
|
1461
|
+
}
|
|
1462
|
+
/** Whether checker `index` of `count` looked for a result for a declaration of file `file` and found none (`wanted`). */
|
|
1463
|
+
export function isWanted(wanted, count, file, index) {
|
|
1464
|
+
return (Atomics.load(wanted, file * forbiddenWords(count) + (index >>> 5)) & (1 << (index & 31))) !== 0;
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* An open-addressing table in a SharedArrayBuffer, from a key (a symbol or node id) to a result's state: 0 until a
|
|
1468
|
+
* checker posts it, then `postedState`.
|
|
1469
|
+
*/
|
|
1470
|
+
export class ResultTable {
|
|
1471
|
+
words;
|
|
1472
|
+
constructor(buffer) {
|
|
1473
|
+
this.words = new Int32Array(buffer);
|
|
1474
|
+
}
|
|
1475
|
+
/** The slot of `key`, inserted if absent; -1 if the table is full. */
|
|
1476
|
+
slot(key) {
|
|
1477
|
+
const words = this.words;
|
|
1478
|
+
const mask = resultTableSize - 1;
|
|
1479
|
+
let h = Math.imul(key, 0x9e3779b1) >>> 12;
|
|
1480
|
+
for (let probe = 0; probe < 64; probe++) {
|
|
1481
|
+
const i = (h + probe) & mask;
|
|
1482
|
+
const existing = Atomics.load(words, 2 * i);
|
|
1483
|
+
if (existing === key + 1)
|
|
1484
|
+
return i;
|
|
1485
|
+
if (existing === 0) {
|
|
1486
|
+
const previous = Atomics.compareExchange(words, 2 * i, 0, key + 1);
|
|
1487
|
+
if (previous === 0 || previous === key + 1)
|
|
1488
|
+
return i;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
return -1;
|
|
1492
|
+
}
|
|
1493
|
+
state(slot) {
|
|
1494
|
+
return Atomics.load(this.words, 2 * slot + 1);
|
|
1495
|
+
}
|
|
1496
|
+
/** The slot of `key`, or -1 if it has none. */
|
|
1497
|
+
find(key) {
|
|
1498
|
+
const words = this.words;
|
|
1499
|
+
const mask = resultTableSize - 1;
|
|
1500
|
+
let h = Math.imul(key, 0x9e3779b1) >>> 12;
|
|
1501
|
+
for (let probe = 0; probe < 64; probe++) {
|
|
1502
|
+
const i = (h + probe) & mask;
|
|
1503
|
+
const existing = Atomics.load(words, 2 * i);
|
|
1504
|
+
if (existing === key + 1)
|
|
1505
|
+
return i;
|
|
1506
|
+
if (existing === 0)
|
|
1507
|
+
return -1;
|
|
1508
|
+
}
|
|
1509
|
+
return -1;
|
|
1510
|
+
}
|
|
1511
|
+
/** Sets the state of `slot` to a posted result's unless one is there already. */
|
|
1512
|
+
publish(slot, state) {
|
|
1513
|
+
Atomics.compareExchange(this.words, 2 * slot + 1, 0, state);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
/** TSC_TS_SHARE_MIN_MS: the shortest computation a checker posts, in milliseconds (`shareFloorTotalMs` split by the checkers by default). */
|
|
1517
|
+
const shareMinValue = process.env.TSC_TS_SHARE_MIN_MS;
|
|
1518
|
+
/**
|
|
1519
|
+
* The floor, in milliseconds of checker time split over the checkers that share: 1 ms with 4 checkers, 0.25 ms with
|
|
1520
|
+
* 16.
|
|
1521
|
+
*/
|
|
1522
|
+
const shareFloorTotalMs = 4;
|
|
1523
|
+
/** `TSC_TS_SHARE_<name>` as a number, or `fallback`. */
|
|
1524
|
+
function shareNumber(name, fallback) {
|
|
1525
|
+
const value = process.env[name];
|
|
1526
|
+
if (value === undefined)
|
|
1527
|
+
return fallback;
|
|
1528
|
+
const parsed = Number(value);
|
|
1529
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* The posting rule's cost model: a post appends at most `(kappa*T - p0)/e` records (`T` the computation's time), a
|
|
1533
|
+
* take builds at most `lambda*T/c`, `p0` is what a post costs itself, `e` each record a post adds and `c` each record
|
|
1534
|
+
* a take builds, all in microseconds. The price instrumentation's replay (`TSC_TS_SHARE_PRICE`) fits them; the
|
|
1535
|
+
* `TSC_TS_SHARE_*` variables override them for measurement.
|
|
1536
|
+
*
|
|
1537
|
+
* Read where they are used, not once at module evaluation: this module is in an import cycle (it imports
|
|
1538
|
+
* `checker-symbols.js`, which imports `checker.js`, which imports this module), and scriptc rejects code that runs at
|
|
1539
|
+
* module evaluation there (SC1016: a class the cycle reaches can be accessed before its declaration runs), so a
|
|
1540
|
+
* `const kappa = shareNumber(...)` at the top level does not build.
|
|
1541
|
+
*/
|
|
1542
|
+
function shareKappa() {
|
|
1543
|
+
return shareNumber('TSC_TS_SHARE_KAPPA', 0.25);
|
|
1544
|
+
}
|
|
1545
|
+
function shareLambda() {
|
|
1546
|
+
return shareNumber('TSC_TS_SHARE_LAMBDA', 0.3);
|
|
1547
|
+
}
|
|
1548
|
+
function sharePostUs() {
|
|
1549
|
+
return shareNumber('TSC_TS_SHARE_P0_US', 0.3);
|
|
1550
|
+
}
|
|
1551
|
+
function shareExportRecordUs() {
|
|
1552
|
+
return shareNumber('TSC_TS_SHARE_E_US', 1.2);
|
|
1553
|
+
}
|
|
1554
|
+
function shareBuildRecordUs() {
|
|
1555
|
+
return shareNumber('TSC_TS_SHARE_C_US', 6.59);
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Whether a run posts cost-bounded is its configuration's choice (`RunConfig.bounded`), not a rule here: off by
|
|
1559
|
+
* default, because a bounded post costs a run that gains nothing by it (T3 server's c16 check was 8-9% slower),
|
|
1560
|
+
* and turned on where the project's own runs measured it faster (`run-config.ts`). A bounded run keeps the 2-8 ms
|
|
1561
|
+
* floor's sharing gate, posts only results another checker demanded, and budgets both the records a post adds and
|
|
1562
|
+
* the records a take builds; an unbounded run keeps Phase 1's rule and posts every result over the floor.
|
|
1563
|
+
*/
|
|
1564
|
+
/** The floor's total in milliseconds before the cost-bounded rule (`shareFloorTotalMs`): 2 ms at 16, 8 ms at 4. */
|
|
1565
|
+
const shareFloorTotalMsPhase1 = 32;
|
|
1566
|
+
/**
|
|
1567
|
+
* The rule of the design's Phase 2: a result is posted when it took at least the floor (`ThreadSharing.minMs`), and a
|
|
1568
|
+
* consumer builds at most `lambda*T/c` records to take one, where `T` is the producer's time for it.
|
|
1569
|
+
*/
|
|
1570
|
+
export class CostBoundedRule {
|
|
1571
|
+
bounded;
|
|
1572
|
+
/** `bounded` false is Phase 1's rule: the same floor, and a take that may build any number of records. */
|
|
1573
|
+
constructor(bounded) {
|
|
1574
|
+
this.bounded = bounded;
|
|
1575
|
+
}
|
|
1576
|
+
posts(sharing, _key, ms, _diagnosticFiles, _fileIndex) {
|
|
1577
|
+
return ms >= sharing.minMs;
|
|
1578
|
+
}
|
|
1579
|
+
buildBudget(ms) {
|
|
1580
|
+
return this.bounded ? Math.floor((shareLambda() * ms * 1000) / shareBuildRecordUs()) : Number.POSITIVE_INFINITY;
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
// Debugging: TSC_TS_SHARE_BLOCK and TSC_TS_SHARE_ALLOW name parts of file names (comma-separated, each optionally with
|
|
1584
|
+
// a range of declaration positions, `name@start-end`) whose results are never or only translated, and
|
|
1585
|
+
// TSC_TS_SHARE_TRACE=1 prints each translation.
|
|
1586
|
+
const shareBlockValue = process.env.TSC_TS_SHARE_BLOCK;
|
|
1587
|
+
const shareAllowValue = process.env.TSC_TS_SHARE_ALLOW;
|
|
1588
|
+
const shareTraceValue = process.env.TSC_TS_SHARE_TRACE;
|
|
1589
|
+
// Debugging: TSC_TS_SHARE_VERIFY=1 computes each result a checker could translate, translates it after, and prints
|
|
1590
|
+
// the results whose translation prints differently; =2 checks that a translation creates types record by record, in
|
|
1591
|
+
// the order the producer created them.
|
|
1592
|
+
const shareVerifyValue = process.env.TSC_TS_SHARE_VERIFY;
|
|
1593
|
+
/** Checks a translation against the computation it replaces (TSC_TS_SHARE_VERIFY). */
|
|
1594
|
+
function verifyTranslation(c, kind, node, own, translated) {
|
|
1595
|
+
const sharing = c.threadSharing;
|
|
1596
|
+
if (translated === undefined)
|
|
1597
|
+
return;
|
|
1598
|
+
sharing.verified++;
|
|
1599
|
+
if (translated === own)
|
|
1600
|
+
return;
|
|
1601
|
+
const a = typeToString(c, own);
|
|
1602
|
+
const b = typeToString(c, translated);
|
|
1603
|
+
if (a === b) {
|
|
1604
|
+
sharing.verifiedIdentity++;
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1607
|
+
process.stderr.write('share-verify: checker ' +
|
|
1608
|
+
sharing.data.index +
|
|
1609
|
+
' ' +
|
|
1610
|
+
kind +
|
|
1611
|
+
' of ' +
|
|
1612
|
+
getSourceFileOfNode(node).fileName +
|
|
1613
|
+
':' +
|
|
1614
|
+
node.pos +
|
|
1615
|
+
' computed ' +
|
|
1616
|
+
a +
|
|
1617
|
+
' translated ' +
|
|
1618
|
+
b +
|
|
1619
|
+
'\n');
|
|
1620
|
+
}
|
|
1621
|
+
/** Whether a part of `list` names `fileName`, and `pos` when the part ends in `@start-end`. */
|
|
1622
|
+
function namesFile(list, fileName, pos) {
|
|
1623
|
+
if (list === undefined)
|
|
1624
|
+
return false;
|
|
1625
|
+
for (const part of list.split(',')) {
|
|
1626
|
+
if (part === '')
|
|
1627
|
+
continue;
|
|
1628
|
+
const at = part.indexOf('@');
|
|
1629
|
+
if (at < 0) {
|
|
1630
|
+
if (fileName.includes(part))
|
|
1631
|
+
return true;
|
|
1632
|
+
continue;
|
|
1633
|
+
}
|
|
1634
|
+
const dash = part.indexOf('-', at);
|
|
1635
|
+
if (fileName.includes(part.slice(0, at)) &&
|
|
1636
|
+
pos >= Number(part.slice(at + 1, dash)) &&
|
|
1637
|
+
pos < Number(part.slice(dash + 1)))
|
|
1638
|
+
return true;
|
|
1639
|
+
}
|
|
1640
|
+
return false;
|
|
1641
|
+
}
|
|
1642
|
+
/** Whether the debugging options keep a result for a declaration at `node` from being translated. */
|
|
1643
|
+
function translationBlocked(node) {
|
|
1644
|
+
if (shareBlockValue === undefined && shareAllowValue === undefined)
|
|
1645
|
+
return false;
|
|
1646
|
+
const fileName = getSourceFileOfNode(node).fileName;
|
|
1647
|
+
if (namesFile(shareBlockValue, fileName, node.pos))
|
|
1648
|
+
return true;
|
|
1649
|
+
return shareAllowValue !== undefined && !namesFile(shareAllowValue, fileName, node.pos);
|
|
1650
|
+
}
|
|
1651
|
+
function traceTranslation(c, kind, node, producer) {
|
|
1652
|
+
if (shareTraceValue !== '1')
|
|
1653
|
+
return;
|
|
1654
|
+
process.stderr.write('share: checker ' +
|
|
1655
|
+
c.threadSharing.data.index +
|
|
1656
|
+
' translated ' +
|
|
1657
|
+
kind +
|
|
1658
|
+
' of ' +
|
|
1659
|
+
getSourceFileOfNode(node).fileName +
|
|
1660
|
+
':' +
|
|
1661
|
+
node.pos +
|
|
1662
|
+
' from ' +
|
|
1663
|
+
producer +
|
|
1664
|
+
'\n');
|
|
1665
|
+
}
|
|
1666
|
+
let threadSharingData = undefined;
|
|
1667
|
+
/** Sets the sharing data of this checker thread; its first checker shares with the other threads. */
|
|
1668
|
+
export function setThreadSharingData(data) {
|
|
1669
|
+
threadSharingData = data;
|
|
1670
|
+
}
|
|
1671
|
+
/** Gives `c` the thread's sharing state, if the thread shares and no checker of it has it yet. */
|
|
1672
|
+
export function startThreadSharing(c) {
|
|
1673
|
+
const data = threadSharingData;
|
|
1674
|
+
if (data === undefined)
|
|
1675
|
+
return;
|
|
1676
|
+
threadSharingData = undefined;
|
|
1677
|
+
c.threadSharing = new ThreadSharing(c, data);
|
|
1678
|
+
}
|
|
1679
|
+
/** A checker's state of sharing with the other checker threads. */
|
|
1680
|
+
/** A set of ids (symbol or node ids), a bit each. */
|
|
1681
|
+
export class IdBits {
|
|
1682
|
+
bits = new Uint32Array(1024);
|
|
1683
|
+
has(id) {
|
|
1684
|
+
const word = id >>> 5;
|
|
1685
|
+
return word < this.bits.length && (this.bits[word] & (1 << (id & 31))) !== 0;
|
|
1686
|
+
}
|
|
1687
|
+
add(id) {
|
|
1688
|
+
const word = id >>> 5;
|
|
1689
|
+
if (word >= this.bits.length) {
|
|
1690
|
+
let length = this.bits.length * 2;
|
|
1691
|
+
while (length <= word)
|
|
1692
|
+
length *= 2;
|
|
1693
|
+
const bits = new Uint32Array(length);
|
|
1694
|
+
bits.set(this.bits);
|
|
1695
|
+
this.bits = bits;
|
|
1696
|
+
}
|
|
1697
|
+
this.bits[word] = this.bits[word] | (1 << (id & 31));
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
* The files of the diagnostics of results, by key (a symbol or declaration id), with a bit per key: most results have
|
|
1702
|
+
* none, and the bit answers that without a lookup. A file is its index in the program (`Checker.fileIndex`), and -1
|
|
1703
|
+
* a diagnostic without a file.
|
|
1704
|
+
*/
|
|
1705
|
+
export class FilesByKey {
|
|
1706
|
+
files = new Map();
|
|
1707
|
+
keys = new IdBits();
|
|
1708
|
+
get(key) {
|
|
1709
|
+
return this.keys.has(key) ? this.files.get(key) : undefined;
|
|
1710
|
+
}
|
|
1711
|
+
set(key, files) {
|
|
1712
|
+
this.keys.add(key);
|
|
1713
|
+
this.files.set(key, files);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
export class ThreadSharing {
|
|
1717
|
+
c;
|
|
1718
|
+
data;
|
|
1719
|
+
types;
|
|
1720
|
+
returns;
|
|
1721
|
+
/** TSC_TS_SHARE_MIN_MS: the shortest computation this checker posts. */
|
|
1722
|
+
minMs;
|
|
1723
|
+
/**
|
|
1724
|
+
* Whether this run is cost-bounded, which the run's configuration chose (`RunConfig.bounded`, off by default and
|
|
1725
|
+
* learned from the project's records). Without it the run keeps Phase 1's behavior: no demand bits, no export or
|
|
1726
|
+
* take budget, the 2-8 ms floor.
|
|
1727
|
+
*/
|
|
1728
|
+
bounded;
|
|
1729
|
+
/**
|
|
1730
|
+
* The rule that decides which of this checker's results are posted, and how much a take may build. A small-result
|
|
1731
|
+
* tier stacks on it by constructing its own rule here. Built per checker, not once at module evaluation, for the
|
|
1732
|
+
* reason the cost model's functions give (`shareKappa`).
|
|
1733
|
+
*/
|
|
1734
|
+
rule;
|
|
1735
|
+
initialIndexes = new Map();
|
|
1736
|
+
initial;
|
|
1737
|
+
numberLogs = [];
|
|
1738
|
+
recordTables = [];
|
|
1739
|
+
stringLogs = [];
|
|
1740
|
+
used;
|
|
1741
|
+
takers;
|
|
1742
|
+
forbidden;
|
|
1743
|
+
/** The checkers that missed on a key in each file (`ThreadSharingData.wanted`). */
|
|
1744
|
+
wanted;
|
|
1745
|
+
/** The files this checker noted a miss on, so that each is marked in `wanted` once. */
|
|
1746
|
+
wantedFiles = new IdBits();
|
|
1747
|
+
/** The stop switch of every checker (`ThreadSharingData.control`). */
|
|
1748
|
+
control;
|
|
1749
|
+
/** This checker's row of the counters the main thread reads (`ThreadSharingData.stats`). */
|
|
1750
|
+
stats;
|
|
1751
|
+
row;
|
|
1752
|
+
/** The number of results this checker posted. */
|
|
1753
|
+
posted = 0;
|
|
1754
|
+
translated = 0;
|
|
1755
|
+
/**
|
|
1756
|
+
* Set while this checker exports a result into its store. A computation nested in the export walk can reach
|
|
1757
|
+
* another shared result: posting it would write its records in the middle of the record being exported, and an
|
|
1758
|
+
* export that failed would rewind over the posted result's words.
|
|
1759
|
+
*/
|
|
1760
|
+
exporting = false;
|
|
1761
|
+
/** Shared results a nested computation left to the checkers that compute them. */
|
|
1762
|
+
nested = 0;
|
|
1763
|
+
/** Outermost shared-kind computations: nesting depth, the kind of the current one, and the time by kind. */
|
|
1764
|
+
depth = 0;
|
|
1765
|
+
kind = 0;
|
|
1766
|
+
kindMs = [0, 0, 0, 0];
|
|
1767
|
+
/** Kinds: 0 owned, 1 computed here for a file another checker took, 2 translated, 3 other. */
|
|
1768
|
+
addOutermost(ms) {
|
|
1769
|
+
this.kindMs[this.kind] += ms;
|
|
1770
|
+
this.kind = 3;
|
|
1771
|
+
this.writeStats();
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Copies this checker's counters into its row of `stats`, the memory the main thread reads them from
|
|
1775
|
+
* while checking runs. Called where a counter changes, a few times per result at most.
|
|
1776
|
+
*/
|
|
1777
|
+
writeStats() {
|
|
1778
|
+
const s = this.stats;
|
|
1779
|
+
const row = this.row;
|
|
1780
|
+
for (let k = 0; k < shareStatKinds; k++)
|
|
1781
|
+
s[row + k] = this.kindMs[k];
|
|
1782
|
+
s[row + shareStatExport] = this.exportMs;
|
|
1783
|
+
s[row + shareStatTranslation] = this.translationMs;
|
|
1784
|
+
// A translation reads its records in place, so there is no separate unpacking time: shareStatUnpack stays 0.
|
|
1785
|
+
s[row + shareStatPosted] = this.posted;
|
|
1786
|
+
s[row + shareStatTranslated] = this.translated;
|
|
1787
|
+
}
|
|
1788
|
+
/** Adds to the milliseconds this checker saved by translating results instead of computing them. */
|
|
1789
|
+
addSaved(ms) {
|
|
1790
|
+
const at = this.row + shareStatSaved;
|
|
1791
|
+
this.stats[at] = this.stats[at] + ms;
|
|
1792
|
+
}
|
|
1793
|
+
/** Whether the main thread stopped translating posted results (control 2): this checker computes them. */
|
|
1794
|
+
stoppedTranslating() {
|
|
1795
|
+
return Atomics.load(this.control, 0) === 2;
|
|
1796
|
+
}
|
|
1797
|
+
notShareable = 0;
|
|
1798
|
+
notShareableMs = 0;
|
|
1799
|
+
/** Whether the outermost computations are timed by kind (TSC_TS_SHARE_SUMMARY). */
|
|
1800
|
+
timing = process.env.TSC_TS_SHARE_SUMMARY !== undefined;
|
|
1801
|
+
/** TSC_TS_SHARE_VERIFY: translations checked, and those equal only as text. */
|
|
1802
|
+
verified = 0;
|
|
1803
|
+
verifiedIdentity = 0;
|
|
1804
|
+
belowMin = 0;
|
|
1805
|
+
belowMinMs = 0;
|
|
1806
|
+
/** Results whose export passed the budget `kappa*T`, and translations that stopped at `lambda*T/c`. */
|
|
1807
|
+
overBudget = 0;
|
|
1808
|
+
overBudgetMs = 0;
|
|
1809
|
+
stoppedTranslations = 0;
|
|
1810
|
+
/** Results not posted because no checker that may take one missed on a key in the declaration's file. */
|
|
1811
|
+
notDemanded = 0;
|
|
1812
|
+
exportFailed = 0;
|
|
1813
|
+
exportFailedMs = 0;
|
|
1814
|
+
exportFailures = new Map();
|
|
1815
|
+
/** TSC_TS_SHARE_VERIFY=2: records whose translation created types before an earlier record's. */
|
|
1816
|
+
orderViolations = 0;
|
|
1817
|
+
storeFailed = 0;
|
|
1818
|
+
/** Of `storeFailed`, the results that didn't fit in this checker's logs. */
|
|
1819
|
+
logFull = 0;
|
|
1820
|
+
computedPrivately = 0;
|
|
1821
|
+
/** Results this checker computed and kept because the main thread stopped sharing (control 1 or 2). */
|
|
1822
|
+
stopped = 0;
|
|
1823
|
+
/** How often a posted result couldn't be taken here; and results for declarations of the checker's own files. */
|
|
1824
|
+
sawDoneUnusable = 0;
|
|
1825
|
+
owned = 0;
|
|
1826
|
+
/** The program's nodes results named, by id. */
|
|
1827
|
+
nodesById = new Map();
|
|
1828
|
+
origins = new MergedOrigins();
|
|
1829
|
+
translationMs = 0;
|
|
1830
|
+
exportMs = 0;
|
|
1831
|
+
/** The symbol and signature whose next `getTypeOfSymbol` or `getReturnTypeOfSignature` computes here. */
|
|
1832
|
+
computing = undefined;
|
|
1833
|
+
computingSignature = undefined;
|
|
1834
|
+
/** The value type of `symbol`, or else the return type of `sig`, computed here. */
|
|
1835
|
+
computeHere(symbol, sig) {
|
|
1836
|
+
if (symbol !== undefined) {
|
|
1837
|
+
this.computing = symbol;
|
|
1838
|
+
return getTypeOfSymbol(this.c, symbol);
|
|
1839
|
+
}
|
|
1840
|
+
this.computingSignature = sig;
|
|
1841
|
+
return getReturnTypeOfSignature(this.c, sig);
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* The files of the diagnostics each value type (by symbol id) and return type (by declaration id) reported, with
|
|
1845
|
+
* those of the results it used, cached and translated ones too; only for results with diagnostics. A checker that
|
|
1846
|
+
* takes a result checks none of these files, since it would have reported the diagnostics in them.
|
|
1847
|
+
*/
|
|
1848
|
+
typeFiles = new FilesByKey();
|
|
1849
|
+
returnFiles = new FilesByKey();
|
|
1850
|
+
/** The files of the computations in progress, innermost last. */
|
|
1851
|
+
fileStack = [];
|
|
1852
|
+
/** Adds `files` to those of the computation in progress. */
|
|
1853
|
+
noteFiles(files) {
|
|
1854
|
+
const stack = this.fileStack;
|
|
1855
|
+
if (files === undefined || stack.length === 0)
|
|
1856
|
+
return;
|
|
1857
|
+
let top = stack[stack.length - 1];
|
|
1858
|
+
if (top === undefined) {
|
|
1859
|
+
top = new Set();
|
|
1860
|
+
stack[stack.length - 1] = top;
|
|
1861
|
+
}
|
|
1862
|
+
for (const f of files)
|
|
1863
|
+
top.add(f);
|
|
1864
|
+
}
|
|
1865
|
+
/** The last `computeShared`: whether its result can be shared, and how long it took. */
|
|
1866
|
+
lastShareable = false;
|
|
1867
|
+
lastMs = 0;
|
|
1868
|
+
/** `tracked`, recording whether the result can be shared, which it can't when the computation met a resolution cycle. */
|
|
1869
|
+
computeShared(files, key, symbol, sig) {
|
|
1870
|
+
const c = this.c;
|
|
1871
|
+
const cycles = c.resolutionCycleCount;
|
|
1872
|
+
const start = performance.now();
|
|
1873
|
+
const t = this.tracked(files, key, symbol, sig);
|
|
1874
|
+
this.lastMs = performance.now() - start;
|
|
1875
|
+
this.lastShareable = cycles === c.resolutionCycleCount;
|
|
1876
|
+
return t;
|
|
1877
|
+
}
|
|
1878
|
+
/** Runs `compute`, keeping in `files` under `key` the files of its diagnostics and of the results it used. */
|
|
1879
|
+
tracked(files, key, symbol, sig) {
|
|
1880
|
+
const c = this.c;
|
|
1881
|
+
const diagnostics = c.diagnostics.added;
|
|
1882
|
+
const suggestions = c.suggestionDiagnostics.added;
|
|
1883
|
+
const deferred = c.deferredDiagnosticFiles;
|
|
1884
|
+
const diagnosticsBefore = diagnostics.length;
|
|
1885
|
+
const suggestionsBefore = suggestions.length;
|
|
1886
|
+
const deferredBefore = deferred.length;
|
|
1887
|
+
this.fileStack.push(undefined);
|
|
1888
|
+
try {
|
|
1889
|
+
return this.computeHere(symbol, sig);
|
|
1890
|
+
}
|
|
1891
|
+
finally {
|
|
1892
|
+
let own = this.fileStack.pop();
|
|
1893
|
+
for (let i = diagnosticsBefore; i < diagnostics.length; i++) {
|
|
1894
|
+
if (own === undefined)
|
|
1895
|
+
own = new Set();
|
|
1896
|
+
const file = diagnostics[i].file;
|
|
1897
|
+
own.add(file === undefined ? -1 : this.fileIndexOfName(file.fileName));
|
|
1898
|
+
}
|
|
1899
|
+
for (let i = suggestionsBefore; i < suggestions.length; i++) {
|
|
1900
|
+
if (own === undefined)
|
|
1901
|
+
own = new Set();
|
|
1902
|
+
const file = suggestions[i].file;
|
|
1903
|
+
own.add(file === undefined ? -1 : this.fileIndexOfName(file.fileName));
|
|
1904
|
+
}
|
|
1905
|
+
// A deferred diagnostic is reported where its file is checked, as the diagnostics it reported are.
|
|
1906
|
+
for (let i = deferredBefore; i < deferred.length; i++) {
|
|
1907
|
+
if (own === undefined)
|
|
1908
|
+
own = new Set();
|
|
1909
|
+
own.add(deferred[i]);
|
|
1910
|
+
}
|
|
1911
|
+
if (own !== undefined) {
|
|
1912
|
+
const list = [...own];
|
|
1913
|
+
files.set(key, list);
|
|
1914
|
+
this.noteFiles(list);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
/**
|
|
1919
|
+
* The index of the program file named `fileName`, or -1: a diagnostic in a file this checker hasn't is one every
|
|
1920
|
+
* checker would report, like a diagnostic without a file.
|
|
1921
|
+
*/
|
|
1922
|
+
fileIndexOfName(fileName) {
|
|
1923
|
+
let files = this.filesByIndex;
|
|
1924
|
+
if (files === undefined) {
|
|
1925
|
+
files = new Map();
|
|
1926
|
+
for (const [file, index] of this.c.fileIndex)
|
|
1927
|
+
files.set(file.fileName, index);
|
|
1928
|
+
this.filesByIndex = files;
|
|
1929
|
+
}
|
|
1930
|
+
return files.get(fileName) ?? -1;
|
|
1931
|
+
}
|
|
1932
|
+
/** The index of each file by name, built on first use. */
|
|
1933
|
+
filesByIndex = undefined;
|
|
1934
|
+
constructor(c, data) {
|
|
1935
|
+
this.c = c;
|
|
1936
|
+
// `tracked` reads the diagnostics a computation added, and deferred, from these lists.
|
|
1937
|
+
c.diagnostics.added = [];
|
|
1938
|
+
c.suggestionDiagnostics.added = [];
|
|
1939
|
+
c.deferredDiagnosticFiles = [];
|
|
1940
|
+
this.data = data;
|
|
1941
|
+
this.bounded = data.bounded;
|
|
1942
|
+
this.rule = new CostBoundedRule(this.bounded);
|
|
1943
|
+
this.used = new Int32Array(data.used);
|
|
1944
|
+
this.takers = new Int32Array(data.takers);
|
|
1945
|
+
this.forbidden = new Int32Array(data.forbidden);
|
|
1946
|
+
this.wanted = new Int32Array(data.wanted);
|
|
1947
|
+
this.control = new Int32Array(data.control);
|
|
1948
|
+
this.stats = new Float64Array(data.stats);
|
|
1949
|
+
this.row = data.index * shareStatColumns;
|
|
1950
|
+
this.types = new ResultTable(data.typeTable);
|
|
1951
|
+
this.returns = new ResultTable(data.returnTable);
|
|
1952
|
+
// The floor, lowered with the rest of the 2-8 ms threshold band when posting is cost-bounded: a posted result pays
|
|
1953
|
+
// when enough checkers need it, so it falls as checkers are added, to 0.25 ms with 16. Below the bounded count the
|
|
1954
|
+
// run keeps the 2-8 ms band, where the posts the extra floor would add are what the c4 gate measured as a cost.
|
|
1955
|
+
this.minMs =
|
|
1956
|
+
shareMinValue === undefined
|
|
1957
|
+
? (this.bounded ? shareFloorTotalMs : shareFloorTotalMsPhase1) / data.count
|
|
1958
|
+
: Number(shareMinValue);
|
|
1959
|
+
this.initial = initialTypes(c);
|
|
1960
|
+
for (let i = 0; i < this.initial.length; i++)
|
|
1961
|
+
this.initialIndexes.set(this.initial[i].id, i);
|
|
1962
|
+
for (let k = 0; k < data.count; k++) {
|
|
1963
|
+
this.numberLogs.push(new Int32Array(data.numberLogs[k]));
|
|
1964
|
+
this.recordTables.push(new Int32Array(data.recordTables[k]));
|
|
1965
|
+
this.stringLogs.push(new Uint16Array(data.stringLogs[k]));
|
|
1966
|
+
}
|
|
1967
|
+
if (process.env.TSC_TS_SHARE_SUMMARY !== undefined)
|
|
1968
|
+
process.on('exit', () => process.stderr.write(this.summary() + '\n'));
|
|
1969
|
+
}
|
|
1970
|
+
summary() {
|
|
1971
|
+
// The stores are written through a local cursor; the shared counters are only for this summary.
|
|
1972
|
+
const writer = this.storeExporter?.writer;
|
|
1973
|
+
const me = this.data.index;
|
|
1974
|
+
if (writer !== undefined) {
|
|
1975
|
+
this.used[usedStride * me] = writer.at;
|
|
1976
|
+
this.used[usedStride * me + 1] = writer.unitAt;
|
|
1977
|
+
}
|
|
1978
|
+
return ('checker ' +
|
|
1979
|
+
me +
|
|
1980
|
+
': outermost ms owned/computed here/translated/other ' +
|
|
1981
|
+
this.kindMs.map((v) => v.toFixed(0)).join('/') +
|
|
1982
|
+
'; posted ' +
|
|
1983
|
+
this.posted +
|
|
1984
|
+
' (' +
|
|
1985
|
+
this.storedRecords +
|
|
1986
|
+
' records), translated ' +
|
|
1987
|
+
this.translated +
|
|
1988
|
+
' (' +
|
|
1989
|
+
this.translationMs.toFixed(0) +
|
|
1990
|
+
' ms), export ' +
|
|
1991
|
+
this.exportMs.toFixed(0) +
|
|
1992
|
+
' ms, computed here ' +
|
|
1993
|
+
this.computedPrivately +
|
|
1994
|
+
' (' +
|
|
1995
|
+
this.sawDoneUnusable +
|
|
1996
|
+
' posted but not taken, ' +
|
|
1997
|
+
this.stopped +
|
|
1998
|
+
' after the stop switch), owned ' +
|
|
1999
|
+
this.owned +
|
|
2000
|
+
'; not posted: cycles ' +
|
|
2001
|
+
this.notShareable +
|
|
2002
|
+
' (' +
|
|
2003
|
+
this.notShareableMs.toFixed(0) +
|
|
2004
|
+
' ms), quick ' +
|
|
2005
|
+
this.belowMin +
|
|
2006
|
+
' (' +
|
|
2007
|
+
this.belowMinMs.toFixed(0) +
|
|
2008
|
+
' ms), not demanded ' +
|
|
2009
|
+
this.notDemanded +
|
|
2010
|
+
', over the export budget ' +
|
|
2011
|
+
this.overBudget +
|
|
2012
|
+
' (' +
|
|
2013
|
+
this.overBudgetMs.toFixed(0) +
|
|
2014
|
+
' ms), takes stopped at their budget ' +
|
|
2015
|
+
this.stoppedTranslations +
|
|
2016
|
+
', not exported ' +
|
|
2017
|
+
this.exportFailed +
|
|
2018
|
+
' (' +
|
|
2019
|
+
this.exportFailedMs.toFixed(0) +
|
|
2020
|
+
' ms: ' +
|
|
2021
|
+
[...this.exportFailures]
|
|
2022
|
+
.sort((a, b) => b[1] - a[1])
|
|
2023
|
+
.slice(0, 4)
|
|
2024
|
+
.map(([k, v]) => k + ' ' + v.toFixed(0))
|
|
2025
|
+
.join('; ') +
|
|
2026
|
+
'), in an export ' +
|
|
2027
|
+
this.nested +
|
|
2028
|
+
', not stored ' +
|
|
2029
|
+
this.storeFailed +
|
|
2030
|
+
' (logs full ' +
|
|
2031
|
+
this.logFull +
|
|
2032
|
+
', used ' +
|
|
2033
|
+
this.used[usedStride * me] +
|
|
2034
|
+
' numbers, ' +
|
|
2035
|
+
this.used[usedStride * me + 1] +
|
|
2036
|
+
' code units)' +
|
|
2037
|
+
(shareVerifyValue === '1'
|
|
2038
|
+
? '; verified ' + this.verified + ' (' + this.verifiedIdentity + ' equal as text)'
|
|
2039
|
+
: '') +
|
|
2040
|
+
(shareVerifyValue === '2' ? '; order violations ' + this.orderViolations : ''));
|
|
2041
|
+
}
|
|
2042
|
+
/**
|
|
2043
|
+
* Whether this checker checks `file`, or may: a result computed for a declaration in it is never taken here. That is
|
|
2044
|
+
* a file it took, and one checked in statement ranges; a file no checker took yet it never checks once it took a
|
|
2045
|
+
* result for it (`forbid`).
|
|
2046
|
+
*/
|
|
2047
|
+
owns(file) {
|
|
2048
|
+
const index = this.c.fileIndex.get(file);
|
|
2049
|
+
return index === undefined || this.ownsIndex(index);
|
|
2050
|
+
}
|
|
2051
|
+
/** Whether this checker checks file `index`, or may; -1 names a diagnostic without a file, which it has. */
|
|
2052
|
+
ownsIndex(index) {
|
|
2053
|
+
if (index < 0)
|
|
2054
|
+
return true;
|
|
2055
|
+
const taker = Atomics.load(this.takers, index);
|
|
2056
|
+
if (taker === 0)
|
|
2057
|
+
return false;
|
|
2058
|
+
return taker !== -2 && (taker < 0 || taker === this.data.index + 1);
|
|
2059
|
+
}
|
|
2060
|
+
/**
|
|
2061
|
+
* Notes that this checker looked for a result for a declaration in `file` and found none: a checker posts results
|
|
2062
|
+
* for that file only then (`demanded`). One `Atomics.or` per file and checker.
|
|
2063
|
+
*/
|
|
2064
|
+
want(file) {
|
|
2065
|
+
if (!this.bounded)
|
|
2066
|
+
return;
|
|
2067
|
+
const index = this.c.fileIndex.get(file);
|
|
2068
|
+
if (index === undefined || this.wantedFiles.has(index))
|
|
2069
|
+
return;
|
|
2070
|
+
this.wantedFiles.add(index);
|
|
2071
|
+
const me = this.data.index;
|
|
2072
|
+
Atomics.or(this.wanted, index * forbiddenWords(this.data.count) + (me >>> 5), 1 << (me & 31));
|
|
2073
|
+
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Whether a checker other than this one and the file's taker missed on a key in file `index`: someone other than
|
|
2076
|
+
* the checkers that already compute its declarations would take a result for one of them.
|
|
2077
|
+
*/
|
|
2078
|
+
demanded(index) {
|
|
2079
|
+
const count = this.data.count;
|
|
2080
|
+
const me = this.data.index;
|
|
2081
|
+
const words = forbiddenWords(count);
|
|
2082
|
+
const taker = Atomics.load(this.takers, index);
|
|
2083
|
+
const base = index * words;
|
|
2084
|
+
for (let w = 0; w < words; w++) {
|
|
2085
|
+
let bits = Atomics.load(this.wanted, base + w);
|
|
2086
|
+
if (w === me >>> 5)
|
|
2087
|
+
bits &= ~(1 << (me & 31));
|
|
2088
|
+
if (taker > 0 && w === (taker - 1) >>> 5)
|
|
2089
|
+
bits &= ~(1 << ((taker - 1) & 31));
|
|
2090
|
+
if (bits !== 0)
|
|
2091
|
+
return true;
|
|
2092
|
+
}
|
|
2093
|
+
return false;
|
|
2094
|
+
}
|
|
2095
|
+
/** After taking a result for a declaration in `file`: if no checker took the file yet, this one never will. */
|
|
2096
|
+
forbid(file) {
|
|
2097
|
+
const index = this.c.fileIndex.get(file);
|
|
2098
|
+
if (index !== undefined)
|
|
2099
|
+
this.forbidIndex(index);
|
|
2100
|
+
}
|
|
2101
|
+
forbidIndex(index) {
|
|
2102
|
+
if (index < 0)
|
|
2103
|
+
return;
|
|
2104
|
+
const me = this.data.index;
|
|
2105
|
+
if (Atomics.load(this.takers, index) === 0)
|
|
2106
|
+
Atomics.or(this.forbidden, index * forbiddenWords(this.data.count) + (me >>> 5), 1 << (me & 31));
|
|
2107
|
+
}
|
|
2108
|
+
/**
|
|
2109
|
+
* Whether taking a result would leave file `index` to no checker: no checker took it, and every other checker
|
|
2110
|
+
* took results for its declarations already. The main thread would check it, alone.
|
|
2111
|
+
*/
|
|
2112
|
+
forbidsLast(index) {
|
|
2113
|
+
if (Atomics.load(this.takers, index) !== 0)
|
|
2114
|
+
return false;
|
|
2115
|
+
const count = this.data.count;
|
|
2116
|
+
const me = this.data.index;
|
|
2117
|
+
const words = forbiddenWords(count);
|
|
2118
|
+
for (let w = 0; w < words; w++) {
|
|
2119
|
+
// The bits of the checkers this word holds, and this checker's.
|
|
2120
|
+
const n = Math.min(32, count - 32 * w);
|
|
2121
|
+
const all = n === 32 ? -1 : (1 << n) - 1;
|
|
2122
|
+
const mine = me >>> 5 === w ? 1 << (me & 31) : 0;
|
|
2123
|
+
if ((Atomics.load(this.forbidden, index * words + w) | mine) !== all)
|
|
2124
|
+
return false;
|
|
2125
|
+
}
|
|
2126
|
+
return true;
|
|
2127
|
+
}
|
|
2128
|
+
/** The result checker `k` posted at `offset` in its number log: the record of its type, and the files it named. */
|
|
2129
|
+
result(k, offset) {
|
|
2130
|
+
const numbers = this.numberLogs[k];
|
|
2131
|
+
const root = numbers[offset];
|
|
2132
|
+
const computeMs = numbers[offset + 1] / 1000;
|
|
2133
|
+
const count = numbers[offset + 2];
|
|
2134
|
+
const files = [];
|
|
2135
|
+
for (let i = 0; i < count; i++)
|
|
2136
|
+
files.push(numbers[offset + 3 + i]);
|
|
2137
|
+
return new StoredResult(root, files, computeMs);
|
|
2138
|
+
}
|
|
2139
|
+
/** The exporter of this checker's store: it exports each type once. */
|
|
2140
|
+
storeExporter = undefined;
|
|
2141
|
+
/**
|
|
2142
|
+
* Exports `t` into this checker's store and logs a result with it as the root; returns its state for the result
|
|
2143
|
+
* tables, -1 if it doesn't fit in the logs or a node or symbol in it can't be named across threads, or why it can't
|
|
2144
|
+
* be exported.
|
|
2145
|
+
*/
|
|
2146
|
+
post(t, diagnosticFiles, computeMs) {
|
|
2147
|
+
const c = this.c;
|
|
2148
|
+
const me = this.data.index;
|
|
2149
|
+
let exporter = this.storeExporter;
|
|
2150
|
+
if (exporter === undefined) {
|
|
2151
|
+
const writer = new StoreWriter(this.numberLogs[me], this.stringLogs[me], this.recordTables[me], c.fileIndex);
|
|
2152
|
+
exporter = new Exporter(c, this.initialIndexes, writer);
|
|
2153
|
+
exporter.nodeLimit = this.data.nodeIds;
|
|
2154
|
+
exporter.symbolLimit = this.data.symbolIds;
|
|
2155
|
+
exporter.originsCache = this.origins;
|
|
2156
|
+
this.storeExporter = exporter;
|
|
2157
|
+
}
|
|
2158
|
+
// The export budget: a post appends at most `(kappa*T - p0)/e` records, so it costs at most `kappa*T` even when
|
|
2159
|
+
// the result is over it, and an over-budget result is not posted.
|
|
2160
|
+
if (this.bounded) {
|
|
2161
|
+
const maxRecords = Math.floor((shareKappa() * computeMs * 1000 - sharePostUs()) / shareExportRecordUs());
|
|
2162
|
+
if (maxRecords < 0)
|
|
2163
|
+
return budgetFailure;
|
|
2164
|
+
exporter.limit = exporter.base + maxRecords;
|
|
2165
|
+
}
|
|
2166
|
+
else
|
|
2167
|
+
exporter.limit = Number.POSITIVE_INFINITY;
|
|
2168
|
+
const writer = exporter.writer;
|
|
2169
|
+
exporter.failure = undefined;
|
|
2170
|
+
exporter.mergedOrigins = undefined;
|
|
2171
|
+
exporter.base = this.storedRecords;
|
|
2172
|
+
exporter.count = 0;
|
|
2173
|
+
const at = writer.at;
|
|
2174
|
+
const unitAt = writer.unitAt;
|
|
2175
|
+
this.exporting = true;
|
|
2176
|
+
try {
|
|
2177
|
+
const root = exporter.type(t);
|
|
2178
|
+
if (exporter.failure !== undefined) {
|
|
2179
|
+
const failure = exporter.failure;
|
|
2180
|
+
forgetExport(exporter, at, unitAt);
|
|
2181
|
+
return failure;
|
|
2182
|
+
}
|
|
2183
|
+
// The result's own words, at the cursor after the records it added: its root record, how long the result
|
|
2184
|
+
// took to compute (microseconds: a checker that translates it saved that much), and the files its
|
|
2185
|
+
// diagnostics are in.
|
|
2186
|
+
const header = writer.at;
|
|
2187
|
+
writer.word(root);
|
|
2188
|
+
writer.word(Math.round(computeMs * 1000));
|
|
2189
|
+
writer.word(diagnosticFiles.length);
|
|
2190
|
+
for (const index of diagnosticFiles)
|
|
2191
|
+
writer.word(index);
|
|
2192
|
+
if (writer.full) {
|
|
2193
|
+
this.logFull++;
|
|
2194
|
+
forgetExport(exporter, at, unitAt);
|
|
2195
|
+
return -1;
|
|
2196
|
+
}
|
|
2197
|
+
const count = exporter.count;
|
|
2198
|
+
exporter.base += count;
|
|
2199
|
+
exporter.count = 0;
|
|
2200
|
+
exporter.addedTypes.length = 0;
|
|
2201
|
+
exporter.addedProperties.length = 0;
|
|
2202
|
+
this.posted++;
|
|
2203
|
+
this.storedRecords += count;
|
|
2204
|
+
this.writeStats();
|
|
2205
|
+
// Only this checker writes its logs and store; the result table's state publishes what it wrote.
|
|
2206
|
+
return postedState(this.data.count, me, header);
|
|
2207
|
+
}
|
|
2208
|
+
finally {
|
|
2209
|
+
this.exporting = false;
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
/** The records this checker stored. */
|
|
2213
|
+
storedRecords = 0;
|
|
2214
|
+
/** The readers of the other checkers' stores. */
|
|
2215
|
+
readers = [];
|
|
2216
|
+
/** The translation of `posted` into this checker, or undefined if it can't be taken here. */
|
|
2217
|
+
translatePosted(producer, posted, files, key, declarationFile) {
|
|
2218
|
+
for (const index of posted.files)
|
|
2219
|
+
if (this.ownsIndex(index) || this.forbidsLast(index))
|
|
2220
|
+
return undefined;
|
|
2221
|
+
const declarationIndex = this.c.fileIndex.get(declarationFile);
|
|
2222
|
+
if (declarationIndex !== undefined && this.forbidsLast(declarationIndex))
|
|
2223
|
+
return undefined;
|
|
2224
|
+
const start = performance.now();
|
|
2225
|
+
let reader = this.readers[producer];
|
|
2226
|
+
if (reader === undefined) {
|
|
2227
|
+
reader = new StoreReader(this, producer);
|
|
2228
|
+
this.readers[producer] = reader;
|
|
2229
|
+
}
|
|
2230
|
+
// The translation budget: building more records than the rule allows costs more than computing the result again,
|
|
2231
|
+
// where `T` is the time the producer's computation took (`StoredResult.computeMs`). The walk stops at the bound
|
|
2232
|
+
// before anything is built.
|
|
2233
|
+
const t = reader.translate(posted.root, this.rule.buildBudget(posted.computeMs));
|
|
2234
|
+
if (t === undefined && reader.stopped)
|
|
2235
|
+
this.stoppedTranslations++;
|
|
2236
|
+
this.translationMs += performance.now() - start;
|
|
2237
|
+
if (t !== undefined) {
|
|
2238
|
+
this.translated++;
|
|
2239
|
+
// Translating the result saved the time its producer's computation took (`post`'s header).
|
|
2240
|
+
this.addSaved(posted.computeMs);
|
|
2241
|
+
for (const index of posted.files)
|
|
2242
|
+
this.forbidIndex(index);
|
|
2243
|
+
if (posted.files.length > 0) {
|
|
2244
|
+
files.set(key, posted.files);
|
|
2245
|
+
this.noteFiles(posted.files);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
this.writeStats();
|
|
2249
|
+
return t;
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
/** A result in a checker's store: the record of its type, and the files of its diagnostics. */
|
|
2253
|
+
export class StoredResult {
|
|
2254
|
+
root;
|
|
2255
|
+
files;
|
|
2256
|
+
/** How long computing the result took its producer, in milliseconds. */
|
|
2257
|
+
computeMs;
|
|
2258
|
+
constructor(root, files, computeMs = 0) {
|
|
2259
|
+
this.root = root;
|
|
2260
|
+
this.files = files;
|
|
2261
|
+
this.computeMs = computeMs;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
function readText(strings, start, length) {
|
|
2265
|
+
let text = '';
|
|
2266
|
+
for (let j = 0; j < length; j++)
|
|
2267
|
+
text += String.fromCharCode(strings[start + j]);
|
|
2268
|
+
return text;
|
|
2269
|
+
}
|
|
2270
|
+
/** Forgets the types and properties a failed export of a store gave indexes, and its words. */
|
|
2271
|
+
function forgetExport(exporter, at, unitAt) {
|
|
2272
|
+
for (const t of exporter.addedTypes)
|
|
2273
|
+
exporter.indexes.delete(t);
|
|
2274
|
+
for (const prop of exporter.addedProperties)
|
|
2275
|
+
exporter.properties.delete(prop);
|
|
2276
|
+
exporter.addedTypes.length = 0;
|
|
2277
|
+
exporter.addedProperties.length = 0;
|
|
2278
|
+
exporter.count = 0;
|
|
2279
|
+
exporter.failure = undefined;
|
|
2280
|
+
exporter.writer.at = at;
|
|
2281
|
+
exporter.writer.unitAt = unitAt;
|
|
2282
|
+
}
|
|
2283
|
+
/**
|
|
2284
|
+
* Runs `compute` for the result keyed `key` in `table`, then exports and posts it if it can be shared and took long
|
|
2285
|
+
* enough, unless another checker posted it meanwhile. Nothing is written for the others before: a checker that finds
|
|
2286
|
+
* no result computes its own.
|
|
2287
|
+
*/
|
|
2288
|
+
function computeAndPost(sharing, table, files, key, symbol, sig, declarationFile) {
|
|
2289
|
+
const t = sharing.computeShared(files, key, symbol, sig);
|
|
2290
|
+
const ms = sharing.lastMs;
|
|
2291
|
+
if (!sharing.lastShareable) {
|
|
2292
|
+
sharing.notShareable++;
|
|
2293
|
+
sharing.notShareableMs += ms;
|
|
2294
|
+
return t;
|
|
2295
|
+
}
|
|
2296
|
+
let diagnosticFiles;
|
|
2297
|
+
if (sharing.bounded) {
|
|
2298
|
+
// The main thread stopped sharing at its window (control 1 or 2): this result is the checker's own,
|
|
2299
|
+
// and the others compute theirs, as they do when they find none posted.
|
|
2300
|
+
if (Atomics.load(sharing.control, 0) !== 0) {
|
|
2301
|
+
sharing.stopped++;
|
|
2302
|
+
return t;
|
|
2303
|
+
}
|
|
2304
|
+
const index = sharing.c.fileIndex.get(declarationFile);
|
|
2305
|
+
if (index === undefined)
|
|
2306
|
+
return t;
|
|
2307
|
+
// The rule priced this result: a quick computation is cheaper to repeat than to export, post and translate.
|
|
2308
|
+
diagnosticFiles = files.get(key) ?? [];
|
|
2309
|
+
if (!sharing.rule.posts(sharing, key, ms, diagnosticFiles, index)) {
|
|
2310
|
+
sharing.belowMin++;
|
|
2311
|
+
sharing.belowMinMs += ms;
|
|
2312
|
+
return t;
|
|
2313
|
+
}
|
|
2314
|
+
// A result is posted only for a declaration whose file another checker that may take it missed on: a file only
|
|
2315
|
+
// its own checkers read has nobody to take it.
|
|
2316
|
+
if (!sharing.demanded(index)) {
|
|
2317
|
+
sharing.notDemanded++;
|
|
2318
|
+
return t;
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
else {
|
|
2322
|
+
// Below the bounded count the run is Phase 1's, and takes the same path: the floor first, then the stop switch,
|
|
2323
|
+
// and none of the bounded path's lookups (the file index and the diagnostics) is made.
|
|
2324
|
+
if (ms < sharing.minMs) {
|
|
2325
|
+
sharing.belowMin++;
|
|
2326
|
+
sharing.belowMinMs += ms;
|
|
2327
|
+
return t;
|
|
2328
|
+
}
|
|
2329
|
+
if (Atomics.load(sharing.control, 0) !== 0) {
|
|
2330
|
+
sharing.stopped++;
|
|
2331
|
+
return t;
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
// A result computed inside this checker's export walk doesn't have the store to itself: the walk would write over
|
|
2335
|
+
// its records, so it stays with the checkers that compute it.
|
|
2336
|
+
if (sharing.exporting) {
|
|
2337
|
+
sharing.nested++;
|
|
2338
|
+
return t;
|
|
2339
|
+
}
|
|
2340
|
+
const slot = table.slot(key);
|
|
2341
|
+
if (slot < 0 || table.state(slot) !== 0)
|
|
2342
|
+
return t;
|
|
2343
|
+
const start = performance.now();
|
|
2344
|
+
// Diagnostics stay with this checker; the others only learn which files they are in.
|
|
2345
|
+
const state = sharing.post(t, diagnosticFiles ?? files.get(key) ?? [], ms);
|
|
2346
|
+
if (state === budgetFailure) {
|
|
2347
|
+
sharing.overBudget++;
|
|
2348
|
+
sharing.overBudgetMs += ms;
|
|
2349
|
+
}
|
|
2350
|
+
else if (typeof state === 'string') {
|
|
2351
|
+
sharing.exportFailed++;
|
|
2352
|
+
sharing.exportFailedMs += ms;
|
|
2353
|
+
sharing.exportFailures.set(state, (sharing.exportFailures.get(state) ?? 0) + ms);
|
|
2354
|
+
}
|
|
2355
|
+
else if (state === -1)
|
|
2356
|
+
sharing.storeFailed++;
|
|
2357
|
+
else
|
|
2358
|
+
table.publish(slot, state);
|
|
2359
|
+
sharing.exportMs += performance.now() - start;
|
|
2360
|
+
sharing.writeStats();
|
|
2361
|
+
return t;
|
|
2362
|
+
}
|
|
2363
|
+
/** Shares the value type of `symbol` with the other checker threads, computing it with `compute` where needed. */
|
|
2364
|
+
export function threadTypeOfSymbol(c, symbol) {
|
|
2365
|
+
const sharing = c.threadSharing;
|
|
2366
|
+
if (!sharing.timing || sharing.depth > 0 || c.symbolTypes.get(getSymbolId(symbol)) !== undefined)
|
|
2367
|
+
return threadTypeOfSymbolWorker(c, symbol);
|
|
2368
|
+
const start = performance.now();
|
|
2369
|
+
sharing.kind = 3;
|
|
2370
|
+
sharing.depth++;
|
|
2371
|
+
try {
|
|
2372
|
+
return threadTypeOfSymbolWorker(c, symbol);
|
|
2373
|
+
}
|
|
2374
|
+
finally {
|
|
2375
|
+
sharing.depth--;
|
|
2376
|
+
sharing.addOutermost(performance.now() - start);
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
function threadTypeOfSymbolWorker(c, symbol) {
|
|
2380
|
+
const sharing = c.threadSharing;
|
|
2381
|
+
const id = getSymbolId(symbol);
|
|
2382
|
+
const cached = c.symbolTypes.get(id);
|
|
2383
|
+
if (cached !== undefined) {
|
|
2384
|
+
// Most results have no diagnostics: then there is nothing to look up.
|
|
2385
|
+
if (sharing.fileStack.length > 0)
|
|
2386
|
+
sharing.noteFiles(sharing.typeFiles.get(id));
|
|
2387
|
+
return cached;
|
|
2388
|
+
}
|
|
2389
|
+
if (id > sharing.data.symbolIds)
|
|
2390
|
+
return sharing.tracked(sharing.typeFiles, id, symbol, undefined);
|
|
2391
|
+
const declaration = symbol.valueDeclaration;
|
|
2392
|
+
const file = getSourceFileOfNode(declaration);
|
|
2393
|
+
// A declaration with a type annotation: computing its type resolves the annotation, and translating the records
|
|
2394
|
+
// does too (`NodeType` resolves the node), so sharing saves nothing on it and costs a lookup. Below the bounded
|
|
2395
|
+
// count the exclusion is off, as it is in Phase 1.
|
|
2396
|
+
if (sharing.bounded && getType(declaration) !== undefined)
|
|
2397
|
+
return sharing.tracked(sharing.typeFiles, id, symbol, undefined);
|
|
2398
|
+
const table = sharing.types;
|
|
2399
|
+
if (!sharing.owns(file)) {
|
|
2400
|
+
// The stop switch is read before the table: a checker that stops translating computes the result itself.
|
|
2401
|
+
const slot = sharing.stoppedTranslating() ? -1 : table.find(id);
|
|
2402
|
+
const state = slot < 0 ? 0 : table.state(slot);
|
|
2403
|
+
if (state <= -2 &&
|
|
2404
|
+
findResolutionCycleStartIndex(c, symbol, 0 /* TypeSystemPropertyName.Type */) < 0 &&
|
|
2405
|
+
!translationBlocked(declaration)) {
|
|
2406
|
+
const producer = postedProducer(sharing.data.count, state);
|
|
2407
|
+
const posted = sharing.result(producer, postedOffset(sharing.data.count, state));
|
|
2408
|
+
if (shareVerifyValue === '1') {
|
|
2409
|
+
const own = sharing.tracked(sharing.typeFiles, id, symbol, undefined);
|
|
2410
|
+
verifyTranslation(c, 'types', declaration, own, sharing.translatePosted(producer, posted, sharing.typeFiles, id, file));
|
|
2411
|
+
return own;
|
|
2412
|
+
}
|
|
2413
|
+
const t = sharing.translatePosted(producer, posted, sharing.typeFiles, id, file);
|
|
2414
|
+
if (t !== undefined) {
|
|
2415
|
+
traceTranslation(c, 'types', declaration, producer);
|
|
2416
|
+
if (sharing.depth === 1)
|
|
2417
|
+
sharing.kind = 2;
|
|
2418
|
+
sharing.forbid(file);
|
|
2419
|
+
const again = c.symbolTypes.get(id);
|
|
2420
|
+
if (again !== undefined)
|
|
2421
|
+
return again;
|
|
2422
|
+
c.symbolTypes.set(id, t);
|
|
2423
|
+
return t;
|
|
2424
|
+
}
|
|
2425
|
+
sharing.sawDoneUnusable++;
|
|
2426
|
+
}
|
|
2427
|
+
// This checker needed a result for one of the file's declarations and has none: the others post its results only
|
|
2428
|
+
// then.
|
|
2429
|
+
sharing.want(file);
|
|
2430
|
+
sharing.computedPrivately++;
|
|
2431
|
+
if (sharing.depth === 1)
|
|
2432
|
+
sharing.kind = 1;
|
|
2433
|
+
}
|
|
2434
|
+
else {
|
|
2435
|
+
sharing.owned++;
|
|
2436
|
+
if (sharing.depth === 1)
|
|
2437
|
+
sharing.kind = 0;
|
|
2438
|
+
}
|
|
2439
|
+
return computeAndPost(sharing, table, sharing.typeFiles, id, symbol, undefined, file);
|
|
2440
|
+
}
|
|
2441
|
+
/** Notes that the computation in progress used the cached return type of `sig` (see `ThreadSharing.typeFiles`). */
|
|
2442
|
+
export function noteReturnTypeUse(c, sig) {
|
|
2443
|
+
const sharing = c.threadSharing;
|
|
2444
|
+
if (sharing.fileStack.length === 0 || sig.declaration === undefined)
|
|
2445
|
+
return;
|
|
2446
|
+
sharing.noteFiles(sharing.returnFiles.get(sig.declaration.id));
|
|
2447
|
+
}
|
|
2448
|
+
export function threadReturnType(c, sig) {
|
|
2449
|
+
const sharing = c.threadSharing;
|
|
2450
|
+
if (!sharing.timing || sharing.depth > 0)
|
|
2451
|
+
return threadReturnTypeWorker(c, sig);
|
|
2452
|
+
const start = performance.now();
|
|
2453
|
+
sharing.kind = 3;
|
|
2454
|
+
sharing.depth++;
|
|
2455
|
+
try {
|
|
2456
|
+
return threadReturnTypeWorker(c, sig);
|
|
2457
|
+
}
|
|
2458
|
+
finally {
|
|
2459
|
+
sharing.depth--;
|
|
2460
|
+
sharing.addOutermost(performance.now() - start);
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
function threadReturnTypeWorker(c, sig) {
|
|
2464
|
+
const sharing = c.threadSharing;
|
|
2465
|
+
const declaration = sig.declaration;
|
|
2466
|
+
const key = declaration.id;
|
|
2467
|
+
if (key > sharing.data.nodeIds)
|
|
2468
|
+
return sharing.tracked(sharing.returnFiles, key, undefined, sig);
|
|
2469
|
+
const file = getSourceFileOfNode(declaration);
|
|
2470
|
+
// A declaration with a return type annotation: computing the return type resolves the annotation, and translating
|
|
2471
|
+
// the records does too, so sharing saves nothing on it and costs a lookup. Below the bounded count the exclusion is
|
|
2472
|
+
// off, as it is in Phase 1.
|
|
2473
|
+
if (sharing.bounded && getType(declaration) !== undefined)
|
|
2474
|
+
return sharing.tracked(sharing.returnFiles, key, undefined, sig);
|
|
2475
|
+
const table = sharing.returns;
|
|
2476
|
+
if (!sharing.owns(file)) {
|
|
2477
|
+
const slot = sharing.stoppedTranslating() ? -1 : table.find(key);
|
|
2478
|
+
const state = slot < 0 ? 0 : table.state(slot);
|
|
2479
|
+
if (state <= -2 &&
|
|
2480
|
+
findResolutionCycleStartIndex(c, sig, 3 /* TypeSystemPropertyName.ResolvedReturnType */) < 0 &&
|
|
2481
|
+
!translationBlocked(declaration)) {
|
|
2482
|
+
const producer = postedProducer(sharing.data.count, state);
|
|
2483
|
+
const posted = sharing.result(producer, postedOffset(sharing.data.count, state));
|
|
2484
|
+
if (shareVerifyValue === '1') {
|
|
2485
|
+
const own = sharing.tracked(sharing.returnFiles, key, undefined, sig);
|
|
2486
|
+
verifyTranslation(c, 'returns', declaration, own, sharing.translatePosted(producer, posted, sharing.returnFiles, key, file));
|
|
2487
|
+
return own;
|
|
2488
|
+
}
|
|
2489
|
+
const t = sharing.translatePosted(producer, posted, sharing.returnFiles, key, file);
|
|
2490
|
+
if (t !== undefined) {
|
|
2491
|
+
traceTranslation(c, 'returns', declaration, producer);
|
|
2492
|
+
if (sharing.depth === 1)
|
|
2493
|
+
sharing.kind = 2;
|
|
2494
|
+
sharing.forbid(file);
|
|
2495
|
+
return t;
|
|
2496
|
+
}
|
|
2497
|
+
sharing.sawDoneUnusable++;
|
|
2498
|
+
}
|
|
2499
|
+
sharing.want(file);
|
|
2500
|
+
sharing.computedPrivately++;
|
|
2501
|
+
if (sharing.depth === 1)
|
|
2502
|
+
sharing.kind = 1;
|
|
2503
|
+
}
|
|
2504
|
+
else {
|
|
2505
|
+
sharing.owned++;
|
|
2506
|
+
if (sharing.depth === 1)
|
|
2507
|
+
sharing.kind = 0;
|
|
2508
|
+
}
|
|
2509
|
+
return computeAndPost(sharing, table, sharing.returnFiles, key, undefined, sig, file);
|
|
2510
|
+
}
|
|
2511
|
+
// ---- Records in a checker's store
|
|
2512
|
+
//
|
|
2513
|
+
// Records travel between threads as numbers and strings only: a class instance received in a worker makes the native
|
|
2514
|
+
// build store the number fields of every class it can reach as doubles. A node is written as its file, range, kind
|
|
2515
|
+
// and id, and found again by descending from the file's root; a symbol of the program as the node it is the symbol
|
|
2516
|
+
// of; a merged symbol by the id of a symbol it merged; a string as its range in the store's string log.
|
|
2517
|
+
/** A double and its two int32 halves, sharing their bytes. */
|
|
2518
|
+
class DoubleWords {
|
|
2519
|
+
f = new Float64Array(1);
|
|
2520
|
+
i;
|
|
2521
|
+
constructor() {
|
|
2522
|
+
this.i = new Int32Array(this.f.buffer);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
let doubleWordsValue = undefined;
|
|
2526
|
+
function doubleWords() {
|
|
2527
|
+
if (doubleWordsValue === undefined)
|
|
2528
|
+
doubleWordsValue = new DoubleWords();
|
|
2529
|
+
return doubleWordsValue;
|
|
2530
|
+
}
|
|
2531
|
+
/** Collects the children of a node (`forEachChild`). */
|
|
2532
|
+
class ChildVisitor extends NodeVisitor {
|
|
2533
|
+
children = [];
|
|
2534
|
+
visitNode(node) {
|
|
2535
|
+
this.children.push(node);
|
|
2536
|
+
return false;
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
/** The nodes of the program records name, by id, found by descending from their file through the nodes that contain them. */
|
|
2540
|
+
export class NodeFinder {
|
|
2541
|
+
files;
|
|
2542
|
+
nodesById;
|
|
2543
|
+
visitor = undefined;
|
|
2544
|
+
constructor(files, nodesById) {
|
|
2545
|
+
this.files = files;
|
|
2546
|
+
this.nodesById = nodesById;
|
|
2547
|
+
}
|
|
2548
|
+
/** The node of file `fileIndex` with the range `pos`-`end` and id `id`; undefined if the program hasn't it. */
|
|
2549
|
+
find(fileIndex, pos, end, id) {
|
|
2550
|
+
const known = this.nodesById.get(id);
|
|
2551
|
+
if (known !== undefined)
|
|
2552
|
+
return known;
|
|
2553
|
+
const file = this.files[fileIndex];
|
|
2554
|
+
if (file === undefined)
|
|
2555
|
+
return undefined;
|
|
2556
|
+
let visitor = this.visitor;
|
|
2557
|
+
if (visitor === undefined)
|
|
2558
|
+
visitor = this.visitor = new ChildVisitor();
|
|
2559
|
+
let node = file;
|
|
2560
|
+
for (;;) {
|
|
2561
|
+
if (node.id === id) {
|
|
2562
|
+
if (node.pos !== pos || node.end !== end)
|
|
2563
|
+
return undefined;
|
|
2564
|
+
this.nodesById.set(id, node);
|
|
2565
|
+
return node;
|
|
2566
|
+
}
|
|
2567
|
+
visitor.children.length = 0;
|
|
2568
|
+
node.forEachChild(visitor);
|
|
2569
|
+
let next = undefined;
|
|
2570
|
+
for (const child of visitor.children)
|
|
2571
|
+
if (child.pos <= pos && end <= child.end) {
|
|
2572
|
+
// The innermost of nested nodes with one range is found by its id further down.
|
|
2573
|
+
if (child.id === id) {
|
|
2574
|
+
if (child.pos !== pos || child.end !== end)
|
|
2575
|
+
return undefined;
|
|
2576
|
+
this.nodesById.set(id, child);
|
|
2577
|
+
return child;
|
|
2578
|
+
}
|
|
2579
|
+
if (next === undefined)
|
|
2580
|
+
next = child;
|
|
2581
|
+
}
|
|
2582
|
+
if (next === undefined)
|
|
2583
|
+
return undefined;
|
|
2584
|
+
node = next;
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
/**
|
|
2589
|
+
* Reads the records of a checker's store where it wrote them. `begin` starts a record at its offset in the number log
|
|
2590
|
+
* and finds its parts without decoding its kind's fields: its refs, its alias, its symbol, its node, then the fields
|
|
2591
|
+
* at `fields`.
|
|
2592
|
+
*/
|
|
2593
|
+
export class RecordReader {
|
|
2594
|
+
numbers;
|
|
2595
|
+
strings;
|
|
2596
|
+
table;
|
|
2597
|
+
finder;
|
|
2598
|
+
/** The record in progress: its header and kind, and where its refs are. */
|
|
2599
|
+
header = 0;
|
|
2600
|
+
kind = 0;
|
|
2601
|
+
refAt = 0;
|
|
2602
|
+
refCount = 0;
|
|
2603
|
+
/** Where its alias refs are, if it has an alias; -1 if none. */
|
|
2604
|
+
aliasRefAt = -1;
|
|
2605
|
+
aliasRefCount = 0;
|
|
2606
|
+
/** How its alias is named: `SymbolNaming` and a merged symbol id, or a node at `aliasNodeStart`. */
|
|
2607
|
+
aliasNaming = -1;
|
|
2608
|
+
aliasMergedId = -1;
|
|
2609
|
+
aliasNodeStart = -1;
|
|
2610
|
+
/** How its symbol is named: the kind of naming, a merged symbol id, or a node at `symbolNodeStart`. */
|
|
2611
|
+
symbolNaming = 0;
|
|
2612
|
+
symbolMergedId = -1;
|
|
2613
|
+
symbolNodeStart = -1;
|
|
2614
|
+
/** Where its node is, if it has one; -1 if none. */
|
|
2615
|
+
nodeStart = -1;
|
|
2616
|
+
/** The offset of its kind's own fields. */
|
|
2617
|
+
fields = 0;
|
|
2618
|
+
/** The records a record names, filled by `scan`. */
|
|
2619
|
+
deps = [];
|
|
2620
|
+
constructor(numbers, strings, table, files, nodesById) {
|
|
2621
|
+
this.numbers = numbers;
|
|
2622
|
+
this.strings = strings;
|
|
2623
|
+
this.table = table;
|
|
2624
|
+
this.finder = new NodeFinder(files, nodesById);
|
|
2625
|
+
}
|
|
2626
|
+
/** Starts the record at `index`; false if the store hasn't it. */
|
|
2627
|
+
begin(index) {
|
|
2628
|
+
if (index < 0 || index >= this.table.length)
|
|
2629
|
+
return false;
|
|
2630
|
+
const start = this.table[index];
|
|
2631
|
+
if (start <= 0)
|
|
2632
|
+
return false;
|
|
2633
|
+
const numbers = this.numbers;
|
|
2634
|
+
const at = start - 1;
|
|
2635
|
+
const header = numbers[at];
|
|
2636
|
+
this.header = header;
|
|
2637
|
+
this.kind = header & 31 /* RecordHeader.KindMask */;
|
|
2638
|
+
let count = (header >>> 16) & RefCountMask;
|
|
2639
|
+
this.refAt = at + 1;
|
|
2640
|
+
if (count === 65535 /* RecordHeader.RefEscape */) {
|
|
2641
|
+
count = numbers[this.refAt];
|
|
2642
|
+
this.refAt++;
|
|
2643
|
+
}
|
|
2644
|
+
this.refCount = count;
|
|
2645
|
+
this.locate();
|
|
2646
|
+
return true;
|
|
2647
|
+
}
|
|
2648
|
+
/** Finds the record's alias refs, its symbol and its node, and the fields that follow them. */
|
|
2649
|
+
locate() {
|
|
2650
|
+
const numbers = this.numbers;
|
|
2651
|
+
const header = this.header;
|
|
2652
|
+
let p = this.refAt + this.refCount;
|
|
2653
|
+
this.aliasNaming = -1;
|
|
2654
|
+
this.aliasMergedId = -1;
|
|
2655
|
+
this.aliasNodeStart = -1;
|
|
2656
|
+
this.aliasRefAt = -1;
|
|
2657
|
+
this.aliasRefCount = 0;
|
|
2658
|
+
if ((header & 32 /* RecordHeader.HasAlias */) !== 0) {
|
|
2659
|
+
if ((header & 1024 /* RecordHeader.AliasMerged */) !== 0) {
|
|
2660
|
+
this.aliasNaming = 3 /* SymbolNaming.Merged */;
|
|
2661
|
+
this.aliasMergedId = numbers[p++];
|
|
2662
|
+
}
|
|
2663
|
+
else {
|
|
2664
|
+
this.aliasNaming = numbers[p] === 1 ? 2 /* SymbolNaming.Export */ : 1 /* SymbolNaming.Node */;
|
|
2665
|
+
this.aliasNodeStart = p + 1;
|
|
2666
|
+
p = this.aliasNodeStart + this.nodeWords(this.aliasNodeStart);
|
|
2667
|
+
}
|
|
2668
|
+
this.aliasRefCount = numbers[p];
|
|
2669
|
+
this.aliasRefAt = p + 1;
|
|
2670
|
+
p = this.aliasRefAt + this.aliasRefCount;
|
|
2671
|
+
}
|
|
2672
|
+
const naming = (header & 192 /* RecordHeader.NamingMask */) >>> 6 /* RecordHeader.NamingShift */;
|
|
2673
|
+
this.symbolNaming = naming;
|
|
2674
|
+
this.symbolMergedId = -1;
|
|
2675
|
+
this.symbolNodeStart = -1;
|
|
2676
|
+
if (naming === 3 /* SymbolNaming.Merged */)
|
|
2677
|
+
this.symbolMergedId = numbers[p++];
|
|
2678
|
+
else if (naming !== 0 /* SymbolNaming.None */) {
|
|
2679
|
+
this.symbolNodeStart = p;
|
|
2680
|
+
p += this.nodeWords(p);
|
|
2681
|
+
}
|
|
2682
|
+
this.nodeStart = -1;
|
|
2683
|
+
if ((header & 256 /* RecordHeader.HasNode */) !== 0) {
|
|
2684
|
+
this.nodeStart = p;
|
|
2685
|
+
p += this.nodeWords(p);
|
|
2686
|
+
}
|
|
2687
|
+
this.fields = p;
|
|
2688
|
+
}
|
|
2689
|
+
/** The words a node at `p` takes: its file index, range and id, or one word for no node. */
|
|
2690
|
+
nodeWords(p) {
|
|
2691
|
+
return this.numbers[p] < 0 ? 1 : 4;
|
|
2692
|
+
}
|
|
2693
|
+
/** The node at `p`; undefined if it is none or the program hasn't it. */
|
|
2694
|
+
readNode(p) {
|
|
2695
|
+
if (p < 0 || this.numbers[p] < 0)
|
|
2696
|
+
return undefined;
|
|
2697
|
+
const numbers = this.numbers;
|
|
2698
|
+
return this.finder.find(numbers[p], numbers[p + 1], numbers[p + 2], numbers[p + 3]);
|
|
2699
|
+
}
|
|
2700
|
+
/** The record's own node; undefined if it has none or the program hasn't it. */
|
|
2701
|
+
node() {
|
|
2702
|
+
return this.readNode(this.nodeStart);
|
|
2703
|
+
}
|
|
2704
|
+
doubleAt(p) {
|
|
2705
|
+
const words = doubleWords();
|
|
2706
|
+
words.i[0] = this.numbers[p];
|
|
2707
|
+
words.i[1] = this.numbers[p + 1];
|
|
2708
|
+
return words.f[0];
|
|
2709
|
+
}
|
|
2710
|
+
textAt(p) {
|
|
2711
|
+
return readText(this.strings, this.numbers[p], this.numbers[p + 1]);
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Collects in `deps` the indexes of the records the record in progress needs: its refs, its alias refs, and the
|
|
2715
|
+
* types of its own fields that are records (a union's origin, an object literal's completion, a completed object's
|
|
2716
|
+
* members' types). A record is written before the records it needs.
|
|
2717
|
+
*/
|
|
2718
|
+
scan() {
|
|
2719
|
+
const numbers = this.numbers;
|
|
2720
|
+
const deps = this.deps;
|
|
2721
|
+
deps.length = 0;
|
|
2722
|
+
for (let i = 0; i < this.refCount; i++)
|
|
2723
|
+
deps.push(numbers[this.refAt + i]);
|
|
2724
|
+
for (let i = 0; i < this.aliasRefCount; i++)
|
|
2725
|
+
deps.push(numbers[this.aliasRefAt + i]);
|
|
2726
|
+
let p = this.fields;
|
|
2727
|
+
switch (this.kind) {
|
|
2728
|
+
case 12 /* RecordKind.Union */:
|
|
2729
|
+
case 22 /* RecordKind.AnonymousObject */:
|
|
2730
|
+
// The origin of a union, and the completion of an object literal.
|
|
2731
|
+
deps.push(numbers[p + 1]);
|
|
2732
|
+
break;
|
|
2733
|
+
case 23 /* RecordKind.CompleteObject */: {
|
|
2734
|
+
// The object literal completed, then each index signature's key and value types.
|
|
2735
|
+
deps.push(numbers[p]);
|
|
2736
|
+
const count = numbers[p + 1];
|
|
2737
|
+
let q = p + 2;
|
|
2738
|
+
for (let i = 0; i < count; i++) {
|
|
2739
|
+
deps.push(numbers[q], numbers[q + 1]);
|
|
2740
|
+
q += 3;
|
|
2741
|
+
q += this.nodeWords(q);
|
|
2742
|
+
const components = numbers[q++];
|
|
2743
|
+
for (let j = 0; j < components; j++)
|
|
2744
|
+
q += this.nodeWords(q);
|
|
2745
|
+
}
|
|
2746
|
+
break;
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
/** The bits of a record header that hold the number of refs, or `RefEscape` if the number is a word of its own. */
|
|
2752
|
+
const RefCountMask = 0xffff;
|
|
2753
|
+
/**
|
|
2754
|
+
* A consumer's translations of another checker's store: each record is read where it is, and translated once, when a
|
|
2755
|
+
* result first needs it, in the order of the store, which is the order the producer exported them in.
|
|
2756
|
+
*/
|
|
2757
|
+
class StoreReader {
|
|
2758
|
+
sharing;
|
|
2759
|
+
producer;
|
|
2760
|
+
translator;
|
|
2761
|
+
reader;
|
|
2762
|
+
/** Whether the last `translate` stopped at its budget, having built nothing. */
|
|
2763
|
+
stopped = false;
|
|
2764
|
+
/** By record: the type it translated to, the symbol a property record makes, and whether a completion is done. */
|
|
2765
|
+
types = new LinkTable();
|
|
2766
|
+
symbols = new LinkTable();
|
|
2767
|
+
completed = new LinkTable();
|
|
2768
|
+
constructor(sharing, producer) {
|
|
2769
|
+
this.sharing = sharing;
|
|
2770
|
+
this.producer = producer;
|
|
2771
|
+
this.translator = new Translator(sharing.c, this);
|
|
2772
|
+
this.reader = new RecordReader(sharing.numberLogs[producer], sharing.stringLogs[producer], sharing.recordTables[producer], sharing.c.files, sharing.nodesById);
|
|
2773
|
+
}
|
|
2774
|
+
/**
|
|
2775
|
+
* Whether record `index` is translated: a property record made its symbol, an object literal got its members, a
|
|
2776
|
+
* shell whose members come later only counts with them. A translation that fails after it built a shell leaves
|
|
2777
|
+
* the empty type behind, and a later translation of the shell alone would take it for the object.
|
|
2778
|
+
*/
|
|
2779
|
+
isBuilt(index) {
|
|
2780
|
+
if (!this.reader.begin(index))
|
|
2781
|
+
return false;
|
|
2782
|
+
const kind = this.reader.kind;
|
|
2783
|
+
if (kind === 24 /* RecordKind.Property */)
|
|
2784
|
+
return this.symbols.get(index) !== undefined;
|
|
2785
|
+
if (kind === 23 /* RecordKind.CompleteObject */)
|
|
2786
|
+
return this.completed.get(index) !== undefined;
|
|
2787
|
+
if (this.types.get(index) === undefined)
|
|
2788
|
+
return false;
|
|
2789
|
+
if (kind !== 22 /* RecordKind.AnonymousObject */)
|
|
2790
|
+
return true;
|
|
2791
|
+
const completion = this.reader.numbers[this.reader.fields + 1];
|
|
2792
|
+
return completion < 0 || this.completed.get(completion) !== undefined;
|
|
2793
|
+
}
|
|
2794
|
+
/** Whether the record in progress names only merged symbols this program has. */
|
|
2795
|
+
present(reader) {
|
|
2796
|
+
const merged = this.sharing.c.mergedSymbols;
|
|
2797
|
+
if (reader.aliasNaming === 3 /* SymbolNaming.Merged */ && !merged.has(reader.aliasMergedId))
|
|
2798
|
+
return false;
|
|
2799
|
+
return reader.symbolNaming !== 3 /* SymbolNaming.Merged */ || merged.has(reader.symbolMergedId);
|
|
2800
|
+
}
|
|
2801
|
+
/**
|
|
2802
|
+
* The translation of record `root` and the records it needs; undefined if one can't be translated here, or if the
|
|
2803
|
+
* records it would build pass `budget`.
|
|
2804
|
+
*/
|
|
2805
|
+
translate(root, budget = Number.POSITIVE_INFINITY) {
|
|
2806
|
+
const c = this.sharing.c;
|
|
2807
|
+
const translator = this.translator;
|
|
2808
|
+
const reader = this.reader;
|
|
2809
|
+
translator.failed = false;
|
|
2810
|
+
const needed = new Set();
|
|
2811
|
+
const stack = [root];
|
|
2812
|
+
this.stopped = false;
|
|
2813
|
+
while (stack.length > 0) {
|
|
2814
|
+
const i = stack.pop();
|
|
2815
|
+
if (needed.has(i) || this.isBuilt(i))
|
|
2816
|
+
continue;
|
|
2817
|
+
if (needed.size >= budget) {
|
|
2818
|
+
this.stopped = true;
|
|
2819
|
+
return undefined;
|
|
2820
|
+
}
|
|
2821
|
+
if (!reader.begin(i) || !this.present(reader))
|
|
2822
|
+
return undefined;
|
|
2823
|
+
needed.add(i);
|
|
2824
|
+
reader.scan();
|
|
2825
|
+
const deps = reader.deps;
|
|
2826
|
+
for (let k = 0; k < deps.length; k++) {
|
|
2827
|
+
const j = deps[k];
|
|
2828
|
+
if (j >= 0)
|
|
2829
|
+
stack.push(j);
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
const order = [...needed].sort((a, b) => a - b);
|
|
2833
|
+
// Translating a type node resolves its type alias first, which fails where that is in progress: before any
|
|
2834
|
+
// record is translated. A translation can start translations of this store again (resolving a type alias, or
|
|
2835
|
+
// a type of a symbol), which translate some of these records first.
|
|
2836
|
+
for (const i of order) {
|
|
2837
|
+
if (this.isBuilt(i))
|
|
2838
|
+
continue;
|
|
2839
|
+
reader.begin(i);
|
|
2840
|
+
const kind = reader.kind;
|
|
2841
|
+
if (kind !== 8 /* RecordKind.NodeType */ && kind !== 16 /* RecordKind.Conditional */ && kind !== 21 /* RecordKind.DistributedConditional */)
|
|
2842
|
+
continue;
|
|
2843
|
+
const node = reader.node();
|
|
2844
|
+
if (node === undefined)
|
|
2845
|
+
return undefined;
|
|
2846
|
+
translator.aliasOfNode(node);
|
|
2847
|
+
}
|
|
2848
|
+
if (translator.failed) {
|
|
2849
|
+
translator.failed = false;
|
|
2850
|
+
return undefined;
|
|
2851
|
+
}
|
|
2852
|
+
const verifyOrder = shareVerifyValue === '2';
|
|
2853
|
+
let lastNew = -1;
|
|
2854
|
+
for (const i of order) {
|
|
2855
|
+
if (this.isBuilt(i))
|
|
2856
|
+
continue;
|
|
2857
|
+
reader.begin(i);
|
|
2858
|
+
const before = verifyOrder ? c.typeCount : 0;
|
|
2859
|
+
switch (reader.kind) {
|
|
2860
|
+
case 24 /* RecordKind.Property */: {
|
|
2861
|
+
const symbol = translator.property(i);
|
|
2862
|
+
if (symbol === undefined) {
|
|
2863
|
+
translator.failed = false;
|
|
2864
|
+
return undefined;
|
|
2865
|
+
}
|
|
2866
|
+
this.symbols.set(i, symbol);
|
|
2867
|
+
continue;
|
|
2868
|
+
}
|
|
2869
|
+
case 23 /* RecordKind.CompleteObject */:
|
|
2870
|
+
if (!translator.complete(i)) {
|
|
2871
|
+
translator.failed = false;
|
|
2872
|
+
return undefined;
|
|
2873
|
+
}
|
|
2874
|
+
this.completed.set(i, true);
|
|
2875
|
+
continue;
|
|
2876
|
+
default: {
|
|
2877
|
+
const t = translator.record(i);
|
|
2878
|
+
if (t === undefined) {
|
|
2879
|
+
translator.failed = false;
|
|
2880
|
+
return undefined;
|
|
2881
|
+
}
|
|
2882
|
+
this.types.set(i, t);
|
|
2883
|
+
// The types a translation creates, record by record, are created in the order the producer created them.
|
|
2884
|
+
if (verifyOrder && c.typeCount > before) {
|
|
2885
|
+
if (before < lastNew) {
|
|
2886
|
+
const violations = ++this.sharing.orderViolations;
|
|
2887
|
+
if (violations <= 20)
|
|
2888
|
+
process.stderr.write('share-verify: checker ' +
|
|
2889
|
+
this.sharing.data.index +
|
|
2890
|
+
' record ' +
|
|
2891
|
+
i +
|
|
2892
|
+
' created type ' +
|
|
2893
|
+
c.typeCount +
|
|
2894
|
+
' after ' +
|
|
2895
|
+
lastNew +
|
|
2896
|
+
'\n');
|
|
2897
|
+
}
|
|
2898
|
+
lastNew = c.typeCount;
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
return this.types.get(root);
|
|
2904
|
+
}
|
|
2905
|
+
}
|