From eb317b2f4dd16094aa1084ceaed7a561d25dffc3 Mon Sep 17 00:00:00 2001 From: Dimitri Mitropoulos Date: Wed, 14 Oct 2026 20:55:18 -0400 Subject: [PATCH 01/35] Create types in a stable order when iterating symbol tables Type ids are creation order, and --generateTrace writes every type a checker creates in id order. Three places create types while they iterate a symbol table, whose iteration order varies from run to run, so the type files differed between runs of the same program: - getInferTypeParameters gets the declared type of each infer type parameter in map order. The result is already sorted; the types are now created in symbol order too. - getNamedMembers checks whether each member is a value, which can resolve an alias, in map order and sorts afterwards. The members are now sorted first. - getAliasForSymbolInContainer and buildExternalModuleContainerIndex resolve every export in map order. Exports that are not aliases still resolve in map order, since that has no side effects; aliases are now resolved last, sorted. The results of all four functions are unchanged. --- tsc/internal/checker/checker.go | 41 +- tsc/internal/checker/symbolaccessibility.go | 27 +- tsc/internal/execute/tsctests/tsc_test.go | 61 ++ ...teTrace-creates-types-in-a-stable-order.js | 554 ++++++++++++++++++ 4 files changed, 665 insertions(+), 18 deletions(-) create mode 100644 tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-types-in-a-stable-order.js diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index d392785d4181f..d4de86657fb42 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -22550,23 +22550,29 @@ func (c *Checker) getNamedMembers(members ast.SymbolTable, container *ast.Symbol // For classes and interfaces, we store explicitly declared members ahead of inherited members. This ensures we process // explicitly declared members first in type relations, which is beneficial because explicitly declared members are more // likely to contain discriminating differences. See for example https://github.com/microsoft/TypeScript/tsc/issues/1968. - result := make([]*ast.Symbol, 0, len(members)) - var containedCount int - if container != nil && container.Flags()&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) != 0 { - for id, symbol := range members { - if c.isNamedMember(symbol, id) && c.isDeclarationContainedBy(symbol, container) { - result = append(result, symbol) - } + symbols := make([]*ast.Symbol, 0, len(members)) + for id, symbol := range members { + if !isReservedMemberName(id) { + symbols = append(symbols, symbol) } - containedCount = len(result) } - for id, symbol := range members { - if c.isNamedMember(symbol, id) && (container == nil || container.Flags()&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) == 0 || !c.isDeclarationContainedBy(symbol, container)) { + // Sort before checking which members are values: that can resolve aliases (creating types), and the symbol + // table is randomly iterated. + c.sortSymbols(symbols) + if container == nil || container.Flags()&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) == 0 { + return slices.DeleteFunc(symbols, func(symbol *ast.Symbol) bool { return !c.symbolIsValue(symbol) }) + } + result := make([]*ast.Symbol, 0, len(symbols)) + for _, symbol := range symbols { + if c.symbolIsValue(symbol) && c.isDeclarationContainedBy(symbol, container) { + result = append(result, symbol) + } + } + for _, symbol := range symbols { + if c.symbolIsValue(symbol) && !c.isDeclarationContainedBy(symbol, container) { result = append(result, symbol) } } - c.sortSymbols(result[:containedCount]) - c.sortSymbols(result[containedCount:]) return result } @@ -24363,12 +24369,19 @@ func (c *Checker) getOuterTypeParameters(node *ast.Node, includeThisTypes bool) } func (c *Checker) getInferTypeParameters(node *ast.Node) []*Type { - var result []*Type + var symbols []*ast.Symbol for _, symbol := range node.Locals() { if symbol.Flags()&ast.SymbolFlagsTypeParameter != 0 { - result = append(result, c.getDeclaredTypeOfSymbol(symbol)) + symbols = append(symbols, symbol) } } + // Getting the declared types creates them, so do it in a stable order rather than in the random iteration order + // of the symbol table. + c.sortSymbols(symbols) + var result []*Type + for _, symbol := range symbols { + result = append(result, c.getDeclaredTypeOfSymbol(symbol)) + } slices.SortFunc(result, CompareTypes) return result } diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index 389980a60ff64..bf4150b0cbf47 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -262,9 +262,9 @@ func (c *Checker) buildExternalModuleContainerIndex() { } container := c.getSymbolOfDeclaration(file.AsNode()) index.moduleOrder[container] = len(index.moduleOrder) - for _, exported := range c.getExportsOfSymbol(container) { + c.forEachSymbolInResolutionOrder(c.getExportsOfSymbol(container), func(exported *ast.Symbol) { index.add(c.getResolvedTarget(exported), container) - } + }) if exportEquals := container.Exports()[ast.InternalSymbolNameExportEquals]; exportEquals != nil { index.add(c.getResolvedTarget(exportEquals), container) } @@ -272,6 +272,25 @@ func (c *Checker) buildExternalModuleContainerIndex() { index.complete = true } +// forEachSymbolInResolutionOrder calls f for each symbol of a symbol table, in an order that does not depend on the +// table's random iteration order wherever resolving the symbols can have side effects. Symbols that are not aliases +// resolve to themselves and come first, in table order. Resolving an alias can create types, so aliases come last, +// sorted. +func (c *Checker) forEachSymbolInResolutionOrder(symbols ast.SymbolTable, f func(symbol *ast.Symbol)) { + var aliases []*ast.Symbol + for _, symbol := range symbols { + if symbol.Flags()&ast.SymbolFlagsAlias != 0 { + aliases = append(aliases, symbol) + } else { + f(symbol) + } + } + c.sortSymbols(aliases) + for _, symbol := range aliases { + f(symbol) + } +} + func (c *Checker) scanExternalModuleContainers(symbol *ast.Symbol) []*ast.Symbol { var containers []*ast.Symbol for _, file := range c.program.SourceFiles() { @@ -420,11 +439,11 @@ func (c *Checker) getAliasForSymbolInContainer(container *ast.Symbol, symbol *as return quick } var candidates []*ast.Symbol - for _, exported := range exports { + c.forEachSymbolInResolutionOrder(exports, func(exported *ast.Symbol) { if c.getSymbolIfSameReference(exported, symbol) != nil { candidates = append(candidates, exported) } - } + }) if len(candidates) > 0 { c.sortSymbols(candidates) // _must_ sort exports for stable results - symbol table is randomly iterated return candidates[0] diff --git a/tsc/internal/execute/tsctests/tsc_test.go b/tsc/internal/execute/tsctests/tsc_test.go index aff5f93620582..519ba582c98da 100644 --- a/tsc/internal/execute/tsctests/tsc_test.go +++ b/tsc/internal/execute/tsctests/tsc_test.go @@ -5078,6 +5078,16 @@ func TestGenerateTrace(t *testing.T) { }, commandLineArgs: []string{"--generateTrace", "/home/src/workspaces/project/trace", "--singleThreaded"}, }, + { + // Type ids are creation order. Each part of this project makes the checker create types while it + // iterates a symbol table with more than eight entries (whose iteration order varies from run to run): + // the infer type parameters of a conditional type in a declaration file, a namespace import whose + // members are aliases of namespace imports, and declaration emit of a type no import of main.ts + // exports, which resolves the `export =` re-exports of every module. + subScenario: "generateTrace creates types in a stable order", + files: generateTraceStableOrderFiles(), + commandLineArgs: []string{"--generateTrace", "/home/src/workspaces/project/trace", "--singleThreaded"}, + }, } for _, c := range cases { @@ -5085,6 +5095,57 @@ func TestGenerateTrace(t *testing.T) { } } +func generateTraceStableOrderFiles() FileMap { + files := FileMap{ + "/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(` + { + "compilerOptions": { + "strict": true, + "skipLibCheck": true, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "out" + }, + "files": ["main.ts", "locales/index.d.ts"] + }`), + "/home/src/workspaces/project/fields.d.ts": stringtestutil.Dedent(` + export type Fields = T extends { a: infer A; b: infer B; c: infer C; d: infer D; e: infer E; f: infer F; g: infer G; h: infer H; i: infer I; j: infer J; k: infer K; l: infer L } ? [A, B, C, D, E, F, G, H, I, J, K, L] : never; + `), + "/home/src/workspaces/project/gadget.d.ts": stringtestutil.Dedent(` + export interface Gadget { + id: number; + } + `), + "/home/src/workspaces/project/widget.d.ts": stringtestutil.Dedent(` + import { Gadget } from "./gadget"; + export declare function makeWidget(): Gadget; + `), + "/home/src/workspaces/project/main.ts": stringtestutil.Dedent(` + import * as parts from "./parts/index"; + import { Fields } from "./fields"; + import { makeWidget } from "./widget"; + + export const fields: Fields<{ a: 1; b: 2; c: 3; d: 4; e: 5; f: 6; g: 7; h: 8; i: 9; j: 10; k: 11; l: 12 }> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + export const allParts = parts; + export const widget = makeWidget(); + `), + } + var localesIndex, partsIndex strings.Builder + parts := []string{"alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu"} + for _, locale := range []string{"ar", "de", "en", "es", "fr", "he", "it", "ja", "ko", "nl", "pl", "pt"} { + files["/home/src/workspaces/project/locales/"+locale+".d.ts"] = fmt.Sprintf("declare const _default: () => { locale: %q };\nexport = _default;\n", locale) + fmt.Fprintf(&localesIndex, "export { default as %s } from \"./%s\";\n", locale, locale) + } + for _, part := range parts { + files["/home/src/workspaces/project/parts/"+part+".d.ts"] = fmt.Sprintf("export declare const %s: { name: %q };\n", part, part) + fmt.Fprintf(&partsIndex, "import * as %s from \"./%s\";\n", part, part) + } + fmt.Fprintf(&partsIndex, "export { %s };\n", strings.Join(parts, ", ")) + files["/home/src/workspaces/project/locales/index.d.ts"] = localesIndex.String() + files["/home/src/workspaces/project/parts/index.d.ts"] = partsIndex.String() + return files +} + func TestTscContentMapperEmit(t *testing.T) { t.Parallel() (&tscInput{ diff --git a/tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-types-in-a-stable-order.js b/tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-types-in-a-stable-order.js new file mode 100644 index 0000000000000..0cbad41700637 --- /dev/null +++ b/tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-types-in-a-stable-order.js @@ -0,0 +1,554 @@ +currentDirectory::/home/src/workspaces/project +useCaseSensitiveFileNames::true +Input:: +//// [/home/src/workspaces/project/fields.d.ts] *new* +export type Fields = T extends { a: infer A; b: infer B; c: infer C; d: infer D; e: infer E; f: infer F; g: infer G; h: infer H; i: infer I; j: infer J; k: infer K; l: infer L } ? [A, B, C, D, E, F, G, H, I, J, K, L] : never; +//// [/home/src/workspaces/project/gadget.d.ts] *new* +export interface Gadget { + id: number; +} +//// [/home/src/workspaces/project/locales/ar.d.ts] *new* +declare const _default: () => { locale: "ar" }; +export = _default; + +//// [/home/src/workspaces/project/locales/de.d.ts] *new* +declare const _default: () => { locale: "de" }; +export = _default; + +//// [/home/src/workspaces/project/locales/en.d.ts] *new* +declare const _default: () => { locale: "en" }; +export = _default; + +//// [/home/src/workspaces/project/locales/es.d.ts] *new* +declare const _default: () => { locale: "es" }; +export = _default; + +//// [/home/src/workspaces/project/locales/fr.d.ts] *new* +declare const _default: () => { locale: "fr" }; +export = _default; + +//// [/home/src/workspaces/project/locales/he.d.ts] *new* +declare const _default: () => { locale: "he" }; +export = _default; + +//// [/home/src/workspaces/project/locales/index.d.ts] *new* +export { default as ar } from "./ar"; +export { default as de } from "./de"; +export { default as en } from "./en"; +export { default as es } from "./es"; +export { default as fr } from "./fr"; +export { default as he } from "./he"; +export { default as it } from "./it"; +export { default as ja } from "./ja"; +export { default as ko } from "./ko"; +export { default as nl } from "./nl"; +export { default as pl } from "./pl"; +export { default as pt } from "./pt"; + +//// [/home/src/workspaces/project/locales/it.d.ts] *new* +declare const _default: () => { locale: "it" }; +export = _default; + +//// [/home/src/workspaces/project/locales/ja.d.ts] *new* +declare const _default: () => { locale: "ja" }; +export = _default; + +//// [/home/src/workspaces/project/locales/ko.d.ts] *new* +declare const _default: () => { locale: "ko" }; +export = _default; + +//// [/home/src/workspaces/project/locales/nl.d.ts] *new* +declare const _default: () => { locale: "nl" }; +export = _default; + +//// [/home/src/workspaces/project/locales/pl.d.ts] *new* +declare const _default: () => { locale: "pl" }; +export = _default; + +//// [/home/src/workspaces/project/locales/pt.d.ts] *new* +declare const _default: () => { locale: "pt" }; +export = _default; + +//// [/home/src/workspaces/project/main.ts] *new* +import * as parts from "./parts/index"; +import { Fields } from "./fields"; +import { makeWidget } from "./widget"; + +export const fields: Fields<{ a: 1; b: 2; c: 3; d: 4; e: 5; f: 6; g: 7; h: 8; i: 9; j: 10; k: 11; l: 12 }> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; +export const allParts = parts; +export const widget = makeWidget(); +//// [/home/src/workspaces/project/parts/alpha.d.ts] *new* +export declare const alpha: { name: "alpha" }; + +//// [/home/src/workspaces/project/parts/beta.d.ts] *new* +export declare const beta: { name: "beta" }; + +//// [/home/src/workspaces/project/parts/delta.d.ts] *new* +export declare const delta: { name: "delta" }; + +//// [/home/src/workspaces/project/parts/epsilon.d.ts] *new* +export declare const epsilon: { name: "epsilon" }; + +//// [/home/src/workspaces/project/parts/eta.d.ts] *new* +export declare const eta: { name: "eta" }; + +//// [/home/src/workspaces/project/parts/gamma.d.ts] *new* +export declare const gamma: { name: "gamma" }; + +//// [/home/src/workspaces/project/parts/index.d.ts] *new* +import * as alpha from "./alpha"; +import * as beta from "./beta"; +import * as gamma from "./gamma"; +import * as delta from "./delta"; +import * as epsilon from "./epsilon"; +import * as zeta from "./zeta"; +import * as eta from "./eta"; +import * as theta from "./theta"; +import * as iota from "./iota"; +import * as kappa from "./kappa"; +import * as lambda from "./lambda"; +import * as mu from "./mu"; +export { alpha, beta, gamma, delta, epsilon, zeta, eta, theta, iota, kappa, lambda, mu }; + +//// [/home/src/workspaces/project/parts/iota.d.ts] *new* +export declare const iota: { name: "iota" }; + +//// [/home/src/workspaces/project/parts/kappa.d.ts] *new* +export declare const kappa: { name: "kappa" }; + +//// [/home/src/workspaces/project/parts/lambda.d.ts] *new* +export declare const lambda: { name: "lambda" }; + +//// [/home/src/workspaces/project/parts/mu.d.ts] *new* +export declare const mu: { name: "mu" }; + +//// [/home/src/workspaces/project/parts/theta.d.ts] *new* +export declare const theta: { name: "theta" }; + +//// [/home/src/workspaces/project/parts/zeta.d.ts] *new* +export declare const zeta: { name: "zeta" }; + +//// [/home/src/workspaces/project/tsconfig.json] *new* +{ + "compilerOptions": { + "strict": true, + "skipLibCheck": true, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "out" + }, + "files": ["main.ts", "locales/index.d.ts"] +} +//// [/home/src/workspaces/project/widget.d.ts] *new* +import { Gadget } from "./gadget"; +export declare function makeWidget(): Gadget; + +tsgo --generateTrace /home/src/workspaces/project/trace --singleThreaded +ExitStatus:: Success +Output:: +//// [/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts] *Lib* +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +interface SymbolConstructor { + (desc?: string | number): symbol; + for(name: string): symbol; + readonly toStringTag: symbol; +} +declare var Symbol: SymbolConstructor; +interface Symbol { + readonly [Symbol.toStringTag]: string; +} +declare const console: { log(msg: any): void; }; +//// [/home/src/workspaces/project/out/main.d.ts] *new* +import * as parts from "./parts/index"; +import { Fields } from "./fields"; +export declare const fields: Fields<{ + a: 1; + b: 2; + c: 3; + d: 4; + e: 5; + f: 6; + g: 7; + h: 8; + i: 9; + j: 10; + k: 11; + l: 12; +}>; +export declare const allParts: typeof parts; +export declare const widget: import("./gadget").Gadget; + +//// [/home/src/workspaces/project/trace/legend.json] *new* +[ + { + "configFilePath": "/home/src/workspaces/project/tsconfig.json", + "tracePath": "/home/src/workspaces/project/trace/trace.json", + "typesPath": "/home/src/workspaces/project/trace/types_0.json", + "checkerId": 0 + } +] +//// [/home/src/workspaces/project/trace/trace.json] *new* +[ +{"pid":1,"tid":1,"ph":"M","cat":"__metadata","ts":1,"name":"process_name","args":{"name":"tsgo"}}, +{"pid":1,"tid":1,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"Main"}}, +{"pid":1,"tid":1,"ph":"M","cat":"disabled-by-default-devtools.timeline","ts":1,"name":"TracingStartedInBrowser"}, +{"pid":1,"tid":1,"ph":"B","cat":"program","ts":2,"name":"createProgram","args":{"configFilePath":"/home/src/workspaces/project/tsconfig.json"}}, +{"pid":1,"tid":181085097,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"B","cat":"parse","ts":3,"name":"createSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"E","cat":"parse","ts":4,"name":"createSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":373807619,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/index.d.ts"}}, +{"pid":1,"tid":373807619,"ph":"B","cat":"parse","ts":5,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/index.d.ts"}}, +{"pid":1,"tid":373807619,"ph":"E","cat":"parse","ts":6,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/index.d.ts"}}, +{"pid":1,"tid":872471718,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/pt.d.ts"}}, +{"pid":1,"tid":872471718,"ph":"B","cat":"parse","ts":7,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/pt.d.ts"}}, +{"pid":1,"tid":872471718,"ph":"E","cat":"parse","ts":8,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/pt.d.ts"}}, +{"pid":1,"tid":944314902,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/pl.d.ts"}}, +{"pid":1,"tid":944314902,"ph":"B","cat":"parse","ts":9,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/pl.d.ts"}}, +{"pid":1,"tid":944314902,"ph":"E","cat":"parse","ts":10,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/pl.d.ts"}}, +{"pid":1,"tid":255493617,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/nl.d.ts"}}, +{"pid":1,"tid":255493617,"ph":"B","cat":"parse","ts":11,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/nl.d.ts"}}, +{"pid":1,"tid":255493617,"ph":"E","cat":"parse","ts":12,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/nl.d.ts"}}, +{"pid":1,"tid":376655012,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/ko.d.ts"}}, +{"pid":1,"tid":376655012,"ph":"B","cat":"parse","ts":13,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/ko.d.ts"}}, +{"pid":1,"tid":376655012,"ph":"E","cat":"parse","ts":14,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/ko.d.ts"}}, +{"pid":1,"tid":345504644,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/ja.d.ts"}}, +{"pid":1,"tid":345504644,"ph":"B","cat":"parse","ts":15,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/ja.d.ts"}}, +{"pid":1,"tid":345504644,"ph":"E","cat":"parse","ts":16,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/ja.d.ts"}}, +{"pid":1,"tid":450563598,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/it.d.ts"}}, +{"pid":1,"tid":450563598,"ph":"B","cat":"parse","ts":17,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/it.d.ts"}}, +{"pid":1,"tid":450563598,"ph":"E","cat":"parse","ts":18,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/it.d.ts"}}, +{"pid":1,"tid":141527137,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/he.d.ts"}}, +{"pid":1,"tid":141527137,"ph":"B","cat":"parse","ts":19,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/he.d.ts"}}, +{"pid":1,"tid":141527137,"ph":"E","cat":"parse","ts":20,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/he.d.ts"}}, +{"pid":1,"tid":883991556,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/fr.d.ts"}}, +{"pid":1,"tid":883991556,"ph":"B","cat":"parse","ts":21,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/fr.d.ts"}}, +{"pid":1,"tid":883991556,"ph":"E","cat":"parse","ts":22,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/fr.d.ts"}}, +{"pid":1,"tid":455027228,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/es.d.ts"}}, +{"pid":1,"tid":455027228,"ph":"B","cat":"parse","ts":23,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/es.d.ts"}}, +{"pid":1,"tid":455027228,"ph":"E","cat":"parse","ts":24,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/es.d.ts"}}, +{"pid":1,"tid":616565165,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/en.d.ts"}}, +{"pid":1,"tid":616565165,"ph":"B","cat":"parse","ts":25,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/en.d.ts"}}, +{"pid":1,"tid":616565165,"ph":"E","cat":"parse","ts":26,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/en.d.ts"}}, +{"pid":1,"tid":930019567,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/de.d.ts"}}, +{"pid":1,"tid":930019567,"ph":"B","cat":"parse","ts":27,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/de.d.ts"}}, +{"pid":1,"tid":930019567,"ph":"E","cat":"parse","ts":28,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/de.d.ts"}}, +{"pid":1,"tid":743285103,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/locales/ar.d.ts"}}, +{"pid":1,"tid":743285103,"ph":"B","cat":"parse","ts":29,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/ar.d.ts"}}, +{"pid":1,"tid":743285103,"ph":"E","cat":"parse","ts":30,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/locales/ar.d.ts"}}, +{"pid":1,"tid":100209852,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":100209852,"ph":"B","cat":"parse","ts":31,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":100209852,"ph":"E","cat":"parse","ts":32,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":540121770,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/widget.d.ts"}}, +{"pid":1,"tid":540121770,"ph":"B","cat":"parse","ts":33,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/widget.d.ts"}}, +{"pid":1,"tid":540121770,"ph":"E","cat":"parse","ts":34,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/widget.d.ts"}}, +{"pid":1,"tid":411501950,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/gadget.d.ts"}}, +{"pid":1,"tid":411501950,"ph":"B","cat":"parse","ts":35,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/gadget.d.ts"}}, +{"pid":1,"tid":411501950,"ph":"E","cat":"parse","ts":36,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/gadget.d.ts"}}, +{"pid":1,"tid":454685436,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/fields.d.ts"}}, +{"pid":1,"tid":454685436,"ph":"B","cat":"parse","ts":37,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/fields.d.ts"}}, +{"pid":1,"tid":454685436,"ph":"E","cat":"parse","ts":38,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/fields.d.ts"}}, +{"pid":1,"tid":911467565,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/index.d.ts"}}, +{"pid":1,"tid":911467565,"ph":"B","cat":"parse","ts":39,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/index.d.ts"}}, +{"pid":1,"tid":911467565,"ph":"E","cat":"parse","ts":40,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/index.d.ts"}}, +{"pid":1,"tid":3296854,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/mu.d.ts"}}, +{"pid":1,"tid":3296854,"ph":"B","cat":"parse","ts":41,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/mu.d.ts"}}, +{"pid":1,"tid":3296854,"ph":"E","cat":"parse","ts":42,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/mu.d.ts"}}, +{"pid":1,"tid":172708103,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/lambda.d.ts"}}, +{"pid":1,"tid":172708103,"ph":"B","cat":"parse","ts":43,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/lambda.d.ts"}}, +{"pid":1,"tid":172708103,"ph":"E","cat":"parse","ts":44,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/lambda.d.ts"}}, +{"pid":1,"tid":887942961,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/kappa.d.ts"}}, +{"pid":1,"tid":887942961,"ph":"B","cat":"parse","ts":45,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/kappa.d.ts"}}, +{"pid":1,"tid":887942961,"ph":"E","cat":"parse","ts":46,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/kappa.d.ts"}}, +{"pid":1,"tid":757955809,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/iota.d.ts"}}, +{"pid":1,"tid":757955809,"ph":"B","cat":"parse","ts":47,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/iota.d.ts"}}, +{"pid":1,"tid":757955809,"ph":"E","cat":"parse","ts":48,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/iota.d.ts"}}, +{"pid":1,"tid":909662959,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/theta.d.ts"}}, +{"pid":1,"tid":909662959,"ph":"B","cat":"parse","ts":49,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/theta.d.ts"}}, +{"pid":1,"tid":909662959,"ph":"E","cat":"parse","ts":50,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/theta.d.ts"}}, +{"pid":1,"tid":86181510,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/eta.d.ts"}}, +{"pid":1,"tid":86181510,"ph":"B","cat":"parse","ts":51,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/eta.d.ts"}}, +{"pid":1,"tid":86181510,"ph":"E","cat":"parse","ts":52,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/eta.d.ts"}}, +{"pid":1,"tid":813403241,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/zeta.d.ts"}}, +{"pid":1,"tid":813403241,"ph":"B","cat":"parse","ts":53,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/zeta.d.ts"}}, +{"pid":1,"tid":813403241,"ph":"E","cat":"parse","ts":54,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/zeta.d.ts"}}, +{"pid":1,"tid":758077059,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/epsilon.d.ts"}}, +{"pid":1,"tid":758077059,"ph":"B","cat":"parse","ts":55,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/epsilon.d.ts"}}, +{"pid":1,"tid":758077059,"ph":"E","cat":"parse","ts":56,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/epsilon.d.ts"}}, +{"pid":1,"tid":424664868,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/delta.d.ts"}}, +{"pid":1,"tid":424664868,"ph":"B","cat":"parse","ts":57,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/delta.d.ts"}}, +{"pid":1,"tid":424664868,"ph":"E","cat":"parse","ts":58,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/delta.d.ts"}}, +{"pid":1,"tid":562550315,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/gamma.d.ts"}}, +{"pid":1,"tid":562550315,"ph":"B","cat":"parse","ts":59,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/gamma.d.ts"}}, +{"pid":1,"tid":562550315,"ph":"E","cat":"parse","ts":60,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/gamma.d.ts"}}, +{"pid":1,"tid":212488040,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/beta.d.ts"}}, +{"pid":1,"tid":212488040,"ph":"B","cat":"parse","ts":61,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/beta.d.ts"}}, +{"pid":1,"tid":212488040,"ph":"E","cat":"parse","ts":62,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/beta.d.ts"}}, +{"pid":1,"tid":180310947,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/parts/alpha.d.ts"}}, +{"pid":1,"tid":180310947,"ph":"B","cat":"parse","ts":63,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/alpha.d.ts"}}, +{"pid":1,"tid":180310947,"ph":"E","cat":"parse","ts":64,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/parts/alpha.d.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"program","ts":65,"name":"createProgram","args":{"configFilePath":"/home/src/workspaces/project/tsconfig.json"}}, +{"pid":1,"tid":1,"ph":"B","cat":"bind","ts":66,"name":"bindSourceFiles"}, +{"pid":1,"tid":373807619,"ph":"B","cat":"bind","ts":67,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/index.d.ts"}}, +{"pid":1,"tid":373807619,"ph":"E","cat":"bind","ts":68,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/index.d.ts"}}, +{"pid":1,"tid":872471718,"ph":"B","cat":"bind","ts":69,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/pt.d.ts"}}, +{"pid":1,"tid":872471718,"ph":"E","cat":"bind","ts":70,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/pt.d.ts"}}, +{"pid":1,"tid":944314902,"ph":"B","cat":"bind","ts":71,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/pl.d.ts"}}, +{"pid":1,"tid":944314902,"ph":"E","cat":"bind","ts":72,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/pl.d.ts"}}, +{"pid":1,"tid":255493617,"ph":"B","cat":"bind","ts":73,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/nl.d.ts"}}, +{"pid":1,"tid":255493617,"ph":"E","cat":"bind","ts":74,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/nl.d.ts"}}, +{"pid":1,"tid":376655012,"ph":"B","cat":"bind","ts":75,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/ko.d.ts"}}, +{"pid":1,"tid":376655012,"ph":"E","cat":"bind","ts":76,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/ko.d.ts"}}, +{"pid":1,"tid":345504644,"ph":"B","cat":"bind","ts":77,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/ja.d.ts"}}, +{"pid":1,"tid":345504644,"ph":"E","cat":"bind","ts":78,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/ja.d.ts"}}, +{"pid":1,"tid":450563598,"ph":"B","cat":"bind","ts":79,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/it.d.ts"}}, +{"pid":1,"tid":450563598,"ph":"E","cat":"bind","ts":80,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/it.d.ts"}}, +{"pid":1,"tid":141527137,"ph":"B","cat":"bind","ts":81,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/he.d.ts"}}, +{"pid":1,"tid":141527137,"ph":"E","cat":"bind","ts":82,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/he.d.ts"}}, +{"pid":1,"tid":883991556,"ph":"B","cat":"bind","ts":83,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/fr.d.ts"}}, +{"pid":1,"tid":883991556,"ph":"E","cat":"bind","ts":84,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/fr.d.ts"}}, +{"pid":1,"tid":455027228,"ph":"B","cat":"bind","ts":85,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/es.d.ts"}}, +{"pid":1,"tid":455027228,"ph":"E","cat":"bind","ts":86,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/es.d.ts"}}, +{"pid":1,"tid":616565165,"ph":"B","cat":"bind","ts":87,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/en.d.ts"}}, +{"pid":1,"tid":616565165,"ph":"E","cat":"bind","ts":88,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/en.d.ts"}}, +{"pid":1,"tid":930019567,"ph":"B","cat":"bind","ts":89,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/de.d.ts"}}, +{"pid":1,"tid":930019567,"ph":"E","cat":"bind","ts":90,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/de.d.ts"}}, +{"pid":1,"tid":743285103,"ph":"B","cat":"bind","ts":91,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/ar.d.ts"}}, +{"pid":1,"tid":743285103,"ph":"E","cat":"bind","ts":92,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/locales/ar.d.ts"}}, +{"pid":1,"tid":100209852,"ph":"B","cat":"bind","ts":93,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":100209852,"ph":"E","cat":"bind","ts":94,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":540121770,"ph":"B","cat":"bind","ts":95,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/widget.d.ts"}}, +{"pid":1,"tid":540121770,"ph":"E","cat":"bind","ts":96,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/widget.d.ts"}}, +{"pid":1,"tid":411501950,"ph":"B","cat":"bind","ts":97,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/gadget.d.ts"}}, +{"pid":1,"tid":411501950,"ph":"E","cat":"bind","ts":98,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/gadget.d.ts"}}, +{"pid":1,"tid":454685436,"ph":"B","cat":"bind","ts":99,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/fields.d.ts"}}, +{"pid":1,"tid":454685436,"ph":"E","cat":"bind","ts":100,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/fields.d.ts"}}, +{"pid":1,"tid":911467565,"ph":"B","cat":"bind","ts":101,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/index.d.ts"}}, +{"pid":1,"tid":911467565,"ph":"E","cat":"bind","ts":102,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/index.d.ts"}}, +{"pid":1,"tid":3296854,"ph":"B","cat":"bind","ts":103,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/mu.d.ts"}}, +{"pid":1,"tid":3296854,"ph":"E","cat":"bind","ts":104,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/mu.d.ts"}}, +{"pid":1,"tid":172708103,"ph":"B","cat":"bind","ts":105,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/lambda.d.ts"}}, +{"pid":1,"tid":172708103,"ph":"E","cat":"bind","ts":106,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/lambda.d.ts"}}, +{"pid":1,"tid":887942961,"ph":"B","cat":"bind","ts":107,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/kappa.d.ts"}}, +{"pid":1,"tid":887942961,"ph":"E","cat":"bind","ts":108,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/kappa.d.ts"}}, +{"pid":1,"tid":757955809,"ph":"B","cat":"bind","ts":109,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/iota.d.ts"}}, +{"pid":1,"tid":757955809,"ph":"E","cat":"bind","ts":110,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/iota.d.ts"}}, +{"pid":1,"tid":909662959,"ph":"B","cat":"bind","ts":111,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/theta.d.ts"}}, +{"pid":1,"tid":909662959,"ph":"E","cat":"bind","ts":112,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/theta.d.ts"}}, +{"pid":1,"tid":86181510,"ph":"B","cat":"bind","ts":113,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/eta.d.ts"}}, +{"pid":1,"tid":86181510,"ph":"E","cat":"bind","ts":114,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/eta.d.ts"}}, +{"pid":1,"tid":813403241,"ph":"B","cat":"bind","ts":115,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/zeta.d.ts"}}, +{"pid":1,"tid":813403241,"ph":"E","cat":"bind","ts":116,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/zeta.d.ts"}}, +{"pid":1,"tid":758077059,"ph":"B","cat":"bind","ts":117,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/epsilon.d.ts"}}, +{"pid":1,"tid":758077059,"ph":"E","cat":"bind","ts":118,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/epsilon.d.ts"}}, +{"pid":1,"tid":424664868,"ph":"B","cat":"bind","ts":119,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/delta.d.ts"}}, +{"pid":1,"tid":424664868,"ph":"E","cat":"bind","ts":120,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/delta.d.ts"}}, +{"pid":1,"tid":562550315,"ph":"B","cat":"bind","ts":121,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/gamma.d.ts"}}, +{"pid":1,"tid":562550315,"ph":"E","cat":"bind","ts":122,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/gamma.d.ts"}}, +{"pid":1,"tid":212488040,"ph":"B","cat":"bind","ts":123,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/beta.d.ts"}}, +{"pid":1,"tid":212488040,"ph":"E","cat":"bind","ts":124,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/beta.d.ts"}}, +{"pid":1,"tid":180310947,"ph":"B","cat":"bind","ts":125,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/alpha.d.ts"}}, +{"pid":1,"tid":180310947,"ph":"E","cat":"bind","ts":126,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/parts/alpha.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"B","cat":"bind","ts":127,"name":"bindSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"E","cat":"bind","ts":128,"name":"bindSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"bind","ts":129,"name":"bindSourceFiles"}, +{"pid":1,"tid":1,"ph":"B","cat":"check","ts":130,"name":"checkSourceFiles"}, +{"pid":1,"tid":2,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"checker:0"}}, +{"pid":1,"tid":2,"ph":"B","cat":"check","ts":131,"name":"checkSourceFile","args":{"checkerId":0,"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":2,"ph":"E","cat":"check","ts":132,"name":"checkSourceFile","args":{"checkerId":0,"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"check","ts":133,"name":"checkSourceFiles"}, +{"pid":1,"tid":1,"ph":"B","cat":"emit","ts":134,"name":"emit"}, +{"pid":1,"tid":100209852,"ph":"B","cat":"emit","ts":135,"name":"emit","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"B","cat":"emit","ts":136,"name":"emitDeclarationFileOrBundle","args":{"declarationFilePath":"/home/src/workspaces/project/out/main.d.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"emit","ts":137,"name":"emitDeclarationFileOrBundle","args":{"declarationFilePath":"/home/src/workspaces/project/out/main.d.ts"}}, +{"pid":1,"tid":100209852,"ph":"E","cat":"emit","ts":138,"name":"emit","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"emit","ts":139,"name":"emit"} +] + +//// [/home/src/workspaces/project/trace/types_0.json] *new* +[{"id":1,"intrinsicName":"any","recursionId":0,"flags":["Any"]}, +{"id":2,"intrinsicName":"any","recursionId":1,"flags":["Any"]}, +{"id":3,"intrinsicName":"any","recursionId":2,"flags":["Any"]}, +{"id":4,"intrinsicName":"any","recursionId":3,"flags":["Any"]}, +{"id":5,"intrinsicName":"error","recursionId":4,"flags":["Any"]}, +{"id":6,"intrinsicName":"unresolved","recursionId":5,"flags":["Any"]}, +{"id":7,"intrinsicName":"any","recursionId":6,"flags":["Any"]}, +{"id":8,"intrinsicName":"intrinsic","recursionId":7,"flags":["Any"]}, +{"id":9,"intrinsicName":"unknown","recursionId":8,"flags":["Unknown"]}, +{"id":10,"intrinsicName":"undefined","recursionId":9,"flags":["Undefined"]}, +{"id":11,"intrinsicName":"undefined","recursionId":10,"flags":["Undefined"]}, +{"id":12,"intrinsicName":"undefined","recursionId":11,"flags":["Undefined"]}, +{"id":13,"intrinsicName":"null","recursionId":12,"flags":["Null"]}, +{"id":14,"intrinsicName":"string","recursionId":13,"flags":["String"]}, +{"id":15,"intrinsicName":"number","recursionId":14,"flags":["Number"]}, +{"id":16,"intrinsicName":"bigint","recursionId":15,"flags":["BigInt"]}, +{"id":17,"recursionId":16,"flags":["BooleanLiteral"],"display":"false"}, +{"id":18,"recursionId":17,"flags":["BooleanLiteral"],"display":"false"}, +{"id":19,"recursionId":18,"flags":["BooleanLiteral"],"display":"true"}, +{"id":20,"recursionId":19,"flags":["BooleanLiteral"],"display":"true"}, +{"id":21,"recursionId":20,"unionTypes":[17,19],"flags":["Boolean","Union"],"display":"boolean"}, +{"id":22,"intrinsicName":"symbol","recursionId":21,"flags":["ESSymbol"]}, +{"id":23,"intrinsicName":"void","recursionId":22,"flags":["Void"]}, +{"id":24,"intrinsicName":"never","recursionId":23,"flags":["Never"]}, +{"id":25,"intrinsicName":"never","recursionId":24,"flags":["Never"]}, +{"id":26,"intrinsicName":"never","recursionId":25,"flags":["Never"]}, +{"id":27,"intrinsicName":"never","recursionId":26,"flags":["Never"]}, +{"id":28,"intrinsicName":"object","recursionId":27,"flags":["NonPrimitive"]}, +{"id":29,"recursionId":28,"unionTypes":[14,15],"flags":["Union"],"display":"string | number"}, +{"id":30,"recursionId":29,"unionTypes":[14,15,22],"flags":["Union"],"display":"string | number | symbol"}, +{"id":31,"recursionId":30,"unionTypes":[15,16],"flags":["Union"],"display":"number | bigint"}, +{"id":32,"recursionId":31,"flags":["TemplateLiteral"],"display":"`${number}`"}, +{"id":33,"recursionId":32,"unionTypes":[10,13,14,15,16,17,19],"flags":["Union"],"display":"string | number | bigint | boolean | null | undefined"}, +{"id":34,"intrinsicName":"never","recursionId":33,"flags":["Never"]}, +{"id":35,"recursionId":34,"flags":["Object"],"display":"{}"}, +{"id":36,"recursionId":35,"flags":["Object"],"display":"{}"}, +{"id":37,"recursionId":36,"flags":["Object"],"display":"{}"}, +{"id":38,"symbolName":"__type","recursionId":37,"flags":["Object"],"display":"{}"}, +{"id":39,"recursionId":38,"flags":["Object"],"display":"{}"}, +{"id":40,"recursionId":39,"unionTypes":[10,13,39],"flags":["Union"],"display":"{} | null | undefined"}, +{"id":41,"recursionId":40,"flags":["Object"],"display":"{}"}, +{"id":42,"recursionId":41,"flags":["Object"],"display":"{}"}, +{"id":43,"recursionId":42,"flags":["Object"],"display":"{}"}, +{"id":44,"recursionId":43,"flags":["Object"],"display":"{}"}, +{"id":45,"recursionId":44,"flags":["Object"],"display":"{}"}, +{"id":46,"recursionId":45,"flags":["TypeParameter"]}, +{"id":47,"recursionId":46,"flags":["TypeParameter"]}, +{"id":48,"recursionId":47,"flags":["TypeParameter"]}, +{"id":49,"recursionId":48,"flags":["TypeParameter"]}, +{"id":50,"recursionId":49,"flags":["TypeParameter"]}, +{"id":51,"recursionId":50,"flags":["StringLiteral"],"display":"\"\""}, +{"id":52,"recursionId":51,"flags":["NumberLiteral"],"display":"0"}, +{"id":53,"recursionId":52,"flags":["BigIntLiteral"],"display":"0n"}, +{"id":54,"recursionId":53,"flags":["StringLiteral"],"display":"\"bigint\""}, +{"id":55,"recursionId":54,"flags":["StringLiteral"],"display":"\"boolean\""}, +{"id":56,"recursionId":55,"flags":["StringLiteral"],"display":"\"function\""}, +{"id":57,"recursionId":56,"flags":["StringLiteral"],"display":"\"number\""}, +{"id":58,"recursionId":57,"flags":["StringLiteral"],"display":"\"object\""}, +{"id":59,"recursionId":58,"flags":["StringLiteral"],"display":"\"string\""}, +{"id":60,"recursionId":59,"flags":["StringLiteral"],"display":"\"symbol\""}, +{"id":61,"recursionId":60,"flags":["StringLiteral"],"display":"\"undefined\""}, +{"id":62,"recursionId":61,"unionTypes":[54,55,56,57,58,59,60,61],"flags":["Union"],"display":"\"bigint\" | \"boolean\" | \"function\" | \"number\" | \"object\" | \"string\" | \"symbol\" | \"undefined\""}, +{"id":63,"symbolName":"IArguments","recursionId":62,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":6,"character":1},"end":{"line":6,"character":24}},"flags":["Object"]}, +{"id":64,"symbolName":"globalThis","recursionId":63,"flags":["Object"],"display":"typeof globalThis"}, +{"id":65,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[66],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":66,"symbolName":"T","recursionId":65,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":17},"end":{"line":11,"character":18}},"flags":["TypeParameter"]}, +{"id":67,"symbolName":"Array","recursionId":64,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["TypeParameter"]}, +{"id":68,"symbolName":"Object","recursionId":66,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":8,"character":1},"end":{"line":8,"character":20}},"flags":["Object"]}, +{"id":69,"symbolName":"Function","recursionId":67,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":3,"character":1},"end":{"line":3,"character":22}},"flags":["Object"]}, +{"id":70,"symbolName":"CallableFunction","recursionId":68,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":4,"character":1},"end":{"line":4,"character":30}},"flags":["Object"]}, +{"id":71,"symbolName":"NewableFunction","recursionId":69,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":5,"character":1},"end":{"line":5,"character":29}},"flags":["Object"]}, +{"id":72,"symbolName":"String","recursionId":70,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":10,"character":1},"end":{"line":10,"character":34}},"flags":["Object"]}, +{"id":73,"symbolName":"Number","recursionId":71,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":7,"character":1},"end":{"line":7,"character":41}},"flags":["Object"]}, +{"id":74,"symbolName":"Boolean","recursionId":72,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":2,"character":1},"end":{"line":2,"character":21}},"flags":["Object"]}, +{"id":75,"symbolName":"RegExp","recursionId":73,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":9,"character":1},"end":{"line":9,"character":20}},"flags":["Object"]}, +{"id":76,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[1],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":77,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[2],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":78,"symbolName":"ReadonlyArray","recursionId":74,"instantiatedType":78,"typeArguments":[79],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":1},"end":{"line":12,"character":30}},"flags":["Object"]}, +{"id":79,"symbolName":"T","recursionId":75,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":25},"end":{"line":12,"character":26}},"flags":["TypeParameter"]}, +{"id":80,"symbolName":"ReadonlyArray","recursionId":74,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":1},"end":{"line":12,"character":30}},"flags":["TypeParameter"]}, +{"id":81,"symbolName":"ReadonlyArray","recursionId":74,"instantiatedType":78,"typeArguments":[1],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":1},"end":{"line":12,"character":30}},"flags":["Object"]}, +{"id":82,"symbolName":"\"/home/src/workspaces/project/parts/index\"","recursionId":76,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/index.d.ts","start":{"line":1,"character":1},"end":{"line":14,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/index\")"}, +{"id":83,"symbolName":"\"/home/src/workspaces/project/parts/alpha\"","recursionId":77,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/alpha.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/alpha\")"}, +{"id":84,"symbolName":"\"/home/src/workspaces/project/parts/beta\"","recursionId":78,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/beta.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/beta\")"}, +{"id":85,"symbolName":"\"/home/src/workspaces/project/parts/gamma\"","recursionId":79,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/gamma.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/gamma\")"}, +{"id":86,"symbolName":"\"/home/src/workspaces/project/parts/delta\"","recursionId":80,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/delta.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/delta\")"}, +{"id":87,"symbolName":"\"/home/src/workspaces/project/parts/epsilon\"","recursionId":81,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/epsilon.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/epsilon\")"}, +{"id":88,"symbolName":"\"/home/src/workspaces/project/parts/zeta\"","recursionId":82,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/zeta.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/zeta\")"}, +{"id":89,"symbolName":"\"/home/src/workspaces/project/parts/eta\"","recursionId":83,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/eta.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/eta\")"}, +{"id":90,"symbolName":"\"/home/src/workspaces/project/parts/theta\"","recursionId":84,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/theta.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/theta\")"}, +{"id":91,"symbolName":"\"/home/src/workspaces/project/parts/iota\"","recursionId":85,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/iota.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/iota\")"}, +{"id":92,"symbolName":"\"/home/src/workspaces/project/parts/kappa\"","recursionId":86,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/kappa.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/kappa\")"}, +{"id":93,"symbolName":"\"/home/src/workspaces/project/parts/lambda\"","recursionId":87,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/lambda.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/lambda\")"}, +{"id":94,"symbolName":"\"/home/src/workspaces/project/parts/mu\"","recursionId":88,"firstDeclaration":{"path":"/home/src/workspaces/project/parts/mu.d.ts","start":{"line":1,"character":1},"end":{"line":2,"character":1}},"flags":["Object"],"display":"typeof import(\"/home/src/workspaces/project/parts/mu\")"}, +{"id":95,"recursionId":89,"flags":["NumberLiteral"],"display":"1"}, +{"id":96,"recursionId":90,"flags":["NumberLiteral"],"display":"1"}, +{"id":97,"recursionId":91,"flags":["NumberLiteral"],"display":"2"}, +{"id":98,"recursionId":92,"flags":["NumberLiteral"],"display":"2"}, +{"id":99,"recursionId":93,"flags":["NumberLiteral"],"display":"3"}, +{"id":100,"recursionId":94,"flags":["NumberLiteral"],"display":"3"}, +{"id":101,"recursionId":95,"flags":["NumberLiteral"],"display":"4"}, +{"id":102,"recursionId":96,"flags":["NumberLiteral"],"display":"4"}, +{"id":103,"recursionId":97,"flags":["NumberLiteral"],"display":"5"}, +{"id":104,"recursionId":98,"flags":["NumberLiteral"],"display":"5"}, +{"id":105,"recursionId":99,"flags":["NumberLiteral"],"display":"6"}, +{"id":106,"recursionId":100,"flags":["NumberLiteral"],"display":"6"}, +{"id":107,"recursionId":101,"flags":["NumberLiteral"],"display":"7"}, +{"id":108,"recursionId":102,"flags":["NumberLiteral"],"display":"7"}, +{"id":109,"recursionId":103,"flags":["NumberLiteral"],"display":"8"}, +{"id":110,"recursionId":104,"flags":["NumberLiteral"],"display":"8"}, +{"id":111,"recursionId":105,"flags":["NumberLiteral"],"display":"9"}, +{"id":112,"recursionId":106,"flags":["NumberLiteral"],"display":"9"}, +{"id":113,"recursionId":107,"flags":["NumberLiteral"],"display":"10"}, +{"id":114,"recursionId":108,"flags":["NumberLiteral"],"display":"10"}, +{"id":115,"recursionId":109,"flags":["NumberLiteral"],"display":"11"}, +{"id":116,"recursionId":110,"flags":["NumberLiteral"],"display":"11"}, +{"id":117,"recursionId":111,"flags":["NumberLiteral"],"display":"12"}, +{"id":118,"recursionId":112,"flags":["NumberLiteral"],"display":"12"}, +{"id":119,"symbolName":"__type","recursionId":113,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":5,"character":29},"end":{"line":5,"character":106}},"flags":["Object"],"display":"{ a: 1; b: 2; c: 3; d: 4; e: 5; f: 6; g: 7; h: 8; i: 9; j: 10; k: 11; l: 12; }"}, +{"id":120,"symbolName":"T","recursionId":114,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":20},"end":{"line":1,"character":21}},"flags":["TypeParameter"]}, +{"id":121,"symbolName":"T","recursionId":114,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":20},"end":{"line":1,"character":21}},"flags":["TypeParameter"]}, +{"id":122,"symbolName":"__type","recursionId":115,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":35},"end":{"line":1,"character":181}},"flags":["Object"],"display":"{ a: A; b: B; c: C; d: D; e: E; f: F; g: G; h: H; i: I; j: J; k: K; l: L; }"}, +{"id":123,"symbolName":"A","recursionId":116,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":46},"end":{"line":1,"character":47}},"flags":["TypeParameter"]}, +{"id":124,"symbolName":"B","recursionId":117,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":58},"end":{"line":1,"character":59}},"flags":["TypeParameter"]}, +{"id":125,"symbolName":"C","recursionId":118,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":70},"end":{"line":1,"character":71}},"flags":["TypeParameter"]}, +{"id":126,"symbolName":"D","recursionId":119,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":82},"end":{"line":1,"character":83}},"flags":["TypeParameter"]}, +{"id":127,"symbolName":"E","recursionId":120,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":94},"end":{"line":1,"character":95}},"flags":["TypeParameter"]}, +{"id":128,"symbolName":"F","recursionId":121,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":106},"end":{"line":1,"character":107}},"flags":["TypeParameter"]}, +{"id":129,"symbolName":"G","recursionId":122,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":118},"end":{"line":1,"character":119}},"flags":["TypeParameter"]}, +{"id":130,"symbolName":"H","recursionId":123,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":130},"end":{"line":1,"character":131}},"flags":["TypeParameter"]}, +{"id":131,"symbolName":"I","recursionId":124,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":142},"end":{"line":1,"character":143}},"flags":["TypeParameter"]}, +{"id":132,"symbolName":"J","recursionId":125,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":154},"end":{"line":1,"character":155}},"flags":["TypeParameter"]}, +{"id":133,"symbolName":"K","recursionId":126,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":166},"end":{"line":1,"character":167}},"flags":["TypeParameter"]}, +{"id":134,"symbolName":"L","recursionId":127,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":178},"end":{"line":1,"character":179}},"flags":["TypeParameter"]}, +{"id":135,"symbolName":"__type","recursionId":115,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":35},"end":{"line":1,"character":181}},"flags":["Object"],"display":"{ a: unknown; b: unknown; c: unknown; d: unknown; e: unknown; f: unknown; g: unknown; h: unknown; i: unknown; j: unknown; k: unknown; l: unknown; }"}, +{"id":136,"symbolName":"Fields","recursionId":128,"aliasTypeArguments":[120],"conditionalCheckType":121,"conditionalExtendsType":122,"conditionalTrueType":-1,"conditionalFalseType":-1,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":1},"end":{"line":1,"character":229}},"flags":["Conditional"]}, +{"id":137,"symbolName":"__type","recursionId":115,"firstDeclaration":{"path":"/home/src/workspaces/project/fields.d.ts","start":{"line":1,"character":35},"end":{"line":1,"character":181}},"flags":["Object"],"display":"{ a: 1; b: 2; c: 3; d: 4; e: 5; f: 6; g: 7; h: 8; i: 9; j: 10; k: 11; l: 12; }"}, +{"id":138,"recursionId":129,"flags":["TypeParameter"]}, +{"id":139,"recursionId":130,"flags":["TypeParameter"]}, +{"id":140,"recursionId":131,"flags":["TypeParameter"]}, +{"id":141,"recursionId":132,"flags":["TypeParameter"]}, +{"id":142,"recursionId":133,"flags":["TypeParameter"]}, +{"id":143,"recursionId":134,"flags":["TypeParameter"]}, +{"id":144,"recursionId":135,"flags":["TypeParameter"]}, +{"id":145,"recursionId":136,"flags":["TypeParameter"]}, +{"id":146,"recursionId":137,"flags":["TypeParameter"]}, +{"id":147,"recursionId":138,"flags":["TypeParameter"]}, +{"id":148,"recursionId":139,"flags":["TypeParameter"]}, +{"id":149,"recursionId":140,"flags":["TypeParameter"]}, +{"id":150,"recursionId":141,"isTuple":true,"instantiatedType":150,"typeArguments":[138,139,140,141,142,143,144,145,146,147,148,149],"flags":["Object"]}, +{"id":151,"recursionId":142,"flags":["TypeParameter"]}, +{"id":152,"recursionId":143,"instantiatedType":150,"typeArguments":[123,124,125,126,127,128,129,130,131,132,133,134],"flags":["Object"]}, +{"id":153,"recursionId":141,"instantiatedType":150,"typeArguments":[95,97,99,101,103,105,107,109,111,113,115,117],"flags":["Object"]}, +{"id":154,"recursionId":144,"instantiatedType":150,"typeArguments":[95,97,99,101,103,105,107,109,111,113,115,117],"flags":["Object"]}, +{"id":155,"recursionId":145,"unionTypes":[138,139,140,141,142,143,144,145,146,147,148,149],"flags":["Union"],"display":"? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ?"}, +{"id":156,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[155],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":157,"recursionId":146,"unionTypes":[95,97,99,101,103,105,107,109,111,113,115,117],"flags":["Union"],"display":"1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12"}, +{"id":158,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[157],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":159,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[157,153],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":160,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[157,154],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":161,"symbolName":"makeWidget","recursionId":147,"firstDeclaration":{"path":"/home/src/workspaces/project/widget.d.ts","start":{"line":2,"character":1},"end":{"line":2,"character":46}},"flags":["Object"],"display":"() => Gadget"}, +{"id":162,"symbolName":"Gadget","recursionId":148,"firstDeclaration":{"path":"/home/src/workspaces/project/gadget.d.ts","start":{"line":1,"character":1},"end":{"line":3,"character":2}},"flags":["Object"]}, +{"id":163,"symbolName":"__type","recursionId":149,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/ar.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"ar\"; }"}, +{"id":164,"symbolName":"__type","recursionId":150,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/de.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"de\"; }"}, +{"id":165,"symbolName":"__type","recursionId":151,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/en.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"en\"; }"}, +{"id":166,"symbolName":"__type","recursionId":152,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/es.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"es\"; }"}, +{"id":167,"symbolName":"__type","recursionId":153,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/fr.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"fr\"; }"}, +{"id":168,"symbolName":"__type","recursionId":154,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/he.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"he\"; }"}, +{"id":169,"symbolName":"__type","recursionId":155,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/it.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"it\"; }"}, +{"id":170,"symbolName":"__type","recursionId":156,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/ja.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"ja\"; }"}, +{"id":171,"symbolName":"__type","recursionId":157,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/ko.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"ko\"; }"}, +{"id":172,"symbolName":"__type","recursionId":158,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/nl.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"nl\"; }"}, +{"id":173,"symbolName":"__type","recursionId":159,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/pl.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"pl\"; }"}, +{"id":174,"symbolName":"__type","recursionId":160,"firstDeclaration":{"path":"/home/src/workspaces/project/locales/pt.d.ts","start":{"line":1,"character":25},"end":{"line":1,"character":47}},"flags":["Object"],"display":"() => { locale: \"pt\"; }"}] + + From e1ba729b21b62b451793d1c578b0fa2508c3eb8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 09:52:01 +0200 Subject: [PATCH 02/35] Add tests for symbol table resolution order flakiness --- ...nalModuleContainerIndexDeclarationOrder.js | 81 ++++++ ...duleContainerIndexDeclarationOrder.symbols | 180 +++++++++++++ ...ModuleContainerIndexDeclarationOrder.types | 164 ++++++++++++ ...embersResolutionOrderExportStar.errors.txt | 64 +++++ ...mespaceMembersResolutionOrderExportStar.js | 245 ++++++++++++++++++ ...ceMembersResolutionOrderExportStar.symbols | 163 ++++++++++++ ...paceMembersResolutionOrderExportStar.types | 194 ++++++++++++++ ...onEmitExternalModuleContainerIndexOrder.js | 81 ++++++ ...tExternalModuleContainerIndexOrder.symbols | 180 +++++++++++++ ...mitExternalModuleContainerIndexOrder.types | 164 ++++++++++++ ...oFlakyDeclarationEmitRenamedExportOrder.js | 79 ++++++ ...yDeclarationEmitRenamedExportOrder.symbols | 182 +++++++++++++ ...akyDeclarationEmitRenamedExportOrder.types | 166 ++++++++++++ ...NamespaceMembersResolutionOrder.errors.txt | 61 +++++ ...gnosticsNamespaceMembersResolutionOrder.js | 221 ++++++++++++++++ ...icsNamespaceMembersResolutionOrder.symbols | 161 ++++++++++++ ...sticsNamespaceMembersResolutionOrder.types | 192 ++++++++++++++ ...nalModuleContainerIndexDeclarationOrder.ts | 73 ++++++ ...mespaceMembersResolutionOrderExportStar.ts | 67 +++++ ...onEmitExternalModuleContainerIndexOrder.ts | 73 ++++++ ...oFlakyDeclarationEmitRenamedExportOrder.ts | 72 +++++ ...gnosticsNamespaceMembersResolutionOrder.ts | 64 +++++ 22 files changed, 2927 insertions(+) create mode 100644 tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.js create mode 100644 tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.types create mode 100644 tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.js create mode 100644 tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.types create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.js create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.types create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.js create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.types create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.js create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.types create mode 100644 tsc/testdata/tests/cases/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.ts create mode 100644 tsc/testdata/tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.ts create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitRenamedExportOrder.ts create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.js b/tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.js new file mode 100644 index 0000000000000..935e9baeed1ad --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.js @@ -0,0 +1,81 @@ +//// [tests/cases/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.ts] //// + +//// [ambient.d.ts] +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +//// [index.d.ts] +export { v as b } from "ia"; +export { v as a } from "ib"; +export declare const f1: 1; +export declare const f2: 2; +export declare const f3: 3; +export declare const f4: 4; +export declare const f5: 5; +export declare const f6: 6; +export declare const f7: 7; +export declare const f8: 8; +export declare const f9: 9; +export declare const f10: 10; + +//// [gadget.d.ts] +export interface Gadget { id: number } + +//// [widget.d.ts] +import { Gadget } from "./gadget"; +export declare function makeWidget(): Gadget; + +//// [main.ts] +/// +import { f1 } from "./index"; +import { makeWidget } from "./widget"; +declare function expand(): { [K in keyof X]: X[K] }; +export const keep = f1; +export const w = makeWidget(); +export const obsA = expand(); +export const obsB = expand(); + + + + +//// [main.d.ts] +export declare const keep: 1; +export declare const w: import("./gadget").Gadget; +export declare const obsA: { + pb: 0; + readonly mb: 1; + v: 0; +}; +export declare const obsB: { + v: 0; +}; diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.symbols b/tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.symbols new file mode 100644 index 0000000000000..3847b78195e27 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.symbols @@ -0,0 +1,180 @@ +//// [tests/cases/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.ts] //// + +=== /main.ts === +/// +import { f1 } from "./index"; +>f1 : Symbol(f1, Decl(main.ts, 1, 8)) + +import { makeWidget } from "./widget"; +>makeWidget : Symbol(makeWidget, Decl(main.ts, 2, 8)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 2, 38)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) + +export const keep = f1; +>keep : Symbol(keep, Decl(main.ts, 4, 12)) +>f1 : Symbol(f1, Decl(main.ts, 1, 8)) + +export const w = makeWidget(); +>w : Symbol(w, Decl(main.ts, 5, 12)) +>makeWidget : Symbol(makeWidget, Decl(main.ts, 2, 8)) + +export const obsA = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 6, 12)) +>expand : Symbol(expand, Decl(main.ts, 2, 38)) + +export const obsB = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 7, 12)) +>expand : Symbol(expand, Decl(main.ts, 2, 38)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} + +=== /index.d.ts === +export { v as b } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>b : Symbol(b, Decl(index.d.ts, 0, 8)) + +export { v as a } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>a : Symbol(a, Decl(index.d.ts, 1, 8)) + +export declare const f1: 1; +>f1 : Symbol(f1, Decl(index.d.ts, 2, 20)) + +export declare const f2: 2; +>f2 : Symbol(f2, Decl(index.d.ts, 3, 20)) + +export declare const f3: 3; +>f3 : Symbol(f3, Decl(index.d.ts, 4, 20)) + +export declare const f4: 4; +>f4 : Symbol(f4, Decl(index.d.ts, 5, 20)) + +export declare const f5: 5; +>f5 : Symbol(f5, Decl(index.d.ts, 6, 20)) + +export declare const f6: 6; +>f6 : Symbol(f6, Decl(index.d.ts, 7, 20)) + +export declare const f7: 7; +>f7 : Symbol(f7, Decl(index.d.ts, 8, 20)) + +export declare const f8: 8; +>f8 : Symbol(f8, Decl(index.d.ts, 9, 20)) + +export declare const f9: 9; +>f9 : Symbol(f9, Decl(index.d.ts, 10, 20)) + +export declare const f10: 10; +>f10 : Symbol(f10, Decl(index.d.ts, 11, 20)) + +=== /gadget.d.ts === +export interface Gadget { id: number } +>Gadget : Symbol(Gadget, Decl(gadget.d.ts, 0, 0)) +>id : Symbol(Gadget.id, Decl(gadget.d.ts, 0, 25)) + +=== /widget.d.ts === +import { Gadget } from "./gadget"; +>Gadget : Symbol(Gadget, Decl(widget.d.ts, 0, 8)) + +export declare function makeWidget(): Gadget; +>makeWidget : Symbol(makeWidget, Decl(widget.d.ts, 0, 34)) +>Gadget : Symbol(Gadget, Decl(widget.d.ts, 0, 8)) + diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.types b/tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.types new file mode 100644 index 0000000000000..f7cb243d2a23e --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.types @@ -0,0 +1,164 @@ +//// [tests/cases/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.ts] //// + +=== /main.ts === +/// +import { f1 } from "./index"; +>f1 : 1 + +import { makeWidget } from "./widget"; +>makeWidget : () => import("./gadget").Gadget + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export const keep = f1; +>keep : 1 +>f1 : 1 + +export const w = makeWidget(); +>w : import("./gadget").Gadget +>makeWidget() : import("./gadget").Gadget +>makeWidget : () => import("./gadget").Gadget + +export const obsA = expand(); +>obsA : { pb: 0; readonly mb: 1; v: 0; } +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } + +export const obsB = expand(); +>obsB : { v: 0; } +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} + +=== /index.d.ts === +export { v as b } from "ia"; +>v : 0 +>b : 0 + +export { v as a } from "ib"; +>v : 0 +>a : 0 + +export declare const f1: 1; +>f1 : 1 + +export declare const f2: 2; +>f2 : 2 + +export declare const f3: 3; +>f3 : 3 + +export declare const f4: 4; +>f4 : 4 + +export declare const f5: 5; +>f5 : 5 + +export declare const f6: 6; +>f6 : 6 + +export declare const f7: 7; +>f7 : 7 + +export declare const f8: 8; +>f8 : 8 + +export declare const f9: 9; +>f9 : 9 + +export declare const f10: 10; +>f10 : 10 + +=== /gadget.d.ts === +export interface Gadget { id: number } +>id : number + +=== /widget.d.ts === +import { Gadget } from "./gadget"; +>Gadget : any + +export declare function makeWidget(): Gadget; +>makeWidget : () => Gadget + diff --git a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.errors.txt b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.errors.txt new file mode 100644 index 0000000000000..bff4827ef673c --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.errors.txt @@ -0,0 +1,64 @@ +/main.ts(8,32): error TS2339: Property 'ma' does not exist on type '{}'. + + +==== /main.ts (1 errors) ==== + import * as idx from "./index"; + const all = { ...idx }; + import * as MA from "./ma"; + import * as MB from "./mb"; + export const fromA = MA.pa; + export const fromB = MB.pb; + export const checkA: 1 = MA.pa.mb; + export const checkB: 1 = MB.pb.ma; + ~~ +!!! error TS2339: Property 'ma' does not exist on type '{}'. + +==== /ma.js (0 errors) ==== + export { v as pa } from "./xa"; + export const ma = 1; + +==== /mb.js (0 errors) ==== + export { v as pb } from "./xb"; + export const mb = 1; + +==== /xa.js (0 errors) ==== + /** @type {typeof import("./mb")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /xb.js (0 errors) ==== + /** @type {typeof import("./ma")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /ia.js (0 errors) ==== + /** @type {typeof import("./ma")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /ib.js (0 errors) ==== + /** @type {typeof import("./mb")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /star.js (0 errors) ==== + export { v as a } from "./ia"; + +==== /index.js (0 errors) ==== + export { v as b } from "./ib"; + export * from "./star"; + export const f1 = 1; + export const f2 = 2; + export const f3 = 3; + export const f4 = 4; + export const f5 = 5; + export const f6 = 6; + export const f7 = 7; + export const f8 = 8; + export const f9 = 9; + export const f10 = 10; + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.js b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.js new file mode 100644 index 0000000000000..e7f345491f402 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.js @@ -0,0 +1,245 @@ +//// [tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts] //// + +//// [ma.js] +export { v as pa } from "./xa"; +export const ma = 1; + +//// [mb.js] +export { v as pb } from "./xb"; +export const mb = 1; + +//// [xa.js] +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [xb.js] +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [ia.js] +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [ib.js] +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [star.js] +export { v as a } from "./ia"; + +//// [index.js] +export { v as b } from "./ib"; +export * from "./star"; +export const f1 = 1; +export const f2 = 2; +export const f3 = 3; +export const f4 = 4; +export const f5 = 5; +export const f6 = 6; +export const f7 = 7; +export const f8 = 8; +export const f9 = 9; +export const f10 = 10; + +//// [main.ts] +import * as idx from "./index"; +const all = { ...idx }; +import * as MA from "./ma"; +import * as MB from "./mb"; +export const fromA = MA.pa; +export const fromB = MB.pb; +export const checkA: 1 = MA.pa.mb; +export const checkB: 1 = MB.pb.ma; + + +//// [xa.js] +"use strict"; +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [ma.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ma = exports.pa = void 0; +var xa_1 = require("./xa"); +Object.defineProperty(exports, "pa", { enumerable: true, get: function () { return xa_1.v; } }); +exports.ma = 1; +//// [xb.js] +"use strict"; +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [mb.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.mb = exports.pb = void 0; +var xb_1 = require("./xb"); +Object.defineProperty(exports, "pb", { enumerable: true, get: function () { return xb_1.v; } }); +exports.mb = 1; +//// [ib.js] +"use strict"; +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [ia.js] +"use strict"; +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [star.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.a = void 0; +var ia_1 = require("./ia"); +Object.defineProperty(exports, "a", { enumerable: true, get: function () { return ia_1.v; } }); +//// [index.js] +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.f10 = exports.f9 = exports.f8 = exports.f7 = exports.f6 = exports.f5 = exports.f4 = exports.f3 = exports.f2 = exports.f1 = exports.b = void 0; +var ib_1 = require("./ib"); +Object.defineProperty(exports, "b", { enumerable: true, get: function () { return ib_1.v; } }); +__exportStar(require("./star"), exports); +exports.f1 = 1; +exports.f2 = 2; +exports.f3 = 3; +exports.f4 = 4; +exports.f5 = 5; +exports.f6 = 6; +exports.f7 = 7; +exports.f8 = 8; +exports.f9 = 9; +exports.f10 = 10; +//// [main.js] +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.checkB = exports.checkA = exports.fromB = exports.fromA = void 0; +const idx = __importStar(require("./index")); +const all = { ...idx }; +const MA = __importStar(require("./ma")); +const MB = __importStar(require("./mb")); +exports.fromA = MA.pa; +exports.fromB = MB.pb; +exports.checkA = MA.pa.mb; +exports.checkB = MB.pb.ma; + + +//// [xa.d.ts] +export = o; +declare const o: { + v: { + pb: {}; + mb: 1; + }; +}; +//// [ma.d.ts] +export { v as pa } from "./xa"; +export declare const ma = 1; +//// [xb.d.ts] +export = o; +declare const o: { + v: {}; +}; +//// [mb.d.ts] +export { v as pb } from "./xb"; +export declare const mb = 1; +//// [ib.d.ts] +export = o; +declare const o: { + v: { + pb: {}; + mb: 1; + }; +}; +//// [ia.d.ts] +export = o; +declare const o: { + v: { + pa: { + pb: {}; + mb: 1; + }; + ma: 1; + }; +}; +//// [star.d.ts] +export { v as a } from "./ia"; +//// [index.d.ts] +export { v as b } from "./ib"; +export * from "./star"; +export declare const f1 = 1; +export declare const f2 = 2; +export declare const f3 = 3; +export declare const f4 = 4; +export declare const f5 = 5; +export declare const f6 = 6; +export declare const f7 = 7; +export declare const f8 = 8; +export declare const f9 = 9; +export declare const f10 = 10; +//// [main.d.ts] +export declare const fromA: { + pb: {}; + mb: 1; +}; +export declare const fromB: {}; +export declare const checkA: 1; +export declare const checkB: 1; diff --git a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.symbols b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.symbols new file mode 100644 index 0000000000000..6997e4d5a273d --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.symbols @@ -0,0 +1,163 @@ +//// [tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts] //// + +=== /main.ts === +import * as idx from "./index"; +>idx : Symbol(idx, Decl(main.ts, 0, 6)) + +const all = { ...idx }; +>all : Symbol(all, Decl(main.ts, 1, 5)) +>idx : Symbol(idx, Decl(main.ts, 0, 6)) + +import * as MA from "./ma"; +>MA : Symbol(MA, Decl(main.ts, 2, 6)) + +import * as MB from "./mb"; +>MB : Symbol(MB, Decl(main.ts, 3, 6)) + +export const fromA = MA.pa; +>fromA : Symbol(fromA, Decl(main.ts, 4, 12)) +>MA.pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) +>MA : Symbol(MA, Decl(main.ts, 2, 6)) +>pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) + +export const fromB = MB.pb; +>fromB : Symbol(fromB, Decl(main.ts, 5, 12)) +>MB.pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) +>MB : Symbol(MB, Decl(main.ts, 3, 6)) +>pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) + +export const checkA: 1 = MA.pa.mb; +>checkA : Symbol(checkA, Decl(main.ts, 6, 12)) +>MA.pa.mb : Symbol(mb, Decl(mb.js, 1, 12)) +>MA.pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) +>MA : Symbol(MA, Decl(main.ts, 2, 6)) +>pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) +>mb : Symbol(mb, Decl(mb.js, 1, 12)) + +export const checkB: 1 = MB.pb.ma; +>checkB : Symbol(checkB, Decl(main.ts, 7, 12)) +>MB.pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) +>MB : Symbol(MB, Decl(main.ts, 3, 6)) +>pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) + +=== /ma.js === +export { v as pa } from "./xa"; +>v : Symbol(v, Decl(xa.js, 2, 11)) +>pa : Symbol(pa, Decl(ma.js, 0, 8)) + +export const ma = 1; +>ma : Symbol(ma, Decl(ma.js, 1, 12)) + +=== /mb.js === +export { v as pb } from "./xb"; +>v : Symbol(v, Decl(xb.js, 2, 11)) +>pb : Symbol(pb, Decl(mb.js, 0, 8)) + +export const mb = 1; +>mb : Symbol(mb, Decl(mb.js, 1, 12)) + +=== /xa.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(xa.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(xa.js, 2, 5)) +>v : Symbol(v, Decl(xa.js, 2, 11)) +>M : Symbol(M, Decl(xa.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(xa.js, 0, 0)) +>module : Symbol(module, Decl(xa.js, 0, 0)) +>exports : Symbol(exports, Decl(xa.js, 0, 0)) +>o : Symbol(o, Decl(xa.js, 2, 5)) + +=== /xb.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(xb.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(xb.js, 2, 5)) +>v : Symbol(v, Decl(xb.js, 2, 11)) +>M : Symbol(M, Decl(xb.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(xb.js, 0, 0)) +>module : Symbol(module, Decl(xb.js, 0, 0)) +>exports : Symbol(exports, Decl(xb.js, 0, 0)) +>o : Symbol(o, Decl(xb.js, 2, 5)) + +=== /ia.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(ia.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(ia.js, 2, 5)) +>v : Symbol(v, Decl(ia.js, 2, 11)) +>M : Symbol(M, Decl(ia.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(ia.js, 0, 0)) +>module : Symbol(module, Decl(ia.js, 0, 0)) +>exports : Symbol(exports, Decl(ia.js, 0, 0)) +>o : Symbol(o, Decl(ia.js, 2, 5)) + +=== /ib.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(ib.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(ib.js, 2, 5)) +>v : Symbol(v, Decl(ib.js, 2, 11)) +>M : Symbol(M, Decl(ib.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(ib.js, 0, 0)) +>module : Symbol(module, Decl(ib.js, 0, 0)) +>exports : Symbol(exports, Decl(ib.js, 0, 0)) +>o : Symbol(o, Decl(ib.js, 2, 5)) + +=== /star.js === +export { v as a } from "./ia"; +>v : Symbol(v, Decl(ia.js, 2, 11)) +>a : Symbol(a, Decl(star.js, 0, 8)) + +=== /index.js === +export { v as b } from "./ib"; +>v : Symbol(v, Decl(ib.js, 2, 11)) +>b : Symbol(b, Decl(index.js, 0, 8)) + +export * from "./star"; +export const f1 = 1; +>f1 : Symbol(f1, Decl(index.js, 2, 12)) + +export const f2 = 2; +>f2 : Symbol(f2, Decl(index.js, 3, 12)) + +export const f3 = 3; +>f3 : Symbol(f3, Decl(index.js, 4, 12)) + +export const f4 = 4; +>f4 : Symbol(f4, Decl(index.js, 5, 12)) + +export const f5 = 5; +>f5 : Symbol(f5, Decl(index.js, 6, 12)) + +export const f6 = 6; +>f6 : Symbol(f6, Decl(index.js, 7, 12)) + +export const f7 = 7; +>f7 : Symbol(f7, Decl(index.js, 8, 12)) + +export const f8 = 8; +>f8 : Symbol(f8, Decl(index.js, 9, 12)) + +export const f9 = 9; +>f9 : Symbol(f9, Decl(index.js, 10, 12)) + +export const f10 = 10; +>f10 : Symbol(f10, Decl(index.js, 11, 12)) + diff --git a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.types b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.types new file mode 100644 index 0000000000000..49f1de0b3ac44 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.types @@ -0,0 +1,194 @@ +//// [tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts] //// + +=== /main.ts === +import * as idx from "./index"; +>idx : typeof idx + +const all = { ...idx }; +>all : { a: { pa: { pb: {}; mb: 1; }; ma: 1; }; b: { pb: {}; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } +>{ ...idx } : { a: { pa: { pb: {}; mb: 1; }; ma: 1; }; b: { pb: {}; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } +>idx : typeof idx + +import * as MA from "./ma"; +>MA : typeof MA + +import * as MB from "./mb"; +>MB : typeof MB + +export const fromA = MA.pa; +>fromA : { pb: {}; mb: 1; } +>MA.pa : { pb: {}; mb: 1; } +>MA : typeof MA +>pa : { pb: {}; mb: 1; } + +export const fromB = MB.pb; +>fromB : {} +>MB.pb : {} +>MB : typeof MB +>pb : {} + +export const checkA: 1 = MA.pa.mb; +>checkA : 1 +>MA.pa.mb : 1 +>MA.pa : { pb: {}; mb: 1; } +>MA : typeof MA +>pa : { pb: {}; mb: 1; } +>mb : 1 + +export const checkB: 1 = MB.pb.ma; +>checkB : 1 +>MB.pb.ma : any +>MB.pb : {} +>MB : typeof MB +>pb : {} +>ma : any + +=== /ma.js === +export { v as pa } from "./xa"; +>v : { pb: {}; mb: 1; } +>pa : { pb: {}; mb: 1; } + +export const ma = 1; +>ma : 1 +>1 : 1 + +=== /mb.js === +export { v as pb } from "./xb"; +>v : {} +>pb : {} + +export const mb = 1; +>mb : 1 +>1 : 1 + +=== /xa.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./mb") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: { pb: {}; mb: 1; }; } +>{ v: { ...M } } : { v: { pb: {}; mb: 1; }; } +>v : { pb: {}; mb: 1; } +>{ ...M } : { pb: {}; mb: 1; } +>M : typeof import("./mb") + +module.exports = o; +>module.exports = o : { v: { pb: {}; mb: 1; }; } +>module.exports : { v: { pb: {}; mb: 1; }; } +>module : { exports: { v: { pb: {}; mb: 1; }; }; } +>exports : { v: { pb: {}; mb: 1; }; } +>o : { v: { pb: {}; mb: 1; }; } + +=== /xb.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./ma") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: {}; } +>{ v: { ...M } } : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>{ ...M } : { pa: { pb: {}; mb: 1; }; ma: 1; } +>M : typeof import("./ma") + +module.exports = o; +>module.exports = o : { v: {}; } +>module.exports : { v: {}; } +>module : { exports: { v: {}; }; } +>exports : { v: {}; } +>o : { v: {}; } + +=== /ia.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./ma") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>{ v: { ...M } } : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>{ ...M } : { pa: { pb: {}; mb: 1; }; ma: 1; } +>M : typeof import("./ma") + +module.exports = o; +>module.exports = o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>module.exports : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>module : { exports: { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; }; } +>exports : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } + +=== /ib.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./mb") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: { pb: {}; mb: 1; }; } +>{ v: { ...M } } : { v: { pb: {}; mb: 1; }; } +>v : { pb: {}; mb: 1; } +>{ ...M } : { pb: {}; mb: 1; } +>M : typeof import("./mb") + +module.exports = o; +>module.exports = o : { v: { pb: {}; mb: 1; }; } +>module.exports : { v: { pb: {}; mb: 1; }; } +>module : { exports: { v: { pb: {}; mb: 1; }; }; } +>exports : { v: { pb: {}; mb: 1; }; } +>o : { v: { pb: {}; mb: 1; }; } + +=== /star.js === +export { v as a } from "./ia"; +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>a : { pa: { pb: {}; mb: 1; }; ma: 1; } + +=== /index.js === +export { v as b } from "./ib"; +>v : { pb: {}; mb: 1; } +>b : { pb: {}; mb: 1; } + +export * from "./star"; +export const f1 = 1; +>f1 : 1 +>1 : 1 + +export const f2 = 2; +>f2 : 2 +>2 : 2 + +export const f3 = 3; +>f3 : 3 +>3 : 3 + +export const f4 = 4; +>f4 : 4 +>4 : 4 + +export const f5 = 5; +>f5 : 5 +>5 : 5 + +export const f6 = 6; +>f6 : 6 +>6 : 6 + +export const f7 = 7; +>f7 : 7 +>7 : 7 + +export const f8 = 8; +>f8 : 8 +>8 : 8 + +export const f9 = 9; +>f9 : 9 +>9 : 9 + +export const f10 = 10; +>f10 : 10 +>10 : 10 + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.js b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.js new file mode 100644 index 0000000000000..b04d7f8d88c86 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.js @@ -0,0 +1,81 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.ts] //// + +//// [ambient.d.ts] +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +//// [index.d.ts] +export { v as a } from "ia"; +export { v as b } from "ib"; +export declare const f1: 1; +export declare const f2: 2; +export declare const f3: 3; +export declare const f4: 4; +export declare const f5: 5; +export declare const f6: 6; +export declare const f7: 7; +export declare const f8: 8; +export declare const f9: 9; +export declare const f10: 10; + +//// [gadget.d.ts] +export interface Gadget { id: number } + +//// [widget.d.ts] +import { Gadget } from "./gadget"; +export declare function makeWidget(): Gadget; + +//// [main.ts] +/// +import { f1 } from "./index"; +import { makeWidget } from "./widget"; +declare function expand(): { [K in keyof X]: X[K] }; +export const keep = f1; +export const w = makeWidget(); +export const obsA = expand(); +export const obsB = expand(); + + + + +//// [main.d.ts] +export declare const keep: 1; +export declare const w: import("./gadget").Gadget; +export declare const obsA: { + pb: 0; + readonly mb: 1; + v: 0; +}; +export declare const obsB: { + v: 0; +}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.symbols new file mode 100644 index 0000000000000..7750beccf74ec --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.symbols @@ -0,0 +1,180 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.ts] //// + +=== /main.ts === +/// +import { f1 } from "./index"; +>f1 : Symbol(f1, Decl(main.ts, 1, 8)) + +import { makeWidget } from "./widget"; +>makeWidget : Symbol(makeWidget, Decl(main.ts, 2, 8)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 2, 38)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) + +export const keep = f1; +>keep : Symbol(keep, Decl(main.ts, 4, 12)) +>f1 : Symbol(f1, Decl(main.ts, 1, 8)) + +export const w = makeWidget(); +>w : Symbol(w, Decl(main.ts, 5, 12)) +>makeWidget : Symbol(makeWidget, Decl(main.ts, 2, 8)) + +export const obsA = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 6, 12)) +>expand : Symbol(expand, Decl(main.ts, 2, 38)) + +export const obsB = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 7, 12)) +>expand : Symbol(expand, Decl(main.ts, 2, 38)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} + +=== /index.d.ts === +export { v as a } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>a : Symbol(a, Decl(index.d.ts, 0, 8)) + +export { v as b } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>b : Symbol(b, Decl(index.d.ts, 1, 8)) + +export declare const f1: 1; +>f1 : Symbol(f1, Decl(index.d.ts, 2, 20)) + +export declare const f2: 2; +>f2 : Symbol(f2, Decl(index.d.ts, 3, 20)) + +export declare const f3: 3; +>f3 : Symbol(f3, Decl(index.d.ts, 4, 20)) + +export declare const f4: 4; +>f4 : Symbol(f4, Decl(index.d.ts, 5, 20)) + +export declare const f5: 5; +>f5 : Symbol(f5, Decl(index.d.ts, 6, 20)) + +export declare const f6: 6; +>f6 : Symbol(f6, Decl(index.d.ts, 7, 20)) + +export declare const f7: 7; +>f7 : Symbol(f7, Decl(index.d.ts, 8, 20)) + +export declare const f8: 8; +>f8 : Symbol(f8, Decl(index.d.ts, 9, 20)) + +export declare const f9: 9; +>f9 : Symbol(f9, Decl(index.d.ts, 10, 20)) + +export declare const f10: 10; +>f10 : Symbol(f10, Decl(index.d.ts, 11, 20)) + +=== /gadget.d.ts === +export interface Gadget { id: number } +>Gadget : Symbol(Gadget, Decl(gadget.d.ts, 0, 0)) +>id : Symbol(Gadget.id, Decl(gadget.d.ts, 0, 25)) + +=== /widget.d.ts === +import { Gadget } from "./gadget"; +>Gadget : Symbol(Gadget, Decl(widget.d.ts, 0, 8)) + +export declare function makeWidget(): Gadget; +>makeWidget : Symbol(makeWidget, Decl(widget.d.ts, 0, 34)) +>Gadget : Symbol(Gadget, Decl(widget.d.ts, 0, 8)) + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.types new file mode 100644 index 0000000000000..351c0f5869478 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.types @@ -0,0 +1,164 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.ts] //// + +=== /main.ts === +/// +import { f1 } from "./index"; +>f1 : 1 + +import { makeWidget } from "./widget"; +>makeWidget : () => import("./gadget").Gadget + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export const keep = f1; +>keep : 1 +>f1 : 1 + +export const w = makeWidget(); +>w : import("./gadget").Gadget +>makeWidget() : import("./gadget").Gadget +>makeWidget : () => import("./gadget").Gadget + +export const obsA = expand(); +>obsA : { pb: 0; readonly mb: 1; v: 0; } +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } + +export const obsB = expand(); +>obsB : { v: 0; } +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} + +=== /index.d.ts === +export { v as a } from "ia"; +>v : 0 +>a : 0 + +export { v as b } from "ib"; +>v : 0 +>b : 0 + +export declare const f1: 1; +>f1 : 1 + +export declare const f2: 2; +>f2 : 2 + +export declare const f3: 3; +>f3 : 3 + +export declare const f4: 4; +>f4 : 4 + +export declare const f5: 5; +>f5 : 5 + +export declare const f6: 6; +>f6 : 6 + +export declare const f7: 7; +>f7 : 7 + +export declare const f8: 8; +>f8 : 8 + +export declare const f9: 9; +>f9 : 9 + +export declare const f10: 10; +>f10 : 10 + +=== /gadget.d.ts === +export interface Gadget { id: number } +>id : number + +=== /widget.d.ts === +import { Gadget } from "./gadget"; +>Gadget : any + +export declare function makeWidget(): Gadget; +>makeWidget : () => Gadget + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.js b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.js new file mode 100644 index 0000000000000..ea5bdabd550b2 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.js @@ -0,0 +1,79 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitRenamedExportOrder.ts] //// + +//// [ambient.d.ts] +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +//// [globals.d.ts] +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); + +//// [lib.d.ts] +interface X { x: 1 } +export { X as Y }; +export { v as a } from "ia"; +export { v as b } from "ib"; +export declare const f1: 1; +export declare const f2: 2; +export declare const f3: 3; +export declare const f4: 4; +export declare const f5: 5; +export declare const f6: 6; +export declare const f7: 7; +export declare const f8: 8; +export declare const f9: 9; +export declare const f10: 10; +export declare function getX(): X; + +//// [main.ts] +/// +/// +import { getX } from "./lib"; +declare function expand(): { [K in keyof X]: X[K] }; +export const x = getX(); +export const obsA = expand(); +export const obsB = expand(); + + + + +//// [main.d.ts] +export declare const x: import("./lib").Y; +export declare const obsA: { + pb: 0; + readonly mb: 1; + v: 0; +}; +export declare const obsB: { + v: 0; +}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.symbols new file mode 100644 index 0000000000000..0c99a97d3064b --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.symbols @@ -0,0 +1,182 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitRenamedExportOrder.ts] //// + +=== /main.ts === +/// +/// +import { getX } from "./lib"; +>getX : Symbol(getX, Decl(main.ts, 2, 8)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 2, 29)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) + +export const x = getX(); +>x : Symbol(x, Decl(main.ts, 4, 12)) +>getX : Symbol(getX, Decl(main.ts, 2, 8)) + +export const obsA = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 5, 12)) +>expand : Symbol(expand, Decl(main.ts, 2, 29)) +>oxa : Symbol(oxa, Decl(globals.d.ts, 0, 13)) + +export const obsB = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 6, 12)) +>expand : Symbol(expand, Decl(main.ts, 2, 29)) +>oxb : Symbol(oxb, Decl(globals.d.ts, 1, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} + +=== /globals.d.ts === +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(globals.d.ts, 0, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(globals.d.ts, 1, 13)) + +=== /lib.d.ts === +interface X { x: 1 } +>X : Symbol(X, Decl(lib.d.ts, --, --)) +>x : Symbol(X.x, Decl(lib.d.ts, --, --)) + +export { X as Y }; +>X : Symbol(X, Decl(lib.d.ts, --, --)) +>Y : Symbol(Y, Decl(lib.d.ts, --, --)) + +export { v as a } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>a : Symbol(a, Decl(lib.d.ts, --, --)) + +export { v as b } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>b : Symbol(b, Decl(lib.d.ts, --, --)) + +export declare const f1: 1; +>f1 : Symbol(f1, Decl(lib.d.ts, --, --)) + +export declare const f2: 2; +>f2 : Symbol(f2, Decl(lib.d.ts, --, --)) + +export declare const f3: 3; +>f3 : Symbol(f3, Decl(lib.d.ts, --, --)) + +export declare const f4: 4; +>f4 : Symbol(f4, Decl(lib.d.ts, --, --)) + +export declare const f5: 5; +>f5 : Symbol(f5, Decl(lib.d.ts, --, --)) + +export declare const f6: 6; +>f6 : Symbol(f6, Decl(lib.d.ts, --, --)) + +export declare const f7: 7; +>f7 : Symbol(f7, Decl(lib.d.ts, --, --)) + +export declare const f8: 8; +>f8 : Symbol(f8, Decl(lib.d.ts, --, --)) + +export declare const f9: 9; +>f9 : Symbol(f9, Decl(lib.d.ts, --, --)) + +export declare const f10: 10; +>f10 : Symbol(f10, Decl(lib.d.ts, --, --)) + +export declare function getX(): X; +>getX : Symbol(getX, Decl(lib.d.ts, --, --)) +>X : Symbol(X, Decl(lib.d.ts, --, --)) + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.types new file mode 100644 index 0000000000000..ad400806b641d --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitRenamedExportOrder.types @@ -0,0 +1,166 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitRenamedExportOrder.ts] //// + +=== /main.ts === +/// +/// +import { getX } from "./lib"; +>getX : () => import("./lib").Y + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export const x = getX(); +>x : import("./lib").Y +>getX() : import("./lib").Y +>getX : () => import("./lib").Y + +export const obsA = expand(); +>obsA : { pb: 0; readonly mb: 1; v: 0; } +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +export const obsB = expand(); +>obsB : { v: 0; } +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} + +=== /globals.d.ts === +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +=== /lib.d.ts === +interface X { x: 1 } +>x : 1 + +export { X as Y }; +>X : any +>Y : any + +export { v as a } from "ia"; +>v : 0 +>a : 0 + +export { v as b } from "ib"; +>v : 0 +>b : 0 + +export declare const f1: 1; +>f1 : 1 + +export declare const f2: 2; +>f2 : 2 + +export declare const f3: 3; +>f3 : 3 + +export declare const f4: 4; +>f4 : 4 + +export declare const f5: 5; +>f5 : 5 + +export declare const f6: 6; +>f6 : 6 + +export declare const f7: 7; +>f7 : 7 + +export declare const f8: 8; +>f8 : 8 + +export declare const f9: 9; +>f9 : 9 + +export declare const f10: 10; +>f10 : 10 + +export declare function getX(): X; +>getX : () => X + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.errors.txt b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.errors.txt new file mode 100644 index 0000000000000..fb286e6d925c7 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.errors.txt @@ -0,0 +1,61 @@ +/main.ts(8,32): error TS2339: Property 'ma' does not exist on type '{}'. + + +==== /main.ts (1 errors) ==== + import * as idx from "./index"; + const all = { ...idx }; + import * as MA from "./ma"; + import * as MB from "./mb"; + export const fromA = MA.pa; + export const fromB = MB.pb; + export const checkA: 1 = MA.pa.mb; + export const checkB: 1 = MB.pb.ma; + ~~ +!!! error TS2339: Property 'ma' does not exist on type '{}'. + +==== /ma.js (0 errors) ==== + export { v as pa } from "./xa"; + export const ma = 1; + +==== /mb.js (0 errors) ==== + export { v as pb } from "./xb"; + export const mb = 1; + +==== /xa.js (0 errors) ==== + /** @type {typeof import("./mb")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /xb.js (0 errors) ==== + /** @type {typeof import("./ma")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /ia.js (0 errors) ==== + /** @type {typeof import("./ma")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /ib.js (0 errors) ==== + /** @type {typeof import("./mb")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /index.js (0 errors) ==== + export { v as a } from "./ia"; + export { v as b } from "./ib"; + export const f1 = 1; + export const f2 = 2; + export const f3 = 3; + export const f4 = 4; + export const f5 = 5; + export const f6 = 6; + export const f7 = 7; + export const f8 = 8; + export const f9 = 9; + export const f10 = 10; + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.js b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.js new file mode 100644 index 0000000000000..85b0024d3067d --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.js @@ -0,0 +1,221 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts] //// + +//// [ma.js] +export { v as pa } from "./xa"; +export const ma = 1; + +//// [mb.js] +export { v as pb } from "./xb"; +export const mb = 1; + +//// [xa.js] +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [xb.js] +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [ia.js] +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [ib.js] +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [index.js] +export { v as a } from "./ia"; +export { v as b } from "./ib"; +export const f1 = 1; +export const f2 = 2; +export const f3 = 3; +export const f4 = 4; +export const f5 = 5; +export const f6 = 6; +export const f7 = 7; +export const f8 = 8; +export const f9 = 9; +export const f10 = 10; + +//// [main.ts] +import * as idx from "./index"; +const all = { ...idx }; +import * as MA from "./ma"; +import * as MB from "./mb"; +export const fromA = MA.pa; +export const fromB = MB.pb; +export const checkA: 1 = MA.pa.mb; +export const checkB: 1 = MB.pb.ma; + + +//// [xb.js] +"use strict"; +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [mb.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.mb = exports.pb = void 0; +var xb_1 = require("./xb"); +Object.defineProperty(exports, "pb", { enumerable: true, get: function () { return xb_1.v; } }); +exports.mb = 1; +//// [xa.js] +"use strict"; +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [ma.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ma = exports.pa = void 0; +var xa_1 = require("./xa"); +Object.defineProperty(exports, "pa", { enumerable: true, get: function () { return xa_1.v; } }); +exports.ma = 1; +//// [ia.js] +"use strict"; +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [ib.js] +"use strict"; +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [index.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.f10 = exports.f9 = exports.f8 = exports.f7 = exports.f6 = exports.f5 = exports.f4 = exports.f3 = exports.f2 = exports.f1 = exports.b = exports.a = void 0; +var ia_1 = require("./ia"); +Object.defineProperty(exports, "a", { enumerable: true, get: function () { return ia_1.v; } }); +var ib_1 = require("./ib"); +Object.defineProperty(exports, "b", { enumerable: true, get: function () { return ib_1.v; } }); +exports.f1 = 1; +exports.f2 = 2; +exports.f3 = 3; +exports.f4 = 4; +exports.f5 = 5; +exports.f6 = 6; +exports.f7 = 7; +exports.f8 = 8; +exports.f9 = 9; +exports.f10 = 10; +//// [main.js] +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.checkB = exports.checkA = exports.fromB = exports.fromA = void 0; +const idx = __importStar(require("./index")); +const all = { ...idx }; +const MA = __importStar(require("./ma")); +const MB = __importStar(require("./mb")); +exports.fromA = MA.pa; +exports.fromB = MB.pb; +exports.checkA = MA.pa.mb; +exports.checkB = MB.pb.ma; + + +//// [xb.d.ts] +export = o; +declare const o: { + v: {}; +}; +//// [mb.d.ts] +export { v as pb } from "./xb"; +export declare const mb = 1; +//// [xa.d.ts] +export = o; +declare const o: { + v: { + pb: {}; + mb: 1; + }; +}; +//// [ma.d.ts] +export { v as pa } from "./xa"; +export declare const ma = 1; +//// [ia.d.ts] +export = o; +declare const o: { + v: { + pa: { + pb: {}; + mb: 1; + }; + ma: 1; + }; +}; +//// [ib.d.ts] +export = o; +declare const o: { + v: { + pb: {}; + mb: 1; + }; +}; +//// [index.d.ts] +export { v as a } from "./ia"; +export { v as b } from "./ib"; +export declare const f1 = 1; +export declare const f2 = 2; +export declare const f3 = 3; +export declare const f4 = 4; +export declare const f5 = 5; +export declare const f6 = 6; +export declare const f7 = 7; +export declare const f8 = 8; +export declare const f9 = 9; +export declare const f10 = 10; +//// [main.d.ts] +export declare const fromA: { + pb: {}; + mb: 1; +}; +export declare const fromB: {}; +export declare const checkA: 1; +export declare const checkB: 1; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.symbols new file mode 100644 index 0000000000000..aaa25b0469d2f --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.symbols @@ -0,0 +1,161 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts] //// + +=== /main.ts === +import * as idx from "./index"; +>idx : Symbol(idx, Decl(main.ts, 0, 6)) + +const all = { ...idx }; +>all : Symbol(all, Decl(main.ts, 1, 5)) +>idx : Symbol(idx, Decl(main.ts, 0, 6)) + +import * as MA from "./ma"; +>MA : Symbol(MA, Decl(main.ts, 2, 6)) + +import * as MB from "./mb"; +>MB : Symbol(MB, Decl(main.ts, 3, 6)) + +export const fromA = MA.pa; +>fromA : Symbol(fromA, Decl(main.ts, 4, 12)) +>MA.pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) +>MA : Symbol(MA, Decl(main.ts, 2, 6)) +>pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) + +export const fromB = MB.pb; +>fromB : Symbol(fromB, Decl(main.ts, 5, 12)) +>MB.pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) +>MB : Symbol(MB, Decl(main.ts, 3, 6)) +>pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) + +export const checkA: 1 = MA.pa.mb; +>checkA : Symbol(checkA, Decl(main.ts, 6, 12)) +>MA.pa.mb : Symbol(mb, Decl(mb.js, 1, 12)) +>MA.pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) +>MA : Symbol(MA, Decl(main.ts, 2, 6)) +>pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) +>mb : Symbol(mb, Decl(mb.js, 1, 12)) + +export const checkB: 1 = MB.pb.ma; +>checkB : Symbol(checkB, Decl(main.ts, 7, 12)) +>MB.pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) +>MB : Symbol(MB, Decl(main.ts, 3, 6)) +>pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) + +=== /ma.js === +export { v as pa } from "./xa"; +>v : Symbol(v, Decl(xa.js, 2, 11)) +>pa : Symbol(pa, Decl(ma.js, 0, 8)) + +export const ma = 1; +>ma : Symbol(ma, Decl(ma.js, 1, 12)) + +=== /mb.js === +export { v as pb } from "./xb"; +>v : Symbol(v, Decl(xb.js, 2, 11)) +>pb : Symbol(pb, Decl(mb.js, 0, 8)) + +export const mb = 1; +>mb : Symbol(mb, Decl(mb.js, 1, 12)) + +=== /xa.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(xa.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(xa.js, 2, 5)) +>v : Symbol(v, Decl(xa.js, 2, 11)) +>M : Symbol(M, Decl(xa.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(xa.js, 0, 0)) +>module : Symbol(module, Decl(xa.js, 0, 0)) +>exports : Symbol(exports, Decl(xa.js, 0, 0)) +>o : Symbol(o, Decl(xa.js, 2, 5)) + +=== /xb.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(xb.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(xb.js, 2, 5)) +>v : Symbol(v, Decl(xb.js, 2, 11)) +>M : Symbol(M, Decl(xb.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(xb.js, 0, 0)) +>module : Symbol(module, Decl(xb.js, 0, 0)) +>exports : Symbol(exports, Decl(xb.js, 0, 0)) +>o : Symbol(o, Decl(xb.js, 2, 5)) + +=== /ia.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(ia.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(ia.js, 2, 5)) +>v : Symbol(v, Decl(ia.js, 2, 11)) +>M : Symbol(M, Decl(ia.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(ia.js, 0, 0)) +>module : Symbol(module, Decl(ia.js, 0, 0)) +>exports : Symbol(exports, Decl(ia.js, 0, 0)) +>o : Symbol(o, Decl(ia.js, 2, 5)) + +=== /ib.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(ib.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(ib.js, 2, 5)) +>v : Symbol(v, Decl(ib.js, 2, 11)) +>M : Symbol(M, Decl(ib.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(ib.js, 0, 0)) +>module : Symbol(module, Decl(ib.js, 0, 0)) +>exports : Symbol(exports, Decl(ib.js, 0, 0)) +>o : Symbol(o, Decl(ib.js, 2, 5)) + +=== /index.js === +export { v as a } from "./ia"; +>v : Symbol(v, Decl(ia.js, 2, 11)) +>a : Symbol(a, Decl(index.js, 0, 8)) + +export { v as b } from "./ib"; +>v : Symbol(v, Decl(ib.js, 2, 11)) +>b : Symbol(b, Decl(index.js, 1, 8)) + +export const f1 = 1; +>f1 : Symbol(f1, Decl(index.js, 2, 12)) + +export const f2 = 2; +>f2 : Symbol(f2, Decl(index.js, 3, 12)) + +export const f3 = 3; +>f3 : Symbol(f3, Decl(index.js, 4, 12)) + +export const f4 = 4; +>f4 : Symbol(f4, Decl(index.js, 5, 12)) + +export const f5 = 5; +>f5 : Symbol(f5, Decl(index.js, 6, 12)) + +export const f6 = 6; +>f6 : Symbol(f6, Decl(index.js, 7, 12)) + +export const f7 = 7; +>f7 : Symbol(f7, Decl(index.js, 8, 12)) + +export const f8 = 8; +>f8 : Symbol(f8, Decl(index.js, 9, 12)) + +export const f9 = 9; +>f9 : Symbol(f9, Decl(index.js, 10, 12)) + +export const f10 = 10; +>f10 : Symbol(f10, Decl(index.js, 11, 12)) + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.types new file mode 100644 index 0000000000000..7813095f076be --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.types @@ -0,0 +1,192 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts] //// + +=== /main.ts === +import * as idx from "./index"; +>idx : typeof idx + +const all = { ...idx }; +>all : { a: { pa: { pb: {}; mb: 1; }; ma: 1; }; b: { pb: {}; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } +>{ ...idx } : { a: { pa: { pb: {}; mb: 1; }; ma: 1; }; b: { pb: {}; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } +>idx : typeof idx + +import * as MA from "./ma"; +>MA : typeof MA + +import * as MB from "./mb"; +>MB : typeof MB + +export const fromA = MA.pa; +>fromA : { pb: {}; mb: 1; } +>MA.pa : { pb: {}; mb: 1; } +>MA : typeof MA +>pa : { pb: {}; mb: 1; } + +export const fromB = MB.pb; +>fromB : {} +>MB.pb : {} +>MB : typeof MB +>pb : {} + +export const checkA: 1 = MA.pa.mb; +>checkA : 1 +>MA.pa.mb : 1 +>MA.pa : { pb: {}; mb: 1; } +>MA : typeof MA +>pa : { pb: {}; mb: 1; } +>mb : 1 + +export const checkB: 1 = MB.pb.ma; +>checkB : 1 +>MB.pb.ma : any +>MB.pb : {} +>MB : typeof MB +>pb : {} +>ma : any + +=== /ma.js === +export { v as pa } from "./xa"; +>v : { pb: {}; mb: 1; } +>pa : { pb: {}; mb: 1; } + +export const ma = 1; +>ma : 1 +>1 : 1 + +=== /mb.js === +export { v as pb } from "./xb"; +>v : {} +>pb : {} + +export const mb = 1; +>mb : 1 +>1 : 1 + +=== /xa.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./mb") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: { pb: {}; mb: 1; }; } +>{ v: { ...M } } : { v: { pb: {}; mb: 1; }; } +>v : { pb: {}; mb: 1; } +>{ ...M } : { pb: {}; mb: 1; } +>M : typeof import("./mb") + +module.exports = o; +>module.exports = o : { v: { pb: {}; mb: 1; }; } +>module.exports : { v: { pb: {}; mb: 1; }; } +>module : { exports: { v: { pb: {}; mb: 1; }; }; } +>exports : { v: { pb: {}; mb: 1; }; } +>o : { v: { pb: {}; mb: 1; }; } + +=== /xb.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./ma") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: {}; } +>{ v: { ...M } } : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>{ ...M } : { pa: { pb: {}; mb: 1; }; ma: 1; } +>M : typeof import("./ma") + +module.exports = o; +>module.exports = o : { v: {}; } +>module.exports : { v: {}; } +>module : { exports: { v: {}; }; } +>exports : { v: {}; } +>o : { v: {}; } + +=== /ia.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./ma") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>{ v: { ...M } } : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>{ ...M } : { pa: { pb: {}; mb: 1; }; ma: 1; } +>M : typeof import("./ma") + +module.exports = o; +>module.exports = o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>module.exports : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>module : { exports: { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; }; } +>exports : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } + +=== /ib.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./mb") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: { pb: {}; mb: 1; }; } +>{ v: { ...M } } : { v: { pb: {}; mb: 1; }; } +>v : { pb: {}; mb: 1; } +>{ ...M } : { pb: {}; mb: 1; } +>M : typeof import("./mb") + +module.exports = o; +>module.exports = o : { v: { pb: {}; mb: 1; }; } +>module.exports : { v: { pb: {}; mb: 1; }; } +>module : { exports: { v: { pb: {}; mb: 1; }; }; } +>exports : { v: { pb: {}; mb: 1; }; } +>o : { v: { pb: {}; mb: 1; }; } + +=== /index.js === +export { v as a } from "./ia"; +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>a : { pa: { pb: {}; mb: 1; }; ma: 1; } + +export { v as b } from "./ib"; +>v : { pb: {}; mb: 1; } +>b : { pb: {}; mb: 1; } + +export const f1 = 1; +>f1 : 1 +>1 : 1 + +export const f2 = 2; +>f2 : 2 +>2 : 2 + +export const f3 = 3; +>f3 : 3 +>3 : 3 + +export const f4 = 4; +>f4 : 4 +>4 : 4 + +export const f5 = 5; +>f5 : 5 +>5 : 5 + +export const f6 = 6; +>f6 : 6 +>6 : 6 + +export const f7 = 7; +>f7 : 7 +>7 : 7 + +export const f8 = 8; +>f8 : 8 +>8 : 8 + +export const f9 = 9; +>f9 : 9 +>9 : 9 + +export const f10 = 10; +>f10 : 10 +>10 : 10 + diff --git a/tsc/testdata/tests/cases/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.ts b/tsc/testdata/tests/cases/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.ts new file mode 100644 index 0000000000000..e068b9826487c --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/declarationEmitExternalModuleContainerIndexDeclarationOrder.ts @@ -0,0 +1,73 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @declaration: true +// @emitDeclarationOnly: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +// @Filename: /index.d.ts +export { v as b } from "ia"; +export { v as a } from "ib"; +export declare const f1: 1; +export declare const f2: 2; +export declare const f3: 3; +export declare const f4: 4; +export declare const f5: 5; +export declare const f6: 6; +export declare const f7: 7; +export declare const f8: 8; +export declare const f9: 9; +export declare const f10: 10; + +// @Filename: /gadget.d.ts +export interface Gadget { id: number } + +// @Filename: /widget.d.ts +import { Gadget } from "./gadget"; +export declare function makeWidget(): Gadget; + +// @Filename: /main.ts +/// +import { f1 } from "./index"; +import { makeWidget } from "./widget"; +declare function expand(): { [K in keyof X]: X[K] }; +export const keep = f1; +export const w = makeWidget(); +export const obsA = expand(); +export const obsB = expand(); diff --git a/tsc/testdata/tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts b/tsc/testdata/tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts new file mode 100644 index 0000000000000..47f869222be63 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts @@ -0,0 +1,67 @@ +// @strict: true +// @module: commonjs +// @target: es2020 +// @allowJs: true +// @checkJs: false +// @declaration: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ma.js +export { v as pa } from "./xa"; +export const ma = 1; + +// @Filename: /mb.js +export { v as pb } from "./xb"; +export const mb = 1; + +// @Filename: /xa.js +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /xb.js +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /ia.js +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /ib.js +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /star.js +export { v as a } from "./ia"; + +// @Filename: /index.js +export { v as b } from "./ib"; +export * from "./star"; +export const f1 = 1; +export const f2 = 2; +export const f3 = 3; +export const f4 = 4; +export const f5 = 5; +export const f6 = 6; +export const f7 = 7; +export const f8 = 8; +export const f9 = 9; +export const f10 = 10; + +// @Filename: /main.ts +import * as idx from "./index"; +const all = { ...idx }; +import * as MA from "./ma"; +import * as MB from "./mb"; +export const fromA = MA.pa; +export const fromB = MB.pb; +export const checkA: 1 = MA.pa.mb; +export const checkB: 1 = MB.pb.ma; diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.ts new file mode 100644 index 0000000000000..3e00eb2833ede --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitExternalModuleContainerIndexOrder.ts @@ -0,0 +1,73 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @declaration: true +// @emitDeclarationOnly: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +// @Filename: /index.d.ts +export { v as a } from "ia"; +export { v as b } from "ib"; +export declare const f1: 1; +export declare const f2: 2; +export declare const f3: 3; +export declare const f4: 4; +export declare const f5: 5; +export declare const f6: 6; +export declare const f7: 7; +export declare const f8: 8; +export declare const f9: 9; +export declare const f10: 10; + +// @Filename: /gadget.d.ts +export interface Gadget { id: number } + +// @Filename: /widget.d.ts +import { Gadget } from "./gadget"; +export declare function makeWidget(): Gadget; + +// @Filename: /main.ts +/// +import { f1 } from "./index"; +import { makeWidget } from "./widget"; +declare function expand(): { [K in keyof X]: X[K] }; +export const keep = f1; +export const w = makeWidget(); +export const obsA = expand(); +export const obsB = expand(); diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitRenamedExportOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitRenamedExportOrder.ts new file mode 100644 index 0000000000000..4bacfefc46fab --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitRenamedExportOrder.ts @@ -0,0 +1,72 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @declaration: true +// @emitDeclarationOnly: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +// @Filename: /globals.d.ts +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); + +// @Filename: /lib.d.ts +interface X { x: 1 } +export { X as Y }; +export { v as a } from "ia"; +export { v as b } from "ib"; +export declare const f1: 1; +export declare const f2: 2; +export declare const f3: 3; +export declare const f4: 4; +export declare const f5: 5; +export declare const f6: 6; +export declare const f7: 7; +export declare const f8: 8; +export declare const f9: 9; +export declare const f10: 10; +export declare function getX(): X; + +// @Filename: /main.ts +/// +/// +import { getX } from "./lib"; +declare function expand(): { [K in keyof X]: X[K] }; +export const x = getX(); +export const obsA = expand(); +export const obsB = expand(); diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts new file mode 100644 index 0000000000000..14f8c0ed89cf4 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts @@ -0,0 +1,64 @@ +// @strict: true +// @module: commonjs +// @target: es2020 +// @allowJs: true +// @checkJs: false +// @declaration: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ma.js +export { v as pa } from "./xa"; +export const ma = 1; + +// @Filename: /mb.js +export { v as pb } from "./xb"; +export const mb = 1; + +// @Filename: /xa.js +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /xb.js +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /ia.js +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /ib.js +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /index.js +export { v as a } from "./ia"; +export { v as b } from "./ib"; +export const f1 = 1; +export const f2 = 2; +export const f3 = 3; +export const f4 = 4; +export const f5 = 5; +export const f6 = 6; +export const f7 = 7; +export const f8 = 8; +export const f9 = 9; +export const f10 = 10; + +// @Filename: /main.ts +import * as idx from "./index"; +const all = { ...idx }; +import * as MA from "./ma"; +import * as MB from "./mb"; +export const fromA = MA.pa; +export const fromB = MB.pb; +export const checkA: 1 = MA.pa.mb; +export const checkB: 1 = MB.pb.ma; From 6c7193b6e3903bf094e96ad135d206c4f47df91b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 09:52:02 +0200 Subject: [PATCH 03/35] Visit scope variables in a stable order when looking for variable containers --- tsc/internal/checker/symbolaccessibility.go | 11 +- ...larationEmitVariableMatchesInScopeOrder.js | 59 +++++++++ ...ionEmitVariableMatchesInScopeOrder.symbols | 117 ++++++++++++++++++ ...ationEmitVariableMatchesInScopeOrder.types | 105 ++++++++++++++++ ...larationEmitVariableMatchesInScopeOrder.ts | 50 ++++++++ 5 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.js create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.types create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.ts diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index bf4150b0cbf47..dd762911fadd0 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -144,8 +144,17 @@ func (c *Checker) getWithAlternativeContainers(container *ast.Symbol, symbol *as c.getDeclaredTypeOfSymbol(container).flags&TypeFlagsObject != 0 { c.someSymbolTableInScope(enclosingDeclaration, func(t ast.SymbolTable, _ symbolTableID, _ bool, _ bool, _ *ast.Node) bool { found := false + var values []*ast.Symbol for _, s := range t { - if s.Flags()&leftMeaning != 0 && c.getTypeOfSymbol(s) == c.getDeclaredTypeOfSymbol(container) { + if s.Flags()&leftMeaning != 0 { + values = append(values, s) + } + } + // Getting the types of the values can create types and resolve aliases, so do it in a stable order + // rather than in the random iteration order of the symbol table. + c.sortSymbols(values) + for _, s := range values { + if c.getTypeOfSymbol(s) == c.getDeclaredTypeOfSymbol(container) { variableMatches = append(variableMatches, s) found = true } diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.js b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.js new file mode 100644 index 0000000000000..30a76df171c66 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.js @@ -0,0 +1,59 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.ts] //// + +//// [ambient.d.ts] +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +//// [globals.d.ts] +declare const gb: { [K in keyof typeof import("ma")]: 0 }; +declare const ga: { [K in keyof typeof import("mb")]: 0 }; +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); + +//// [keys.d.ts] +interface Keys { readonly key: unique symbol } +declare const keys: Keys; +declare function mk(): { [keys.key]: 1 }; + +//// [main.ts] +/// +/// +/// +declare function expand(): { [K in keyof X]: X[K] }; +export const obj = mk(); +export const obsA = expand(); +export const obsB = expand(); + + + + +//// [main.d.ts] +export declare const obj: { + [Keys.key]: 1; +}; +export declare const obsA: { + pb: 0; + readonly mb: 1; + v: 0; +}; +export declare const obsB: { + v: 0; +}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.symbols new file mode 100644 index 0000000000000..39cfe1287f026 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.symbols @@ -0,0 +1,117 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.ts] //// + +=== /main.ts === +/// +/// +/// +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 0, 0)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) + +export const obj = mk(); +>obj : Symbol(obj, Decl(main.ts, 4, 12)) +>mk : Symbol(mk, Decl(keys.d.ts, 1, 25)) + +export const obsA = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 5, 12)) +>expand : Symbol(expand, Decl(main.ts, 0, 0)) +>oxa : Symbol(oxa, Decl(globals.d.ts, 2, 13)) + +export const obsB = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 6, 12)) +>expand : Symbol(expand, Decl(main.ts, 0, 0)) +>oxb : Symbol(oxb, Decl(globals.d.ts, 3, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} + +=== /globals.d.ts === +declare const gb: { [K in keyof typeof import("ma")]: 0 }; +>gb : Symbol(gb, Decl(globals.d.ts, 0, 13)) +>K : Symbol(K, Decl(globals.d.ts, 0, 21)) + +declare const ga: { [K in keyof typeof import("mb")]: 0 }; +>ga : Symbol(ga, Decl(globals.d.ts, 1, 13)) +>K : Symbol(K, Decl(globals.d.ts, 1, 21)) + +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(globals.d.ts, 2, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(globals.d.ts, 3, 13)) + +=== /keys.d.ts === +interface Keys { readonly key: unique symbol } +>Keys : Symbol(Keys, Decl(keys.d.ts, 0, 0)) +>key : Symbol(Keys.key, Decl(keys.d.ts, 0, 16)) + +declare const keys: Keys; +>keys : Symbol(keys, Decl(keys.d.ts, 1, 13)) +>Keys : Symbol(Keys, Decl(keys.d.ts, 0, 0)) + +declare function mk(): { [keys.key]: 1 }; +>mk : Symbol(mk, Decl(keys.d.ts, 1, 25)) +>[keys.key] : Symbol([keys.key], Decl(keys.d.ts, 2, 24)) +>keys.key : Symbol(Keys.key, Decl(keys.d.ts, 0, 16)) +>keys : Symbol(keys, Decl(keys.d.ts, 1, 13)) +>key : Symbol(Keys.key, Decl(keys.d.ts, 0, 16)) + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.types new file mode 100644 index 0000000000000..2e41e20ad32be --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.types @@ -0,0 +1,105 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.ts] //// + +=== /main.ts === +/// +/// +/// +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export const obj = mk(); +>obj : { [Keys.key]: 1; } +>mk() : { [Keys.key]: 1; } +>mk : () => { [keys.key]: 1; } + +export const obsA = expand(); +>obsA : { pb: 0; readonly mb: 1; v: 0; } +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +export const obsB = expand(); +>obsB : { v: 0; } +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} + +=== /globals.d.ts === +declare const gb: { [K in keyof typeof import("ma")]: 0 }; +>gb : { pa: 0; readonly ma: 0; } + +declare const ga: { [K in keyof typeof import("mb")]: 0 }; +>ga : { pb: 0; readonly mb: 0; } + +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +=== /keys.d.ts === +interface Keys { readonly key: unique symbol } +>key : unique symbol + +declare const keys: Keys; +>keys : Keys + +declare function mk(): { [keys.key]: 1 }; +>mk : () => { [keys.key]: 1; } +>[keys.key] : 1 +>keys.key : unique symbol +>keys : Keys +>key : unique symbol + diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.ts new file mode 100644 index 0000000000000..543e04e6a4f81 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitVariableMatchesInScopeOrder.ts @@ -0,0 +1,50 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @declaration: true +// @emitDeclarationOnly: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +// @Filename: /globals.d.ts +declare const gb: { [K in keyof typeof import("ma")]: 0 }; +declare const ga: { [K in keyof typeof import("mb")]: 0 }; +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); + +// @Filename: /keys.d.ts +interface Keys { readonly key: unique symbol } +declare const keys: Keys; +declare function mk(): { [keys.key]: 1 }; + +// @Filename: /main.ts +/// +/// +/// +declare function expand(): { [K in keyof X]: X[K] }; +export const obj = mk(); +export const obsA = expand(); +export const obsB = expand(); From 9f20625f9fcf1142144995ef6e0ce2db5fcb2fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 11:01:41 +0200 Subject: [PATCH 04/35] Resolve alias exports of export= modules in a stable order --- tsc/internal/checker/checker.go | 24 ++- ...qualsWithOtherExportsCheckOrder.errors.txt | 63 +++++++ ...rtEqualsWithOtherExportsCheckOrder.symbols | 159 ++++++++++++++++ ...portEqualsWithOtherExportsCheckOrder.types | 129 +++++++++++++ ...ExportEqualsWithOtherExportsImportOrder.js | 75 ++++++++ ...tEqualsWithOtherExportsImportOrder.symbols | 177 ++++++++++++++++++ ...ortEqualsWithOtherExportsImportOrder.types | 143 ++++++++++++++ ...yExportEqualsWithOtherExportsCheckOrder.ts | 61 ++++++ ...ExportEqualsWithOtherExportsImportOrder.ts | 68 +++++++ 9 files changed, 895 insertions(+), 4 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.types create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.js create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.types create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.ts create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.ts diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index d4de86657fb42..91dccc1bf3ccd 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -5919,8 +5919,24 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) { } func (c *Checker) hasExportedMembersOfKind(moduleSymbol *ast.Symbol, kind ast.SymbolFlags) bool { + // Resolving an alias can create types, so resolve aliases last and in a stable order rather than in the random + // iteration order of the symbol table. + var aliases []*ast.Symbol for _, symbol := range moduleSymbol.Exports() { - if symbol.Name() != ast.InternalSymbolNameExportEquals && c.getSymbolFlags(symbol)&kind != 0 { + if symbol.Name() == ast.InternalSymbolNameExportEquals { + continue + } + if symbol.Flags()&ast.SymbolFlagsAlias != 0 { + aliases = append(aliases, symbol) + continue + } + if c.getSymbolFlags(symbol)&kind != 0 { + return true + } + } + c.sortSymbols(aliases) + for _, symbol := range aliases { + if c.getSymbolFlags(symbol)&kind != 0 { return true } } @@ -16618,9 +16634,9 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as } // A CommonJS module defined by an 'export=' might also export typedefs, stored on the original module if originalModule != nil && len(originalModule.Exports()) > 1 { - for _, symbol := range originalModule.Exports() { + c.forEachSymbolInResolutionOrder(originalModule.Exports(), func(symbol *ast.Symbol) { if symbol.Name() == ast.InternalSymbolNameExportEquals || symbol.Name() == ast.InternalSymbolNameExportStar { - continue + return } flags := c.getSymbolFlags(symbol) if flags&(ast.SymbolFlagsType|ast.SymbolFlagsNamespace) != 0 && @@ -16628,7 +16644,7 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as exports[symbol.Name()] == nil { exports[symbol.Name()] = symbol } - } + }) } for name := range nonTypeOnlyNames.Keys() { delete(typeOnlyExportStarMap, name) diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.errors.txt b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.errors.txt new file mode 100644 index 0000000000000..d81eb346f2055 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.errors.txt @@ -0,0 +1,63 @@ +/mm.ts(5,1): error TS2309: An export assignment cannot be used in a module with other exported elements. +/mm.ts(19,30): error TS2339: Property 'pa' does not exist on type 'O'. + + +==== /mm.ts (2 errors) ==== + /// + declare const oxa: typeof import("xa"); + declare const oxb: typeof import("xb"); + declare const o: { x: 1 }; + export = o; + ~~~~~~~~~~~ +!!! error TS2309: An export assignment cannot be used in a module with other exported elements. + export { v as a } from "ia"; + export { v as b } from "ib"; + export interface F1 {} + export interface F2 {} + export interface F3 {} + export interface F4 {} + export interface F5 {} + export interface F6 {} + export interface F7 {} + export interface F8 {} + export interface F9 {} + export interface F10 {} + export const checkA: 0 = oxa.pb; + export const checkB: 0 = oxb.pa; + ~~ +!!! error TS2339: Property 'pa' does not exist on type 'O'. + +==== /ambient.d.ts (0 errors) ==== + declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; + } + declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; + } + declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.symbols new file mode 100644 index 0000000000000..74a9fa86901eb --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.symbols @@ -0,0 +1,159 @@ +//// [tests/cases/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.ts] //// + +=== /mm.ts === +/// +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(mm.ts, 1, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(mm.ts, 2, 13)) + +declare const o: { x: 1 }; +>o : Symbol(o, Decl(mm.ts, 3, 13)) +>x : Symbol(x, Decl(mm.ts, 3, 18)) + +export = o; +>o : Symbol(o, Decl(mm.ts, 3, 13)) + +export { v as a } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>a : Symbol(a, Decl(mm.ts, 5, 8)) + +export { v as b } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>b : Symbol(b, Decl(mm.ts, 6, 8)) + +export interface F1 {} +>F1 : Symbol(F1, Decl(mm.ts, 6, 28)) + +export interface F2 {} +>F2 : Symbol(F2, Decl(mm.ts, 7, 22)) + +export interface F3 {} +>F3 : Symbol(F3, Decl(mm.ts, 8, 22)) + +export interface F4 {} +>F4 : Symbol(F4, Decl(mm.ts, 9, 22)) + +export interface F5 {} +>F5 : Symbol(F5, Decl(mm.ts, 10, 22)) + +export interface F6 {} +>F6 : Symbol(F6, Decl(mm.ts, 11, 22)) + +export interface F7 {} +>F7 : Symbol(F7, Decl(mm.ts, 12, 22)) + +export interface F8 {} +>F8 : Symbol(F8, Decl(mm.ts, 13, 22)) + +export interface F9 {} +>F9 : Symbol(F9, Decl(mm.ts, 14, 22)) + +export interface F10 {} +>F10 : Symbol(F10, Decl(mm.ts, 15, 22)) + +export const checkA: 0 = oxa.pb; +>checkA : Symbol(checkA, Decl(mm.ts, 17, 12)) +>oxa.pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) +>oxa : Symbol(oxa, Decl(mm.ts, 1, 13)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + +export const checkB: 0 = oxb.pa; +>checkB : Symbol(checkB, Decl(mm.ts, 18, 12)) +>oxb : Symbol(oxb, Decl(mm.ts, 2, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.types new file mode 100644 index 0000000000000..44664dcadfb80 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.types @@ -0,0 +1,129 @@ +//// [tests/cases/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.ts] //// + +=== /mm.ts === +/// +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +declare const o: { x: 1 }; +>o : { x: 1; } +>x : 1 + +export = o; +>o : { x: 1; } + +export { v as a } from "ia"; +>v : 0 +>a : 0 + +export { v as b } from "ib"; +>v : 0 +>b : 0 + +export interface F1 {} +export interface F2 {} +export interface F3 {} +export interface F4 {} +export interface F5 {} +export interface F6 {} +export interface F7 {} +export interface F8 {} +export interface F9 {} +export interface F10 {} +export const checkA: 0 = oxa.pb; +>checkA : 0 +>oxa.pb : 0 +>oxa : O +>pb : 0 + +export const checkB: 0 = oxb.pa; +>checkB : 0 +>oxb.pa : any +>oxb : O +>pa : any + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.js b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.js new file mode 100644 index 0000000000000..37e7a9ff94890 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.js @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.ts] //// + +//// [ambient.d.ts] +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "mm" { + const o: { x: 1 }; + export = o; + export { v as a } from "ia"; + export { v as b } from "ib"; + export interface F1 {} + export interface F2 {} + export interface F3 {} + export interface F4 {} + export interface F5 {} + export interface F6 {} + export interface F7 {} + export interface F8 {} + export interface F9 {} + export interface F10 {} +} + +//// [main.ts] +/// +import { x } from "mm"; +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +export const keep = x; +export const obsA = expand(); +export const obsB = expand(); + + + + +//// [main.d.ts] +export declare const keep: 1; +export declare const obsA: { + pb: 0; + readonly mb: 1; + v: 0; +}; +export declare const obsB: { + v: 0; +}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.symbols new file mode 100644 index 0000000000000..0e5471b217c97 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.symbols @@ -0,0 +1,177 @@ +//// [tests/cases/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.ts] //// + +=== /main.ts === +/// +import { x } from "mm"; +>x : Symbol(x, Decl(main.ts, 1, 8)) + +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) + +export const keep = x; +>keep : Symbol(keep, Decl(main.ts, 5, 12)) +>x : Symbol(x, Decl(main.ts, 1, 8)) + +export const obsA = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 6, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +export const obsB = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 7, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} +declare module "mm" { +>"mm" : Symbol("mm", Decl(ambient.d.ts, 31, 1)) + + const o: { x: 1 }; +>o : Symbol(o, Decl(ambient.d.ts, 33, 9)) +>x : Symbol(x, Decl(ambient.d.ts, 33, 14)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 33, 9)) + + export { v as a } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>a : Symbol(a, Decl(ambient.d.ts, 35, 12)) + + export { v as b } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>b : Symbol(b, Decl(ambient.d.ts, 36, 12)) + + export interface F1 {} +>F1 : Symbol(F1, Decl(ambient.d.ts, 36, 32)) + + export interface F2 {} +>F2 : Symbol(F2, Decl(ambient.d.ts, 37, 26)) + + export interface F3 {} +>F3 : Symbol(F3, Decl(ambient.d.ts, 38, 26)) + + export interface F4 {} +>F4 : Symbol(F4, Decl(ambient.d.ts, 39, 26)) + + export interface F5 {} +>F5 : Symbol(F5, Decl(ambient.d.ts, 40, 26)) + + export interface F6 {} +>F6 : Symbol(F6, Decl(ambient.d.ts, 41, 26)) + + export interface F7 {} +>F7 : Symbol(F7, Decl(ambient.d.ts, 42, 26)) + + export interface F8 {} +>F8 : Symbol(F8, Decl(ambient.d.ts, 43, 26)) + + export interface F9 {} +>F9 : Symbol(F9, Decl(ambient.d.ts, 44, 26)) + + export interface F10 {} +>F10 : Symbol(F10, Decl(ambient.d.ts, 45, 26)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.types new file mode 100644 index 0000000000000..c0ba114c78355 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.types @@ -0,0 +1,143 @@ +//// [tests/cases/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.ts] //// + +=== /main.ts === +/// +import { x } from "mm"; +>x : 1 + +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export const keep = x; +>keep : 1 +>x : 1 + +export const obsA = expand(); +>obsA : { pb: 0; readonly mb: 1; v: 0; } +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +export const obsB = expand(); +>obsB : { v: 0; } +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "mm" { +>"mm" : typeof import("mm") + + const o: { x: 1 }; +>o : { x: 1; } +>x : 1 + + export = o; +>o : { x: 1; } + + export { v as a } from "ia"; +>v : 0 +>a : 0 + + export { v as b } from "ib"; +>v : 0 +>b : 0 + + export interface F1 {} + export interface F2 {} + export interface F3 {} + export interface F4 {} + export interface F5 {} + export interface F6 {} + export interface F7 {} + export interface F8 {} + export interface F9 {} + export interface F10 {} +} + diff --git a/tsc/testdata/tests/cases/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.ts new file mode 100644 index 0000000000000..7e31032b5522c --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyExportEqualsWithOtherExportsCheckOrder.ts @@ -0,0 +1,61 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @noEmit: true +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +// @Filename: /mm.ts +/// +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare const o: { x: 1 }; +export = o; +export { v as a } from "ia"; +export { v as b } from "ib"; +export interface F1 {} +export interface F2 {} +export interface F3 {} +export interface F4 {} +export interface F5 {} +export interface F6 {} +export interface F7 {} +export interface F8 {} +export interface F9 {} +export interface F10 {} +export const checkA: 0 = oxa.pb; +export const checkB: 0 = oxb.pa; diff --git a/tsc/testdata/tests/cases/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.ts new file mode 100644 index 0000000000000..32586d0fc9125 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyExportEqualsWithOtherExportsImportOrder.ts @@ -0,0 +1,68 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @declaration: true +// @emitDeclarationOnly: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "mm" { + const o: { x: 1 }; + export = o; + export { v as a } from "ia"; + export { v as b } from "ib"; + export interface F1 {} + export interface F2 {} + export interface F3 {} + export interface F4 {} + export interface F5 {} + export interface F6 {} + export interface F7 {} + export interface F8 {} + export interface F9 {} + export interface F10 {} +} + +// @Filename: /main.ts +/// +import { x } from "mm"; +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +export const keep = x; +export const obsA = expand(); +export const obsB = expand(); From 5e7481bf33239876004a33e89686d24c50605cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 11:27:28 +0200 Subject: [PATCH 05/35] Check export aliases in a stable order when naming a symbol through its parent --- tsc/internal/checker/nodebuilderimpl.go | 8 +- ...ationEmitExportEqualsQualifiedNameOrder.js | 82 ++++++++ ...EmitExportEqualsQualifiedNameOrder.symbols | 188 ++++++++++++++++++ ...onEmitExportEqualsQualifiedNameOrder.types | 173 ++++++++++++++++ ...ationEmitExportEqualsQualifiedNameOrder.ts | 73 +++++++ 5 files changed, 520 insertions(+), 4 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.js create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.types create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.ts diff --git a/tsc/internal/checker/nodebuilderimpl.go b/tsc/internal/checker/nodebuilderimpl.go index 3d84ff3bd4094..e9bfb02d3d2d0 100644 --- a/tsc/internal/checker/nodebuilderimpl.go +++ b/tsc/internal/checker/nodebuilderimpl.go @@ -778,12 +778,12 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index symbolName = symbol.Name() } else { results := make(map[*ast.Symbol]string, 1) - for name, ex := range exports { - if b.ch.getSymbolIfSameReference(ex, symbol) != nil && !isLateBoundName(name) && name != ast.InternalSymbolNameExportEquals { - results[ex] = name + b.ch.forEachSymbolInResolutionOrder(exports, func(ex *ast.Symbol) { + if b.ch.getSymbolIfSameReference(ex, symbol) != nil && !isLateBoundName(ex.Name()) && ex.Name() != ast.InternalSymbolNameExportEquals { + results[ex] = ex.Name() // break // must collect all results and sort them - exports are randomly iterated } - } + }) resultSymbols := slices.Collect(maps.Keys(results)) if len(resultSymbols) > 0 { b.ch.sortSymbols(resultSymbols) diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.js b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.js new file mode 100644 index 0000000000000..2413425ee0027 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.js @@ -0,0 +1,82 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.ts] //// + +//// [ambient.d.ts] +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "mt" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; +} +declare module "mm" { + import t = require("mt"); + export = t; + export const C: unique symbol; + global { + const gc: { c: typeof C }; + } +} + +//// [main.ts] +/// +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +export const w = gc; +export const obsA = expand(); +export const obsB = expand(); + + + + +//// [main.d.ts] +export declare const w: { + c: typeof import("mm").C; +}; +export declare const obsA: { + pb: 0; + readonly mb: 1; + v: 0; +}; +export declare const obsB: { + v: 0; +}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.symbols new file mode 100644 index 0000000000000..43d526421d7bb --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.symbols @@ -0,0 +1,188 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.ts] //// + +=== /main.ts === +/// +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(main.ts, 1, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(main.ts, 2, 13)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 2, 39)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>X : Symbol(X, Decl(main.ts, 3, 24)) +>K : Symbol(K, Decl(main.ts, 3, 33)) + +export const w = gc; +>w : Symbol(w, Decl(main.ts, 4, 12)) +>gc : Symbol(gc, Decl(ambient.d.ts, 51, 13)) + +export const obsA = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 5, 12)) +>expand : Symbol(expand, Decl(main.ts, 2, 39)) +>oxa : Symbol(oxa, Decl(main.ts, 1, 13)) + +export const obsB = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 6, 12)) +>expand : Symbol(expand, Decl(main.ts, 2, 39)) +>oxb : Symbol(oxb, Decl(main.ts, 2, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} +declare module "mt" { +>"mt" : Symbol("mt", Decl(ambient.d.ts, 31, 1)) + + export { v as a } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>a : Symbol(a, Decl(ambient.d.ts, 33, 12)) + + export { v as b } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>b : Symbol(b, Decl(ambient.d.ts, 34, 12)) + + export const f1: 1; +>f1 : Symbol(f1, Decl(ambient.d.ts, 35, 16)) + + export const f2: 2; +>f2 : Symbol(f2, Decl(ambient.d.ts, 36, 16)) + + export const f3: 3; +>f3 : Symbol(f3, Decl(ambient.d.ts, 37, 16)) + + export const f4: 4; +>f4 : Symbol(f4, Decl(ambient.d.ts, 38, 16)) + + export const f5: 5; +>f5 : Symbol(f5, Decl(ambient.d.ts, 39, 16)) + + export const f6: 6; +>f6 : Symbol(f6, Decl(ambient.d.ts, 40, 16)) + + export const f7: 7; +>f7 : Symbol(f7, Decl(ambient.d.ts, 41, 16)) + + export const f8: 8; +>f8 : Symbol(f8, Decl(ambient.d.ts, 42, 16)) + + export const f9: 9; +>f9 : Symbol(f9, Decl(ambient.d.ts, 43, 16)) + + export const f10: 10; +>f10 : Symbol(f10, Decl(ambient.d.ts, 44, 16)) +} +declare module "mm" { +>"mm" : Symbol("mm", Decl(ambient.d.ts, 45, 1)) + + import t = require("mt"); +>t : Symbol(t, Decl(ambient.d.ts, 46, 21)) + + export = t; +>t : Symbol(t, Decl(ambient.d.ts, 46, 21)) + + export const C: unique symbol; +>C : Symbol(C, Decl(ambient.d.ts, 49, 16)) + + global { +>global : Symbol(global, Decl(ambient.d.ts, 49, 34)) + + const gc: { c: typeof C }; +>gc : Symbol(gc, Decl(ambient.d.ts, 51, 13)) +>c : Symbol(c, Decl(ambient.d.ts, 51, 19)) +>C : Symbol(C, Decl(ambient.d.ts, 49, 16)) + } +} + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.types new file mode 100644 index 0000000000000..6e3734d808ac2 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.types @@ -0,0 +1,173 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.ts] //// + +=== /main.ts === +/// +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export const w = gc; +>w : { c: typeof import("mm").C; } +>gc : { c: typeof import("mm").C; } + +export const obsA = expand(); +>obsA : { pb: 0; readonly mb: 1; v: 0; } +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +export const obsB = expand(); +>obsB : { v: 0; } +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "mt" { +>"mt" : typeof import("mt") + + export { v as a } from "ia"; +>v : 0 +>a : 0 + + export { v as b } from "ib"; +>v : 0 +>b : 0 + + export const f1: 1; +>f1 : 1 + + export const f2: 2; +>f2 : 2 + + export const f3: 3; +>f3 : 3 + + export const f4: 4; +>f4 : 4 + + export const f5: 5; +>f5 : 5 + + export const f6: 6; +>f6 : 6 + + export const f7: 7; +>f7 : 7 + + export const f8: 8; +>f8 : 8 + + export const f9: 9; +>f9 : 9 + + export const f10: 10; +>f10 : 10 +} +declare module "mm" { +>"mm" : typeof import("mm") + + import t = require("mt"); +>t : typeof t + + export = t; +>t : typeof t + + export const C: unique symbol; +>C : unique symbol + + global { +>global : typeof global + + const gc: { c: typeof C }; +>gc : { c: typeof C; } +>c : unique symbol +>C : unique symbol + } +} + diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.ts new file mode 100644 index 0000000000000..89b31e8e9ea77 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitExportEqualsQualifiedNameOrder.ts @@ -0,0 +1,73 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @declaration: true +// @emitDeclarationOnly: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "mt" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; +} +declare module "mm" { + import t = require("mt"); + export = t; + export const C: unique symbol; + global { + const gc: { c: typeof C }; + } +} + +// @Filename: /main.ts +/// +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +export const w = gc; +export const obsA = expand(); +export const obsB = expand(); From 12ad75c164d2379b198fd65fb36179729a19add0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 11:49:55 +0200 Subject: [PATCH 06/35] Check export * collisions in a stable order --- tsc/internal/checker/checker.go | 9 +- ...nosticsExportStarCollisionOrder.errors.txt | 84 +++++++ ...iagnosticsExportStarCollisionOrder.symbols | 217 ++++++++++++++++++ ...yDiagnosticsExportStarCollisionOrder.types | 202 ++++++++++++++++ ...akyDeclarationEmitUmdGlobalAliasesOrder.ts | 129 +++++++++++ ...lakyDiagnosticsExportStarCollisionOrder.ts | 82 +++++++ ...oFlakyDiagnosticsNonExportedMemberOrder.ts | 64 ++++++ ...FlakyDiagnosticsSpellingSuggestionOrder.ts | 121 ++++++++++ 8 files changed, 905 insertions(+), 3 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.types create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.ts create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsExportStarCollisionOrder.ts create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNonExportedMemberOrder.ts create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.ts diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 91dccc1bf3ccd..ae160eee29a4f 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -16657,9 +16657,12 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables */ func (c *Checker) extendExportSymbols(target ast.SymbolTable, source ast.SymbolTable, lookupTable ExportCollisionTable, exportNode *ast.Node) { - for id, sourceSymbol := range source { + // Checking for collisions resolves aliases, which creates types, so visit aliases last and in a stable order + // rather than in the random iteration order of the symbol table. + c.forEachSymbolInResolutionOrder(source, func(sourceSymbol *ast.Symbol) { + id := sourceSymbol.Name() if id == ast.InternalSymbolNameDefault { - continue + return } targetSymbol := target[id] if targetSymbol == nil { @@ -16673,7 +16676,7 @@ func (c *Checker) extendExportSymbols(target ast.SymbolTable, source ast.SymbolT s := lookupTable[id] s.exportsWithDuplicate = append(s.exportsWithDuplicate, exportNode) } - } + }) } func (c *Checker) ResolveAlias(symbol *ast.Symbol) (*ast.Symbol, bool) { diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.errors.txt b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.errors.txt new file mode 100644 index 0000000000000..a2ecba905fe18 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.errors.txt @@ -0,0 +1,84 @@ +/main.ts(7,14): error TS2322: Type '{ pb: 0; readonly mb: 1; v: 0; }' is not assignable to type 'never'. +/main.ts(8,14): error TS2322: Type '{ v: 0; }' is not assignable to type 'never'. + + +==== /main.ts (2 errors) ==== + /// + import { f1 } from "m1"; + declare const oxa: typeof import("xa"); + declare const oxb: typeof import("xb"); + declare function expand(): { [K in keyof X]: X[K] }; + export const keep = f1; + export const obsA: never = expand(); + ~~~~ +!!! error TS2322: Type '{ pb: 0; readonly mb: 1; v: 0; }' is not assignable to type 'never'. + export const obsB: never = expand(); + ~~~~ +!!! error TS2322: Type '{ v: 0; }' is not assignable to type 'never'. + +==== /ambient.d.ts (0 errors) ==== + declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; + } + declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; + } + declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "s1" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; + } + declare module "s2" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; + } + declare module "m1" { + export * from "s1"; + export * from "s2"; + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.symbols new file mode 100644 index 0000000000000..5ca84074f7a11 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.symbols @@ -0,0 +1,217 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsExportStarCollisionOrder.ts] //// + +=== /main.ts === +/// +import { f1 } from "m1"; +>f1 : Symbol(f1, Decl(main.ts, 1, 8)) + +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) + +export const keep = f1; +>keep : Symbol(keep, Decl(main.ts, 5, 12)) +>f1 : Symbol(f1, Decl(main.ts, 1, 8)) + +export const obsA: never = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 6, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +export const obsB: never = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 7, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} +declare module "s1" { +>"s1" : Symbol("s1", Decl(ambient.d.ts, 31, 1)) + + export { v as a } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>a : Symbol(a, Decl(ambient.d.ts, 33, 12)) + + export { v as b } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>b : Symbol(b, Decl(ambient.d.ts, 34, 12)) + + export const f1: 1; +>f1 : Symbol(f1, Decl(ambient.d.ts, 35, 16)) + + export const f2: 2; +>f2 : Symbol(f2, Decl(ambient.d.ts, 36, 16)) + + export const f3: 3; +>f3 : Symbol(f3, Decl(ambient.d.ts, 37, 16)) + + export const f4: 4; +>f4 : Symbol(f4, Decl(ambient.d.ts, 38, 16)) + + export const f5: 5; +>f5 : Symbol(f5, Decl(ambient.d.ts, 39, 16)) + + export const f6: 6; +>f6 : Symbol(f6, Decl(ambient.d.ts, 40, 16)) + + export const f7: 7; +>f7 : Symbol(f7, Decl(ambient.d.ts, 41, 16)) + + export const f8: 8; +>f8 : Symbol(f8, Decl(ambient.d.ts, 42, 16)) + + export const f9: 9; +>f9 : Symbol(f9, Decl(ambient.d.ts, 43, 16)) + + export const f10: 10; +>f10 : Symbol(f10, Decl(ambient.d.ts, 44, 16)) +} +declare module "s2" { +>"s2" : Symbol("s2", Decl(ambient.d.ts, 45, 1)) + + export { v as a } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>a : Symbol(a, Decl(ambient.d.ts, 47, 12)) + + export { v as b } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>b : Symbol(b, Decl(ambient.d.ts, 48, 12)) + + export const f1: 1; +>f1 : Symbol(f1, Decl(ambient.d.ts, 49, 16)) + + export const f2: 2; +>f2 : Symbol(f2, Decl(ambient.d.ts, 50, 16)) + + export const f3: 3; +>f3 : Symbol(f3, Decl(ambient.d.ts, 51, 16)) + + export const f4: 4; +>f4 : Symbol(f4, Decl(ambient.d.ts, 52, 16)) + + export const f5: 5; +>f5 : Symbol(f5, Decl(ambient.d.ts, 53, 16)) + + export const f6: 6; +>f6 : Symbol(f6, Decl(ambient.d.ts, 54, 16)) + + export const f7: 7; +>f7 : Symbol(f7, Decl(ambient.d.ts, 55, 16)) + + export const f8: 8; +>f8 : Symbol(f8, Decl(ambient.d.ts, 56, 16)) + + export const f9: 9; +>f9 : Symbol(f9, Decl(ambient.d.ts, 57, 16)) + + export const f10: 10; +>f10 : Symbol(f10, Decl(ambient.d.ts, 58, 16)) +} +declare module "m1" { +>"m1" : Symbol("m1", Decl(ambient.d.ts, 59, 1)) + + export * from "s1"; + export * from "s2"; +} + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.types new file mode 100644 index 0000000000000..925b972b915c6 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarCollisionOrder.types @@ -0,0 +1,202 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsExportStarCollisionOrder.ts] //// + +=== /main.ts === +/// +import { f1 } from "m1"; +>f1 : 1 + +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export const keep = f1; +>keep : 1 +>f1 : 1 + +export const obsA: never = expand(); +>obsA : never +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +export const obsB: never = expand(); +>obsB : never +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "s1" { +>"s1" : typeof import("s1") + + export { v as a } from "ia"; +>v : 0 +>a : 0 + + export { v as b } from "ib"; +>v : 0 +>b : 0 + + export const f1: 1; +>f1 : 1 + + export const f2: 2; +>f2 : 2 + + export const f3: 3; +>f3 : 3 + + export const f4: 4; +>f4 : 4 + + export const f5: 5; +>f5 : 5 + + export const f6: 6; +>f6 : 6 + + export const f7: 7; +>f7 : 7 + + export const f8: 8; +>f8 : 8 + + export const f9: 9; +>f9 : 9 + + export const f10: 10; +>f10 : 10 +} +declare module "s2" { +>"s2" : typeof import("s2") + + export { v as a } from "ia"; +>v : 0 +>a : 0 + + export { v as b } from "ib"; +>v : 0 +>b : 0 + + export const f1: 1; +>f1 : 1 + + export const f2: 2; +>f2 : 2 + + export const f3: 3; +>f3 : 3 + + export const f4: 4; +>f4 : 4 + + export const f5: 5; +>f5 : 5 + + export const f6: 6; +>f6 : 6 + + export const f7: 7; +>f7 : 7 + + export const f8: 8; +>f8 : 8 + + export const f9: 9; +>f9 : 9 + + export const f10: 10; +>f10 : 10 +} +declare module "m1" { +>"m1" : typeof import("m1") + + export * from "s1"; + export * from "s2"; +} + diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.ts new file mode 100644 index 0000000000000..b207295dd5723 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.ts @@ -0,0 +1,129 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @declaration: true +// @emitDeclarationOnly: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "mm" { + export const C: unique symbol; + global { + const gc: { c: typeof C }; + } +} + +// @Filename: /ua.d.ts +import { v } from "ia"; +export = v; +export as namespace UA; + +// @Filename: /ub.d.ts +import { v } from "ib"; +export = v; +export as namespace UB; + +// @Filename: /uf1.d.ts +declare const x: 1; +export = x; +export as namespace UF1; + +// @Filename: /uf2.d.ts +declare const x: 2; +export = x; +export as namespace UF2; + +// @Filename: /uf3.d.ts +declare const x: 3; +export = x; +export as namespace UF3; + +// @Filename: /uf4.d.ts +declare const x: 4; +export = x; +export as namespace UF4; + +// @Filename: /uf5.d.ts +declare const x: 5; +export = x; +export as namespace UF5; + +// @Filename: /uf6.d.ts +declare const x: 6; +export = x; +export as namespace UF6; + +// @Filename: /uf7.d.ts +declare const x: 7; +export = x; +export as namespace UF7; + +// @Filename: /uf8.d.ts +declare const x: 8; +export = x; +export as namespace UF8; + +// @Filename: /uf9.d.ts +declare const x: 9; +export = x; +export as namespace UF9; + +// @Filename: /uf10.d.ts +declare const x: 10; +export = x; +export as namespace UF10; + +// @Filename: /main.ts +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +const w = gc; +const obsA = expand(); +const obsB = expand(); diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsExportStarCollisionOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsExportStarCollisionOrder.ts new file mode 100644 index 0000000000000..5865d51dd4ebe --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsExportStarCollisionOrder.ts @@ -0,0 +1,82 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @noEmit: true +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "s1" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; +} +declare module "s2" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; +} +declare module "m1" { + export * from "s1"; + export * from "s2"; +} + +// @Filename: /main.ts +/// +import { f1 } from "m1"; +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +export const keep = f1; +export const obsA: never = expand(); +export const obsB: never = expand(); diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNonExportedMemberOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNonExportedMemberOrder.ts new file mode 100644 index 0000000000000..13baed3b85905 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNonExportedMemberOrder.ts @@ -0,0 +1,64 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @noEmit: true +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "mt" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; + const zz: 1; +} + +// @Filename: /main.ts +/// +import { zz } from "mt"; +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +export const obsA: never = expand(); +export const obsB: never = expand(); diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.ts new file mode 100644 index 0000000000000..1c742585da63a --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.ts @@ -0,0 +1,121 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @noEmit: true +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +// @Filename: /ua.d.ts +import { v } from "ia"; +export = v; +export as namespace UA; + +// @Filename: /ub.d.ts +import { v } from "ib"; +export = v; +export as namespace UB; + +// @Filename: /uf1.d.ts +declare const x: 1; +export = x; +export as namespace UF1; + +// @Filename: /uf2.d.ts +declare const x: 2; +export = x; +export as namespace UF2; + +// @Filename: /uf3.d.ts +declare const x: 3; +export = x; +export as namespace UF3; + +// @Filename: /uf4.d.ts +declare const x: 4; +export = x; +export as namespace UF4; + +// @Filename: /uf5.d.ts +declare const x: 5; +export = x; +export as namespace UF5; + +// @Filename: /uf6.d.ts +declare const x: 6; +export = x; +export as namespace UF6; + +// @Filename: /uf7.d.ts +declare const x: 7; +export = x; +export as namespace UF7; + +// @Filename: /uf8.d.ts +declare const x: 8; +export = x; +export as namespace UF8; + +// @Filename: /uf9.d.ts +declare const x: 9; +export = x; +export as namespace UF9; + +// @Filename: /uf10.d.ts +declare const x: 10; +export = x; +export as namespace UF10; + +// @Filename: /main.ts +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +const q = zz; +const obsA: never = expand(); +const obsB: never = expand(); From d8fb3c7e6341602e870d37e73a7984300a82bbfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 11:51:19 +0200 Subject: [PATCH 07/35] Look for a non-exported member's export in a stable order --- tsc/internal/checker/checker.go | 9 +- ...agnosticsNonExportedMemberOrder.errors.txt | 70 ++++++++ ...yDiagnosticsNonExportedMemberOrder.symbols | 169 ++++++++++++++++++ ...akyDiagnosticsNonExportedMemberOrder.types | 154 ++++++++++++++++ 4 files changed, 400 insertions(+), 2 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.types diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index ae160eee29a4f..ade17f26175b7 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -15235,8 +15235,13 @@ func (c *Checker) reportNonExportedMember(name *ast.Node, declarationName string c.error(name, diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName) } } else { - exportedSymbol := findInMap(exports, func(symbol *ast.Symbol) bool { - return c.getSymbolIfSameReference(symbol, localSymbol) != nil + // Looking for the export resolves aliases, which creates types, so do it in a stable order rather than + // in the random iteration order of the symbol table. + var exportedSymbol *ast.Symbol + c.forEachSymbolInResolutionOrder(exports, func(symbol *ast.Symbol) { + if exportedSymbol == nil && c.getSymbolIfSameReference(symbol, localSymbol) != nil { + exportedSymbol = symbol + } }) var diagnostic *ast.Diagnostic if exportedSymbol != nil { diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.errors.txt b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.errors.txt new file mode 100644 index 0000000000000..aba9bd814f87b --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.errors.txt @@ -0,0 +1,70 @@ +/main.ts(2,10): error TS2459: Module '"mt"' declares 'zz' locally, but it is not exported. +/main.ts(6,14): error TS2322: Type '{ pb: 0; readonly mb: 1; v: 0; }' is not assignable to type 'never'. +/main.ts(7,14): error TS2322: Type '{ v: 0; }' is not assignable to type 'never'. + + +==== /main.ts (3 errors) ==== + /// + import { zz } from "mt"; + ~~ +!!! error TS2459: Module '"mt"' declares 'zz' locally, but it is not exported. +!!! related TS2728 /ambient.d.ts:46:11: 'zz' is declared here. + declare const oxa: typeof import("xa"); + declare const oxb: typeof import("xb"); + declare function expand(): { [K in keyof X]: X[K] }; + export const obsA: never = expand(); + ~~~~ +!!! error TS2322: Type '{ pb: 0; readonly mb: 1; v: 0; }' is not assignable to type 'never'. + export const obsB: never = expand(); + ~~~~ +!!! error TS2322: Type '{ v: 0; }' is not assignable to type 'never'. + +==== /ambient.d.ts (0 errors) ==== + declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; + } + declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; + } + declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "mt" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; + const zz: 1; + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.symbols new file mode 100644 index 0000000000000..c5f4fec719b8c --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.symbols @@ -0,0 +1,169 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsNonExportedMemberOrder.ts] //// + +=== /main.ts === +/// +import { zz } from "mt"; +>zz : Symbol(zz, Decl(main.ts, 1, 8)) + +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) + +export const obsA: never = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 5, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +export const obsB: never = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 6, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} +declare module "mt" { +>"mt" : Symbol("mt", Decl(ambient.d.ts, 31, 1)) + + export { v as a } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>a : Symbol(a, Decl(ambient.d.ts, 33, 12)) + + export { v as b } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>b : Symbol(b, Decl(ambient.d.ts, 34, 12)) + + export const f1: 1; +>f1 : Symbol(f1, Decl(ambient.d.ts, 35, 16)) + + export const f2: 2; +>f2 : Symbol(f2, Decl(ambient.d.ts, 36, 16)) + + export const f3: 3; +>f3 : Symbol(f3, Decl(ambient.d.ts, 37, 16)) + + export const f4: 4; +>f4 : Symbol(f4, Decl(ambient.d.ts, 38, 16)) + + export const f5: 5; +>f5 : Symbol(f5, Decl(ambient.d.ts, 39, 16)) + + export const f6: 6; +>f6 : Symbol(f6, Decl(ambient.d.ts, 40, 16)) + + export const f7: 7; +>f7 : Symbol(f7, Decl(ambient.d.ts, 41, 16)) + + export const f8: 8; +>f8 : Symbol(f8, Decl(ambient.d.ts, 42, 16)) + + export const f9: 9; +>f9 : Symbol(f9, Decl(ambient.d.ts, 43, 16)) + + export const f10: 10; +>f10 : Symbol(f10, Decl(ambient.d.ts, 44, 16)) + + const zz: 1; +>zz : Symbol(zz, Decl(ambient.d.ts, 45, 9)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.types new file mode 100644 index 0000000000000..00ba3854da277 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNonExportedMemberOrder.types @@ -0,0 +1,154 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsNonExportedMemberOrder.ts] //// + +=== /main.ts === +/// +import { zz } from "mt"; +>zz : any + +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export const obsA: never = expand(); +>obsA : never +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +export const obsB: never = expand(); +>obsB : never +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "mt" { +>"mt" : typeof import("mt") + + export { v as a } from "ia"; +>v : 0 +>a : 0 + + export { v as b } from "ib"; +>v : 0 +>b : 0 + + export const f1: 1; +>f1 : 1 + + export const f2: 2; +>f2 : 2 + + export const f3: 3; +>f3 : 3 + + export const f4: 4; +>f4 : 4 + + export const f5: 5; +>f5 : 5 + + export const f6: 6; +>f6 : 6 + + export const f7: 7; +>f7 : 7 + + export const f8: 8; +>f8 : 8 + + export const f9: 9; +>f9 : 9 + + export const f10: 10; +>f10 : 10 + + const zz: 1; +>zz : 1 +} + From 1ea3e6ad52a4d96b97a1394ea9a87ee2d70d55e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 11:52:55 +0200 Subject: [PATCH 08/35] Sort cached symbol table aliases before resolving them --- tsc/internal/checker/symbolaccessibility.go | 3 + ...akyDeclarationEmitUmdGlobalAliasesOrder.js | 143 +++++++++ ...clarationEmitUmdGlobalAliasesOrder.symbols | 273 ++++++++++++++++++ ...DeclarationEmitUmdGlobalAliasesOrder.types | 258 +++++++++++++++++ 4 files changed, 677 insertions(+) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.js create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.types diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index dd762911fadd0..a5a4b89a2c0e1 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -613,6 +613,9 @@ func (c *Checker) getSymbolTableAliases(symbols ast.SymbolTable, tableId symbolT aliases = append(aliases, sym) } } + // The aliases are resolved in this order, which creates types, so sort them rather than using the random + // iteration order of the symbol table. + c.sortSymbols(aliases) if kind == stKindGlobals || kind == stKindExports || kind == stKindResolvedExports { if c.symbolTableAliasCache == nil { c.symbolTableAliasCache = make(map[symbolTableID][]*ast.Symbol) diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.js b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.js new file mode 100644 index 0000000000000..f297255bfad65 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.js @@ -0,0 +1,143 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.ts] //// + +//// [ambient.d.ts] +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "mm" { + export const C: unique symbol; + global { + const gc: { c: typeof C }; + } +} + +//// [ua.d.ts] +import { v } from "ia"; +export = v; +export as namespace UA; + +//// [ub.d.ts] +import { v } from "ib"; +export = v; +export as namespace UB; + +//// [uf1.d.ts] +declare const x: 1; +export = x; +export as namespace UF1; + +//// [uf2.d.ts] +declare const x: 2; +export = x; +export as namespace UF2; + +//// [uf3.d.ts] +declare const x: 3; +export = x; +export as namespace UF3; + +//// [uf4.d.ts] +declare const x: 4; +export = x; +export as namespace UF4; + +//// [uf5.d.ts] +declare const x: 5; +export = x; +export as namespace UF5; + +//// [uf6.d.ts] +declare const x: 6; +export = x; +export as namespace UF6; + +//// [uf7.d.ts] +declare const x: 7; +export = x; +export as namespace UF7; + +//// [uf8.d.ts] +declare const x: 8; +export = x; +export as namespace UF8; + +//// [uf9.d.ts] +declare const x: 9; +export = x; +export as namespace UF9; + +//// [uf10.d.ts] +declare const x: 10; +export = x; +export as namespace UF10; + +//// [main.ts] +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +const w = gc; +const obsA = expand(); +const obsB = expand(); + + + + +//// [main.d.ts] +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { + [K in keyof X]: X[K]; +}; +declare const w: { + c: typeof import("mm").C; +}; +declare const obsA: { + pb: 0; + readonly mb: 1; + v: 0; +}; +declare const obsB: { + v: 0; +}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.symbols new file mode 100644 index 0000000000000..7613d3b6c6cc6 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.symbols @@ -0,0 +1,273 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.ts] //// + +=== /main.ts === +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(main.ts, 13, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(main.ts, 14, 13)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 14, 39)) +>X : Symbol(X, Decl(main.ts, 15, 24)) +>K : Symbol(K, Decl(main.ts, 15, 33)) +>X : Symbol(X, Decl(main.ts, 15, 24)) +>X : Symbol(X, Decl(main.ts, 15, 24)) +>K : Symbol(K, Decl(main.ts, 15, 33)) + +const w = gc; +>w : Symbol(w, Decl(main.ts, 16, 5)) +>gc : Symbol(gc, Decl(ambient.d.ts, 35, 13)) + +const obsA = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 17, 5)) +>expand : Symbol(expand, Decl(main.ts, 14, 39)) +>oxa : Symbol(oxa, Decl(main.ts, 13, 13)) + +const obsB = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 18, 5)) +>expand : Symbol(expand, Decl(main.ts, 14, 39)) +>oxb : Symbol(oxb, Decl(main.ts, 14, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(UA, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(UB, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} +declare module "mm" { +>"mm" : Symbol("mm", Decl(ambient.d.ts, 31, 1)) + + export const C: unique symbol; +>C : Symbol(C, Decl(ambient.d.ts, 33, 16)) + + global { +>global : Symbol(global, Decl(ambient.d.ts, 33, 34)) + + const gc: { c: typeof C }; +>gc : Symbol(gc, Decl(ambient.d.ts, 35, 13)) +>c : Symbol(c, Decl(ambient.d.ts, 35, 19)) +>C : Symbol(C, Decl(ambient.d.ts, 33, 16)) + } +} + +=== /ua.d.ts === +import { v } from "ia"; +>v : Symbol(v, Decl(ua.d.ts, 0, 8)) + +export = v; +>v : Symbol(v, Decl(ua.d.ts, 0, 8)) + +export as namespace UA; +>UA : Symbol(UA, Decl(ua.d.ts, 1, 11)) + +=== /ub.d.ts === +import { v } from "ib"; +>v : Symbol(v, Decl(ub.d.ts, 0, 8)) + +export = v; +>v : Symbol(v, Decl(ub.d.ts, 0, 8)) + +export as namespace UB; +>UB : Symbol(UB, Decl(ub.d.ts, 1, 11)) + +=== /uf1.d.ts === +declare const x: 1; +>x : Symbol(x, Decl(uf1.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf1.d.ts, 0, 13)) + +export as namespace UF1; +>UF1 : Symbol(UF1, Decl(uf1.d.ts, 1, 11)) + +=== /uf2.d.ts === +declare const x: 2; +>x : Symbol(x, Decl(uf2.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf2.d.ts, 0, 13)) + +export as namespace UF2; +>UF2 : Symbol(UF2, Decl(uf2.d.ts, 1, 11)) + +=== /uf3.d.ts === +declare const x: 3; +>x : Symbol(x, Decl(uf3.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf3.d.ts, 0, 13)) + +export as namespace UF3; +>UF3 : Symbol(UF3, Decl(uf3.d.ts, 1, 11)) + +=== /uf4.d.ts === +declare const x: 4; +>x : Symbol(x, Decl(uf4.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf4.d.ts, 0, 13)) + +export as namespace UF4; +>UF4 : Symbol(UF4, Decl(uf4.d.ts, 1, 11)) + +=== /uf5.d.ts === +declare const x: 5; +>x : Symbol(x, Decl(uf5.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf5.d.ts, 0, 13)) + +export as namespace UF5; +>UF5 : Symbol(UF5, Decl(uf5.d.ts, 1, 11)) + +=== /uf6.d.ts === +declare const x: 6; +>x : Symbol(x, Decl(uf6.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf6.d.ts, 0, 13)) + +export as namespace UF6; +>UF6 : Symbol(UF6, Decl(uf6.d.ts, 1, 11)) + +=== /uf7.d.ts === +declare const x: 7; +>x : Symbol(x, Decl(uf7.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf7.d.ts, 0, 13)) + +export as namespace UF7; +>UF7 : Symbol(UF7, Decl(uf7.d.ts, 1, 11)) + +=== /uf8.d.ts === +declare const x: 8; +>x : Symbol(x, Decl(uf8.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf8.d.ts, 0, 13)) + +export as namespace UF8; +>UF8 : Symbol(UF8, Decl(uf8.d.ts, 1, 11)) + +=== /uf9.d.ts === +declare const x: 9; +>x : Symbol(x, Decl(uf9.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf9.d.ts, 0, 13)) + +export as namespace UF9; +>UF9 : Symbol(UF9, Decl(uf9.d.ts, 1, 11)) + +=== /uf10.d.ts === +declare const x: 10; +>x : Symbol(x, Decl(uf10.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf10.d.ts, 0, 13)) + +export as namespace UF10; +>UF10 : Symbol(UF10, Decl(uf10.d.ts, 1, 11)) + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.types new file mode 100644 index 0000000000000..cb6e79ef1518c --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.types @@ -0,0 +1,258 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitUmdGlobalAliasesOrder.ts] //// + +=== /main.ts === +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +const w = gc; +>w : { c: typeof import("mm").C; } +>gc : { c: typeof import("mm").C; } + +const obsA = expand(); +>obsA : { pb: 0; readonly mb: 1; v: 0; } +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +const obsB = expand(); +>obsB : { v: 0; } +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "mm" { +>"mm" : typeof import("mm") + + export const C: unique symbol; +>C : unique symbol + + global { +>global : typeof global + + const gc: { c: typeof C }; +>gc : { c: typeof C; } +>c : unique symbol +>C : unique symbol + } +} + +=== /ua.d.ts === +import { v } from "ia"; +>v : 0 + +export = v; +>v : 0 + +export as namespace UA; +>UA : 0 + +=== /ub.d.ts === +import { v } from "ib"; +>v : 0 + +export = v; +>v : 0 + +export as namespace UB; +>UB : 0 + +=== /uf1.d.ts === +declare const x: 1; +>x : 1 + +export = x; +>x : 1 + +export as namespace UF1; +>UF1 : 1 + +=== /uf2.d.ts === +declare const x: 2; +>x : 2 + +export = x; +>x : 2 + +export as namespace UF2; +>UF2 : 2 + +=== /uf3.d.ts === +declare const x: 3; +>x : 3 + +export = x; +>x : 3 + +export as namespace UF3; +>UF3 : 3 + +=== /uf4.d.ts === +declare const x: 4; +>x : 4 + +export = x; +>x : 4 + +export as namespace UF4; +>UF4 : 4 + +=== /uf5.d.ts === +declare const x: 5; +>x : 5 + +export = x; +>x : 5 + +export as namespace UF5; +>UF5 : 5 + +=== /uf6.d.ts === +declare const x: 6; +>x : 6 + +export = x; +>x : 6 + +export as namespace UF6; +>UF6 : 6 + +=== /uf7.d.ts === +declare const x: 7; +>x : 7 + +export = x; +>x : 7 + +export as namespace UF7; +>UF7 : 7 + +=== /uf8.d.ts === +declare const x: 8; +>x : 8 + +export = x; +>x : 8 + +export as namespace UF8; +>UF8 : 8 + +=== /uf9.d.ts === +declare const x: 9; +>x : 9 + +export = x; +>x : 9 + +export as namespace UF9; +>UF9 : 9 + +=== /uf10.d.ts === +declare const x: 10; +>x : 10 + +export = x; +>x : 10 + +export as namespace UF10; +>UF10 : 10 + From 77f8133b5665e4b11ac7242b0c36603520b7b9b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 11:54:14 +0200 Subject: [PATCH 09/35] Check spelling suggestion candidates in a stable order --- tsc/internal/checker/checker.go | 6 +- ...gnosticsSpellingSuggestionOrder.errors.txt | 126 +++++++++ ...DiagnosticsSpellingSuggestionOrder.symbols | 257 ++++++++++++++++++ ...kyDiagnosticsSpellingSuggestionOrder.types | 243 +++++++++++++++++ 4 files changed, 631 insertions(+), 1 deletion(-) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.types diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index ade17f26175b7..45e07507c6797 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -1848,7 +1848,11 @@ func (c *Checker) getSuggestionForSymbolNameLookup(symbols ast.SymbolTable, name if meaning&ast.SymbolFlagsGlobalLookup != 0 { extras = getPrimitiveTypeAliasSuggestions(symbols) } - return c.getSpellingSuggestionForName(name, core.ConcatenateSeq(maps.Values(symbols), extras), meaning) + // Checking a candidate alias resolves it, which creates types, so visit aliases last and in a stable order + // rather than in the random iteration order of the symbol table. + candidates := make([]*ast.Symbol, 0, len(symbols)) + c.forEachSymbolInResolutionOrder(symbols, func(symbol *ast.Symbol) { candidates = append(candidates, symbol) }) + return c.getSpellingSuggestionForName(name, core.ConcatenateSeq(slices.Values(candidates), extras), meaning) } // Given a name and a list of symbols whose names are *not* equal to the name, return a spelling suggestion if there is diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.errors.txt b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.errors.txt new file mode 100644 index 0000000000000..d8667784e78ea --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.errors.txt @@ -0,0 +1,126 @@ +/main.ts(17,11): error TS2304: Cannot find name 'zz'. +/main.ts(18,7): error TS2322: Type '{ pb: 0; readonly mb: 1; v: 0; }' is not assignable to type 'never'. +/main.ts(19,7): error TS2322: Type '{ v: 0; }' is not assignable to type 'never'. + + +==== /main.ts (3 errors) ==== + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + declare const oxa: typeof import("xa"); + declare const oxb: typeof import("xb"); + declare function expand(): { [K in keyof X]: X[K] }; + const q = zz; + ~~ +!!! error TS2304: Cannot find name 'zz'. + const obsA: never = expand(); + ~~~~ +!!! error TS2322: Type '{ pb: 0; readonly mb: 1; v: 0; }' is not assignable to type 'never'. + const obsB: never = expand(); + ~~~~ +!!! error TS2322: Type '{ v: 0; }' is not assignable to type 'never'. + +==== /ambient.d.ts (0 errors) ==== + declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; + } + declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; + } + declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + +==== /ua.d.ts (0 errors) ==== + import { v } from "ia"; + export = v; + export as namespace UA; + +==== /ub.d.ts (0 errors) ==== + import { v } from "ib"; + export = v; + export as namespace UB; + +==== /uf1.d.ts (0 errors) ==== + declare const x: 1; + export = x; + export as namespace UF1; + +==== /uf2.d.ts (0 errors) ==== + declare const x: 2; + export = x; + export as namespace UF2; + +==== /uf3.d.ts (0 errors) ==== + declare const x: 3; + export = x; + export as namespace UF3; + +==== /uf4.d.ts (0 errors) ==== + declare const x: 4; + export = x; + export as namespace UF4; + +==== /uf5.d.ts (0 errors) ==== + declare const x: 5; + export = x; + export as namespace UF5; + +==== /uf6.d.ts (0 errors) ==== + declare const x: 6; + export = x; + export as namespace UF6; + +==== /uf7.d.ts (0 errors) ==== + declare const x: 7; + export = x; + export as namespace UF7; + +==== /uf8.d.ts (0 errors) ==== + declare const x: 8; + export = x; + export as namespace UF8; + +==== /uf9.d.ts (0 errors) ==== + declare const x: 9; + export = x; + export as namespace UF9; + +==== /uf10.d.ts (0 errors) ==== + declare const x: 10; + export = x; + export as namespace UF10; + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.symbols new file mode 100644 index 0000000000000..c855f73560d36 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.symbols @@ -0,0 +1,257 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.ts] //// + +=== /main.ts === +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(main.ts, 13, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(main.ts, 14, 13)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 14, 39)) +>X : Symbol(X, Decl(main.ts, 15, 24)) +>K : Symbol(K, Decl(main.ts, 15, 33)) +>X : Symbol(X, Decl(main.ts, 15, 24)) +>X : Symbol(X, Decl(main.ts, 15, 24)) +>K : Symbol(K, Decl(main.ts, 15, 33)) + +const q = zz; +>q : Symbol(q, Decl(main.ts, 16, 5)) + +const obsA: never = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 17, 5)) +>expand : Symbol(expand, Decl(main.ts, 14, 39)) +>oxa : Symbol(oxa, Decl(main.ts, 13, 13)) + +const obsB: never = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 18, 5)) +>expand : Symbol(expand, Decl(main.ts, 14, 39)) +>oxb : Symbol(oxb, Decl(main.ts, 14, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(UA, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(UB, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} + +=== /ua.d.ts === +import { v } from "ia"; +>v : Symbol(v, Decl(ua.d.ts, 0, 8)) + +export = v; +>v : Symbol(v, Decl(ua.d.ts, 0, 8)) + +export as namespace UA; +>UA : Symbol(UA, Decl(ua.d.ts, 1, 11)) + +=== /ub.d.ts === +import { v } from "ib"; +>v : Symbol(v, Decl(ub.d.ts, 0, 8)) + +export = v; +>v : Symbol(v, Decl(ub.d.ts, 0, 8)) + +export as namespace UB; +>UB : Symbol(UB, Decl(ub.d.ts, 1, 11)) + +=== /uf1.d.ts === +declare const x: 1; +>x : Symbol(x, Decl(uf1.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf1.d.ts, 0, 13)) + +export as namespace UF1; +>UF1 : Symbol(UF1, Decl(uf1.d.ts, 1, 11)) + +=== /uf2.d.ts === +declare const x: 2; +>x : Symbol(x, Decl(uf2.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf2.d.ts, 0, 13)) + +export as namespace UF2; +>UF2 : Symbol(UF2, Decl(uf2.d.ts, 1, 11)) + +=== /uf3.d.ts === +declare const x: 3; +>x : Symbol(x, Decl(uf3.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf3.d.ts, 0, 13)) + +export as namespace UF3; +>UF3 : Symbol(UF3, Decl(uf3.d.ts, 1, 11)) + +=== /uf4.d.ts === +declare const x: 4; +>x : Symbol(x, Decl(uf4.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf4.d.ts, 0, 13)) + +export as namespace UF4; +>UF4 : Symbol(UF4, Decl(uf4.d.ts, 1, 11)) + +=== /uf5.d.ts === +declare const x: 5; +>x : Symbol(x, Decl(uf5.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf5.d.ts, 0, 13)) + +export as namespace UF5; +>UF5 : Symbol(UF5, Decl(uf5.d.ts, 1, 11)) + +=== /uf6.d.ts === +declare const x: 6; +>x : Symbol(x, Decl(uf6.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf6.d.ts, 0, 13)) + +export as namespace UF6; +>UF6 : Symbol(UF6, Decl(uf6.d.ts, 1, 11)) + +=== /uf7.d.ts === +declare const x: 7; +>x : Symbol(x, Decl(uf7.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf7.d.ts, 0, 13)) + +export as namespace UF7; +>UF7 : Symbol(UF7, Decl(uf7.d.ts, 1, 11)) + +=== /uf8.d.ts === +declare const x: 8; +>x : Symbol(x, Decl(uf8.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf8.d.ts, 0, 13)) + +export as namespace UF8; +>UF8 : Symbol(UF8, Decl(uf8.d.ts, 1, 11)) + +=== /uf9.d.ts === +declare const x: 9; +>x : Symbol(x, Decl(uf9.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf9.d.ts, 0, 13)) + +export as namespace UF9; +>UF9 : Symbol(UF9, Decl(uf9.d.ts, 1, 11)) + +=== /uf10.d.ts === +declare const x: 10; +>x : Symbol(x, Decl(uf10.d.ts, 0, 13)) + +export = x; +>x : Symbol(x, Decl(uf10.d.ts, 0, 13)) + +export as namespace UF10; +>UF10 : Symbol(UF10, Decl(uf10.d.ts, 1, 11)) + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.types new file mode 100644 index 0000000000000..0c8a7c9521634 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.types @@ -0,0 +1,243 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsSpellingSuggestionOrder.ts] //// + +=== /main.ts === +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +const q = zz; +>q : any +>zz : any + +const obsA: never = expand(); +>obsA : never +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +const obsB: never = expand(); +>obsB : never +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} + +=== /ua.d.ts === +import { v } from "ia"; +>v : 0 + +export = v; +>v : 0 + +export as namespace UA; +>UA : 0 + +=== /ub.d.ts === +import { v } from "ib"; +>v : 0 + +export = v; +>v : 0 + +export as namespace UB; +>UB : 0 + +=== /uf1.d.ts === +declare const x: 1; +>x : 1 + +export = x; +>x : 1 + +export as namespace UF1; +>UF1 : 1 + +=== /uf2.d.ts === +declare const x: 2; +>x : 2 + +export = x; +>x : 2 + +export as namespace UF2; +>UF2 : 2 + +=== /uf3.d.ts === +declare const x: 3; +>x : 3 + +export = x; +>x : 3 + +export as namespace UF3; +>UF3 : 3 + +=== /uf4.d.ts === +declare const x: 4; +>x : 4 + +export = x; +>x : 4 + +export as namespace UF4; +>UF4 : 4 + +=== /uf5.d.ts === +declare const x: 5; +>x : 5 + +export = x; +>x : 5 + +export as namespace UF5; +>UF5 : 5 + +=== /uf6.d.ts === +declare const x: 6; +>x : 6 + +export = x; +>x : 6 + +export as namespace UF6; +>UF6 : 6 + +=== /uf7.d.ts === +declare const x: 7; +>x : 7 + +export = x; +>x : 7 + +export as namespace UF7; +>UF7 : 7 + +=== /uf8.d.ts === +declare const x: 8; +>x : 8 + +export = x; +>x : 8 + +export as namespace UF8; +>UF8 : 8 + +=== /uf9.d.ts === +declare const x: 9; +>x : 9 + +export = x; +>x : 9 + +export as namespace UF9; +>UF9 : 9 + +=== /uf10.d.ts === +declare const x: 10; +>x : 10 + +export = x; +>x : 10 + +export as namespace UF10; +>UF10 : 10 + From 9fb3d00f207d6c19234cb228b3f60e2a91b63a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 11:57:19 +0200 Subject: [PATCH 10/35] Create index signature sibling types in a stable order --- tsc/internal/checker/checker.go | 6 +- tsc/internal/checker/emitresolver.go | 1 + tsc/internal/execute/tsctests/tsc_test.go | 37 +++ ...gnature-sibling-types-in-a-stable-order.js | 303 ++++++++++++++++++ 4 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-index-signature-sibling-types-in-a-stable-order.js diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 45e07507c6797..3d6b0e1f428b4 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -20089,7 +20089,11 @@ func (c *Checker) resolveDeclaredMembers(t *Type) *InterfaceType { func (c *Checker) getIndexInfosOfSymbol(symbol *ast.Symbol) []*IndexInfo { indexSymbol := c.getIndexSymbol(symbol) if indexSymbol != nil { - return c.getIndexInfosOfIndexSymbol(indexSymbol, slices.Collect(maps.Values(c.getMembersOfSymbol(symbol)))) + // The types of the siblings are created in this order, so sort them rather than using the random iteration + // order of the symbol table. + siblingSymbols := slices.Collect(maps.Values(c.getMembersOfSymbol(symbol))) + c.sortSymbols(siblingSymbols) + return c.getIndexInfosOfIndexSymbol(indexSymbol, siblingSymbols) } return nil } diff --git a/tsc/internal/checker/emitresolver.go b/tsc/internal/checker/emitresolver.go index f0058eb2b28e3..619e8ec645fda 100644 --- a/tsc/internal/checker/emitresolver.go +++ b/tsc/internal/checker/emitresolver.go @@ -754,6 +754,7 @@ func (r *EmitResolver) CreateLateBoundIndexSignatures(container *ast.Node, enclo var instanceInfos []*IndexInfo if instanceIndexSymbol != nil { siblingSymbols := slices.Collect(maps.Values(r.checker.getMembersOfSymbol(sym))) + r.checker.sortSymbols(siblingSymbols) instanceInfos = r.checker.getIndexInfosOfIndexSymbol(instanceIndexSymbol, siblingSymbols) } diff --git a/tsc/internal/execute/tsctests/tsc_test.go b/tsc/internal/execute/tsctests/tsc_test.go index 519ba582c98da..a2e326f9baadd 100644 --- a/tsc/internal/execute/tsctests/tsc_test.go +++ b/tsc/internal/execute/tsctests/tsc_test.go @@ -5088,6 +5088,43 @@ func TestGenerateTrace(t *testing.T) { files: generateTraceStableOrderFiles(), commandLineArgs: []string{"--generateTrace", "/home/src/workspaces/project/trace", "--singleThreaded"}, }, + { + subScenario: "generateTrace creates index signature sibling types in a stable order", + files: FileMap{ + "/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(` + { + "compilerOptions": { + "strict": true, + "skipLibCheck": true, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "out" + }, + "files": ["main.ts", "ambient.d.ts"] + }`), + "/home/src/workspaces/project/ambient.d.ts": stringtestutil.Dedent(` + declare const k1: string; + declare class C { + [k1]: { a: 1 }; + m1: { p1: 1 }; + m2: { p2: 2 }; + m3: { p3: 3 }; + m4: { p4: 4 }; + m5: { p5: 5 }; + m6: { p6: 6 }; + m7: { p7: 7 }; + m8: { p8: 8 }; + m9: { p9: 9 }; + m10: { p10: 10 }; + } + `), + "/home/src/workspaces/project/main.ts": stringtestutil.Dedent(` + declare function expand(): { [K in keyof X]: X[K] }; + export const w = expand(); + `), + }, + commandLineArgs: []string{"--generateTrace", "/home/src/workspaces/project/trace", "--singleThreaded"}, + }, } for _, c := range cases { diff --git a/tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-index-signature-sibling-types-in-a-stable-order.js b/tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-index-signature-sibling-types-in-a-stable-order.js new file mode 100644 index 0000000000000..8a7f9ce43ae68 --- /dev/null +++ b/tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-index-signature-sibling-types-in-a-stable-order.js @@ -0,0 +1,303 @@ +currentDirectory::/home/src/workspaces/project +useCaseSensitiveFileNames::true +Input:: +//// [/home/src/workspaces/project/ambient.d.ts] *new* +declare const k1: string; +declare class C { + [k1]: { a: 1 }; + m1: { p1: 1 }; + m2: { p2: 2 }; + m3: { p3: 3 }; + m4: { p4: 4 }; + m5: { p5: 5 }; + m6: { p6: 6 }; + m7: { p7: 7 }; + m8: { p8: 8 }; + m9: { p9: 9 }; + m10: { p10: 10 }; +} +//// [/home/src/workspaces/project/main.ts] *new* +declare function expand(): { [K in keyof X]: X[K] }; +export const w = expand(); +//// [/home/src/workspaces/project/tsconfig.json] *new* +{ + "compilerOptions": { + "strict": true, + "skipLibCheck": true, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "out" + }, + "files": ["main.ts", "ambient.d.ts"] +} + +tsgo --generateTrace /home/src/workspaces/project/trace --singleThreaded +ExitStatus:: Success +Output:: +//// [/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts] *Lib* +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +interface SymbolConstructor { + (desc?: string | number): symbol; + for(name: string): symbol; + readonly toStringTag: symbol; +} +declare var Symbol: SymbolConstructor; +interface Symbol { + readonly [Symbol.toStringTag]: string; +} +declare const console: { log(msg: any): void; }; +//// [/home/src/workspaces/project/out/main.d.ts] *new* +export declare const w: { + [x: string]: { + a: 1; + } | { + p1: 1; + } | { + p2: 2; + } | { + p3: 3; + } | { + p4: 4; + } | { + p5: 5; + } | { + p6: 6; + } | { + p7: 7; + } | { + p8: 8; + } | { + p9: 9; + } | { + p10: 10; + }; + m1: { + p1: 1; + }; + m2: { + p2: 2; + }; + m3: { + p3: 3; + }; + m4: { + p4: 4; + }; + m5: { + p5: 5; + }; + m6: { + p6: 6; + }; + m7: { + p7: 7; + }; + m8: { + p8: 8; + }; + m9: { + p9: 9; + }; + m10: { + p10: 10; + }; +}; + +//// [/home/src/workspaces/project/trace/legend.json] *new* +[ + { + "configFilePath": "/home/src/workspaces/project/tsconfig.json", + "tracePath": "/home/src/workspaces/project/trace/trace.json", + "typesPath": "/home/src/workspaces/project/trace/types_0.json", + "checkerId": 0 + } +] +//// [/home/src/workspaces/project/trace/trace.json] *new* +[ +{"pid":1,"tid":1,"ph":"M","cat":"__metadata","ts":1,"name":"process_name","args":{"name":"tsgo"}}, +{"pid":1,"tid":1,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"Main"}}, +{"pid":1,"tid":1,"ph":"M","cat":"disabled-by-default-devtools.timeline","ts":1,"name":"TracingStartedInBrowser"}, +{"pid":1,"tid":1,"ph":"B","cat":"program","ts":2,"name":"createProgram","args":{"configFilePath":"/home/src/workspaces/project/tsconfig.json"}}, +{"pid":1,"tid":181085097,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"B","cat":"parse","ts":3,"name":"createSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"E","cat":"parse","ts":4,"name":"createSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":483181977,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":483181977,"ph":"B","cat":"parse","ts":5,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":483181977,"ph":"E","cat":"parse","ts":6,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":100209852,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":100209852,"ph":"B","cat":"parse","ts":7,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":100209852,"ph":"E","cat":"parse","ts":8,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"program","ts":9,"name":"createProgram","args":{"configFilePath":"/home/src/workspaces/project/tsconfig.json"}}, +{"pid":1,"tid":1,"ph":"B","cat":"bind","ts":10,"name":"bindSourceFiles"}, +{"pid":1,"tid":483181977,"ph":"B","cat":"bind","ts":11,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":483181977,"ph":"E","cat":"bind","ts":12,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":100209852,"ph":"B","cat":"bind","ts":13,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":100209852,"ph":"E","cat":"bind","ts":14,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":181085097,"ph":"B","cat":"bind","ts":15,"name":"bindSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"E","cat":"bind","ts":16,"name":"bindSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"bind","ts":17,"name":"bindSourceFiles"}, +{"pid":1,"tid":1,"ph":"B","cat":"check","ts":18,"name":"checkSourceFiles"}, +{"pid":1,"tid":2,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"checker:0"}}, +{"pid":1,"tid":2,"ph":"B","cat":"check","ts":19,"name":"checkSourceFile","args":{"checkerId":0,"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":2,"ph":"E","cat":"check","ts":20,"name":"checkSourceFile","args":{"checkerId":0,"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"check","ts":21,"name":"checkSourceFiles"}, +{"pid":1,"tid":1,"ph":"B","cat":"emit","ts":22,"name":"emit"}, +{"pid":1,"tid":100209852,"ph":"B","cat":"emit","ts":23,"name":"emit","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"B","cat":"emit","ts":24,"name":"emitDeclarationFileOrBundle","args":{"declarationFilePath":"/home/src/workspaces/project/out/main.d.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"emit","ts":25,"name":"emitDeclarationFileOrBundle","args":{"declarationFilePath":"/home/src/workspaces/project/out/main.d.ts"}}, +{"pid":1,"tid":100209852,"ph":"E","cat":"emit","ts":26,"name":"emit","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"emit","ts":27,"name":"emit"} +] + +//// [/home/src/workspaces/project/trace/types_0.json] *new* +[{"id":1,"intrinsicName":"any","recursionId":0,"flags":["Any"]}, +{"id":2,"intrinsicName":"any","recursionId":1,"flags":["Any"]}, +{"id":3,"intrinsicName":"any","recursionId":2,"flags":["Any"]}, +{"id":4,"intrinsicName":"any","recursionId":3,"flags":["Any"]}, +{"id":5,"intrinsicName":"error","recursionId":4,"flags":["Any"]}, +{"id":6,"intrinsicName":"unresolved","recursionId":5,"flags":["Any"]}, +{"id":7,"intrinsicName":"any","recursionId":6,"flags":["Any"]}, +{"id":8,"intrinsicName":"intrinsic","recursionId":7,"flags":["Any"]}, +{"id":9,"intrinsicName":"unknown","recursionId":8,"flags":["Unknown"]}, +{"id":10,"intrinsicName":"undefined","recursionId":9,"flags":["Undefined"]}, +{"id":11,"intrinsicName":"undefined","recursionId":10,"flags":["Undefined"]}, +{"id":12,"intrinsicName":"undefined","recursionId":11,"flags":["Undefined"]}, +{"id":13,"intrinsicName":"null","recursionId":12,"flags":["Null"]}, +{"id":14,"intrinsicName":"string","recursionId":13,"flags":["String"]}, +{"id":15,"intrinsicName":"number","recursionId":14,"flags":["Number"]}, +{"id":16,"intrinsicName":"bigint","recursionId":15,"flags":["BigInt"]}, +{"id":17,"recursionId":16,"flags":["BooleanLiteral"],"display":"false"}, +{"id":18,"recursionId":17,"flags":["BooleanLiteral"],"display":"false"}, +{"id":19,"recursionId":18,"flags":["BooleanLiteral"],"display":"true"}, +{"id":20,"recursionId":19,"flags":["BooleanLiteral"],"display":"true"}, +{"id":21,"recursionId":20,"unionTypes":[17,19],"flags":["Boolean","Union"],"display":"boolean"}, +{"id":22,"intrinsicName":"symbol","recursionId":21,"flags":["ESSymbol"]}, +{"id":23,"intrinsicName":"void","recursionId":22,"flags":["Void"]}, +{"id":24,"intrinsicName":"never","recursionId":23,"flags":["Never"]}, +{"id":25,"intrinsicName":"never","recursionId":24,"flags":["Never"]}, +{"id":26,"intrinsicName":"never","recursionId":25,"flags":["Never"]}, +{"id":27,"intrinsicName":"never","recursionId":26,"flags":["Never"]}, +{"id":28,"intrinsicName":"object","recursionId":27,"flags":["NonPrimitive"]}, +{"id":29,"recursionId":28,"unionTypes":[14,15],"flags":["Union"],"display":"string | number"}, +{"id":30,"recursionId":29,"unionTypes":[14,15,22],"flags":["Union"],"display":"string | number | symbol"}, +{"id":31,"recursionId":30,"unionTypes":[15,16],"flags":["Union"],"display":"number | bigint"}, +{"id":32,"recursionId":31,"flags":["TemplateLiteral"],"display":"`${number}`"}, +{"id":33,"recursionId":32,"unionTypes":[10,13,14,15,16,17,19],"flags":["Union"],"display":"string | number | bigint | boolean | null | undefined"}, +{"id":34,"intrinsicName":"never","recursionId":33,"flags":["Never"]}, +{"id":35,"recursionId":34,"flags":["Object"],"display":"{}"}, +{"id":36,"recursionId":35,"flags":["Object"],"display":"{}"}, +{"id":37,"recursionId":36,"flags":["Object"],"display":"{}"}, +{"id":38,"symbolName":"__type","recursionId":37,"flags":["Object"],"display":"{}"}, +{"id":39,"recursionId":38,"flags":["Object"],"display":"{}"}, +{"id":40,"recursionId":39,"unionTypes":[10,13,39],"flags":["Union"],"display":"{} | null | undefined"}, +{"id":41,"recursionId":40,"flags":["Object"],"display":"{}"}, +{"id":42,"recursionId":41,"flags":["Object"],"display":"{}"}, +{"id":43,"recursionId":42,"flags":["Object"],"display":"{}"}, +{"id":44,"recursionId":43,"flags":["Object"],"display":"{}"}, +{"id":45,"recursionId":44,"flags":["Object"],"display":"{}"}, +{"id":46,"recursionId":45,"flags":["TypeParameter"]}, +{"id":47,"recursionId":46,"flags":["TypeParameter"]}, +{"id":48,"recursionId":47,"flags":["TypeParameter"]}, +{"id":49,"recursionId":48,"flags":["TypeParameter"]}, +{"id":50,"recursionId":49,"flags":["TypeParameter"]}, +{"id":51,"recursionId":50,"flags":["StringLiteral"],"display":"\"\""}, +{"id":52,"recursionId":51,"flags":["NumberLiteral"],"display":"0"}, +{"id":53,"recursionId":52,"flags":["BigIntLiteral"],"display":"0n"}, +{"id":54,"recursionId":53,"flags":["StringLiteral"],"display":"\"bigint\""}, +{"id":55,"recursionId":54,"flags":["StringLiteral"],"display":"\"boolean\""}, +{"id":56,"recursionId":55,"flags":["StringLiteral"],"display":"\"function\""}, +{"id":57,"recursionId":56,"flags":["StringLiteral"],"display":"\"number\""}, +{"id":58,"recursionId":57,"flags":["StringLiteral"],"display":"\"object\""}, +{"id":59,"recursionId":58,"flags":["StringLiteral"],"display":"\"string\""}, +{"id":60,"recursionId":59,"flags":["StringLiteral"],"display":"\"symbol\""}, +{"id":61,"recursionId":60,"flags":["StringLiteral"],"display":"\"undefined\""}, +{"id":62,"recursionId":61,"unionTypes":[54,55,56,57,58,59,60,61],"flags":["Union"],"display":"\"bigint\" | \"boolean\" | \"function\" | \"number\" | \"object\" | \"string\" | \"symbol\" | \"undefined\""}, +{"id":63,"symbolName":"IArguments","recursionId":62,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":6,"character":1},"end":{"line":6,"character":24}},"flags":["Object"]}, +{"id":64,"symbolName":"globalThis","recursionId":63,"flags":["Object"],"display":"typeof globalThis"}, +{"id":65,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[66],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":66,"symbolName":"T","recursionId":65,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":17},"end":{"line":11,"character":18}},"flags":["TypeParameter"]}, +{"id":67,"symbolName":"Array","recursionId":64,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["TypeParameter"]}, +{"id":68,"symbolName":"Object","recursionId":66,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":8,"character":1},"end":{"line":8,"character":20}},"flags":["Object"]}, +{"id":69,"symbolName":"Function","recursionId":67,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":3,"character":1},"end":{"line":3,"character":22}},"flags":["Object"]}, +{"id":70,"symbolName":"CallableFunction","recursionId":68,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":4,"character":1},"end":{"line":4,"character":30}},"flags":["Object"]}, +{"id":71,"symbolName":"NewableFunction","recursionId":69,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":5,"character":1},"end":{"line":5,"character":29}},"flags":["Object"]}, +{"id":72,"symbolName":"String","recursionId":70,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":10,"character":1},"end":{"line":10,"character":34}},"flags":["Object"]}, +{"id":73,"symbolName":"Number","recursionId":71,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":7,"character":1},"end":{"line":7,"character":41}},"flags":["Object"]}, +{"id":74,"symbolName":"Boolean","recursionId":72,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":2,"character":1},"end":{"line":2,"character":21}},"flags":["Object"]}, +{"id":75,"symbolName":"RegExp","recursionId":73,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":9,"character":1},"end":{"line":9,"character":20}},"flags":["Object"]}, +{"id":76,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[1],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":77,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[2],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":78,"symbolName":"ReadonlyArray","recursionId":74,"instantiatedType":78,"typeArguments":[79],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":1},"end":{"line":12,"character":30}},"flags":["Object"]}, +{"id":79,"symbolName":"T","recursionId":75,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":25},"end":{"line":12,"character":26}},"flags":["TypeParameter"]}, +{"id":80,"symbolName":"ReadonlyArray","recursionId":74,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":1},"end":{"line":12,"character":30}},"flags":["TypeParameter"]}, +{"id":81,"symbolName":"ReadonlyArray","recursionId":74,"instantiatedType":78,"typeArguments":[1],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":1},"end":{"line":12,"character":30}},"flags":["Object"]}, +{"id":82,"symbolName":"X","recursionId":76,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":25},"end":{"line":1,"character":26}},"flags":["TypeParameter"]}, +{"id":83,"symbolName":"K","recursionId":77,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":34},"end":{"line":1,"character":46}},"flags":["TypeParameter"]}, +{"id":84,"recursionId":78,"keyofType":82,"flags":["Index"]}, +{"id":85,"symbolName":"__type","recursionId":79,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":31},"end":{"line":1,"character":55}},"flags":["Object"]}, +{"id":86,"recursionId":76,"indexedAccessObjectType":82,"indexedAccessIndexType":83,"flags":["IndexedAccess"]}, +{"id":87,"symbolName":"Symbol","recursionId":80,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":18,"character":13},"end":{"line":18,"character":38}},"flags":["Object"]}, +{"id":88,"symbolName":"SymbolConstructor","recursionId":81,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":13,"character":1},"end":{"line":17,"character":2}},"flags":["Object"]}, +{"id":89,"symbolName":"toStringTag","recursionId":82,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":16,"character":5},"end":{"line":16,"character":34}},"flags":["UniqueESSymbol"]}, +{"id":90,"symbolName":"expand","recursionId":83,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":1},"end":{"line":1,"character":56}},"flags":["Object"],"display":"() => { [K in keyof X]: X[K]; }"}, +{"id":91,"symbolName":"C","recursionId":84,"instantiatedType":91,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":2,"character":1},"end":{"line":14,"character":2}},"flags":["Object"]}, +{"id":92,"symbolName":"C","recursionId":84,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":2,"character":1},"end":{"line":14,"character":2}},"flags":["TypeParameter"]}, +{"id":93,"symbolName":"__type","recursionId":84,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":31},"end":{"line":1,"character":55}},"flags":["Object"]}, +{"id":94,"symbolName":"K","recursionId":77,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":34},"end":{"line":1,"character":46}},"flags":["TypeParameter"]}, +{"id":95,"recursionId":85,"keyofType":91,"flags":["Index"]}, +{"id":96,"symbolName":"__type","recursionId":86,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":3,"character":11},"end":{"line":3,"character":19}},"flags":["Object"],"display":"{ a: 1; }"}, +{"id":97,"symbolName":"__type","recursionId":87,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":4,"character":9},"end":{"line":4,"character":18}},"flags":["Object"],"display":"{ p1: 1; }"}, +{"id":98,"symbolName":"__type","recursionId":88,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":5,"character":9},"end":{"line":5,"character":18}},"flags":["Object"],"display":"{ p2: 2; }"}, +{"id":99,"symbolName":"__type","recursionId":89,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":6,"character":9},"end":{"line":6,"character":18}},"flags":["Object"],"display":"{ p3: 3; }"}, +{"id":100,"symbolName":"__type","recursionId":90,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":7,"character":9},"end":{"line":7,"character":18}},"flags":["Object"],"display":"{ p4: 4; }"}, +{"id":101,"symbolName":"__type","recursionId":91,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":8,"character":9},"end":{"line":8,"character":18}},"flags":["Object"],"display":"{ p5: 5; }"}, +{"id":102,"symbolName":"__type","recursionId":92,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":9,"character":9},"end":{"line":9,"character":18}},"flags":["Object"],"display":"{ p6: 6; }"}, +{"id":103,"symbolName":"__type","recursionId":93,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":10,"character":9},"end":{"line":10,"character":18}},"flags":["Object"],"display":"{ p7: 7; }"}, +{"id":104,"symbolName":"__type","recursionId":94,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":11,"character":9},"end":{"line":11,"character":18}},"flags":["Object"],"display":"{ p8: 8; }"}, +{"id":105,"symbolName":"__type","recursionId":95,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":12,"character":9},"end":{"line":12,"character":18}},"flags":["Object"],"display":"{ p9: 9; }"}, +{"id":106,"symbolName":"__type","recursionId":96,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":13,"character":10},"end":{"line":13,"character":21}},"flags":["Object"],"display":"{ p10: 10; }"}, +{"id":107,"recursionId":97,"flags":["NumberLiteral"],"display":"10"}, +{"id":108,"recursionId":98,"flags":["NumberLiteral"],"display":"10"}, +{"id":109,"recursionId":99,"flags":["NumberLiteral"],"display":"9"}, +{"id":110,"recursionId":100,"flags":["NumberLiteral"],"display":"9"}, +{"id":111,"recursionId":101,"flags":["NumberLiteral"],"display":"8"}, +{"id":112,"recursionId":102,"flags":["NumberLiteral"],"display":"8"}, +{"id":113,"recursionId":103,"flags":["NumberLiteral"],"display":"7"}, +{"id":114,"recursionId":104,"flags":["NumberLiteral"],"display":"7"}, +{"id":115,"recursionId":105,"flags":["NumberLiteral"],"display":"6"}, +{"id":116,"recursionId":106,"flags":["NumberLiteral"],"display":"6"}, +{"id":117,"recursionId":107,"flags":["NumberLiteral"],"display":"5"}, +{"id":118,"recursionId":108,"flags":["NumberLiteral"],"display":"5"}, +{"id":119,"recursionId":109,"flags":["NumberLiteral"],"display":"4"}, +{"id":120,"recursionId":110,"flags":["NumberLiteral"],"display":"4"}, +{"id":121,"recursionId":111,"flags":["NumberLiteral"],"display":"3"}, +{"id":122,"recursionId":112,"flags":["NumberLiteral"],"display":"3"}, +{"id":123,"recursionId":113,"flags":["NumberLiteral"],"display":"2"}, +{"id":124,"recursionId":114,"flags":["NumberLiteral"],"display":"2"}, +{"id":125,"recursionId":115,"flags":["NumberLiteral"],"display":"1"}, +{"id":126,"recursionId":116,"flags":["NumberLiteral"],"display":"1"}, +{"id":127,"recursionId":117,"unionTypes":[96,97,98,99,100,101,102,103,104,105,106],"flags":["Union"],"display":"{ a: 1; } | { p1: 1; } | { p2: 2; } | { p3: 3; } | { p4: 4; } | { p5: 5; } | { p6: 6; } | { p7: 7; } | { p8: 8; } | { p9: 9; } | { p10: 10; }"}, +{"id":128,"recursionId":118,"flags":["StringLiteral"],"display":"\"m1\""}, +{"id":129,"recursionId":119,"flags":["StringLiteral"],"display":"\"m2\""}, +{"id":130,"recursionId":120,"flags":["StringLiteral"],"display":"\"m3\""}, +{"id":131,"recursionId":121,"flags":["StringLiteral"],"display":"\"m4\""}, +{"id":132,"recursionId":122,"flags":["StringLiteral"],"display":"\"m5\""}, +{"id":133,"recursionId":123,"flags":["StringLiteral"],"display":"\"m6\""}, +{"id":134,"recursionId":124,"flags":["StringLiteral"],"display":"\"m7\""}, +{"id":135,"recursionId":125,"flags":["StringLiteral"],"display":"\"m8\""}, +{"id":136,"recursionId":126,"flags":["StringLiteral"],"display":"\"m9\""}, +{"id":137,"recursionId":127,"flags":["StringLiteral"],"display":"\"m10\""}, +{"id":138,"recursionId":128,"unionTypes":[14,15],"flags":["Union"],"display":"keyof C"}] + + From 3f965da4c5e9726abffc1822ba78931dd942a3d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Oct 2026 11:08:59 +0200 Subject: [PATCH 11/35] Only sort scope variables whose types are not resolved yet --- tsc/internal/checker/symbolaccessibility.go | 28 +++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index a5a4b89a2c0e1..d882c66238241 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -144,21 +144,29 @@ func (c *Checker) getWithAlternativeContainers(container *ast.Symbol, symbol *as c.getDeclaredTypeOfSymbol(container).flags&TypeFlagsObject != 0 { c.someSymbolTableInScope(enclosingDeclaration, func(t ast.SymbolTable, _ symbolTableID, _ bool, _ bool, _ *ast.Node) bool { found := false - var values []*ast.Symbol - for _, s := range t { - if s.Flags()&leftMeaning != 0 { - values = append(values, s) - } - } - // Getting the types of the values can create types and resolve aliases, so do it in a stable order - // rather than in the random iteration order of the symbol table. - c.sortSymbols(values) - for _, s := range values { + check := func(s *ast.Symbol) { if c.getTypeOfSymbol(s) == c.getDeclaredTypeOfSymbol(container) { variableMatches = append(variableMatches, s) found = true } } + var unresolved []*ast.Symbol + for _, s := range t { + if s.Flags()&leftMeaning == 0 { + continue + } + if links := c.valueSymbolLinks.TryGet(s); links != nil && links.resolvedType != nil { + check(s) + } else { + unresolved = append(unresolved, s) + } + } + // Getting the types that are not resolved yet can create types and resolve aliases, so do it in a stable + // order rather than in the random iteration order of the symbol table. + c.sortSymbols(unresolved) + for _, s := range unresolved { + check(s) + } return found }) c.sortSymbols(variableMatches) From 29a4a2e51942c45bed264b524b62bf347bda4b82 Mon Sep 17 00:00:00 2001 From: Dimitri Mitropoulos Date: Fri, 16 Oct 2026 21:00:43 -0400 Subject: [PATCH 12/35] Pass symbol table keys to forEachSymbolInResolutionOrder A symbol's key in a table is not always its name: a module augmentation can merge a named declaration into a default export, which stays keyed "default". extendExportSymbols and createAccessFromSymbolChain use the key, so the helper passes it along with the symbol, and sorts aliases by key when they compare equal. --- tsc/internal/checker/checker.go | 9 +-- tsc/internal/checker/nodebuilderimpl.go | 6 +- tsc/internal/checker/symbolaccessibility.go | 35 ++++++--- ...portStarSkipsNamedDefaultExport.errors.txt | 24 ++++++ .../exportStarSkipsNamedDefaultExport.js | 73 +++++++++++++++++++ .../exportStarSkipsNamedDefaultExport.symbols | 40 ++++++++++ .../exportStarSkipsNamedDefaultExport.types | 37 ++++++++++ .../exportStarSkipsNamedDefaultExport.ts | 25 +++++++ 8 files changed, 229 insertions(+), 20 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.js create mode 100644 tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.types create mode 100644 tsc/testdata/tests/cases/compiler/exportStarSkipsNamedDefaultExport.ts diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 3d6b0e1f428b4..cd0426a073195 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -1851,7 +1851,7 @@ func (c *Checker) getSuggestionForSymbolNameLookup(symbols ast.SymbolTable, name // Checking a candidate alias resolves it, which creates types, so visit aliases last and in a stable order // rather than in the random iteration order of the symbol table. candidates := make([]*ast.Symbol, 0, len(symbols)) - c.forEachSymbolInResolutionOrder(symbols, func(symbol *ast.Symbol) { candidates = append(candidates, symbol) }) + c.forEachSymbolInResolutionOrder(symbols, func(_ string, symbol *ast.Symbol) { candidates = append(candidates, symbol) }) return c.getSpellingSuggestionForName(name, core.ConcatenateSeq(slices.Values(candidates), extras), meaning) } @@ -15242,7 +15242,7 @@ func (c *Checker) reportNonExportedMember(name *ast.Node, declarationName string // Looking for the export resolves aliases, which creates types, so do it in a stable order rather than // in the random iteration order of the symbol table. var exportedSymbol *ast.Symbol - c.forEachSymbolInResolutionOrder(exports, func(symbol *ast.Symbol) { + c.forEachSymbolInResolutionOrder(exports, func(_ string, symbol *ast.Symbol) { if exportedSymbol == nil && c.getSymbolIfSameReference(symbol, localSymbol) != nil { exportedSymbol = symbol } @@ -16643,7 +16643,7 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as } // A CommonJS module defined by an 'export=' might also export typedefs, stored on the original module if originalModule != nil && len(originalModule.Exports()) > 1 { - c.forEachSymbolInResolutionOrder(originalModule.Exports(), func(symbol *ast.Symbol) { + c.forEachSymbolInResolutionOrder(originalModule.Exports(), func(_ string, symbol *ast.Symbol) { if symbol.Name() == ast.InternalSymbolNameExportEquals || symbol.Name() == ast.InternalSymbolNameExportStar { return } @@ -16668,8 +16668,7 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as func (c *Checker) extendExportSymbols(target ast.SymbolTable, source ast.SymbolTable, lookupTable ExportCollisionTable, exportNode *ast.Node) { // Checking for collisions resolves aliases, which creates types, so visit aliases last and in a stable order // rather than in the random iteration order of the symbol table. - c.forEachSymbolInResolutionOrder(source, func(sourceSymbol *ast.Symbol) { - id := sourceSymbol.Name() + c.forEachSymbolInResolutionOrder(source, func(id string, sourceSymbol *ast.Symbol) { if id == ast.InternalSymbolNameDefault { return } diff --git a/tsc/internal/checker/nodebuilderimpl.go b/tsc/internal/checker/nodebuilderimpl.go index e9bfb02d3d2d0..ee695716b2e72 100644 --- a/tsc/internal/checker/nodebuilderimpl.go +++ b/tsc/internal/checker/nodebuilderimpl.go @@ -778,9 +778,9 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index symbolName = symbol.Name() } else { results := make(map[*ast.Symbol]string, 1) - b.ch.forEachSymbolInResolutionOrder(exports, func(ex *ast.Symbol) { - if b.ch.getSymbolIfSameReference(ex, symbol) != nil && !isLateBoundName(ex.Name()) && ex.Name() != ast.InternalSymbolNameExportEquals { - results[ex] = ex.Name() + b.ch.forEachSymbolInResolutionOrder(exports, func(name string, ex *ast.Symbol) { + if b.ch.getSymbolIfSameReference(ex, symbol) != nil && !isLateBoundName(name) && name != ast.InternalSymbolNameExportEquals { + results[ex] = name // break // must collect all results and sort them - exports are randomly iterated } }) diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index d882c66238241..477b5964be879 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -3,6 +3,7 @@ package checker import ( "cmp" "slices" + "strings" "github.com/microsoft/TypeScript/tsc/internal/ast" "github.com/microsoft/TypeScript/tsc/internal/collections" @@ -279,7 +280,7 @@ func (c *Checker) buildExternalModuleContainerIndex() { } container := c.getSymbolOfDeclaration(file.AsNode()) index.moduleOrder[container] = len(index.moduleOrder) - c.forEachSymbolInResolutionOrder(c.getExportsOfSymbol(container), func(exported *ast.Symbol) { + c.forEachSymbolInResolutionOrder(c.getExportsOfSymbol(container), func(_ string, exported *ast.Symbol) { index.add(c.getResolvedTarget(exported), container) }) if exportEquals := container.Exports()[ast.InternalSymbolNameExportEquals]; exportEquals != nil { @@ -289,22 +290,32 @@ func (c *Checker) buildExternalModuleContainerIndex() { index.complete = true } -// forEachSymbolInResolutionOrder calls f for each symbol of a symbol table, in an order that does not depend on the +// forEachSymbolInResolutionOrder calls f for each entry of a symbol table, in an order that does not depend on the // table's random iteration order wherever resolving the symbols can have side effects. Symbols that are not aliases // resolve to themselves and come first, in table order. Resolving an alias can create types, so aliases come last, -// sorted. -func (c *Checker) forEachSymbolInResolutionOrder(symbols ast.SymbolTable, f func(symbol *ast.Symbol)) { - var aliases []*ast.Symbol - for _, symbol := range symbols { +// sorted. f gets each symbol's key in the table, which is not always the symbol's name (a default export is keyed +// "default" under its declared name). +func (c *Checker) forEachSymbolInResolutionOrder(symbols ast.SymbolTable, f func(name string, symbol *ast.Symbol)) { + type entry struct { + name string + symbol *ast.Symbol + } + var aliases []entry + for name, symbol := range symbols { if symbol.Flags()&ast.SymbolFlagsAlias != 0 { - aliases = append(aliases, symbol) + aliases = append(aliases, entry{name, symbol}) } else { - f(symbol) + f(name, symbol) } } - c.sortSymbols(aliases) - for _, symbol := range aliases { - f(symbol) + slices.SortFunc(aliases, func(a, b entry) int { + if r := c.compareSymbols(a.symbol, b.symbol); r != 0 { + return r + } + return strings.Compare(a.name, b.name) + }) + for _, alias := range aliases { + f(alias.name, alias.symbol) } } @@ -456,7 +467,7 @@ func (c *Checker) getAliasForSymbolInContainer(container *ast.Symbol, symbol *as return quick } var candidates []*ast.Symbol - c.forEachSymbolInResolutionOrder(exports, func(exported *ast.Symbol) { + c.forEachSymbolInResolutionOrder(exports, func(_ string, exported *ast.Symbol) { if c.getSymbolIfSameReference(exported, symbol) != nil { candidates = append(candidates, exported) } diff --git a/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.errors.txt b/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.errors.txt new file mode 100644 index 0000000000000..c429753fd0a39 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.errors.txt @@ -0,0 +1,24 @@ +/d.ts(1,10): error TS2305: Module '"./c"' has no exported member 'I'. + + +==== /a.ts (0 errors) ==== + interface I {} + export default I; + export interface J {} + +==== /b.ts (0 errors) ==== + export {}; + declare module './a' { + export default interface I { x: number; } + } + +==== /c.ts (0 errors) ==== + export * from "./a"; + +==== /d.ts (1 errors) ==== + import { I, J } from "./c"; + ~ +!!! error TS2305: Module '"./c"' has no exported member 'I'. + export const i: I = { x: 0 }; + export const j: J = {}; + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.js b/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.js new file mode 100644 index 0000000000000..8b8f7e4235860 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.js @@ -0,0 +1,73 @@ +//// [tests/cases/compiler/exportStarSkipsNamedDefaultExport.ts] //// + +//// [a.ts] +interface I {} +export default I; +export interface J {} + +//// [b.ts] +export {}; +declare module './a' { + export default interface I { x: number; } +} + +//// [c.ts] +export * from "./a"; + +//// [d.ts] +import { I, J } from "./c"; +export const i: I = { x: 0 }; +export const j: J = {}; + + +//// [a.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//// [b.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//// [c.js] +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./a"), exports); +//// [d.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.j = exports.i = void 0; +exports.i = { x: 0 }; +exports.j = {}; + + +//// [a.d.ts] +interface I { +} +export default I; +export interface J { +} +//// [b.d.ts] +export {}; +declare module './a' { + export default interface I { + x: number; + } +} +//// [c.d.ts] +export * from "./a"; +//// [d.d.ts] +import { I, J } from "./c"; +export declare const i: I; +export declare const j: J; diff --git a/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.symbols b/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.symbols new file mode 100644 index 0000000000000..b1c1a85c0b06f --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.symbols @@ -0,0 +1,40 @@ +//// [tests/cases/compiler/exportStarSkipsNamedDefaultExport.ts] //// + +=== /a.ts === +interface I {} +>I : Symbol(I, Decl(a.ts, 0, 0), Decl(b.ts, 1, 22)) + +export default I; +>I : Symbol(I, Decl(a.ts, 0, 0), Decl(b.ts, 1, 22)) + +export interface J {} +>J : Symbol(J, Decl(a.ts, 1, 17)) + +=== /b.ts === +export {}; +declare module './a' { +>'./a' : Symbol("./a", Decl(a.ts, 0, 0), Decl(b.ts, 0, 10)) + + export default interface I { x: number; } +>I : Symbol(I, Decl(a.ts, 0, 0), Decl(b.ts, 1, 22)) +>x : Symbol(I.x, Decl(b.ts, 2, 32)) +} + +=== /c.ts === + +export * from "./a"; + +=== /d.ts === +import { I, J } from "./c"; +>I : Symbol(I, Decl(d.ts, 0, 8)) +>J : Symbol(J, Decl(d.ts, 0, 11)) + +export const i: I = { x: 0 }; +>i : Symbol(i, Decl(d.ts, 1, 12)) +>I : Symbol(I, Decl(d.ts, 0, 8)) +>x : Symbol(x, Decl(d.ts, 1, 21)) + +export const j: J = {}; +>j : Symbol(j, Decl(d.ts, 2, 12)) +>J : Symbol(J, Decl(d.ts, 0, 11)) + diff --git a/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.types b/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.types new file mode 100644 index 0000000000000..b9a61d4eb5ac0 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/exportStarSkipsNamedDefaultExport.types @@ -0,0 +1,37 @@ +//// [tests/cases/compiler/exportStarSkipsNamedDefaultExport.ts] //// + +=== /a.ts === +interface I {} +export default I; +>I : I + +export interface J {} + +=== /b.ts === +export {}; +declare module './a' { +>'./a' : typeof import("./a") + + export default interface I { x: number; } +>x : number +} + +=== /c.ts === + +export * from "./a"; + +=== /d.ts === +import { I, J } from "./c"; +>I : any +>J : any + +export const i: I = { x: 0 }; +>i : I +>{ x: 0 } : { x: number; } +>x : number +>0 : 0 + +export const j: J = {}; +>j : J +>{} : {} + diff --git a/tsc/testdata/tests/cases/compiler/exportStarSkipsNamedDefaultExport.ts b/tsc/testdata/tests/cases/compiler/exportStarSkipsNamedDefaultExport.ts new file mode 100644 index 0000000000000..e6f53e3d83519 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/exportStarSkipsNamedDefaultExport.ts @@ -0,0 +1,25 @@ +// @module: commonjs +// @target: es2015 +// @declaration: true + +// A module augmentation can merge a named declaration into a default export, so the +// default export's key in the module's exports is not the name of its symbol. + +// @Filename: /a.ts +interface I {} +export default I; +export interface J {} + +// @Filename: /b.ts +export {}; +declare module './a' { + export default interface I { x: number; } +} + +// @Filename: /c.ts +export * from "./a"; + +// @Filename: /d.ts +import { I, J } from "./c"; +export const i: I = { x: 0 }; +export const j: J = {}; From bd492f0137529cbf70dc5a9105a603c6a10d276b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 18 Oct 2026 19:43:40 +0200 Subject: [PATCH 13/35] Check export * collisions after collecting them, in a stable order --- tsc/internal/checker/checker.go | 30 ++- ...rtStarDeclarationCollisionOrder.errors.txt | 84 +++++++ ...xportStarDeclarationCollisionOrder.symbols | 215 ++++++++++++++++++ ...sExportStarDeclarationCollisionOrder.types | 200 ++++++++++++++++ ...ticsExportStarDeclarationCollisionOrder.ts | 82 +++++++ 5 files changed, 604 insertions(+), 7 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.types create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.ts diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index cd0426a073195..f4c88f38e7573 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -16666,11 +16666,14 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables */ func (c *Checker) extendExportSymbols(target ast.SymbolTable, source ast.SymbolTable, lookupTable ExportCollisionTable, exportNode *ast.Node) { - // Checking for collisions resolves aliases, which creates types, so visit aliases last and in a stable order - // rather than in the random iteration order of the symbol table. - c.forEachSymbolInResolutionOrder(source, func(id string, sourceSymbol *ast.Symbol) { + type collision struct { + id string + symbol *ast.Symbol + } + var collisions []collision + for id, sourceSymbol := range source { if id == ast.InternalSymbolNameDefault { - return + continue } targetSymbol := target[id] if targetSymbol == nil { @@ -16680,11 +16683,24 @@ func (c *Checker) extendExportSymbols(target ast.SymbolTable, source ast.SymbolT specifierText: scanner.GetTextOfNode(exportNode.ModuleSpecifier()), } } - } else if lookupTable != nil && exportNode != nil && c.resolveSymbol(targetSymbol) != c.resolveSymbol(sourceSymbol) { - s := lookupTable[id] - s.exportsWithDuplicate = append(s.exportsWithDuplicate, exportNode) + } else if lookupTable != nil && exportNode != nil { + collisions = append(collisions, collision{id, sourceSymbol}) } + } + // Checking a collision resolves the aliases on both sides, which creates types, so do it in a stable order rather + // than in the random iteration order of the symbol table. + slices.SortFunc(collisions, func(a, b collision) int { + if r := c.compareSymbols(a.symbol, b.symbol); r != 0 { + return r + } + return strings.Compare(a.id, b.id) }) + for _, collision := range collisions { + if c.resolveSymbol(target[collision.id]) != c.resolveSymbol(collision.symbol) { + s := lookupTable[collision.id] + s.exportsWithDuplicate = append(s.exportsWithDuplicate, exportNode) + } + } } func (c *Checker) ResolveAlias(symbol *ast.Symbol) (*ast.Symbol, bool) { diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.errors.txt b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.errors.txt new file mode 100644 index 0000000000000..a05bda29acf17 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.errors.txt @@ -0,0 +1,84 @@ +/main.ts(7,14): error TS2322: Type '{ pb: 0; readonly mb: 1; v: 0; }' is not assignable to type 'never'. +/main.ts(8,14): error TS2322: Type '{ v: 0; }' is not assignable to type 'never'. + + +==== /main.ts (2 errors) ==== + /// + import { f1 } from "m1"; + declare const oxa: typeof import("xa"); + declare const oxb: typeof import("xb"); + declare function expand(): { [K in keyof X]: X[K] }; + export const keep = f1; + export const obsA: never = expand(); + ~~~~ +!!! error TS2322: Type '{ pb: 0; readonly mb: 1; v: 0; }' is not assignable to type 'never'. + export const obsB: never = expand(); + ~~~~ +!!! error TS2322: Type '{ v: 0; }' is not assignable to type 'never'. + +==== /ambient.d.ts (0 errors) ==== + declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; + } + declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; + } + declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; + } + declare module "s1" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; + } + declare module "s2" { + export const a: 1; + export const b: 2; + export const g1: 1; + export const g2: 2; + export const g3: 3; + export const g4: 4; + export const g5: 5; + export const g6: 6; + export const g7: 7; + export const g8: 8; + export const g9: 9; + export const g10: 10; + } + declare module "m1" { + export * from "s1"; + export * from "s2"; + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.symbols new file mode 100644 index 0000000000000..d98ff5854668f --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.symbols @@ -0,0 +1,215 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.ts] //// + +=== /main.ts === +/// +import { f1 } from "m1"; +>f1 : Symbol(f1, Decl(main.ts, 1, 8)) + +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) + +export const keep = f1; +>keep : Symbol(keep, Decl(main.ts, 5, 12)) +>f1 : Symbol(f1, Decl(main.ts, 1, 8)) + +export const obsA: never = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 6, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +export const obsB: never = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 7, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} +declare module "s1" { +>"s1" : Symbol("s1", Decl(ambient.d.ts, 31, 1)) + + export { v as a } from "ia"; +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) +>a : Symbol(a, Decl(ambient.d.ts, 33, 12)) + + export { v as b } from "ib"; +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) +>b : Symbol(b, Decl(ambient.d.ts, 34, 12)) + + export const f1: 1; +>f1 : Symbol(f1, Decl(ambient.d.ts, 35, 16)) + + export const f2: 2; +>f2 : Symbol(f2, Decl(ambient.d.ts, 36, 16)) + + export const f3: 3; +>f3 : Symbol(f3, Decl(ambient.d.ts, 37, 16)) + + export const f4: 4; +>f4 : Symbol(f4, Decl(ambient.d.ts, 38, 16)) + + export const f5: 5; +>f5 : Symbol(f5, Decl(ambient.d.ts, 39, 16)) + + export const f6: 6; +>f6 : Symbol(f6, Decl(ambient.d.ts, 40, 16)) + + export const f7: 7; +>f7 : Symbol(f7, Decl(ambient.d.ts, 41, 16)) + + export const f8: 8; +>f8 : Symbol(f8, Decl(ambient.d.ts, 42, 16)) + + export const f9: 9; +>f9 : Symbol(f9, Decl(ambient.d.ts, 43, 16)) + + export const f10: 10; +>f10 : Symbol(f10, Decl(ambient.d.ts, 44, 16)) +} +declare module "s2" { +>"s2" : Symbol("s2", Decl(ambient.d.ts, 45, 1)) + + export const a: 1; +>a : Symbol(a, Decl(ambient.d.ts, 47, 16)) + + export const b: 2; +>b : Symbol(b, Decl(ambient.d.ts, 48, 16)) + + export const g1: 1; +>g1 : Symbol(g1, Decl(ambient.d.ts, 49, 16)) + + export const g2: 2; +>g2 : Symbol(g2, Decl(ambient.d.ts, 50, 16)) + + export const g3: 3; +>g3 : Symbol(g3, Decl(ambient.d.ts, 51, 16)) + + export const g4: 4; +>g4 : Symbol(g4, Decl(ambient.d.ts, 52, 16)) + + export const g5: 5; +>g5 : Symbol(g5, Decl(ambient.d.ts, 53, 16)) + + export const g6: 6; +>g6 : Symbol(g6, Decl(ambient.d.ts, 54, 16)) + + export const g7: 7; +>g7 : Symbol(g7, Decl(ambient.d.ts, 55, 16)) + + export const g8: 8; +>g8 : Symbol(g8, Decl(ambient.d.ts, 56, 16)) + + export const g9: 9; +>g9 : Symbol(g9, Decl(ambient.d.ts, 57, 16)) + + export const g10: 10; +>g10 : Symbol(g10, Decl(ambient.d.ts, 58, 16)) +} +declare module "m1" { +>"m1" : Symbol("m1", Decl(ambient.d.ts, 59, 1)) + + export * from "s1"; + export * from "s2"; +} + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.types new file mode 100644 index 0000000000000..58541f8aa49ff --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.types @@ -0,0 +1,200 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.ts] //// + +=== /main.ts === +/// +import { f1 } from "m1"; +>f1 : 1 + +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export const keep = f1; +>keep : 1 +>f1 : 1 + +export const obsA: never = expand(); +>obsA : never +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +export const obsB: never = expand(); +>obsB : never +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "s1" { +>"s1" : typeof import("s1") + + export { v as a } from "ia"; +>v : 0 +>a : 0 + + export { v as b } from "ib"; +>v : 0 +>b : 0 + + export const f1: 1; +>f1 : 1 + + export const f2: 2; +>f2 : 2 + + export const f3: 3; +>f3 : 3 + + export const f4: 4; +>f4 : 4 + + export const f5: 5; +>f5 : 5 + + export const f6: 6; +>f6 : 6 + + export const f7: 7; +>f7 : 7 + + export const f8: 8; +>f8 : 8 + + export const f9: 9; +>f9 : 9 + + export const f10: 10; +>f10 : 10 +} +declare module "s2" { +>"s2" : typeof import("s2") + + export const a: 1; +>a : 1 + + export const b: 2; +>b : 2 + + export const g1: 1; +>g1 : 1 + + export const g2: 2; +>g2 : 2 + + export const g3: 3; +>g3 : 3 + + export const g4: 4; +>g4 : 4 + + export const g5: 5; +>g5 : 5 + + export const g6: 6; +>g6 : 6 + + export const g7: 7; +>g7 : 7 + + export const g8: 8; +>g8 : 8 + + export const g9: 9; +>g9 : 9 + + export const g10: 10; +>g10 : 10 +} +declare module "m1" { +>"m1" : typeof import("m1") + + export * from "s1"; + export * from "s2"; +} + diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.ts new file mode 100644 index 0000000000000..886b93754bda6 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsExportStarDeclarationCollisionOrder.ts @@ -0,0 +1,82 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @noEmit: true +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "s1" { + export { v as a } from "ia"; + export { v as b } from "ib"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; +} +declare module "s2" { + export const a: 1; + export const b: 2; + export const g1: 1; + export const g2: 2; + export const g3: 3; + export const g4: 4; + export const g5: 5; + export const g6: 6; + export const g7: 7; + export const g8: 8; + export const g9: 9; + export const g10: 10; +} +declare module "m1" { + export * from "s1"; + export * from "s2"; +} + +// @Filename: /main.ts +/// +import { f1 } from "m1"; +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +export const keep = f1; +export const obsA: never = expand(); +export const obsB: never = expand(); From 60507f556913f906aee0f55cf39082c8be13d642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 18 Oct 2026 19:50:32 +0200 Subject: [PATCH 14/35] Only sort unresolved aliases and let forEachSymbolInResolutionOrder stop early --- tsc/internal/checker/checker.go | 46 ++++++++------------- tsc/internal/checker/nodebuilderimpl.go | 10 +++-- tsc/internal/checker/symbolaccessibility.go | 42 ++++++++++++------- 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index f4c88f38e7573..7ea44c73f6d55 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -1851,7 +1851,10 @@ func (c *Checker) getSuggestionForSymbolNameLookup(symbols ast.SymbolTable, name // Checking a candidate alias resolves it, which creates types, so visit aliases last and in a stable order // rather than in the random iteration order of the symbol table. candidates := make([]*ast.Symbol, 0, len(symbols)) - c.forEachSymbolInResolutionOrder(symbols, func(_ string, symbol *ast.Symbol) { candidates = append(candidates, symbol) }) + c.forEachSymbolInResolutionOrder(symbols, func(_ string, symbol *ast.Symbol) bool { + candidates = append(candidates, symbol) + return false + }) return c.getSpellingSuggestionForName(name, core.ConcatenateSeq(slices.Values(candidates), extras), meaning) } @@ -5923,28 +5926,9 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) { } func (c *Checker) hasExportedMembersOfKind(moduleSymbol *ast.Symbol, kind ast.SymbolFlags) bool { - // Resolving an alias can create types, so resolve aliases last and in a stable order rather than in the random - // iteration order of the symbol table. - var aliases []*ast.Symbol - for _, symbol := range moduleSymbol.Exports() { - if symbol.Name() == ast.InternalSymbolNameExportEquals { - continue - } - if symbol.Flags()&ast.SymbolFlagsAlias != 0 { - aliases = append(aliases, symbol) - continue - } - if c.getSymbolFlags(symbol)&kind != 0 { - return true - } - } - c.sortSymbols(aliases) - for _, symbol := range aliases { - if c.getSymbolFlags(symbol)&kind != 0 { - return true - } - } - return false + return c.forEachSymbolInResolutionOrder(moduleSymbol.Exports(), func(_ string, symbol *ast.Symbol) bool { + return symbol.Name() != ast.InternalSymbolNameExportEquals && c.getSymbolFlags(symbol)&kind != 0 + }) } func (c *Checker) hasShadowedNamespace(symbol *ast.Symbol) bool { @@ -15241,12 +15225,15 @@ func (c *Checker) reportNonExportedMember(name *ast.Node, declarationName string } else { // Looking for the export resolves aliases, which creates types, so do it in a stable order rather than // in the random iteration order of the symbol table. - var exportedSymbol *ast.Symbol - c.forEachSymbolInResolutionOrder(exports, func(_ string, symbol *ast.Symbol) { - if exportedSymbol == nil && c.getSymbolIfSameReference(symbol, localSymbol) != nil { - exportedSymbol = symbol + var exportedSymbols []*ast.Symbol + c.forEachSymbolInResolutionOrder(exports, func(_ string, symbol *ast.Symbol) bool { + if c.getSymbolIfSameReference(symbol, localSymbol) != nil { + exportedSymbols = append(exportedSymbols, symbol) } + return false }) + c.sortSymbols(exportedSymbols) + exportedSymbol := core.FirstOrNil(exportedSymbols) var diagnostic *ast.Diagnostic if exportedSymbol != nil { diagnostic = c.error(name, diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, c.symbolToString(exportedSymbol)) @@ -16643,9 +16630,9 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as } // A CommonJS module defined by an 'export=' might also export typedefs, stored on the original module if originalModule != nil && len(originalModule.Exports()) > 1 { - c.forEachSymbolInResolutionOrder(originalModule.Exports(), func(_ string, symbol *ast.Symbol) { + c.forEachSymbolInResolutionOrder(originalModule.Exports(), func(_ string, symbol *ast.Symbol) bool { if symbol.Name() == ast.InternalSymbolNameExportEquals || symbol.Name() == ast.InternalSymbolNameExportStar { - return + return false } flags := c.getSymbolFlags(symbol) if flags&(ast.SymbolFlagsType|ast.SymbolFlagsNamespace) != 0 && @@ -16653,6 +16640,7 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as exports[symbol.Name()] == nil { exports[symbol.Name()] = symbol } + return false }) } for name := range nonTypeOnlyNames.Keys() { diff --git a/tsc/internal/checker/nodebuilderimpl.go b/tsc/internal/checker/nodebuilderimpl.go index ee695716b2e72..1507b3f2c8180 100644 --- a/tsc/internal/checker/nodebuilderimpl.go +++ b/tsc/internal/checker/nodebuilderimpl.go @@ -778,11 +778,15 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index symbolName = symbol.Name() } else { results := make(map[*ast.Symbol]string, 1) - b.ch.forEachSymbolInResolutionOrder(exports, func(name string, ex *ast.Symbol) { + b.ch.forEachSymbolInResolutionOrder(exports, func(name string, ex *ast.Symbol) bool { if b.ch.getSymbolIfSameReference(ex, symbol) != nil && !isLateBoundName(name) && name != ast.InternalSymbolNameExportEquals { - results[ex] = name - // break // must collect all results and sort them - exports are randomly iterated + // A symbol can be in the table under two keys, so pick one in a way that does not depend on the + // order the entries are visited in. + if previous, ok := results[ex]; !ok || name > previous { + results[ex] = name + } } + return false }) resultSymbols := slices.Collect(maps.Keys(results)) if len(resultSymbols) > 0 { diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index 477b5964be879..2700f3cc37b56 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -280,8 +280,9 @@ func (c *Checker) buildExternalModuleContainerIndex() { } container := c.getSymbolOfDeclaration(file.AsNode()) index.moduleOrder[container] = len(index.moduleOrder) - c.forEachSymbolInResolutionOrder(c.getExportsOfSymbol(container), func(_ string, exported *ast.Symbol) { + c.forEachSymbolInResolutionOrder(c.getExportsOfSymbol(container), func(_ string, exported *ast.Symbol) bool { index.add(c.getResolvedTarget(exported), container) + return false }) if exportEquals := container.Exports()[ast.InternalSymbolNameExportEquals]; exportEquals != nil { index.add(c.getResolvedTarget(exportEquals), container) @@ -290,33 +291,43 @@ func (c *Checker) buildExternalModuleContainerIndex() { index.complete = true } -// forEachSymbolInResolutionOrder calls f for each entry of a symbol table, in an order that does not depend on the -// table's random iteration order wherever resolving the symbols can have side effects. Symbols that are not aliases -// resolve to themselves and come first, in table order. Resolving an alias can create types, so aliases come last, -// sorted. f gets each symbol's key in the table, which is not always the symbol's name (a default export is keyed -// "default" under its declared name). -func (c *Checker) forEachSymbolInResolutionOrder(symbols ast.SymbolTable, f func(name string, symbol *ast.Symbol)) { +// forEachSymbolInResolutionOrder calls f for each entry of a symbol table so that any types f creates are created +// in an order that does not depend on the table's random iteration order. That holds as long as f has no side +// effects for a symbol that is not an alias, or for an alias that is already resolved: those come first, in table +// order. Resolving an alias can create types, so unresolved aliases come last, sorted. f must not depend on the +// order it sees entries in for its result: collect and sort what it finds instead. f returns true to stop, which is +// only allowed when the answer does not depend on which entry stopped it (such as whether any entry matches), and +// forEachSymbolInResolutionOrder then returns true. f gets each symbol's key in the table, which is not always the +// symbol's name (a default export is keyed "default"). +func (c *Checker) forEachSymbolInResolutionOrder(symbols ast.SymbolTable, f func(name string, symbol *ast.Symbol) bool) bool { type entry struct { name string symbol *ast.Symbol } - var aliases []entry + var unresolved []entry for name, symbol := range symbols { if symbol.Flags()&ast.SymbolFlagsAlias != 0 { - aliases = append(aliases, entry{name, symbol}) - } else { - f(name, symbol) + if links := c.aliasSymbolLinks.TryGet(symbol); links == nil || links.aliasTarget == nil { + unresolved = append(unresolved, entry{name, symbol}) + continue + } + } + if f(name, symbol) { + return true } } - slices.SortFunc(aliases, func(a, b entry) int { + slices.SortFunc(unresolved, func(a, b entry) int { if r := c.compareSymbols(a.symbol, b.symbol); r != 0 { return r } return strings.Compare(a.name, b.name) }) - for _, alias := range aliases { - f(alias.name, alias.symbol) + for _, alias := range unresolved { + if f(alias.name, alias.symbol) { + return true + } } + return false } func (c *Checker) scanExternalModuleContainers(symbol *ast.Symbol) []*ast.Symbol { @@ -467,10 +478,11 @@ func (c *Checker) getAliasForSymbolInContainer(container *ast.Symbol, symbol *as return quick } var candidates []*ast.Symbol - c.forEachSymbolInResolutionOrder(exports, func(_ string, exported *ast.Symbol) { + c.forEachSymbolInResolutionOrder(exports, func(_ string, exported *ast.Symbol) bool { if c.getSymbolIfSameReference(exported, symbol) != nil { candidates = append(candidates, exported) } + return false }) if len(candidates) > 0 { c.sortSymbols(candidates) // _must_ sort exports for stable results - symbol table is randomly iterated From 15d13e63e68defcb1568e275d36d00f5c99e7147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 08:55:45 +0200 Subject: [PATCH 15/35] Rename forEachSymbolInResolutionOrder to forEachSymbolTableEntry --- tsc/internal/checker/checker.go | 8 ++++---- tsc/internal/checker/nodebuilderimpl.go | 2 +- tsc/internal/checker/symbolaccessibility.go | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 7ea44c73f6d55..4d11b560df33b 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -1851,7 +1851,7 @@ func (c *Checker) getSuggestionForSymbolNameLookup(symbols ast.SymbolTable, name // Checking a candidate alias resolves it, which creates types, so visit aliases last and in a stable order // rather than in the random iteration order of the symbol table. candidates := make([]*ast.Symbol, 0, len(symbols)) - c.forEachSymbolInResolutionOrder(symbols, func(_ string, symbol *ast.Symbol) bool { + c.forEachSymbolTableEntry(symbols, func(_ string, symbol *ast.Symbol) bool { candidates = append(candidates, symbol) return false }) @@ -5926,7 +5926,7 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) { } func (c *Checker) hasExportedMembersOfKind(moduleSymbol *ast.Symbol, kind ast.SymbolFlags) bool { - return c.forEachSymbolInResolutionOrder(moduleSymbol.Exports(), func(_ string, symbol *ast.Symbol) bool { + return c.forEachSymbolTableEntry(moduleSymbol.Exports(), func(_ string, symbol *ast.Symbol) bool { return symbol.Name() != ast.InternalSymbolNameExportEquals && c.getSymbolFlags(symbol)&kind != 0 }) } @@ -15226,7 +15226,7 @@ func (c *Checker) reportNonExportedMember(name *ast.Node, declarationName string // Looking for the export resolves aliases, which creates types, so do it in a stable order rather than // in the random iteration order of the symbol table. var exportedSymbols []*ast.Symbol - c.forEachSymbolInResolutionOrder(exports, func(_ string, symbol *ast.Symbol) bool { + c.forEachSymbolTableEntry(exports, func(_ string, symbol *ast.Symbol) bool { if c.getSymbolIfSameReference(symbol, localSymbol) != nil { exportedSymbols = append(exportedSymbols, symbol) } @@ -16630,7 +16630,7 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as } // A CommonJS module defined by an 'export=' might also export typedefs, stored on the original module if originalModule != nil && len(originalModule.Exports()) > 1 { - c.forEachSymbolInResolutionOrder(originalModule.Exports(), func(_ string, symbol *ast.Symbol) bool { + c.forEachSymbolTableEntry(originalModule.Exports(), func(_ string, symbol *ast.Symbol) bool { if symbol.Name() == ast.InternalSymbolNameExportEquals || symbol.Name() == ast.InternalSymbolNameExportStar { return false } diff --git a/tsc/internal/checker/nodebuilderimpl.go b/tsc/internal/checker/nodebuilderimpl.go index 1507b3f2c8180..980588acd7e04 100644 --- a/tsc/internal/checker/nodebuilderimpl.go +++ b/tsc/internal/checker/nodebuilderimpl.go @@ -778,7 +778,7 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index symbolName = symbol.Name() } else { results := make(map[*ast.Symbol]string, 1) - b.ch.forEachSymbolInResolutionOrder(exports, func(name string, ex *ast.Symbol) bool { + b.ch.forEachSymbolTableEntry(exports, func(name string, ex *ast.Symbol) bool { if b.ch.getSymbolIfSameReference(ex, symbol) != nil && !isLateBoundName(name) && name != ast.InternalSymbolNameExportEquals { // A symbol can be in the table under two keys, so pick one in a way that does not depend on the // order the entries are visited in. diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index 2700f3cc37b56..15d527b21fe87 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -280,7 +280,7 @@ func (c *Checker) buildExternalModuleContainerIndex() { } container := c.getSymbolOfDeclaration(file.AsNode()) index.moduleOrder[container] = len(index.moduleOrder) - c.forEachSymbolInResolutionOrder(c.getExportsOfSymbol(container), func(_ string, exported *ast.Symbol) bool { + c.forEachSymbolTableEntry(c.getExportsOfSymbol(container), func(_ string, exported *ast.Symbol) bool { index.add(c.getResolvedTarget(exported), container) return false }) @@ -291,15 +291,15 @@ func (c *Checker) buildExternalModuleContainerIndex() { index.complete = true } -// forEachSymbolInResolutionOrder calls f for each entry of a symbol table so that any types f creates are created +// forEachSymbolTableEntry calls f for each entry of a symbol table so that any types f creates are created // in an order that does not depend on the table's random iteration order. That holds as long as f has no side // effects for a symbol that is not an alias, or for an alias that is already resolved: those come first, in table // order. Resolving an alias can create types, so unresolved aliases come last, sorted. f must not depend on the // order it sees entries in for its result: collect and sort what it finds instead. f returns true to stop, which is // only allowed when the answer does not depend on which entry stopped it (such as whether any entry matches), and -// forEachSymbolInResolutionOrder then returns true. f gets each symbol's key in the table, which is not always the +// forEachSymbolTableEntry then returns true. f gets each symbol's key in the table, which is not always the // symbol's name (a default export is keyed "default"). -func (c *Checker) forEachSymbolInResolutionOrder(symbols ast.SymbolTable, f func(name string, symbol *ast.Symbol) bool) bool { +func (c *Checker) forEachSymbolTableEntry(symbols ast.SymbolTable, f func(name string, symbol *ast.Symbol) bool) bool { type entry struct { name string symbol *ast.Symbol @@ -478,7 +478,7 @@ func (c *Checker) getAliasForSymbolInContainer(container *ast.Symbol, symbol *as return quick } var candidates []*ast.Symbol - c.forEachSymbolInResolutionOrder(exports, func(_ string, exported *ast.Symbol) bool { + c.forEachSymbolTableEntry(exports, func(_ string, exported *ast.Symbol) bool { if c.getSymbolIfSameReference(exported, symbol) != nil { candidates = append(candidates, exported) } From fea0ca26b979d6d33d5f39cf03e5778586f1578d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 09:20:19 +0200 Subject: [PATCH 16/35] Add a test for late-bound index signature siblings in declaration emit --- ...mitLateBoundIndexSignatureSiblingsOrder.js | 95 ++++++++++ ...teBoundIndexSignatureSiblingsOrder.symbols | 168 +++++++++++++++++ ...LateBoundIndexSignatureSiblingsOrder.types | 171 ++++++++++++++++++ ...mitLateBoundIndexSignatureSiblingsOrder.ts | 66 +++++++ 4 files changed, 500 insertions(+) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.js create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.types create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.ts diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.js b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.js new file mode 100644 index 0000000000000..da41b8a0dc439 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.js @@ -0,0 +1,95 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.ts] //// + +//// [ambient.d.ts] +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +//// [main.ts] +/// +declare const k: string; +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +export class C { + [k]: unknown; + sa = { ...(null! as typeof import("ma")) }; + sb = { ...(null! as typeof import("mb")) }; + f1 = 1; + f2 = 2; + f3 = 3; + f4 = 4; + f5 = 5; + f6 = 6; + f7 = 7; + f8 = 8; + f9 = 9; + f10 = 10; +} +export const obsA = expand(); +export const obsB = expand(); + + + + +//// [main.d.ts] +declare const k: string; +export declare class C { + [k]: unknown; + sa: { + pa: 0; + ma: 1; + }; + sb: { + pb: 0; + mb: 1; + }; + f1: number; + f2: number; + f3: number; + f4: number; + f5: number; + f6: number; + f7: number; + f8: number; + f9: number; + f10: number; +} +export declare const obsA: { + pb: 0; + readonly mb: 1; + v: 0; +}; +export declare const obsB: { + v: 0; +}; +export {}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.symbols new file mode 100644 index 0000000000000..58a51ee5e09e3 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.symbols @@ -0,0 +1,168 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.ts] //// + +=== /main.ts === +/// +declare const k: string; +>k : Symbol(k, Decl(main.ts, 1, 13)) + +declare const oxa: typeof import("xa"); +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +declare const oxb: typeof import("xb"); +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>X : Symbol(X, Decl(main.ts, 4, 24)) +>K : Symbol(K, Decl(main.ts, 4, 33)) + +export class C { +>C : Symbol(C, Decl(main.ts, 4, 55)) + + [k]: unknown; +>[k] : Symbol(C[k], Decl(main.ts, 5, 16)) +>k : Symbol(k, Decl(main.ts, 1, 13)) + + sa = { ...(null! as typeof import("ma")) }; +>sa : Symbol(C.sa, Decl(main.ts, 6, 17)) + + sb = { ...(null! as typeof import("mb")) }; +>sb : Symbol(C.sb, Decl(main.ts, 7, 47)) + + f1 = 1; +>f1 : Symbol(C.f1, Decl(main.ts, 8, 47)) + + f2 = 2; +>f2 : Symbol(C.f2, Decl(main.ts, 9, 11)) + + f3 = 3; +>f3 : Symbol(C.f3, Decl(main.ts, 10, 11)) + + f4 = 4; +>f4 : Symbol(C.f4, Decl(main.ts, 11, 11)) + + f5 = 5; +>f5 : Symbol(C.f5, Decl(main.ts, 12, 11)) + + f6 = 6; +>f6 : Symbol(C.f6, Decl(main.ts, 13, 11)) + + f7 = 7; +>f7 : Symbol(C.f7, Decl(main.ts, 14, 11)) + + f8 = 8; +>f8 : Symbol(C.f8, Decl(main.ts, 15, 11)) + + f9 = 9; +>f9 : Symbol(C.f9, Decl(main.ts, 16, 11)) + + f10 = 10; +>f10 : Symbol(C.f10, Decl(main.ts, 17, 11)) +} +export const obsA = expand(); +>obsA : Symbol(obsA, Decl(main.ts, 20, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxa : Symbol(oxa, Decl(main.ts, 2, 13)) + +export const obsB = expand(); +>obsB : Symbol(obsB, Decl(main.ts, 21, 12)) +>expand : Symbol(expand, Decl(main.ts, 3, 39)) +>oxb : Symbol(oxb, Decl(main.ts, 3, 13)) + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : Symbol("ma", Decl(ambient.d.ts, 0, 0)) + + export { v as pa } from "xa"; +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) +>pa : Symbol(pa, Decl(ambient.d.ts, 1, 12)) + + export const ma: 1; +>ma : Symbol(ma, Decl(ambient.d.ts, 2, 16)) +} +declare module "mb" { +>"mb" : Symbol("mb", Decl(ambient.d.ts, 3, 1)) + + export { v as pb } from "xb"; +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) +>pb : Symbol(pb, Decl(ambient.d.ts, 5, 12)) + + export const mb: 1; +>mb : Symbol(mb, Decl(ambient.d.ts, 6, 16)) +} +declare module "xa" { +>"xa" : Symbol("xa", Decl(ambient.d.ts, 7, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 8, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 10, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 9, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 11, 9)) +} +declare module "xb" { +>"xb" : Symbol("xb", Decl(ambient.d.ts, 13, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 14, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 16, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 15, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 17, 9)) +} +declare module "ia" { +>"ia" : Symbol("ia", Decl(ambient.d.ts, 19, 1)) + + type T = typeof import("ma"); +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 20, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 22, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 21, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 23, 9)) +} +declare module "ib" { +>"ib" : Symbol("ib", Decl(ambient.d.ts, 25, 1)) + + type T = typeof import("mb"); +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) + + interface O extends T { v: 0 } +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) +>T : Symbol(T, Decl(ambient.d.ts, 26, 21)) +>v : Symbol(O.v, Decl(ambient.d.ts, 28, 27)) + + const o: O; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +>O : Symbol(O, Decl(ambient.d.ts, 27, 33)) + + export = o; +>o : Symbol(o, Decl(ambient.d.ts, 29, 9)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.types b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.types new file mode 100644 index 0000000000000..9ca145132f072 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.types @@ -0,0 +1,171 @@ +//// [tests/cases/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.ts] //// + +=== /main.ts === +/// +declare const k: string; +>k : string + +declare const oxa: typeof import("xa"); +>oxa : O + +declare const oxb: typeof import("xb"); +>oxb : O + +declare function expand(): { [K in keyof X]: X[K] }; +>expand : () => { [K in keyof X]: X[K]; } + +export class C { +>C : C + + [k]: unknown; +>[k] : unknown +>k : string + + sa = { ...(null! as typeof import("ma")) }; +>sa : { pa: 0; ma: 1; } +>{ ...(null! as typeof import("ma")) } : { pa: 0; ma: 1; } +>(null! as typeof import("ma")) : typeof import("ma") +>null! as typeof import("ma") : typeof import("ma") +>null! : never + + sb = { ...(null! as typeof import("mb")) }; +>sb : { pb: 0; mb: 1; } +>{ ...(null! as typeof import("mb")) } : { pb: 0; mb: 1; } +>(null! as typeof import("mb")) : typeof import("mb") +>null! as typeof import("mb") : typeof import("mb") +>null! : never + + f1 = 1; +>f1 : number +>1 : 1 + + f2 = 2; +>f2 : number +>2 : 2 + + f3 = 3; +>f3 : number +>3 : 3 + + f4 = 4; +>f4 : number +>4 : 4 + + f5 = 5; +>f5 : number +>5 : 5 + + f6 = 6; +>f6 : number +>6 : 6 + + f7 = 7; +>f7 : number +>7 : 7 + + f8 = 8; +>f8 : number +>8 : 8 + + f9 = 9; +>f9 : number +>9 : 9 + + f10 = 10; +>f10 : number +>10 : 10 +} +export const obsA = expand(); +>obsA : { pb: 0; readonly mb: 1; v: 0; } +>expand() : { pb: 0; readonly mb: 1; v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxa : O + +export const obsB = expand(); +>obsB : { v: 0; } +>expand() : { v: 0; } +>expand : () => { [K in keyof X]: X[K]; } +>oxb : O + +=== /ambient.d.ts === +declare module "ma" { +>"ma" : typeof import("ma") + + export { v as pa } from "xa"; +>v : 0 +>pa : 0 + + export const ma: 1; +>ma : 1 +} +declare module "mb" { +>"mb" : typeof import("mb") + + export { v as pb } from "xb"; +>v : 0 +>pb : 0 + + export const mb: 1; +>mb : 1 +} +declare module "xa" { +>"xa" : typeof import("xa") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "xb" { +>"xb" : typeof import("xb") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ia" { +>"ia" : typeof import("ia") + + type T = typeof import("ma"); +>T : typeof import("ma") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} +declare module "ib" { +>"ib" : typeof import("ib") + + type T = typeof import("mb"); +>T : typeof import("mb") + + interface O extends T { v: 0 } +>v : 0 + + const o: O; +>o : O + + export = o; +>o : O +} + diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.ts new file mode 100644 index 0000000000000..5b835267e2b7d --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDeclarationEmitLateBoundIndexSignatureSiblingsOrder.ts @@ -0,0 +1,66 @@ +// @strict: true +// @skipLibCheck: true +// @module: commonjs +// @target: es2020 +// @declaration: true +// @emitDeclarationOnly: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ambient.d.ts +declare module "ma" { + export { v as pa } from "xa"; + export const ma: 1; +} +declare module "mb" { + export { v as pb } from "xb"; + export const mb: 1; +} +declare module "xa" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "xb" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ia" { + type T = typeof import("ma"); + interface O extends T { v: 0 } + const o: O; + export = o; +} +declare module "ib" { + type T = typeof import("mb"); + interface O extends T { v: 0 } + const o: O; + export = o; +} + +// @Filename: /main.ts +/// +declare const k: string; +declare const oxa: typeof import("xa"); +declare const oxb: typeof import("xb"); +declare function expand(): { [K in keyof X]: X[K] }; +export class C { + [k]: unknown; + sa = { ...(null! as typeof import("ma")) }; + sb = { ...(null! as typeof import("mb")) }; + f1 = 1; + f2 = 2; + f3 = 3; + f4 = 4; + f5 = 5; + f6 = 6; + f7 = 7; + f8 = 8; + f9 = 9; + f10 = 10; +} +export const obsA = expand(); +export const obsB = expand(); From 27c66a6aa4c72e7ad3f3cc7dcec911fdb879dc5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 09:32:09 +0200 Subject: [PATCH 17/35] Use forEachSymbolTableEntry in getNamedMembers --- tsc/internal/checker/checker.go | 37 +++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 4d11b560df33b..2c410e47997f3 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -22585,29 +22585,30 @@ func (c *Checker) getNamedMembers(members ast.SymbolTable, container *ast.Symbol // For classes and interfaces, we store explicitly declared members ahead of inherited members. This ensures we process // explicitly declared members first in type relations, which is beneficial because explicitly declared members are more // likely to contain discriminating differences. See for example https://github.com/microsoft/TypeScript/tsc/issues/1968. - symbols := make([]*ast.Symbol, 0, len(members)) - for id, symbol := range members { - if !isReservedMemberName(id) { - symbols = append(symbols, symbol) - } - } - // Sort before checking which members are values: that can resolve aliases (creating types), and the symbol - // table is randomly iterated. - c.sortSymbols(symbols) - if container == nil || container.Flags()&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) == 0 { - return slices.DeleteFunc(symbols, func(symbol *ast.Symbol) bool { return !c.symbolIsValue(symbol) }) - } - result := make([]*ast.Symbol, 0, len(symbols)) - for _, symbol := range symbols { - if c.symbolIsValue(symbol) && c.isDeclarationContainedBy(symbol, container) { + result := make([]*ast.Symbol, 0, len(members)) + c.forEachSymbolTableEntry(members, func(id string, symbol *ast.Symbol) bool { + if c.isNamedMember(symbol, id) { result = append(result, symbol) } + return false + }) + if container == nil || container.Flags()&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) == 0 { + c.sortSymbols(result) + return result } - for _, symbol := range symbols { - if c.symbolIsValue(symbol) && !c.isDeclarationContainedBy(symbol, container) { - result = append(result, symbol) + var inherited []*ast.Symbol + containedCount := 0 + for _, symbol := range result { + if c.isDeclarationContainedBy(symbol, container) { + result[containedCount] = symbol + containedCount++ + } else { + inherited = append(inherited, symbol) } } + copy(result[containedCount:], inherited) + c.sortSymbols(result[:containedCount]) + c.sortSymbols(result[containedCount:]) return result } From e9c60c66841b2f23dceef3395f67303f906d94c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 11:29:52 +0200 Subject: [PATCH 18/35] Drop the export name tie-break in createAccessFromSymbolChain --- tsc/internal/checker/nodebuilderimpl.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tsc/internal/checker/nodebuilderimpl.go b/tsc/internal/checker/nodebuilderimpl.go index 980588acd7e04..dbb356e06c1ab 100644 --- a/tsc/internal/checker/nodebuilderimpl.go +++ b/tsc/internal/checker/nodebuilderimpl.go @@ -780,11 +780,8 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index results := make(map[*ast.Symbol]string, 1) b.ch.forEachSymbolTableEntry(exports, func(name string, ex *ast.Symbol) bool { if b.ch.getSymbolIfSameReference(ex, symbol) != nil && !isLateBoundName(name) && name != ast.InternalSymbolNameExportEquals { - // A symbol can be in the table under two keys, so pick one in a way that does not depend on the - // order the entries are visited in. - if previous, ok := results[ex]; !ok || name > previous { - results[ex] = name - } + results[ex] = name + // break // must collect all results and sort them - exports are randomly iterated } return false }) From 655c7faa7780ef3cf8d5e05126d73b78c2484e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 11:42:08 +0200 Subject: [PATCH 19/35] Treat an alias as resolved only when its whole chain is --- tsc/internal/checker/symbolaccessibility.go | 35 ++- ...sResolutionOrderReexportedTypes.errors.txt | 77 +++++++ ...ceMembersResolutionOrderReexportedTypes.js | 206 +++++++++++++++++ ...bersResolutionOrderReexportedTypes.symbols | 189 ++++++++++++++++ ...embersResolutionOrderReexportedTypes.types | 210 ++++++++++++++++++ ...ceMembersResolutionOrderReexportedTypes.ts | 81 +++++++ 6 files changed, 791 insertions(+), 7 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.js create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.types create mode 100644 tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index 15d527b21fe87..65e47be7891ef 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -293,8 +293,8 @@ func (c *Checker) buildExternalModuleContainerIndex() { // forEachSymbolTableEntry calls f for each entry of a symbol table so that any types f creates are created // in an order that does not depend on the table's random iteration order. That holds as long as f has no side -// effects for a symbol that is not an alias, or for an alias that is already resolved: those come first, in table -// order. Resolving an alias can create types, so unresolved aliases come last, sorted. f must not depend on the +// effects for a symbol that is not an alias, or for an alias whose whole chain of aliases is already resolved: those +// come first, in table order. Resolving an alias can create types, so the other aliases come last, sorted. f must not depend on the // order it sees entries in for its result: collect and sort what it finds instead. f returns true to stop, which is // only allowed when the answer does not depend on which entry stopped it (such as whether any entry matches), and // forEachSymbolTableEntry then returns true. f gets each symbol's key in the table, which is not always the @@ -306,11 +306,9 @@ func (c *Checker) forEachSymbolTableEntry(symbols ast.SymbolTable, f func(name s } var unresolved []entry for name, symbol := range symbols { - if symbol.Flags()&ast.SymbolFlagsAlias != 0 { - if links := c.aliasSymbolLinks.TryGet(symbol); links == nil || links.aliasTarget == nil { - unresolved = append(unresolved, entry{name, symbol}) - continue - } + if !c.isAliasChainResolved(symbol) { + unresolved = append(unresolved, entry{name, symbol}) + continue } if f(name, symbol) { return true @@ -330,6 +328,29 @@ func (c *Checker) forEachSymbolTableEntry(symbols ast.SymbolTable, f func(name s return false } +// isAliasChainResolved reports whether symbol is not an alias, or every alias in its chain is resolved. Resolving an +// alias stops at a target with a meaning of its own even when that target is also an alias, so getSymbolFlags and +// getTypeOnlyAliasDeclaration can still resolve later aliases of a chain whose first alias is resolved. +func (c *Checker) isAliasChainResolved(symbol *ast.Symbol) bool { + // A circular chain resolves to the unknown symbol, so the bound only guards against a chain that never ends, which + // then counts as unresolved. + for range 100 { + if symbol.Flags()&ast.SymbolFlagsAlias == 0 { + return true + } + links := c.aliasSymbolLinks.TryGet(symbol) + if links == nil || links.aliasTarget == nil { + return false + } + target := c.getExportSymbolOfValueSymbolIfExported(links.aliasTarget) + if target == symbol || target == c.unknownSymbol { + return true + } + symbol = target + } + return false +} + func (c *Checker) scanExternalModuleContainers(symbol *ast.Symbol) []*ast.Symbol { var containers []*ast.Symbol for _, file := range c.program.SourceFiles() { diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.errors.txt b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.errors.txt new file mode 100644 index 0000000000000..408176b1c59d1 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.errors.txt @@ -0,0 +1,77 @@ +/main.ts(8,32): error TS2339: Property 'ma' does not exist on type '{}'. + + +==== /main.ts (1 errors) ==== + import * as idx from "./d"; + const all = { ...idx }; + import * as MA from "./ma"; + import * as MB from "./mb"; + export const fromA = MA.pa; + export const fromB = MB.pb; + export const checkA: 1 = MA.pa.mb; + export const checkB: 1 = MB.pb.ma; + ~~ +!!! error TS2339: Property 'ma' does not exist on type '{}'. + +==== /ma.js (0 errors) ==== + export { v as pa } from "./xa"; + export const ma = 1; + +==== /mb.js (0 errors) ==== + export { v as pb } from "./xb"; + export const mb = 1; + +==== /xa.js (0 errors) ==== + /** @type {typeof import("./mb")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /xb.js (0 errors) ==== + /** @type {typeof import("./ma")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /ia.js (0 errors) ==== + /** @type {typeof import("./ma")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /ib.js (0 errors) ==== + /** @type {typeof import("./mb")} */ + const M = /** @type {any} */ (null); + const o = { v: { ...M } }; + module.exports = o; + +==== /ia2.d.ts (0 errors) ==== + export { v } from "./ia"; + export type v = number; + +==== /ib2.d.ts (0 errors) ==== + export { v } from "./ib"; + export type v = number; + +==== /index.d.ts (0 errors) ==== + export { v as a } from "./ia2"; + export { v as b } from "./ib2"; + export const f1: 1; + export const f2: 2; + export const f3: 3; + export const f4: 4; + export const f5: 5; + export const f6: 6; + export const f7: 7; + export const f8: 8; + export const f9: 9; + export const f10: 10; + +==== /index2.d.ts (0 errors) ==== + export { v as a } from "./ia2"; + export { v as b } from "./ib2"; + +==== /d.d.ts (0 errors) ==== + export * from "./index"; + export * from "./index2"; + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.js b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.js new file mode 100644 index 0000000000000..beb6f57cf711b --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.js @@ -0,0 +1,206 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts] //// + +//// [ma.js] +export { v as pa } from "./xa"; +export const ma = 1; + +//// [mb.js] +export { v as pb } from "./xb"; +export const mb = 1; + +//// [xa.js] +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [xb.js] +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [ia.js] +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [ib.js] +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +//// [ia2.d.ts] +export { v } from "./ia"; +export type v = number; + +//// [ib2.d.ts] +export { v } from "./ib"; +export type v = number; + +//// [index.d.ts] +export { v as a } from "./ia2"; +export { v as b } from "./ib2"; +export const f1: 1; +export const f2: 2; +export const f3: 3; +export const f4: 4; +export const f5: 5; +export const f6: 6; +export const f7: 7; +export const f8: 8; +export const f9: 9; +export const f10: 10; + +//// [index2.d.ts] +export { v as a } from "./ia2"; +export { v as b } from "./ib2"; + +//// [d.d.ts] +export * from "./index"; +export * from "./index2"; + +//// [main.ts] +import * as idx from "./d"; +const all = { ...idx }; +import * as MA from "./ma"; +import * as MB from "./mb"; +export const fromA = MA.pa; +export const fromB = MB.pb; +export const checkA: 1 = MA.pa.mb; +export const checkB: 1 = MB.pb.ma; + + +//// [xb.js] +"use strict"; +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [mb.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.mb = exports.pb = void 0; +var xb_1 = require("./xb"); +Object.defineProperty(exports, "pb", { enumerable: true, get: function () { return xb_1.v; } }); +exports.mb = 1; +//// [xa.js] +"use strict"; +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [ma.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ma = exports.pa = void 0; +var xa_1 = require("./xa"); +Object.defineProperty(exports, "pa", { enumerable: true, get: function () { return xa_1.v; } }); +exports.ma = 1; +//// [ia.js] +"use strict"; +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [ib.js] +"use strict"; +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; +//// [main.js] +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.checkB = exports.checkA = exports.fromB = exports.fromA = void 0; +const idx = __importStar(require("./d")); +const all = { ...idx }; +const MA = __importStar(require("./ma")); +const MB = __importStar(require("./mb")); +exports.fromA = MA.pa; +exports.fromB = MB.pb; +exports.checkA = MA.pa.mb; +exports.checkB = MB.pb.ma; + + +//// [xb.d.ts] +export = o; +declare const o: { + v: {}; +}; +//// [mb.d.ts] +export { v as pb } from "./xb"; +export declare const mb = 1; +//// [xa.d.ts] +export = o; +declare const o: { + v: { + pb: {}; + mb: 1; + }; +}; +//// [ma.d.ts] +export { v as pa } from "./xa"; +export declare const ma = 1; +//// [ia.d.ts] +export = o; +declare const o: { + v: { + pa: { + pb: {}; + mb: 1; + }; + ma: 1; + }; +}; +//// [ib.d.ts] +export = o; +declare const o: { + v: { + pb: {}; + mb: 1; + }; +}; +//// [main.d.ts] +export declare const fromA: { + pb: {}; + mb: 1; +}; +export declare const fromB: {}; +export declare const checkA: 1; +export declare const checkB: 1; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.symbols new file mode 100644 index 0000000000000..e737ff2cbfb8a --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.symbols @@ -0,0 +1,189 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts] //// + +=== /main.ts === +import * as idx from "./d"; +>idx : Symbol(idx, Decl(main.ts, 0, 6)) + +const all = { ...idx }; +>all : Symbol(all, Decl(main.ts, 1, 5)) +>idx : Symbol(idx, Decl(main.ts, 0, 6)) + +import * as MA from "./ma"; +>MA : Symbol(MA, Decl(main.ts, 2, 6)) + +import * as MB from "./mb"; +>MB : Symbol(MB, Decl(main.ts, 3, 6)) + +export const fromA = MA.pa; +>fromA : Symbol(fromA, Decl(main.ts, 4, 12)) +>MA.pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) +>MA : Symbol(MA, Decl(main.ts, 2, 6)) +>pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) + +export const fromB = MB.pb; +>fromB : Symbol(fromB, Decl(main.ts, 5, 12)) +>MB.pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) +>MB : Symbol(MB, Decl(main.ts, 3, 6)) +>pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) + +export const checkA: 1 = MA.pa.mb; +>checkA : Symbol(checkA, Decl(main.ts, 6, 12)) +>MA.pa.mb : Symbol(mb, Decl(mb.js, 1, 12)) +>MA.pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) +>MA : Symbol(MA, Decl(main.ts, 2, 6)) +>pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) +>mb : Symbol(mb, Decl(mb.js, 1, 12)) + +export const checkB: 1 = MB.pb.ma; +>checkB : Symbol(checkB, Decl(main.ts, 7, 12)) +>MB.pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) +>MB : Symbol(MB, Decl(main.ts, 3, 6)) +>pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) + +=== /ma.js === +export { v as pa } from "./xa"; +>v : Symbol(v, Decl(xa.js, 2, 11)) +>pa : Symbol(pa, Decl(ma.js, 0, 8)) + +export const ma = 1; +>ma : Symbol(ma, Decl(ma.js, 1, 12)) + +=== /mb.js === +export { v as pb } from "./xb"; +>v : Symbol(v, Decl(xb.js, 2, 11)) +>pb : Symbol(pb, Decl(mb.js, 0, 8)) + +export const mb = 1; +>mb : Symbol(mb, Decl(mb.js, 1, 12)) + +=== /xa.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(xa.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(xa.js, 2, 5)) +>v : Symbol(v, Decl(xa.js, 2, 11)) +>M : Symbol(M, Decl(xa.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(xa.js, 0, 0)) +>module : Symbol(module, Decl(xa.js, 0, 0)) +>exports : Symbol(exports, Decl(xa.js, 0, 0)) +>o : Symbol(o, Decl(xa.js, 2, 5)) + +=== /xb.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(xb.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(xb.js, 2, 5)) +>v : Symbol(v, Decl(xb.js, 2, 11)) +>M : Symbol(M, Decl(xb.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(xb.js, 0, 0)) +>module : Symbol(module, Decl(xb.js, 0, 0)) +>exports : Symbol(exports, Decl(xb.js, 0, 0)) +>o : Symbol(o, Decl(xb.js, 2, 5)) + +=== /ia.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(ia.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(ia.js, 2, 5)) +>v : Symbol(v, Decl(ia.js, 2, 11)) +>M : Symbol(M, Decl(ia.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(ia.js, 0, 0)) +>module : Symbol(module, Decl(ia.js, 0, 0)) +>exports : Symbol(exports, Decl(ia.js, 0, 0)) +>o : Symbol(o, Decl(ia.js, 2, 5)) + +=== /ib.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : Symbol(M, Decl(ib.js, 1, 5)) + +const o = { v: { ...M } }; +>o : Symbol(o, Decl(ib.js, 2, 5)) +>v : Symbol(v, Decl(ib.js, 2, 11)) +>M : Symbol(M, Decl(ib.js, 1, 5)) + +module.exports = o; +>module.exports : Symbol(exports, Decl(ib.js, 0, 0)) +>module : Symbol(module, Decl(ib.js, 0, 0)) +>exports : Symbol(exports, Decl(ib.js, 0, 0)) +>o : Symbol(o, Decl(ib.js, 2, 5)) + +=== /ia2.d.ts === +export { v } from "./ia"; +>v : Symbol(v, Decl(ia2.d.ts, 0, 8), Decl(ia2.d.ts, 0, 25)) + +export type v = number; +>v : Symbol(v, Decl(ia2.d.ts, 0, 8), Decl(ia2.d.ts, 0, 25)) + +=== /ib2.d.ts === +export { v } from "./ib"; +>v : Symbol(v, Decl(ib2.d.ts, 0, 8), Decl(ib2.d.ts, 0, 25)) + +export type v = number; +>v : Symbol(v, Decl(ib2.d.ts, 0, 8), Decl(ib2.d.ts, 0, 25)) + +=== /index.d.ts === +export { v as a } from "./ia2"; +>v : Symbol(v, Decl(ia2.d.ts, 0, 8), Decl(ia2.d.ts, 0, 25)) +>a : Symbol(a, Decl(index.d.ts, 0, 8)) + +export { v as b } from "./ib2"; +>v : Symbol(v, Decl(ib2.d.ts, 0, 8), Decl(ib2.d.ts, 0, 25)) +>b : Symbol(b, Decl(index.d.ts, 1, 8)) + +export const f1: 1; +>f1 : Symbol(f1, Decl(index.d.ts, 2, 12)) + +export const f2: 2; +>f2 : Symbol(f2, Decl(index.d.ts, 3, 12)) + +export const f3: 3; +>f3 : Symbol(f3, Decl(index.d.ts, 4, 12)) + +export const f4: 4; +>f4 : Symbol(f4, Decl(index.d.ts, 5, 12)) + +export const f5: 5; +>f5 : Symbol(f5, Decl(index.d.ts, 6, 12)) + +export const f6: 6; +>f6 : Symbol(f6, Decl(index.d.ts, 7, 12)) + +export const f7: 7; +>f7 : Symbol(f7, Decl(index.d.ts, 8, 12)) + +export const f8: 8; +>f8 : Symbol(f8, Decl(index.d.ts, 9, 12)) + +export const f9: 9; +>f9 : Symbol(f9, Decl(index.d.ts, 10, 12)) + +export const f10: 10; +>f10 : Symbol(f10, Decl(index.d.ts, 11, 12)) + +=== /index2.d.ts === +export { v as a } from "./ia2"; +>v : Symbol(v, Decl(ia2.d.ts, 0, 8), Decl(ia2.d.ts, 0, 25)) +>a : Symbol(a, Decl(index2.d.ts, 0, 8)) + +export { v as b } from "./ib2"; +>v : Symbol(v, Decl(ib2.d.ts, 0, 8), Decl(ib2.d.ts, 0, 25)) +>b : Symbol(b, Decl(index2.d.ts, 1, 8)) + +=== /d.d.ts === + +export * from "./index"; +export * from "./index2"; + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.types b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.types new file mode 100644 index 0000000000000..acecbd2516c82 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.types @@ -0,0 +1,210 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts] //// + +=== /main.ts === +import * as idx from "./d"; +>idx : typeof idx + +const all = { ...idx }; +>all : { a: { pa: { pb: {}; mb: 1; }; ma: 1; }; b: { pb: {}; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } +>{ ...idx } : { a: { pa: { pb: {}; mb: 1; }; ma: 1; }; b: { pb: {}; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } +>idx : typeof idx + +import * as MA from "./ma"; +>MA : typeof MA + +import * as MB from "./mb"; +>MB : typeof MB + +export const fromA = MA.pa; +>fromA : { pb: {}; mb: 1; } +>MA.pa : { pb: {}; mb: 1; } +>MA : typeof MA +>pa : { pb: {}; mb: 1; } + +export const fromB = MB.pb; +>fromB : {} +>MB.pb : {} +>MB : typeof MB +>pb : {} + +export const checkA: 1 = MA.pa.mb; +>checkA : 1 +>MA.pa.mb : 1 +>MA.pa : { pb: {}; mb: 1; } +>MA : typeof MA +>pa : { pb: {}; mb: 1; } +>mb : 1 + +export const checkB: 1 = MB.pb.ma; +>checkB : 1 +>MB.pb.ma : any +>MB.pb : {} +>MB : typeof MB +>pb : {} +>ma : any + +=== /ma.js === +export { v as pa } from "./xa"; +>v : { pb: {}; mb: 1; } +>pa : { pb: {}; mb: 1; } + +export const ma = 1; +>ma : 1 +>1 : 1 + +=== /mb.js === +export { v as pb } from "./xb"; +>v : {} +>pb : {} + +export const mb = 1; +>mb : 1 +>1 : 1 + +=== /xa.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./mb") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: { pb: {}; mb: 1; }; } +>{ v: { ...M } } : { v: { pb: {}; mb: 1; }; } +>v : { pb: {}; mb: 1; } +>{ ...M } : { pb: {}; mb: 1; } +>M : typeof import("./mb") + +module.exports = o; +>module.exports = o : { v: { pb: {}; mb: 1; }; } +>module.exports : { v: { pb: {}; mb: 1; }; } +>module : { exports: { v: { pb: {}; mb: 1; }; }; } +>exports : { v: { pb: {}; mb: 1; }; } +>o : { v: { pb: {}; mb: 1; }; } + +=== /xb.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./ma") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: {}; } +>{ v: { ...M } } : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>{ ...M } : { pa: { pb: {}; mb: 1; }; ma: 1; } +>M : typeof import("./ma") + +module.exports = o; +>module.exports = o : { v: {}; } +>module.exports : { v: {}; } +>module : { exports: { v: {}; }; } +>exports : { v: {}; } +>o : { v: {}; } + +=== /ia.js === +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./ma") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>{ v: { ...M } } : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>{ ...M } : { pa: { pb: {}; mb: 1; }; ma: 1; } +>M : typeof import("./ma") + +module.exports = o; +>module.exports = o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>module.exports : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>module : { exports: { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; }; } +>exports : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } + +=== /ib.js === +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +>M : typeof import("./mb") +>(null) : any + +const o = { v: { ...M } }; +>o : { v: { pb: {}; mb: 1; }; } +>{ v: { ...M } } : { v: { pb: {}; mb: 1; }; } +>v : { pb: {}; mb: 1; } +>{ ...M } : { pb: {}; mb: 1; } +>M : typeof import("./mb") + +module.exports = o; +>module.exports = o : { v: { pb: {}; mb: 1; }; } +>module.exports : { v: { pb: {}; mb: 1; }; } +>module : { exports: { v: { pb: {}; mb: 1; }; }; } +>exports : { v: { pb: {}; mb: 1; }; } +>o : { v: { pb: {}; mb: 1; }; } + +=== /ia2.d.ts === +export { v } from "./ia"; +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } + +export type v = number; +>v : number + +=== /ib2.d.ts === +export { v } from "./ib"; +>v : { pb: {}; mb: 1; } + +export type v = number; +>v : number + +=== /index.d.ts === +export { v as a } from "./ia2"; +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>a : { pa: { pb: {}; mb: 1; }; ma: 1; } + +export { v as b } from "./ib2"; +>v : { pb: {}; mb: 1; } +>b : { pb: {}; mb: 1; } + +export const f1: 1; +>f1 : 1 + +export const f2: 2; +>f2 : 2 + +export const f3: 3; +>f3 : 3 + +export const f4: 4; +>f4 : 4 + +export const f5: 5; +>f5 : 5 + +export const f6: 6; +>f6 : 6 + +export const f7: 7; +>f7 : 7 + +export const f8: 8; +>f8 : 8 + +export const f9: 9; +>f9 : 9 + +export const f10: 10; +>f10 : 10 + +=== /index2.d.ts === +export { v as a } from "./ia2"; +>v : { pa: { pb: {}; mb: 1; }; ma: 1; } +>a : { pa: { pb: {}; mb: 1; }; ma: 1; } + +export { v as b } from "./ib2"; +>v : { pb: {}; mb: 1; } +>b : { pb: {}; mb: 1; } + +=== /d.d.ts === + +export * from "./index"; +export * from "./index2"; + diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts new file mode 100644 index 0000000000000..86fe41104d7dd --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts @@ -0,0 +1,81 @@ +// @strict: true +// @module: commonjs +// @target: es2020 +// @allowJs: true +// @checkJs: false +// @skipLibCheck: true +// @declaration: true +// @outDir: /out +// @noImplicitReferences: true + +// @Filename: /ma.js +export { v as pa } from "./xa"; +export const ma = 1; + +// @Filename: /mb.js +export { v as pb } from "./xb"; +export const mb = 1; + +// @Filename: /xa.js +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /xb.js +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /ia.js +/** @type {typeof import("./ma")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /ib.js +/** @type {typeof import("./mb")} */ +const M = /** @type {any} */ (null); +const o = { v: { ...M } }; +module.exports = o; + +// @Filename: /ia2.d.ts +export { v } from "./ia"; +export type v = number; + +// @Filename: /ib2.d.ts +export { v } from "./ib"; +export type v = number; + +// @Filename: /index.d.ts +export { v as a } from "./ia2"; +export { v as b } from "./ib2"; +export const f1: 1; +export const f2: 2; +export const f3: 3; +export const f4: 4; +export const f5: 5; +export const f6: 6; +export const f7: 7; +export const f8: 8; +export const f9: 9; +export const f10: 10; + +// @Filename: /index2.d.ts +export { v as a } from "./ia2"; +export { v as b } from "./ib2"; + +// @Filename: /d.d.ts +export * from "./index"; +export * from "./index2"; + +// @Filename: /main.ts +import * as idx from "./d"; +const all = { ...idx }; +import * as MA from "./ma"; +import * as MB from "./mb"; +export const fromA = MA.pa; +export const fromB = MB.pb; +export const checkA: 1 = MA.pa.mb; +export const checkB: 1 = MB.pb.ma; From 73d726b8555edb906d41423698a8b9baa4084902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 11:43:48 +0200 Subject: [PATCH 20/35] Create static index signature sibling types in a stable order --- tsc/internal/checker/checker.go | 6 +- tsc/internal/execute/tsctests/tsc_test.go | 37 +++ ...gnature-sibling-types-in-a-stable-order.js | 281 ++++++++++++++++++ 3 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-static-index-signature-sibling-types-in-a-stable-order.js diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 2c410e47997f3..d794680fcb3e3 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -21166,7 +21166,11 @@ func (c *Checker) resolveAnonymousTypeMembers(t *Type) { } indexSymbol := members[ast.InternalSymbolNameIndex] if indexSymbol != nil { - indexInfos = c.getIndexInfosOfIndexSymbol(indexSymbol, slices.Collect(maps.Values(members))) + // The types of the siblings are created in this order, so sort them rather than using the random iteration + // order of the symbol table. + siblingSymbols := slices.Collect(maps.Values(members)) + c.sortSymbols(siblingSymbols) + indexInfos = c.getIndexInfosOfIndexSymbol(indexSymbol, siblingSymbols) } else { if baseConstructorIndexInfo != nil { indexInfos = append(indexInfos, baseConstructorIndexInfo) diff --git a/tsc/internal/execute/tsctests/tsc_test.go b/tsc/internal/execute/tsctests/tsc_test.go index a2e326f9baadd..ee6e3fe081692 100644 --- a/tsc/internal/execute/tsctests/tsc_test.go +++ b/tsc/internal/execute/tsctests/tsc_test.go @@ -5125,6 +5125,43 @@ func TestGenerateTrace(t *testing.T) { }, commandLineArgs: []string{"--generateTrace", "/home/src/workspaces/project/trace", "--singleThreaded"}, }, + { + subScenario: "generateTrace creates static index signature sibling types in a stable order", + files: FileMap{ + "/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(` + { + "compilerOptions": { + "strict": true, + "skipLibCheck": true, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "out" + }, + "files": ["main.ts", "ambient.d.ts"] + }`), + "/home/src/workspaces/project/ambient.d.ts": stringtestutil.Dedent(` + declare const k1: string; + declare class C { + static [k1]: { a: 1 }; + static m1: { p1: 1 }; + static m2: { p2: 2 }; + static m3: { p3: 3 }; + static m4: { p4: 4 }; + static m5: { p5: 5 }; + static m6: { p6: 6 }; + static m7: { p7: 7 }; + static m8: { p8: 8 }; + static m9: { p9: 9 }; + static m10: { p10: 10 }; + } + `), + "/home/src/workspaces/project/main.ts": stringtestutil.Dedent(` + declare function expand(): { [K in keyof X]: X[K] }; + export const w = expand(); + `), + }, + commandLineArgs: []string{"--generateTrace", "/home/src/workspaces/project/trace", "--singleThreaded"}, + }, } for _, c := range cases { diff --git a/tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-static-index-signature-sibling-types-in-a-stable-order.js b/tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-static-index-signature-sibling-types-in-a-stable-order.js new file mode 100644 index 0000000000000..c5bbab613c082 --- /dev/null +++ b/tsc/testdata/baselines/reference/tsc/generateTrace/generateTrace-creates-static-index-signature-sibling-types-in-a-stable-order.js @@ -0,0 +1,281 @@ +currentDirectory::/home/src/workspaces/project +useCaseSensitiveFileNames::true +Input:: +//// [/home/src/workspaces/project/ambient.d.ts] *new* +declare const k1: string; +declare class C { + static [k1]: { a: 1 }; + static m1: { p1: 1 }; + static m2: { p2: 2 }; + static m3: { p3: 3 }; + static m4: { p4: 4 }; + static m5: { p5: 5 }; + static m6: { p6: 6 }; + static m7: { p7: 7 }; + static m8: { p8: 8 }; + static m9: { p9: 9 }; + static m10: { p10: 10 }; +} +//// [/home/src/workspaces/project/main.ts] *new* +declare function expand(): { [K in keyof X]: X[K] }; +export const w = expand(); +//// [/home/src/workspaces/project/tsconfig.json] *new* +{ + "compilerOptions": { + "strict": true, + "skipLibCheck": true, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "out" + }, + "files": ["main.ts", "ambient.d.ts"] +} + +tsgo --generateTrace /home/src/workspaces/project/trace --singleThreaded +ExitStatus:: Success +Output:: +//// [/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts] *Lib* +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +interface SymbolConstructor { + (desc?: string | number): symbol; + for(name: string): symbol; + readonly toStringTag: symbol; +} +declare var Symbol: SymbolConstructor; +interface Symbol { + readonly [Symbol.toStringTag]: string; +} +declare const console: { log(msg: any): void; }; +//// [/home/src/workspaces/project/out/main.d.ts] *new* +export declare const w: { + [x: string]: C; + m1: { + p1: 1; + }; + m2: { + p2: 2; + }; + m3: { + p3: 3; + }; + m4: { + p4: 4; + }; + m5: { + p5: 5; + }; + m6: { + p6: 6; + }; + m7: { + p7: 7; + }; + m8: { + p8: 8; + }; + m9: { + p9: 9; + }; + m10: { + p10: 10; + }; + prototype: C; +}; + +//// [/home/src/workspaces/project/trace/legend.json] *new* +[ + { + "configFilePath": "/home/src/workspaces/project/tsconfig.json", + "tracePath": "/home/src/workspaces/project/trace/trace.json", + "typesPath": "/home/src/workspaces/project/trace/types_0.json", + "checkerId": 0 + } +] +//// [/home/src/workspaces/project/trace/trace.json] *new* +[ +{"pid":1,"tid":1,"ph":"M","cat":"__metadata","ts":1,"name":"process_name","args":{"name":"tsgo"}}, +{"pid":1,"tid":1,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"Main"}}, +{"pid":1,"tid":1,"ph":"M","cat":"disabled-by-default-devtools.timeline","ts":1,"name":"TracingStartedInBrowser"}, +{"pid":1,"tid":1,"ph":"B","cat":"program","ts":2,"name":"createProgram","args":{"configFilePath":"/home/src/workspaces/project/tsconfig.json"}}, +{"pid":1,"tid":181085097,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"B","cat":"parse","ts":3,"name":"createSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"E","cat":"parse","ts":4,"name":"createSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":483181977,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":483181977,"ph":"B","cat":"parse","ts":5,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":483181977,"ph":"E","cat":"parse","ts":6,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":100209852,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"file:/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":100209852,"ph":"B","cat":"parse","ts":7,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":100209852,"ph":"E","cat":"parse","ts":8,"name":"createSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"program","ts":9,"name":"createProgram","args":{"configFilePath":"/home/src/workspaces/project/tsconfig.json"}}, +{"pid":1,"tid":1,"ph":"B","cat":"bind","ts":10,"name":"bindSourceFiles"}, +{"pid":1,"tid":483181977,"ph":"B","cat":"bind","ts":11,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":483181977,"ph":"E","cat":"bind","ts":12,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/ambient.d.ts"}}, +{"pid":1,"tid":100209852,"ph":"B","cat":"bind","ts":13,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":100209852,"ph":"E","cat":"bind","ts":14,"name":"bindSourceFile","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":181085097,"ph":"B","cat":"bind","ts":15,"name":"bindSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":181085097,"ph":"E","cat":"bind","ts":16,"name":"bindSourceFile","args":{"path":"/home/src/tslibs/TS/Lib/lib.es2026.full.d.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"bind","ts":17,"name":"bindSourceFiles"}, +{"pid":1,"tid":1,"ph":"B","cat":"check","ts":18,"name":"checkSourceFiles"}, +{"pid":1,"tid":2,"ph":"M","cat":"__metadata","ts":1,"name":"thread_name","args":{"name":"checker:0"}}, +{"pid":1,"tid":2,"ph":"B","cat":"check","ts":19,"name":"checkSourceFile","args":{"checkerId":0,"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":2,"ph":"E","cat":"check","ts":20,"name":"checkSourceFile","args":{"checkerId":0,"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"check","ts":21,"name":"checkSourceFiles"}, +{"pid":1,"tid":1,"ph":"B","cat":"emit","ts":22,"name":"emit"}, +{"pid":1,"tid":100209852,"ph":"B","cat":"emit","ts":23,"name":"emit","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"B","cat":"emit","ts":24,"name":"emitDeclarationFileOrBundle","args":{"declarationFilePath":"/home/src/workspaces/project/out/main.d.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"emit","ts":25,"name":"emitDeclarationFileOrBundle","args":{"declarationFilePath":"/home/src/workspaces/project/out/main.d.ts"}}, +{"pid":1,"tid":100209852,"ph":"E","cat":"emit","ts":26,"name":"emit","args":{"path":"/home/src/workspaces/project/main.ts"}}, +{"pid":1,"tid":1,"ph":"E","cat":"emit","ts":27,"name":"emit"} +] + +//// [/home/src/workspaces/project/trace/types_0.json] *new* +[{"id":1,"intrinsicName":"any","recursionId":0,"flags":["Any"]}, +{"id":2,"intrinsicName":"any","recursionId":1,"flags":["Any"]}, +{"id":3,"intrinsicName":"any","recursionId":2,"flags":["Any"]}, +{"id":4,"intrinsicName":"any","recursionId":3,"flags":["Any"]}, +{"id":5,"intrinsicName":"error","recursionId":4,"flags":["Any"]}, +{"id":6,"intrinsicName":"unresolved","recursionId":5,"flags":["Any"]}, +{"id":7,"intrinsicName":"any","recursionId":6,"flags":["Any"]}, +{"id":8,"intrinsicName":"intrinsic","recursionId":7,"flags":["Any"]}, +{"id":9,"intrinsicName":"unknown","recursionId":8,"flags":["Unknown"]}, +{"id":10,"intrinsicName":"undefined","recursionId":9,"flags":["Undefined"]}, +{"id":11,"intrinsicName":"undefined","recursionId":10,"flags":["Undefined"]}, +{"id":12,"intrinsicName":"undefined","recursionId":11,"flags":["Undefined"]}, +{"id":13,"intrinsicName":"null","recursionId":12,"flags":["Null"]}, +{"id":14,"intrinsicName":"string","recursionId":13,"flags":["String"]}, +{"id":15,"intrinsicName":"number","recursionId":14,"flags":["Number"]}, +{"id":16,"intrinsicName":"bigint","recursionId":15,"flags":["BigInt"]}, +{"id":17,"recursionId":16,"flags":["BooleanLiteral"],"display":"false"}, +{"id":18,"recursionId":17,"flags":["BooleanLiteral"],"display":"false"}, +{"id":19,"recursionId":18,"flags":["BooleanLiteral"],"display":"true"}, +{"id":20,"recursionId":19,"flags":["BooleanLiteral"],"display":"true"}, +{"id":21,"recursionId":20,"unionTypes":[17,19],"flags":["Boolean","Union"],"display":"boolean"}, +{"id":22,"intrinsicName":"symbol","recursionId":21,"flags":["ESSymbol"]}, +{"id":23,"intrinsicName":"void","recursionId":22,"flags":["Void"]}, +{"id":24,"intrinsicName":"never","recursionId":23,"flags":["Never"]}, +{"id":25,"intrinsicName":"never","recursionId":24,"flags":["Never"]}, +{"id":26,"intrinsicName":"never","recursionId":25,"flags":["Never"]}, +{"id":27,"intrinsicName":"never","recursionId":26,"flags":["Never"]}, +{"id":28,"intrinsicName":"object","recursionId":27,"flags":["NonPrimitive"]}, +{"id":29,"recursionId":28,"unionTypes":[14,15],"flags":["Union"],"display":"string | number"}, +{"id":30,"recursionId":29,"unionTypes":[14,15,22],"flags":["Union"],"display":"string | number | symbol"}, +{"id":31,"recursionId":30,"unionTypes":[15,16],"flags":["Union"],"display":"number | bigint"}, +{"id":32,"recursionId":31,"flags":["TemplateLiteral"],"display":"`${number}`"}, +{"id":33,"recursionId":32,"unionTypes":[10,13,14,15,16,17,19],"flags":["Union"],"display":"string | number | bigint | boolean | null | undefined"}, +{"id":34,"intrinsicName":"never","recursionId":33,"flags":["Never"]}, +{"id":35,"recursionId":34,"flags":["Object"],"display":"{}"}, +{"id":36,"recursionId":35,"flags":["Object"],"display":"{}"}, +{"id":37,"recursionId":36,"flags":["Object"],"display":"{}"}, +{"id":38,"symbolName":"__type","recursionId":37,"flags":["Object"],"display":"{}"}, +{"id":39,"recursionId":38,"flags":["Object"],"display":"{}"}, +{"id":40,"recursionId":39,"unionTypes":[10,13,39],"flags":["Union"],"display":"{} | null | undefined"}, +{"id":41,"recursionId":40,"flags":["Object"],"display":"{}"}, +{"id":42,"recursionId":41,"flags":["Object"],"display":"{}"}, +{"id":43,"recursionId":42,"flags":["Object"],"display":"{}"}, +{"id":44,"recursionId":43,"flags":["Object"],"display":"{}"}, +{"id":45,"recursionId":44,"flags":["Object"],"display":"{}"}, +{"id":46,"recursionId":45,"flags":["TypeParameter"]}, +{"id":47,"recursionId":46,"flags":["TypeParameter"]}, +{"id":48,"recursionId":47,"flags":["TypeParameter"]}, +{"id":49,"recursionId":48,"flags":["TypeParameter"]}, +{"id":50,"recursionId":49,"flags":["TypeParameter"]}, +{"id":51,"recursionId":50,"flags":["StringLiteral"],"display":"\"\""}, +{"id":52,"recursionId":51,"flags":["NumberLiteral"],"display":"0"}, +{"id":53,"recursionId":52,"flags":["BigIntLiteral"],"display":"0n"}, +{"id":54,"recursionId":53,"flags":["StringLiteral"],"display":"\"bigint\""}, +{"id":55,"recursionId":54,"flags":["StringLiteral"],"display":"\"boolean\""}, +{"id":56,"recursionId":55,"flags":["StringLiteral"],"display":"\"function\""}, +{"id":57,"recursionId":56,"flags":["StringLiteral"],"display":"\"number\""}, +{"id":58,"recursionId":57,"flags":["StringLiteral"],"display":"\"object\""}, +{"id":59,"recursionId":58,"flags":["StringLiteral"],"display":"\"string\""}, +{"id":60,"recursionId":59,"flags":["StringLiteral"],"display":"\"symbol\""}, +{"id":61,"recursionId":60,"flags":["StringLiteral"],"display":"\"undefined\""}, +{"id":62,"recursionId":61,"unionTypes":[54,55,56,57,58,59,60,61],"flags":["Union"],"display":"\"bigint\" | \"boolean\" | \"function\" | \"number\" | \"object\" | \"string\" | \"symbol\" | \"undefined\""}, +{"id":63,"symbolName":"IArguments","recursionId":62,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":6,"character":1},"end":{"line":6,"character":24}},"flags":["Object"]}, +{"id":64,"symbolName":"globalThis","recursionId":63,"flags":["Object"],"display":"typeof globalThis"}, +{"id":65,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[66],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":66,"symbolName":"T","recursionId":65,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":17},"end":{"line":11,"character":18}},"flags":["TypeParameter"]}, +{"id":67,"symbolName":"Array","recursionId":64,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["TypeParameter"]}, +{"id":68,"symbolName":"Object","recursionId":66,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":8,"character":1},"end":{"line":8,"character":20}},"flags":["Object"]}, +{"id":69,"symbolName":"Function","recursionId":67,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":3,"character":1},"end":{"line":3,"character":22}},"flags":["Object"]}, +{"id":70,"symbolName":"CallableFunction","recursionId":68,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":4,"character":1},"end":{"line":4,"character":30}},"flags":["Object"]}, +{"id":71,"symbolName":"NewableFunction","recursionId":69,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":5,"character":1},"end":{"line":5,"character":29}},"flags":["Object"]}, +{"id":72,"symbolName":"String","recursionId":70,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":10,"character":1},"end":{"line":10,"character":34}},"flags":["Object"]}, +{"id":73,"symbolName":"Number","recursionId":71,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":7,"character":1},"end":{"line":7,"character":41}},"flags":["Object"]}, +{"id":74,"symbolName":"Boolean","recursionId":72,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":2,"character":1},"end":{"line":2,"character":21}},"flags":["Object"]}, +{"id":75,"symbolName":"RegExp","recursionId":73,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":9,"character":1},"end":{"line":9,"character":20}},"flags":["Object"]}, +{"id":76,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[1],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":77,"symbolName":"Array","recursionId":64,"instantiatedType":65,"typeArguments":[2],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":11,"character":1},"end":{"line":11,"character":55}},"flags":["Object"]}, +{"id":78,"symbolName":"ReadonlyArray","recursionId":74,"instantiatedType":78,"typeArguments":[79],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":1},"end":{"line":12,"character":30}},"flags":["Object"]}, +{"id":79,"symbolName":"T","recursionId":75,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":25},"end":{"line":12,"character":26}},"flags":["TypeParameter"]}, +{"id":80,"symbolName":"ReadonlyArray","recursionId":74,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":1},"end":{"line":12,"character":30}},"flags":["TypeParameter"]}, +{"id":81,"symbolName":"ReadonlyArray","recursionId":74,"instantiatedType":78,"typeArguments":[1],"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":12,"character":1},"end":{"line":12,"character":30}},"flags":["Object"]}, +{"id":82,"symbolName":"X","recursionId":76,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":25},"end":{"line":1,"character":26}},"flags":["TypeParameter"]}, +{"id":83,"symbolName":"K","recursionId":77,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":34},"end":{"line":1,"character":46}},"flags":["TypeParameter"]}, +{"id":84,"recursionId":78,"keyofType":82,"flags":["Index"]}, +{"id":85,"symbolName":"__type","recursionId":79,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":31},"end":{"line":1,"character":55}},"flags":["Object"]}, +{"id":86,"recursionId":76,"indexedAccessObjectType":82,"indexedAccessIndexType":83,"flags":["IndexedAccess"]}, +{"id":87,"symbolName":"Symbol","recursionId":80,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":18,"character":13},"end":{"line":18,"character":38}},"flags":["Object"]}, +{"id":88,"symbolName":"SymbolConstructor","recursionId":81,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":13,"character":1},"end":{"line":17,"character":2}},"flags":["Object"]}, +{"id":89,"symbolName":"toStringTag","recursionId":82,"firstDeclaration":{"path":"/home/src/tslibs/ts/lib/lib.es2026.full.d.ts","start":{"line":16,"character":5},"end":{"line":16,"character":34}},"flags":["UniqueESSymbol"]}, +{"id":90,"symbolName":"expand","recursionId":83,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":1},"end":{"line":1,"character":56}},"flags":["Object"],"display":"() => { [K in keyof X]: X[K]; }"}, +{"id":91,"symbolName":"C","recursionId":84,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":2,"character":1},"end":{"line":14,"character":2}},"flags":["Object"],"display":"typeof C"}, +{"id":92,"symbolName":"C","recursionId":85,"instantiatedType":92,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":2,"character":1},"end":{"line":14,"character":2}},"flags":["Object"]}, +{"id":93,"symbolName":"C","recursionId":85,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":2,"character":1},"end":{"line":14,"character":2}},"flags":["TypeParameter"]}, +{"id":94,"symbolName":"__type","recursionId":84,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":31},"end":{"line":1,"character":55}},"flags":["Object"]}, +{"id":95,"symbolName":"K","recursionId":77,"firstDeclaration":{"path":"/home/src/workspaces/project/main.ts","start":{"line":1,"character":34},"end":{"line":1,"character":46}},"flags":["TypeParameter"]}, +{"id":96,"symbolName":"__type","recursionId":86,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":3,"character":18},"end":{"line":3,"character":26}},"flags":["Object"],"display":"{ a: 1; }"}, +{"id":97,"symbolName":"__type","recursionId":87,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":4,"character":16},"end":{"line":4,"character":25}},"flags":["Object"],"display":"{ p1: 1; }"}, +{"id":98,"symbolName":"__type","recursionId":88,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":5,"character":16},"end":{"line":5,"character":25}},"flags":["Object"],"display":"{ p2: 2; }"}, +{"id":99,"symbolName":"__type","recursionId":89,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":6,"character":16},"end":{"line":6,"character":25}},"flags":["Object"],"display":"{ p3: 3; }"}, +{"id":100,"symbolName":"__type","recursionId":90,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":7,"character":16},"end":{"line":7,"character":25}},"flags":["Object"],"display":"{ p4: 4; }"}, +{"id":101,"symbolName":"__type","recursionId":91,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":8,"character":16},"end":{"line":8,"character":25}},"flags":["Object"],"display":"{ p5: 5; }"}, +{"id":102,"symbolName":"__type","recursionId":92,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":9,"character":16},"end":{"line":9,"character":25}},"flags":["Object"],"display":"{ p6: 6; }"}, +{"id":103,"symbolName":"__type","recursionId":93,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":10,"character":16},"end":{"line":10,"character":25}},"flags":["Object"],"display":"{ p7: 7; }"}, +{"id":104,"symbolName":"__type","recursionId":94,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":11,"character":16},"end":{"line":11,"character":25}},"flags":["Object"],"display":"{ p8: 8; }"}, +{"id":105,"symbolName":"__type","recursionId":95,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":12,"character":16},"end":{"line":12,"character":25}},"flags":["Object"],"display":"{ p9: 9; }"}, +{"id":106,"symbolName":"__type","recursionId":96,"firstDeclaration":{"path":"/home/src/workspaces/project/ambient.d.ts","start":{"line":13,"character":17},"end":{"line":13,"character":28}},"flags":["Object"],"display":"{ p10: 10; }"}, +{"id":107,"recursionId":97,"flags":["NumberLiteral"],"display":"10"}, +{"id":108,"recursionId":98,"flags":["NumberLiteral"],"display":"10"}, +{"id":109,"recursionId":99,"flags":["NumberLiteral"],"display":"9"}, +{"id":110,"recursionId":100,"flags":["NumberLiteral"],"display":"9"}, +{"id":111,"recursionId":101,"flags":["NumberLiteral"],"display":"8"}, +{"id":112,"recursionId":102,"flags":["NumberLiteral"],"display":"8"}, +{"id":113,"recursionId":103,"flags":["NumberLiteral"],"display":"7"}, +{"id":114,"recursionId":104,"flags":["NumberLiteral"],"display":"7"}, +{"id":115,"recursionId":105,"flags":["NumberLiteral"],"display":"6"}, +{"id":116,"recursionId":106,"flags":["NumberLiteral"],"display":"6"}, +{"id":117,"recursionId":107,"flags":["NumberLiteral"],"display":"5"}, +{"id":118,"recursionId":108,"flags":["NumberLiteral"],"display":"5"}, +{"id":119,"recursionId":109,"flags":["NumberLiteral"],"display":"4"}, +{"id":120,"recursionId":110,"flags":["NumberLiteral"],"display":"4"}, +{"id":121,"recursionId":111,"flags":["NumberLiteral"],"display":"3"}, +{"id":122,"recursionId":112,"flags":["NumberLiteral"],"display":"3"}, +{"id":123,"recursionId":113,"flags":["NumberLiteral"],"display":"2"}, +{"id":124,"recursionId":114,"flags":["NumberLiteral"],"display":"2"}, +{"id":125,"recursionId":115,"flags":["NumberLiteral"],"display":"1"}, +{"id":126,"recursionId":116,"flags":["NumberLiteral"],"display":"1"}, +{"id":127,"recursionId":117,"flags":["StringLiteral"],"display":"\"m1\""}, +{"id":128,"recursionId":118,"flags":["StringLiteral"],"display":"\"m2\""}, +{"id":129,"recursionId":119,"flags":["StringLiteral"],"display":"\"m3\""}, +{"id":130,"recursionId":120,"flags":["StringLiteral"],"display":"\"m4\""}, +{"id":131,"recursionId":121,"flags":["StringLiteral"],"display":"\"m5\""}, +{"id":132,"recursionId":122,"flags":["StringLiteral"],"display":"\"m6\""}, +{"id":133,"recursionId":123,"flags":["StringLiteral"],"display":"\"m7\""}, +{"id":134,"recursionId":124,"flags":["StringLiteral"],"display":"\"m8\""}, +{"id":135,"recursionId":125,"flags":["StringLiteral"],"display":"\"m9\""}, +{"id":136,"recursionId":126,"flags":["StringLiteral"],"display":"\"m10\""}, +{"id":137,"recursionId":127,"flags":["StringLiteral"],"display":"\"prototype\""}] + + From 70cf86fa2ce77b70a5367195b07266e67b54598e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 12:13:03 +0200 Subject: [PATCH 21/35] Rewrap the forEachSymbolTableEntry doc comment --- tsc/internal/checker/symbolaccessibility.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index 65e47be7891ef..44e6f2db36cc4 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -294,11 +294,11 @@ func (c *Checker) buildExternalModuleContainerIndex() { // forEachSymbolTableEntry calls f for each entry of a symbol table so that any types f creates are created // in an order that does not depend on the table's random iteration order. That holds as long as f has no side // effects for a symbol that is not an alias, or for an alias whose whole chain of aliases is already resolved: those -// come first, in table order. Resolving an alias can create types, so the other aliases come last, sorted. f must not depend on the -// order it sees entries in for its result: collect and sort what it finds instead. f returns true to stop, which is -// only allowed when the answer does not depend on which entry stopped it (such as whether any entry matches), and -// forEachSymbolTableEntry then returns true. f gets each symbol's key in the table, which is not always the -// symbol's name (a default export is keyed "default"). +// come first, in table order. Resolving an alias can create types, so the other aliases come last, sorted. f must +// not depend on the order it sees entries in for its result: collect and sort what it finds instead. f returns true +// to stop, which is only allowed when the answer does not depend on which entry stopped it (such as whether any +// entry matches), and forEachSymbolTableEntry then returns true. f gets each symbol's key in the table, which is +// not always the symbol's name (a default export is keyed "default"). func (c *Checker) forEachSymbolTableEntry(symbols ast.SymbolTable, f func(name string, symbol *ast.Symbol) bool) bool { type entry struct { name string From b9981caa87e8d157c877af6b36c4a47427dfe06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 10:50:51 +0200 Subject: [PATCH 22/35] Make symbol tables insertion-ordered --- tsc/internal/api/session.go | 16 +- .../api/session_symbolresponse_test.go | 4 +- tsc/internal/ast/symbol.go | 209 ++++++++++- tsc/internal/ast/symbol_test.go | 50 +-- tsc/internal/ast/utilities.go | 2 +- tsc/internal/binder/binder.go | 42 +-- tsc/internal/binder/nameresolver.go | 6 +- tsc/internal/checker/checker.go | 351 +++++++++--------- tsc/internal/checker/emitresolver.go | 5 +- tsc/internal/checker/inference.go | 8 +- tsc/internal/checker/jsx.go | 20 +- tsc/internal/checker/nodebuilder_hover.go | 4 +- tsc/internal/checker/nodebuilderimpl.go | 8 +- tsc/internal/checker/nodebuilderscopes.go | 10 +- tsc/internal/checker/services.go | 33 +- tsc/internal/checker/symbolaccessibility.go | 26 +- tsc/internal/checker/types_test.go | 8 +- tsc/internal/checker/utilities.go | 10 +- .../incremental/affectedfileshandler.go | 2 +- tsc/internal/ls/autoimport/extract.go | 18 +- ..._fixclassincorrectlyimplementsinterface.go | 12 +- tsc/internal/ls/completions.go | 4 +- tsc/internal/ls/definition.go | 2 +- tsc/internal/ls/findallreferences.go | 8 +- tsc/internal/modulespecifiers/specifiers.go | 2 +- tsc/internal/printer/namegenerator.go | 2 +- .../transformers/declarations/transform.go | 6 +- 27 files changed, 537 insertions(+), 331 deletions(-) diff --git a/tsc/internal/api/session.go b/tsc/internal/api/session.go index 93d6ab53c303d..d8cbda26f9a06 100644 --- a/tsc/internal/api/session.go +++ b/tsc/internal/api/session.go @@ -70,7 +70,7 @@ func getSourceFileSymbolIndex(sourceFile *ast.SourceFile) map[SymbolID]*ast.Symb addSymbol(symbol.Parent()) addSymbol(symbol.ExportSymbol()) for _, table := range []ast.SymbolTable{symbol.Members(), symbol.Exports()} { - for _, child := range table { + for _, child := range table.All() { addSymbol(child) } } @@ -81,11 +81,11 @@ func getSourceFileSymbolIndex(sourceFile *ast.SourceFile) map[SymbolID]*ast.Symb } addSymbol(node.Symbol()) addSymbol(node.LocalSymbol()) - for _, symbol := range node.Locals() { + for _, symbol := range node.Locals().All() { addSymbol(symbol) } } - for _, symbol := range file.GlobalExports { + for _, symbol := range file.GlobalExports.All() { addSymbol(symbol) } for _, module := range file.PatternAmbientModules { @@ -3446,11 +3446,11 @@ func (s *Session) resolveSymbolTablePropertyOfSymbol(ctx context.Context, params defer release() symbolTable := getter(symbol) - if len(symbolTable) == 0 { + if symbolTable.Len() == 0 { return nil, nil } - if len(symbolTable) == 1 { - for _, sub := range symbolTable { + if symbolTable.Len() == 1 { + for _, sub := range symbolTable.All() { if sd == nil { return []*SymbolResponse{newFileSymbolResponse(sub)}, nil } @@ -3458,8 +3458,8 @@ func (s *Session) resolveSymbolTablePropertyOfSymbol(ctx context.Context, params } } - symbols := make([]*ast.Symbol, 0, len(symbolTable)) - for _, sub := range symbolTable { + symbols := make([]*ast.Symbol, 0, symbolTable.Len()) + for _, sub := range symbolTable.All() { symbols = append(symbols, sub) } if sd == nil { diff --git a/tsc/internal/api/session_symbolresponse_test.go b/tsc/internal/api/session_symbolresponse_test.go index ca60a1bb1fbf4..51a106a341bf1 100644 --- a/tsc/internal/api/session_symbolresponse_test.go +++ b/tsc/internal/api/session_symbolresponse_test.go @@ -85,7 +85,7 @@ func TestSymbolReferencesIdentifyOwnerWithoutDescriptor(t *testing.T) { assert.Assert(t, !strings.Contains(string(encoded), "contentHash")) // A file-owned symbol's relationships are references into the same file. - member := class.Members()["property"] + member := class.Members().Get("property") response := newFileSymbolResponse(member) assert.DeepEqual(t, response.Parent, reference) } @@ -109,6 +109,6 @@ func TestContentMappedSymbolsAreSnapshotOwned(t *testing.T) { assert.NilError(t, err) assert.Equal(t, resolved, class) - reference := newSymbolReference(class.Members()["property"]) + reference := newSymbolReference(class.Members().Get("property")) assert.Equal(t, reference.File, "") } diff --git a/tsc/internal/ast/symbol.go b/tsc/internal/ast/symbol.go index 00312310691c5..702554ff0a16a 100644 --- a/tsc/internal/ast/symbol.go +++ b/tsc/internal/ast/symbol.go @@ -1,6 +1,9 @@ package ast import ( + "iter" + "maps" + "slices" "strings" "sync/atomic" @@ -164,8 +167,212 @@ func (s *Symbol) CombinedLocalAndExportSymbolFlags() SymbolFlags { } // SymbolTable +// +// A SymbolTable maps names to symbols and iterates in insertion order, like Strada's Map, so that iterating a table +// is deterministic and visits symbols in the order the binder and checker added them. A nil SymbolTable is an empty +// table that can be read and iterated but not written, like a nil map. +// +// The entries are kept in insertion order in one slice. Most tables are small, so a table is searched linearly until +// it has more than symbolTableLinearMax entries, and only then gets a hash index of entry positions. An entry does not +// store its key: the key is almost always the symbol's own name, so an entry holds the symbol and the key's length, +// which rejects most non-matching entries without reading the symbol. A key with other text than its symbol's name +// is kept in oddKeys. Delete builds a new entry slice, so an iteration in progress keeps seeing a snapshot. +type SymbolTable = *SymbolMap -type SymbolTable map[string]*Symbol +const symbolTableLinearMax = 16 + +type SymbolMap struct { + entries []symbolMapEntry + index map[string]int32 + oddKeys map[int32]string +} + +type symbolMapEntry struct { + symbol *Symbol + keyLen int32 + oddKey bool +} + +func NewSymbolTable(capacity int) SymbolTable { + m := &SymbolMap{} + if capacity > 0 { + m.entries = make([]symbolMapEntry, 0, capacity) + if capacity > symbolTableLinearMax { + m.index = make(map[string]int32, capacity) + } + } + return m +} + +// SymbolTableOf returns a new table holding symbol under name. +func SymbolTableOf(name string, symbol *Symbol) SymbolTable { + m := NewSymbolTable(1) + m.Set(name, symbol) + return m +} + +func (m *SymbolMap) keyAt(i int, oddKeys map[int32]string) string { + if m.entries[i].oddKey { + return oddKeys[int32(i)] + } + return m.entries[i].symbol.Name() +} + +func (m *SymbolMap) find(key string) int { + if m == nil { + return -1 + } + if m.index != nil { + if i, ok := m.index[key]; ok { + return int(i) + } + return -1 + } + keyLen := int32(len(key)) + for i := range m.entries { + if m.entries[i].keyLen == keyLen && m.keyAt(i, m.oddKeys) == key { + return i + } + } + return -1 +} + +func (m *SymbolMap) Len() int { + if m == nil { + return 0 + } + return len(m.entries) +} + +func (m *SymbolMap) Get(key string) *Symbol { + if i := m.find(key); i >= 0 { + return m.entries[i].symbol + } + return nil +} + +func (m *SymbolMap) Lookup(key string) (*Symbol, bool) { + if i := m.find(key); i >= 0 { + return m.entries[i].symbol, true + } + return nil, false +} + +// Set replaces the symbol of an existing key in place, keeping its position, or adds the key at the end. +func (m *SymbolMap) Set(key string, symbol *Symbol) { + if i := m.find(key); i >= 0 { + m.entries[i].symbol = symbol + if !m.entries[i].oddKey && (symbol == nil || symbol.Name() != key) { + m.setOddKey(int32(i), key) + } + return + } + i := int32(len(m.entries)) + m.entries = append(m.entries, symbolMapEntry{symbol: symbol, keyLen: int32(len(key))}) + if symbol == nil || symbol.Name() != key { + m.setOddKey(i, key) + } + if m.index != nil { + m.index[key] = i + } else if len(m.entries) > symbolTableLinearMax { + m.buildIndex() + } +} + +func (m *SymbolMap) setOddKey(i int32, key string) { + if m.oddKeys == nil { + m.oddKeys = make(map[int32]string) + } + m.entries[i].oddKey = true + m.oddKeys[i] = key +} + +func (m *SymbolMap) buildIndex() { + m.index = make(map[string]int32, len(m.entries)) + for i := range m.entries { + m.index[m.keyAt(i, m.oddKeys)] = int32(i) + } +} + +func (m *SymbolMap) Delete(key string) { + d := m.find(key) + if d < 0 { + return + } + entries := make([]symbolMapEntry, 0, len(m.entries)-1) + var oddKeys map[int32]string + for i := range m.entries { + if i == d { + continue + } + if m.entries[i].oddKey { + if oddKeys == nil { + oddKeys = make(map[int32]string) + } + oddKeys[int32(len(entries))] = m.oddKeys[int32(i)] + } + entries = append(entries, m.entries[i]) + } + m.entries = entries + m.oddKeys = oddKeys + m.index = nil + if len(m.entries) > symbolTableLinearMax { + m.buildIndex() + } +} + +// All iterates over the keys and symbols of the table in insertion order. +func (m *SymbolMap) All() iter.Seq2[string, *Symbol] { + return func(yield func(string, *Symbol) bool) { + if m == nil { + return + } + entries, oddKeys := m.entries, m.oddKeys + for i := range entries { + key := entries[i].symbol.Name() + if entries[i].oddKey { + key = oddKeys[int32(i)] + } + if !yield(key, entries[i].symbol) { + return + } + } + } +} + +func (m *SymbolMap) Keys() iter.Seq[string] { + return func(yield func(string) bool) { + for key := range m.All() { + if !yield(key) { + return + } + } + } +} + +func (m *SymbolMap) Values() iter.Seq[*Symbol] { + return func(yield func(*Symbol) bool) { + for _, symbol := range m.All() { + if !yield(symbol) { + return + } + } + } +} + +func (m *SymbolMap) Clone() SymbolTable { + if m == nil { + return nil + } + clone := &SymbolMap{entries: slices.Clone(m.entries), index: maps.Clone(m.index), oddKeys: maps.Clone(m.oddKeys)} + return clone +} + +func (m *SymbolMap) CopyFrom(source SymbolTable) { + for key, symbol := range source.All() { + m.Set(key, symbol) + } +} const InternalSymbolNamePrefix = "\xFE" // Invalid UTF8 sequence, will never occur as IdentifierName diff --git a/tsc/internal/ast/symbol_test.go b/tsc/internal/ast/symbol_test.go index 1f8f44aaa66d2..d43d726613e46 100644 --- a/tsc/internal/ast/symbol_test.go +++ b/tsc/internal/ast/symbol_test.go @@ -38,8 +38,8 @@ func TestSymbolAccessors(t *testing.T) { parent := ast.NewSymbol() exportSymbol := ast.NewSymbol() declarations := []*ast.Node{declaration} - members := ast.SymbolTable{"member": member} - exports := ast.SymbolTable{"export": export} + members := ast.SymbolTableOf("member", member) + exports := ast.SymbolTableOf("export", export) symbol.SetFlags(ast.SymbolFlagsClass | ast.SymbolFlagsTransient) symbol.SetCheckFlags(ast.CheckFlagsReadonly) @@ -56,8 +56,8 @@ func TestSymbolAccessors(t *testing.T) { assert.Equal(t, symbol.Name(), "C") assert.Equal(t, symbol.Declarations()[0], declaration) assert.Equal(t, symbol.ValueDeclaration(), declaration) - assert.Equal(t, symbol.Members()["member"], member) - assert.Equal(t, symbol.Exports()["export"], export) + assert.Equal(t, symbol.Members().Get("member"), member) + assert.Equal(t, symbol.Exports().Get("export"), export) assert.Equal(t, symbol.Parent(), parent) assert.Equal(t, symbol.ExportSymbol(), exportSymbol) @@ -65,10 +65,10 @@ func TestSymbolAccessors(t *testing.T) { assert.Equal(t, symbol.Declarations()[0], otherDeclaration) symbol.Declarations()[0] = declaration assert.Equal(t, declarations[0], declaration) - symbol.Members()["added"] = export - assert.Equal(t, members["added"], export) - symbol.Exports()["added"] = member - assert.Equal(t, exports["added"], member) + symbol.Members().Set("added", export) + assert.Equal(t, members.Get("added"), export) + symbol.Exports().Set("added", member) + assert.Equal(t, exports.Get("added"), member) symbol.SetFlags(ast.SymbolFlagsNone) symbol.SetCheckFlags(0) @@ -99,21 +99,21 @@ func TestSymbolTableInitialization(t *testing.T) { export := ast.NewSymbol() members := ast.GetMembers(symbol, &arena) - members["member"] = member - assert.Equal(t, symbol.Members()["member"], member) - assert.Equal(t, ast.GetMembers(symbol, &arena)["member"], member) + members.Set("member", member) + assert.Equal(t, symbol.Members().Get("member"), member) + assert.Equal(t, ast.GetMembers(symbol, &arena).Get("member"), member) exports := ast.GetExports(symbol, &arena) - exports["export"] = export - assert.Equal(t, symbol.Exports()["export"], export) - assert.Equal(t, ast.GetExports(symbol, &arena)["export"], export) + exports.Set("export", export) + assert.Equal(t, symbol.Exports().Get("export"), export) + assert.Equal(t, ast.GetExports(symbol, &arena).Get("export"), export) symbol.SetMembers(nil, &arena) symbol.SetExports(nil, &arena) assert.Assert(t, ast.GetMembers(symbol, &arena) != nil) assert.Assert(t, ast.GetExports(symbol, &arena) != nil) - assert.Equal(t, len(symbol.Members()), 0) - assert.Equal(t, len(symbol.Exports()), 0) + assert.Equal(t, symbol.Members().Len(), 0) + assert.Equal(t, symbol.Exports().Len(), 0) } func TestSymbolHotRecordLayout(t *testing.T) { @@ -142,12 +142,12 @@ func TestSymbolSharedExtraData(t *testing.T) { alias.SetSymbolData(symbol) member := ast.NewSymbol() export := ast.NewSymbol() - alias.SetMembers(ast.SymbolTable{"member": member}, &arena) - symbol.SetExports(ast.SymbolTable{"export": export}, &otherArena) + alias.SetMembers(ast.SymbolTableOf("member", member), &arena) + symbol.SetExports(ast.SymbolTableOf("export", export), &otherArena) alias.SetExportSymbol(export, &otherArena) runtime.GC() - assert.Equal(t, symbol.Members()["member"], member) - assert.Equal(t, alias.Exports()["export"], export) + assert.Equal(t, symbol.Members().Get("member"), member) + assert.Equal(t, alias.Exports().Get("export"), export) assert.Equal(t, symbol.ExportSymbol(), export) symbol.SetMembers(nil, &otherArena) alias.SetExports(nil, &arena) @@ -155,14 +155,14 @@ func TestSymbolSharedExtraData(t *testing.T) { assert.Assert(t, alias.Members() == nil) assert.Assert(t, symbol.Exports() == nil) assert.Assert(t, alias.ExportSymbol() == nil) - ast.GetMembers(alias, &otherArena)["new"] = export - ast.GetExports(symbol, &arena)["new"] = member + ast.GetMembers(alias, &otherArena).Set("new", export) + ast.GetExports(symbol, &arena).Set("new", member) for range 1024 { - ast.NewSymbol().SetExports(ast.SymbolTable{"export": export}, &arena) + ast.NewSymbol().SetExports(ast.SymbolTableOf("export", export), &arena) } arena = ast.SymbolExtraArena{} otherArena = ast.SymbolExtraArena{} runtime.GC() - assert.Equal(t, symbol.Members()["new"], export) - assert.Equal(t, alias.Exports()["new"], member) + assert.Equal(t, symbol.Members().Get("new"), export) + assert.Equal(t, alias.Exports().Get("new"), member) } diff --git a/tsc/internal/ast/utilities.go b/tsc/internal/ast/utilities.go index ff11fd6a2c2f4..2c55f0e45dd35 100644 --- a/tsc/internal/ast/utilities.go +++ b/tsc/internal/ast/utilities.go @@ -94,7 +94,7 @@ func (a *SymbolIdGenerator) GetSymbolId(symbol *Symbol) SymbolId { func GetSymbolTable(data *SymbolTable) SymbolTable { if *data == nil { - *data = make(SymbolTable) + *data = NewSymbolTable(0) } return *data } diff --git a/tsc/internal/binder/binder.go b/tsc/internal/binder/binder.go index a95bb19ecdff7..212e1b7266d6c 100644 --- a/tsc/internal/binder/binder.go +++ b/tsc/internal/binder/binder.go @@ -189,10 +189,10 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol // Otherwise, we'll be merging into a compatible existing symbol (for example when // you have multiple 'vars' with the same name in the same container). In this case // just add this node into the declarations list of the symbol. - symbol = symbolTable[name] + symbol = symbolTable.Get(name) if symbol == nil { symbol = b.newSymbol(ast.SymbolFlagsNone, name) - symbolTable[name] = symbol + symbolTable.Set(name, symbol) if isReplaceableByMethod { symbol.SetFlags(symbol.Flags() | ast.SymbolFlagsReplaceableByMethod) } @@ -204,7 +204,7 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol // Javascript constructor-declared symbols can be discarded in favor of // prototype symbols like methods. symbol = b.newSymbol(ast.SymbolFlagsNone, name) - symbolTable[name] = symbol + symbolTable.Set(name, symbol) } else if !(includes&ast.SymbolFlagsVariable != 0 && symbol.Flags()&ast.SymbolFlagsAssignment != 0 || includes&ast.SymbolFlagsAssignment != 0 && symbol.Flags()&ast.SymbolFlagsVariable != 0) { // Assignment declarations are allowed to merge with variables, no matter what other flags they have. @@ -968,11 +968,11 @@ func (b *Binder) bindClassLikeDeclaration(node *ast.Node) { // module might have an exported variable called 'prototype'. We can't allow that as // that would clash with the built-in 'prototype' for the class. prototypeSymbol := b.newSymbol(ast.SymbolFlagsProperty|ast.SymbolFlagsPrototype, "prototype") - symbolExport := ast.GetExports(symbol, &b.symbolExtraArena)[prototypeSymbol.Name()] + symbolExport := ast.GetExports(symbol, &b.symbolExtraArena).Get(prototypeSymbol.Name()) if symbolExport != nil { b.errorOnNode(symbolExport.Declarations()[0], diagnostics.Duplicate_identifier_0, ast.SymbolName(prototypeSymbol)) } - ast.GetExports(symbol, &b.symbolExtraArena)[prototypeSymbol.Name()] = prototypeSymbol + ast.GetExports(symbol, &b.symbolExtraArena).Set(prototypeSymbol.Name(), prototypeSymbol) prototypeSymbol.SetParent(symbol) } @@ -1001,16 +1001,16 @@ func (b *Binder) bindFunctionOrConstructorType(node *ast.Node) { b.addDeclarationToSymbol(symbol, node, ast.SymbolFlagsSignature) typeLiteralSymbol := b.newSymbol(ast.SymbolFlagsTypeLiteral, ast.InternalSymbolNameType) b.addDeclarationToSymbol(typeLiteralSymbol, node, ast.SymbolFlagsTypeLiteral) - typeLiteralSymbol.SetMembers(make(ast.SymbolTable), &b.symbolExtraArena) - typeLiteralSymbol.Members()[symbol.Name()] = symbol + typeLiteralSymbol.SetMembers(ast.NewSymbolTable(0), &b.symbolExtraArena) + typeLiteralSymbol.Members().Set(symbol.Name(), symbol) } func (b *Binder) addLateBoundAssignmentDeclarationToSymbol(node *ast.Node, symbol *ast.Symbol) { exports := ast.GetExports(symbol, &b.symbolExtraArena) - assignmentSymbol := exports[ast.InternalSymbolNameAssignmentDeclaration] + assignmentSymbol := exports.Get(ast.InternalSymbolNameAssignmentDeclaration) if assignmentSymbol == nil { assignmentSymbol = b.newSymbol(ast.SymbolFlagsNone, ast.InternalSymbolNameAssignmentDeclaration) - exports[ast.InternalSymbolNameAssignmentDeclaration] = assignmentSymbol + exports.Set(ast.InternalSymbolNameAssignmentDeclaration, assignmentSymbol) } assignmentSymbol.SetDeclarations(append(assignmentSymbol.Declarations(), node)) } @@ -1045,10 +1045,10 @@ func (b *Binder) bindDeferredExpandoAssignments() { // symbol as a namespace module. func (b *Binder) bindCommonJSTypeExports(moduleSymbol *ast.Symbol) { moduleExports := moduleSymbol.Exports() - if exportEquals := moduleExports[ast.InternalSymbolNameExportEquals]; exportEquals != nil { - for _, symbol := range moduleExports { + if exportEquals := moduleExports.Get(ast.InternalSymbolNameExportEquals); exportEquals != nil { + for _, symbol := range moduleExports.All() { if symbol.Name() != ast.InternalSymbolNameExportEquals && symbol.Flags()&(ast.SymbolFlagsType|ast.SymbolFlagsNamespace) != 0 { - ast.GetExports(exportEquals, &b.symbolExtraArena)[symbol.Name()] = symbol + ast.GetExports(exportEquals, &b.symbolExtraArena).Set(symbol.Name(), symbol) exportEquals.SetFlags(exportEquals.Flags() | ast.SymbolFlagsNamespaceModule) } } @@ -1068,7 +1068,7 @@ func (b *Binder) bindDeferredExpandoAssignment(node *ast.Node) { } else { // We declare expandos only when there are no non-expando declarations for that name. exports := ast.GetExports(symbol, &b.symbolExtraArena) - if existing := exports[b.getDeclarationName(node)]; existing == nil || existing.Flags()&ast.SymbolFlagsAssignment != 0 { + if existing := exports.Get(b.getDeclarationName(node)); existing == nil || existing.Flags()&ast.SymbolFlagsAssignment != 0 { b.declareSymbol(exports, symbol, node, ast.SymbolFlagsProperty|ast.SymbolFlagsAssignment, ast.SymbolFlagsPropertyExcludes) } } @@ -1278,14 +1278,14 @@ func (b *Binder) lookupEntity(node *ast.Node, container *ast.Node) *ast.Symbol { if node.Expression().Kind == ast.KindThisKeyword { if _, symbolTable := b.getThisClassAndSymbolTable(); symbolTable != nil { if name := ast.GetElementOrPropertyAccessName(node); name != nil { - return symbolTable[name.Text()] + return symbolTable.Get(name.Text()) } } return nil } if symbol := getInitializerSymbol(b.lookupEntity(node.Expression(), container)); symbol != nil && symbol.Exports() != nil { if name := ast.GetElementOrPropertyAccessName(node); name != nil { - return symbol.Exports()[name.Text()] + return symbol.Exports().Get(name.Text()) } } return nil @@ -1293,12 +1293,12 @@ func (b *Binder) lookupEntity(node *ast.Node, container *ast.Node) *ast.Symbol { func (b *Binder) lookupName(name string, container *ast.Node) *ast.Symbol { if localsContainer := container.LocalsContainerData(); localsContainer != nil { - if local := localsContainer.Locals[name]; local != nil { + if local := localsContainer.Locals.Get(name); local != nil { return core.OrElse(local.ExportSymbol(), local) } } if declaration := container.DeclarationData(); declaration != nil && declaration.Symbol != nil { - return declaration.Symbol.Exports()[name] + return declaration.Symbol.Exports().Get(name) } return nil } @@ -1627,7 +1627,7 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) { func (b *Binder) declareCommonJSVariable(name string) { locals := ast.GetLocals(b.file.AsNode()) - if locals[name] == nil { + if locals.Get(name) == nil { symbol := b.newSymbol(ast.SymbolFlagsFunctionScopedVariable|ast.SymbolFlagsModuleExports, name) symbol.SetDeclarations(b.newSingleDeclaration(b.file.AsNode())) symbol.SetValueDeclaration(symbol.Declarations()[0]) @@ -1636,10 +1636,10 @@ func (b *Binder) declareCommonJSVariable(name string) { exportsProperty.SetDeclarations(symbol.Declarations()) exportsProperty.SetValueDeclaration(symbol.ValueDeclaration()) exportsProperty.SetParent(symbol) - symbol.SetMembers(make(ast.SymbolTable, 1), &b.symbolExtraArena) - symbol.Members()["exports"] = exportsProperty + symbol.SetMembers(ast.NewSymbolTable(1), &b.symbolExtraArena) + symbol.Members().Set("exports", exportsProperty) } - locals[name] = symbol + locals.Set(name, symbol) } } diff --git a/tsc/internal/binder/nameresolver.go b/tsc/internal/binder/nameresolver.go index a7eff7005e812..4d0db524946cb 100644 --- a/tsc/internal/binder/nameresolver.go +++ b/tsc/internal/binder/nameresolver.go @@ -118,7 +118,7 @@ loop: if ast.IsSourceFile(location) || (ast.IsModuleDeclaration(location) && location.Flags&ast.NodeFlagsAmbient != 0 && !ast.IsGlobalScopeAugmentation(location)) { // It's an external module. First see if the module has an export default and if the local // name of that export default matches. - result = moduleExports[ast.InternalSymbolNameDefault] + result = moduleExports.Get(ast.InternalSymbolNameDefault) if result != nil { localSymbol := GetLocalSymbolForExportDefault(result) if localSymbol != nil && result.Flags()&meaning != 0 && localSymbol.Name() == name { @@ -137,7 +137,7 @@ loop: // 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely* // an alias. If we used &, we'd be throwing out symbols that have non alias aspects, // which is not the desired behavior. - moduleExport := moduleExports[name] + moduleExport := moduleExports.Get(name) if moduleExport != nil && moduleExport.Flags() == ast.SymbolFlagsAlias && (ast.GetDeclarationOfKind(moduleExport, ast.KindExportSpecifier) != nil || ast.GetDeclarationOfKind(moduleExport, ast.KindNamespaceExport) != nil) { break } @@ -429,7 +429,7 @@ func (r *NameResolver) lookup(symbols ast.SymbolTable, name string, meaning ast. } // Default implementation does not support following aliases or merged symbols if meaning != 0 { - symbol := symbols[name] + symbol := symbols.Get(name) if symbol != nil { if symbol.Flags()&meaning != 0 { return symbol diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index d794680fcb3e3..be42451b57e4f 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -961,7 +961,7 @@ func NewChecker(program Program, tracer *Tracer) (*Checker, *sync.Mutex) { c.exactOptionalPropertyTypes = c.compilerOptions.ExactOptionalPropertyTypes == core.TSTrue c.canCollectSymbolAliasAccessibilityData = c.compilerOptions.VerbatimModuleSyntax.IsFalseOrUnknown() c.arrayVariances = []VarianceFlags{VarianceFlagsCovariant} - c.globals = make(ast.SymbolTable, countGlobalSymbols(c.files)) + c.globals = ast.NewSymbolTable(countGlobalSymbols(c.files)) c.evaluate = evaluator.NewEvaluator(c.evaluateEntity, ast.OEKParentheses) c.stringLiteralTypes = make(map[string]*Type) c.numberLiteralTypes = make(map[jsnum.Number]*Type) @@ -995,7 +995,7 @@ func NewChecker(program Program, tracer *Tracer) (*Checker, *sync.Mutex) { c.moduleSymbols = make(map[*ast.Node]*ast.Symbol) c.globalThisSymbol = c.newSymbolEx(ast.SymbolFlagsModule, "globalThis", ast.CheckFlagsReadonly) c.globalThisSymbol.SetExports(c.globals, &c.symbolExtraArena) - c.globals[c.globalThisSymbol.Name()] = c.globalThisSymbol + c.globals.Set(c.globalThisSymbol.Name(), c.globalThisSymbol) c.resolveName = c.createNameResolver().Resolve c.resolveNameForSymbolSuggestion = c.createNameResolverForSuggestion().Resolve c.tupleTypes = make(map[CacheHashKey]*Type) @@ -1163,7 +1163,7 @@ func countGlobalSymbols(files []*ast.SourceFile) int { count := 0 for _, file := range files { if !ast.IsExternalOrCommonJSModule(file) { - count += len(file.Locals) + count += file.Locals.Len() } } return count @@ -1336,12 +1336,12 @@ func (c *Checker) initializeChecker() { for _, file := range c.files { if !ast.IsExternalOrCommonJSModule(file) { // It is an error for a non-external-module (i.e. script) to declare its own `globalThis`. - if fileGlobalThisSymbol := file.Locals["globalThis"]; fileGlobalThisSymbol != nil { + if fileGlobalThisSymbol := file.Locals.Get("globalThis"); fileGlobalThisSymbol != nil { for _, d := range fileGlobalThisSymbol.Declarations() { c.addDiagnostic(NewDiagnosticForNode(d, diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, "globalThis")) } } - for _, symbol := range file.Locals { + for _, symbol := range file.Locals.All() { // We defer merging of global ambient module declarations since they may require other global symbols // and types to be resolved. See https://github.com/microsoft/TypeScript/tsc/issues/2953. if symbol.Flags()&ast.SymbolFlagsModule != 0 && ast.IsAmbientModuleSymbolName(symbol.Name()) { @@ -1355,9 +1355,9 @@ func (c *Checker) initializeChecker() { augmentations = append(augmentations, file.ModuleAugmentations) if file.Symbol != nil { // Merge in UMD exports with first-in-wins semantics (see #9771) - for name, symbol := range file.GlobalExports { - if _, ok := c.globals[name]; !ok { - c.globals[name] = symbol + for name, symbol := range file.GlobalExports.All() { + if _, ok := c.globals.Lookup(name); !ok { + c.globals.Set(name, symbol) } } } @@ -1421,14 +1421,14 @@ func (c *Checker) initializeChecker() { } func (c *Checker) mergeGlobalSymbol(symbol *ast.Symbol) { - globalSymbol := c.globals[symbol.Name()] + globalSymbol := c.globals.Get(symbol.Name()) var merged *ast.Symbol if globalSymbol != nil { merged = c.mergeSymbol(globalSymbol, symbol, false /*unidirectional*/) } else { merged = c.getMergedSymbol(symbol) } - c.globals[symbol.Name()] = merged + c.globals.Set(symbol.Name(), merged) } // Pattern ambient modules are merged together if they have the same pattern and identical import attributes type. @@ -1452,8 +1452,8 @@ func (c *Checker) mergePatternAmbientModules() { } } for _, module := range c.patternAmbientModules { - if _, ok := c.globals[module.Symbol.Name()]; ok { - c.globals[module.Symbol.Name()] = c.getMergedSymbol(module.Symbol) + if _, ok := c.globals.Lookup(module.Symbol.Name()); ok { + c.globals.Set(module.Symbol.Name(), c.getMergedSymbol(module.Symbol)) } } c.patternAmbientModules = grouped @@ -1495,15 +1495,15 @@ func (c *Checker) mergeModuleAugmentation(moduleName *ast.Node) { }) { merged := c.mergeSymbol(moduleAugmentation.Symbol, mainModule, true /*unidirectional*/) // moduleName will be a StringLiteral since this is not `declare global`. - ast.GetSymbolTable(&c.patternAmbientModuleAugmentations)[moduleName.Text()] = merged - ast.GetSymbolTable(&c.patternAmbientModuleAugmentationTargets)[moduleName.Text()] = mainModule + ast.GetSymbolTable(&c.patternAmbientModuleAugmentations).Set(moduleName.Text(), merged) + ast.GetSymbolTable(&c.patternAmbientModuleAugmentationTargets).Set(moduleName.Text(), mainModule) } else { - if mainModule.Exports()[ast.InternalSymbolNameExportStar] != nil && len(moduleAugmentation.Symbol.Exports()) != 0 { + if mainModule.Exports().Get(ast.InternalSymbolNameExportStar) != nil && moduleAugmentation.Symbol.Exports().Len() != 0 { // We may need to merge the module augmentation's exports into the target symbols of the resolved exports resolvedExports := c.getResolvedMembersOrExportsOfSymbol(mainModule, MembersOrExportsResolutionKindResolvedExports) - for key, value := range moduleAugmentation.Symbol.Exports() { - if resolvedExports[key] != nil && mainModule.Exports()[key] == nil { - c.mergeSymbol(resolvedExports[key], value, false /*unidirectional*/) + for key, value := range moduleAugmentation.Symbol.Exports().All() { + if resolvedExports.Get(key) != nil && mainModule.Exports().Get(key) == nil { + c.mergeSymbol(resolvedExports.Get(key), value, false /*unidirectional*/) } } } @@ -1518,7 +1518,7 @@ func (c *Checker) mergeModuleAugmentation(moduleName *ast.Node) { func (c *Checker) addUndefinedToGlobalsOrErrorOnRedeclaration() { name := c.undefinedSymbol.Name() - targetSymbol := c.globals[name] + targetSymbol := c.globals.Get(name) if targetSymbol != nil { for _, declaration := range targetSymbol.Declarations() { if !ast.IsTypeDeclaration(declaration) { @@ -1526,7 +1526,7 @@ func (c *Checker) addUndefinedToGlobalsOrErrorOnRedeclaration() { } } } else { - c.globals[name] = c.undefinedSymbol + c.globals.Set(name, c.undefinedSymbol) } } @@ -1830,7 +1830,7 @@ var primitiveTypeAliasSuggestions = sync.OnceValue(func() map[string]*ast.Symbol func getPrimitiveTypeAliasSuggestions(symbols ast.SymbolTable) iter.Seq[*ast.Symbol] { return func(yield func(*ast.Symbol) bool) { for builtinName, suggestion := range primitiveTypeAliasSuggestions() { - if _, ok := symbols[builtinName]; ok { + if _, ok := symbols.Lookup(builtinName); ok { if !yield(suggestion) { return } @@ -1850,7 +1850,7 @@ func (c *Checker) getSuggestionForSymbolNameLookup(symbols ast.SymbolTable, name } // Checking a candidate alias resolves it, which creates types, so visit aliases last and in a stable order // rather than in the random iteration order of the symbol table. - candidates := make([]*ast.Symbol, 0, len(symbols)) + candidates := make([]*ast.Symbol, 0, symbols.Len()) c.forEachSymbolTableEntry(symbols, func(_ string, symbol *ast.Symbol) bool { candidates = append(candidates, symbol) return false @@ -2249,7 +2249,7 @@ func (c *Checker) addTypeOnlyDeclarationRelatedInfo(diagnostic *ast.Diagnostic, func (c *Checker) getSymbol(symbols ast.SymbolTable, name string, meaning ast.SymbolFlags) *ast.Symbol { if meaning&ast.SymbolFlagsAll != 0 { - symbol := c.getMergedSymbol(symbols[name]) + symbol := c.getMergedSymbol(symbols.Get(name)) if symbol != nil { if symbol.Flags()&meaning != 0 { return symbol @@ -2895,7 +2895,7 @@ func (c *Checker) checkClassStaticBlockDeclaration(node *ast.Node) { // Grammar checking c.checkGrammarModifiers(node) node.ForEachChild(c.checkSourceElement) - if len(node.Locals()) != 0 { + if node.Locals().Len() != 0 { c.registerForUnusedIdentifiersCheck(node) } } @@ -3854,7 +3854,7 @@ func (c *Checker) checkBlock(node *ast.Node) { } else { c.checkSourceElements(node.Statements()) } - if len(node.Locals()) != 0 { + if node.Locals().Len() != 0 { c.registerForUnusedIdentifiersCheck(node) } } @@ -4319,8 +4319,8 @@ func (c *Checker) checkCatchClause(node *ast.Node) { } else { blockLocals := node.AsCatchClause().Block.Locals() if blockLocals != nil { - for caughtName := range node.Locals() { - if blockLocal := blockLocals[caughtName]; blockLocal != nil && blockLocal.ValueDeclaration() != nil && blockLocal.Flags()&ast.SymbolFlagsBlockScopedVariable != 0 { + for caughtName := range node.Locals().All() { + if blockLocal := blockLocals.Get(caughtName); blockLocal != nil && blockLocal.ValueDeclaration() != nil && blockLocal.Flags()&ast.SymbolFlagsBlockScopedVariable != 0 { c.grammarErrorOnNode(blockLocal.ValueDeclaration(), diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, caughtName) } } @@ -5151,7 +5151,7 @@ func (c *Checker) checkInheritedPropertiesAreIdentical(t *Type, typeNode *ast.No return true } seen := make(map[string]InheritanceInfo) - for id, p := range c.resolveDeclaredMembers(t).declaredMembers { + for id, p := range c.resolveDeclaredMembers(t).declaredMembers.All() { if c.isNamedMember(p, id) { seen[p.Name()] = InheritanceInfo{prop: p, containingType: t} } @@ -5605,11 +5605,11 @@ func (c *Checker) checkImportAttributesExpression(node *ast.Node) *Type { links := c.typeNodeLinks.Get(node) if links.resolvedType == nil { symbol := c.newSymbol(ast.SymbolFlagsObjectLiteral, ast.InternalSymbolNameImportAttributes) - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) for _, attribute := range node.AsImportAttributes().Attributes.Nodes { member := c.newSymbol(ast.SymbolFlagsProperty, attribute.Name().Text()) c.valueSymbolLinks.Get(member).resolvedType = c.getRegularTypeOfLiteralType(c.checkExpressionCached(attribute.AsImportAttribute().Value)) - members[member.Name()] = member + members.Set(member.Name(), member) } t := c.newAnonymousType(symbol, members, nil, nil, nil) t.objectFlags |= ObjectFlagsObjectLiteral | ObjectFlagsNonInferrableType @@ -5884,7 +5884,7 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) { moduleSymbol := c.getSymbolOfDeclaration(node) links := c.moduleSymbolLinks.Get(moduleSymbol) if !links.exportsChecked { - exportEqualsSymbol := moduleSymbol.Exports()[ast.InternalSymbolNameExportEquals] + exportEqualsSymbol := moduleSymbol.Exports().Get(ast.InternalSymbolNameExportEquals) // An export assignment is in error if (a) the module exports value members or (b) if the module exports type or // namespace members and the exported entity also exports type or namespace members. if exportEqualsSymbol != nil && (c.hasExportedMembersOfKind(moduleSymbol, ast.SymbolFlagsValue) || c.hasShadowedNamespace(exportEqualsSymbol)) { @@ -5894,7 +5894,7 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) { } } // Checks for export * conflicts - for id, symbol := range c.getExportsOfModule(moduleSymbol) { + for id, symbol := range c.getExportsOfModule(moduleSymbol).All() { if id == ast.InternalSymbolNameExportStar { continue } @@ -6778,8 +6778,8 @@ func (c *Checker) getIterationTypesOfMethod(t *Type, resolver *IterationTypesRes if len(methodSignatures) == 1 && methodType.symbol != nil { globalGeneratorType := resolver.getGlobalGeneratorType() globalIteratorType := resolver.getGlobalIteratorType() - isGeneratorMethod := globalGeneratorType.symbol != nil && globalGeneratorType.symbol.Members()[methodName] == methodType.symbol - isIteratorMethod := !isGeneratorMethod && globalIteratorType.symbol != nil && globalIteratorType.symbol.Members()[methodName] == methodType.symbol + isGeneratorMethod := globalGeneratorType.symbol != nil && globalGeneratorType.symbol.Members().Get(methodName) == methodType.symbol + isIteratorMethod := !isGeneratorMethod && globalIteratorType.symbol != nil && globalIteratorType.symbol.Members().Get(methodName) == methodType.symbol if isGeneratorMethod || isIteratorMethod { typeParameters := core.IfElse(isGeneratorMethod, globalGeneratorType, globalIteratorType).AsInterfaceType().TypeParameters() mapper := methodType.Mapper() @@ -6955,7 +6955,7 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) { if ast.IsExportSpecifier(node) { diag := c.error(errorNode, diagnostics.Types_cannot_appear_in_export_declarations_in_JavaScript_files) if sourceSymbol := ast.GetSourceFileOfNode(node).AsNode().Symbol(); sourceSymbol != nil { - if alreadyExportedSymbol := sourceSymbol.Exports()[node.PropertyNameOrName().Text()]; alreadyExportedSymbol == target { + if alreadyExportedSymbol := sourceSymbol.Exports().Get(node.PropertyNameOrName().Text()); alreadyExportedSymbol == target { if exportingDeclaration := core.Find(alreadyExportedSymbol.Declarations(), ast.IsJSTypeAliasDeclaration); exportingDeclaration != nil { diag.AddRelatedInfo(NewDiagnosticForNode(exportingDeclaration, diagnostics.X_0_is_automatically_exported_here, alreadyExportedSymbol.Name())) } @@ -7342,7 +7342,7 @@ func (c *Checker) checkUnusedClassMembers(node *ast.Node) { func (c *Checker) checkUnusedLocalsAndParameters(node *ast.Node) { var variableParents collections.Set[*ast.Node] var importClauses map[*ast.Node][]*ast.Node - for _, local := range node.Locals() { + for _, local := range node.Locals().All() { referenceKinds := c.symbolReferenceLinks.Get(local).referenceKinds if local.Flags()&ast.SymbolFlagsTypeParameter != 0 && (local.Flags()&ast.SymbolFlagsVariable == 0 || referenceKinds&ast.SymbolFlagsVariable != 0) || local.Flags()&ast.SymbolFlagsTypeParameter == 0 && (referenceKinds != 0 || local.ExportSymbol() != nil || @@ -11572,7 +11572,7 @@ func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, l return c.anyType } if leftType.symbol == c.globalThisSymbol { - globalSymbol := c.globalThisSymbol.Exports()[right.Text()] + globalSymbol := c.globalThisSymbol.Exports().Get(right.Text()) if globalSymbol != nil && globalSymbol.Flags()&ast.SymbolFlagsBlockScoped != 0 { c.error(right, diagnostics.Property_0_does_not_exist_on_type_1, right.Text(), c.TypeToString(leftType)) } else if c.noImplicitAny { @@ -11713,11 +11713,11 @@ func (c *Checker) lookupSymbolForPrivateIdentifierDeclaration(propName string, l for containingClass := getContainingClassExcludingClassDecorators(location); containingClass != nil; containingClass = ast.GetContainingClass(containingClass) { symbol := containingClass.Symbol() name := binder.GetSymbolNameForPrivateIdentifier(symbol, propName) - prop := symbol.Members()[name] + prop := symbol.Members().Get(name) if prop != nil { return prop } - prop = symbol.Exports()[name] + prop = symbol.Exports().Get(name) if prop != nil { return prop } @@ -13388,7 +13388,7 @@ func (c *Checker) checkReferenceExpression(expr *ast.Node, invalidReferenceMessa func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type { // Expando object literals have empty properties but filled exports - if len(node.Properties()) == 0 && node.Symbol() != nil && len(node.Symbol().Exports()) != 0 { + if len(node.Properties()) == 0 && node.Symbol() != nil && node.Symbol().Exports().Len() != 0 { result := c.newAnonymousType(node.Symbol(), node.Symbol().Exports(), nil, nil, nil) if ast.IsInJSFile(node) && !ast.IsInJsonFile(node) { result.objectFlags |= ObjectFlagsJSLiteral @@ -13403,9 +13403,9 @@ func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type c.checkGrammarObjectLiteralExpression(node.AsObjectLiteralExpression(), inDestructuringPattern) var allPropertiesTable ast.SymbolTable if c.strictNullChecks { - allPropertiesTable = make(ast.SymbolTable) + allPropertiesTable = ast.NewSymbolTable(0) } - propertiesTable := make(ast.SymbolTable) + propertiesTable := ast.NewSymbolTable(0) var propertiesArray []*ast.Symbol spread := c.emptyObjectType c.pushCachedContextualType(node) @@ -13512,7 +13512,7 @@ func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type links.target = member member = prop if allPropertiesTable != nil { - allPropertiesTable[prop.Name()] = prop + allPropertiesTable.Set(prop.Name(), prop) } if contextualType != nil && checkMode&CheckModeInferential != 0 && checkMode&CheckModeSkipContextSensitive == 0 && (ast.IsPropertyAssignment(memberDecl) || ast.IsMethodDeclaration(memberDecl)) && c.isContextSensitive(memberDecl) { inferenceContext := c.getInferenceContext(node) @@ -13527,7 +13527,7 @@ func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type if len(propertiesArray) > 0 { spread = c.getSpreadType(spread, createObjectLiteralType(), node.Symbol(), objectFlags, inConstContext) propertiesArray = nil - propertiesTable = make(ast.SymbolTable) + propertiesTable = ast.NewSymbolTable(0) hasComputedStringProperty = false hasComputedNumberProperty = false hasComputedSymbolProperty = false @@ -13571,7 +13571,7 @@ func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type } } } else { - propertiesTable[member.Name()] = member + propertiesTable.Set(member.Name(), member) } propertiesArray = append(propertiesArray, member) } @@ -13583,7 +13583,7 @@ func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type if len(propertiesArray) > 0 { spread = c.getSpreadType(spread, createObjectLiteralType(), node.Symbol(), objectFlags, inConstContext) propertiesArray = nil - propertiesTable = make(ast.SymbolTable) + propertiesTable = ast.NewSymbolTable(0) hasComputedStringProperty = false hasComputedNumberProperty = false } @@ -13626,7 +13626,7 @@ func (c *Checker) checkDeprecatedProperty(name *ast.Node, contextualType *Type) func (c *Checker) checkSpreadPropOverrides(t *Type, props ast.SymbolTable, spread *ast.Node) { for _, right := range c.getPropertiesOfType(t) { if right.Flags()&ast.SymbolFlagsOptional == 0 && right.CheckFlags()&ast.CheckFlagsPartial == 0 { - if left := props[right.Name()]; left != nil { + if left := props.Get(right.Name()); left != nil { diagnostic := c.error(left.ValueDeclaration(), diagnostics.X_0_is_specified_more_than_once_so_this_usage_will_be_overwritten, left.Name()) diagnostic.AddRelatedInfo(NewDiagnosticForNode(spread, diagnostics.This_spread_always_overwrites_this_property)) } @@ -13691,7 +13691,7 @@ func (c *Checker) getSpreadType(left *Type, right *Type, symbol *ast.Symbol, obj } return c.getIntersectionType([]*Type{left, right}) } - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) var skippedPrivateMembers collections.Set[string] var indexInfos []*IndexInfo if left == c.emptyObjectType { @@ -13703,7 +13703,7 @@ func (c *Checker) getSpreadType(left *Type, right *Type, symbol *ast.Symbol, obj if getDeclarationModifierFlagsFromSymbol(rightProp)&(ast.ModifierFlagsPrivate|ast.ModifierFlagsProtected) != 0 { skippedPrivateMembers.Add(rightProp.Name()) } else if c.isSpreadableProperty(rightProp) { - members[rightProp.Name()] = c.getSpreadSymbol(rightProp, readonly) + members.Set(rightProp.Name(), c.getSpreadSymbol(rightProp, readonly)) } } @@ -13711,8 +13711,8 @@ func (c *Checker) getSpreadType(left *Type, right *Type, symbol *ast.Symbol, obj if skippedPrivateMembers.Has(leftProp.Name()) || !c.isSpreadableProperty(leftProp) { continue } - if members[leftProp.Name()] != nil { - rightProp := members[leftProp.Name()] + if members.Get(leftProp.Name()) != nil { + rightProp := members.Get(leftProp.Name()) rightType := c.getTypeOfSymbol(rightProp) if rightProp.Flags()&ast.SymbolFlagsOptional != 0 { declarations := core.Concatenate(leftProp.Declarations(), rightProp.Declarations()) @@ -13735,10 +13735,10 @@ func (c *Checker) getSpreadType(left *Type, right *Type, symbol *ast.Symbol, obj c.spreadLinks.Get(result).rightSpread = rightProp result.SetDeclarations(declarations) links.setNameType(c, c.valueSymbolLinks.Get(leftProp).getNameType()) - members[leftProp.Name()] = result + members.Set(leftProp.Name(), result) } } else { - members[leftProp.Name()] = c.getSpreadSymbol(leftProp, readonly) + members.Set(leftProp.Name(), c.getSpreadSymbol(leftProp, readonly)) } } spreadIndexInfos := core.SameMap(indexInfos, func(info *IndexInfo) *IndexInfo { @@ -13806,7 +13806,7 @@ func (c *Checker) tryMergeUnionOfObjectTypeAndEmptyObject(t *Type, readonly bool return t } // gets the type as if it had been spread, but where everything in the spread is made optional - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) for _, prop := range c.getPropertiesOfType(firstType) { if getDeclarationModifierFlagsFromSymbol(prop)&(ast.ModifierFlagsPrivate|ast.ModifierFlagsProtected) != 0 { // do nothing, skip privates @@ -13823,7 +13823,7 @@ func (c *Checker) tryMergeUnionOfObjectTypeAndEmptyObject(t *Type, readonly bool result.SetDeclarations(prop.Declarations()) links.setNameType(c, c.valueSymbolLinks.Get(prop).getNameType()) c.mappedSymbolLinks.Get(result).syntheticOrigin = prop - members[prop.Name()] = result + members.Set(prop.Name(), result) } } spread := c.newAnonymousType(firstType.symbol, members, nil, nil, c.getIndexInfosOfType(firstType)) @@ -14374,21 +14374,21 @@ func (c *Checker) newProperty(name string, t *Type) *ast.Symbol { } func (c *Checker) combineSymbolTables(first ast.SymbolTable, second ast.SymbolTable) ast.SymbolTable { - if len(first) == 0 { + if first.Len() == 0 { return second } - if len(second) == 0 { + if second.Len() == 0 { return first } - combined := make(ast.SymbolTable) + combined := ast.NewSymbolTable(0) c.mergeSymbolTable(combined, first, false, nil) c.mergeSymbolTable(combined, second, false, nil) return combined } func (c *Checker) mergeSymbolTable(target ast.SymbolTable, source ast.SymbolTable, unidirectional bool, mergedParent *ast.Symbol) { - for id, sourceSymbol := range source { - targetSymbol := target[id] + for id, sourceSymbol := range source.All() { + targetSymbol := target.Get(id) var merged *ast.Symbol if targetSymbol != nil { merged = c.mergeSymbol(targetSymbol, sourceSymbol, unidirectional) @@ -14415,7 +14415,7 @@ func (c *Checker) mergeSymbolTable(target ast.SymbolTable, source ast.SymbolTabl merged.SetParent(mergedParent) } } - target[id] = merged + target.Set(id, merged) } } @@ -14620,8 +14620,8 @@ func (c *Checker) cloneSymbol(symbol *ast.Symbol) *ast.Symbol { result.SetDeclarations(symbol.Declarations()[0:len(symbol.Declarations()):len(symbol.Declarations())]) result.SetParent(symbol.Parent()) result.SetValueDeclaration(symbol.ValueDeclaration()) - result.SetMembers(maps.Clone(symbol.Members()), &c.symbolExtraArena) - result.SetExports(maps.Clone(symbol.Exports()), &c.symbolExtraArena) + result.SetMembers(symbol.Members().Clone(), &c.symbolExtraArena) + result.SetExports(symbol.Exports().Clone(), &c.symbolExtraArena) c.recordMergedSymbol(result, symbol) return result } @@ -14887,13 +14887,13 @@ func (c *Checker) getTargetOfModuleDefault(moduleSymbol *ast.Symbol, node *ast.N } func (c *Checker) reportNonDefaultExport(moduleSymbol *ast.Symbol, node *ast.Node) { - if moduleSymbol.Exports() != nil && moduleSymbol.Exports()[node.Symbol().Name()] != nil { + if moduleSymbol.Exports() != nil && moduleSymbol.Exports().Get(node.Symbol().Name()) != nil { c.error(node, diagnostics.Module_0_has_no_default_export_Did_you_mean_to_use_import_1_from_0_instead, c.symbolToString(moduleSymbol), c.symbolToString(node.Symbol())) } else { diagnostic := c.error(node.Name(), diagnostics.Module_0_has_no_default_export, c.symbolToString(moduleSymbol)) var exportStar *ast.Symbol if moduleSymbol.Exports() != nil { - exportStar = moduleSymbol.Exports()[ast.InternalSymbolNameExportStar] + exportStar = moduleSymbol.Exports().Get(ast.InternalSymbolNameExportStar) } if exportStar != nil { defaultExport := core.Find(exportStar.Declarations(), func(decl *ast.Declaration) bool { @@ -14901,7 +14901,7 @@ func (c *Checker) reportNonDefaultExport(moduleSymbol *ast.Symbol, node *ast.Nod return false } resolvedExternalModuleName := c.resolveExternalModuleName(decl, decl.ModuleSpecifier(), false /*ignoreErrors*/, c.getTypeFromImportAttributes(ast.GetImportAttributes(decl))) - return resolvedExternalModuleName != nil && resolvedExternalModuleName.Exports()[ast.InternalSymbolNameDefault] != nil + return resolvedExternalModuleName != nil && resolvedExternalModuleName.Exports().Get(ast.InternalSymbolNameDefault) != nil }) if defaultExport != nil { diagnostic.AddRelatedInfo(createDiagnosticForNode(defaultExport, diagnostics.X_export_Asterisk_does_not_re_export_a_default)) @@ -14911,12 +14911,12 @@ func (c *Checker) reportNonDefaultExport(moduleSymbol *ast.Symbol, node *ast.Nod } func (c *Checker) resolveExportByName(moduleSymbol *ast.Symbol, name string, sourceNode *ast.Node, dontResolveAlias bool) *ast.Symbol { - exportValue := moduleSymbol.Exports()[ast.InternalSymbolNameExportEquals] + exportValue := moduleSymbol.Exports().Get(ast.InternalSymbolNameExportEquals) var exportSymbol *ast.Symbol if exportValue != nil { exportSymbol = c.getPropertyOfTypeEx(c.getTypeOfSymbol(exportValue), name, true /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/) } else { - exportSymbol = moduleSymbol.Exports()[name] + exportSymbol = moduleSymbol.Exports().Get(name) } resolved := c.resolveSymbolEx(exportSymbol, dontResolveAlias) c.markSymbolOfAliasDeclarationIfTypeOnly(sourceNode, nil) @@ -14998,7 +14998,7 @@ func (c *Checker) getExternalModuleMember(node *ast.Node, specifier *ast.Node, d } var symbolFromVariable *ast.Symbol // First check if module was specified with "export=". If so, get the member from the resolved type - if moduleSymbol != nil && moduleSymbol.Exports()[ast.InternalSymbolNameExportEquals] != nil { + if moduleSymbol != nil && moduleSymbol.Exports().Get(ast.InternalSymbolNameExportEquals) != nil { symbolFromVariable = c.getPropertyOfTypeEx(c.getTypeOfSymbol(targetSymbol), nameText, true /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/) } else { symbolFromVariable = c.getPropertyOfVariable(targetSymbol, nameText) @@ -15006,7 +15006,7 @@ func (c *Checker) getExternalModuleMember(node *ast.Node, specifier *ast.Node, d // if symbolFromVariable is export - get its final target symbolFromVariable = c.resolveSymbolEx(symbolFromVariable, dontResolveAlias) exportContainer := targetSymbol - if moduleSymbol != nil && moduleSymbol.Exports()[ast.InternalSymbolNameExportEquals] != nil { + if moduleSymbol != nil && moduleSymbol.Exports().Get(ast.InternalSymbolNameExportEquals) != nil { // For `export =` modules, supplemental type/namespace exports live on the original module symbol. exportContainer = moduleSymbol } @@ -15084,14 +15084,14 @@ func (c *Checker) combineValueAndTypeSymbols(valueSymbol *ast.Symbol, typeSymbol result.SetParent(typeSymbol.Parent()) } result.SetValueDeclaration(valueSymbol.ValueDeclaration()) - result.SetMembers(maps.Clone(typeSymbol.Members()), &c.symbolExtraArena) - result.SetExports(maps.Clone(valueSymbol.Exports()), &c.symbolExtraArena) + result.SetMembers(typeSymbol.Members().Clone(), &c.symbolExtraArena) + result.SetExports(valueSymbol.Exports().Clone(), &c.symbolExtraArena) return result } func (c *Checker) getExportOfModule(symbol *ast.Symbol, nameText string, specifier *ast.Node, dontResolveAlias bool) *ast.Symbol { if symbol.Flags()&ast.SymbolFlagsModule != 0 { - exportSymbol := c.getExportsOfSymbol(symbol)[nameText] + exportSymbol := c.getExportsOfSymbol(symbol).Get(nameText) resolved := c.resolveSymbolEx(exportSymbol, dontResolveAlias) exportStarDeclaration := c.moduleSymbolLinks.Get(symbol).typeOnlyExportStarMap[nameText] c.markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportStarDeclaration) @@ -15201,7 +15201,7 @@ func (c *Checker) errorNoModuleMemberSymbol(moduleSymbol *ast.Symbol, targetSymb diagnostic.AddRelatedInfo(createDiagnosticForNode(suggestion.ValueDeclaration(), diagnostics.X_0_is_declared_here, suggestionName)) } } else { - if moduleSymbol.Exports()[ast.InternalSymbolNameDefault] != nil { + if moduleSymbol.Exports().Get(ast.InternalSymbolNameDefault) != nil { c.error(name, diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_to_use_import_1_from_0_instead, moduleName, declarationName) } else { c.reportNonExportedMember(name, declarationName, moduleSymbol, moduleName) @@ -15212,11 +15212,11 @@ func (c *Checker) errorNoModuleMemberSymbol(moduleSymbol *ast.Symbol, targetSymb func (c *Checker) reportNonExportedMember(name *ast.Node, declarationName string, moduleSymbol *ast.Symbol, moduleName string) { var localSymbol *ast.Symbol if locals := moduleSymbol.ValueDeclaration().Locals(); locals != nil { - localSymbol = locals[name.Text()] + localSymbol = locals.Get(name.Text()) } exports := moduleSymbol.Exports() if localSymbol != nil { - if exportedEqualsSymbol := exports[ast.InternalSymbolNameExportEquals]; exportedEqualsSymbol != nil { + if exportedEqualsSymbol := exports.Get(ast.InternalSymbolNameExportEquals); exportedEqualsSymbol != nil { if c.getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) != nil { c.reportInvalidImportEqualsExportMember(name, declarationName, moduleName) } else { @@ -15801,8 +15801,8 @@ func (c *Checker) tryResolvePatternAmbientModule(resolvedSymbol *ast.Symbol, mod }) if len(candidates) > 0 { - augmentation := c.patternAmbientModuleAugmentations[moduleReference] - augmentationTarget := c.patternAmbientModuleAugmentationTargets[moduleReference] + augmentation := c.patternAmbientModuleAugmentations.Get(moduleReference) + augmentationTarget := c.patternAmbientModuleAugmentationTargets.Get(moduleReference) if len(candidates) == 1 { mergedCandidate := c.getMergedSymbol(candidates[0].Symbol) @@ -15956,7 +15956,7 @@ func (c *Checker) tryFindAmbientModule(moduleName string, withAugmentations bool func (c *Checker) GetAmbientModules() []*ast.Symbol { c.ambientModulesOnce.Do(func() { seen := make(map[*ast.Symbol]struct{}) - for sym, global := range c.globals { + for sym, global := range c.globals.All() { if ast.IsAmbientModuleSymbolName(sym) { c.ambientModules = append(c.ambientModules, global) seen[global] = struct{}{} @@ -15975,7 +15975,7 @@ func (c *Checker) GetAmbientModules() []*ast.Symbol { func (c *Checker) resolveExternalModuleSymbol(moduleSymbol *ast.Symbol, dontResolveAlias bool) *ast.Symbol { if moduleSymbol != nil { - exportEquals := c.resolveSymbolEx(moduleSymbol.Exports()[ast.InternalSymbolNameExportEquals], dontResolveAlias) + exportEquals := c.resolveSymbolEx(moduleSymbol.Exports().Get(ast.InternalSymbolNameExportEquals), dontResolveAlias) if exportEquals != nil { return c.getMergedSymbol(exportEquals) } @@ -16125,12 +16125,12 @@ func (c *Checker) isCommonJSRequire(node *ast.Node) bool { } func (c *Checker) createDefaultPropertyWrapperForModule(symbol *ast.Symbol, originalSymbol *ast.Symbol, anonymousSymbol *ast.Symbol) *Type { - memberTable := make(ast.SymbolTable) + memberTable := ast.NewSymbolTable(0) newSymbol := c.newSymbol(ast.SymbolFlagsAlias, ast.InternalSymbolNameDefault) newSymbol.SetParent(originalSymbol) c.valueSymbolLinks.Get(newSymbol).setNameType(c, c.getStringLiteralType("default")) c.aliasSymbolLinks.Get(newSymbol).aliasTarget = c.resolveSymbol(symbol) - memberTable[ast.InternalSymbolNameDefault] = newSymbol + memberTable.Set(ast.InternalSymbolNameDefault, newSymbol) if anonymousSymbol == nil && originalSymbol != nil { anonymousSymbol = c.newSymbol(ast.SymbolFlagsObjectLiteral, ast.InternalSymbolNameObject) anonymousSymbol.SetDeclarations(originalSymbol.Declarations()) @@ -16142,8 +16142,8 @@ func (c *Checker) cloneTypeAsModuleType(symbol *ast.Symbol, moduleType *Type, re result := c.newSymbol(symbol.Flags(), symbol.Name()) result.SetDeclarations(slices.Clone(symbol.Declarations())) result.SetValueDeclaration(symbol.ValueDeclaration()) - result.SetMembers(maps.Clone(symbol.Members()), &c.symbolExtraArena) - result.SetExports(maps.Clone(symbol.Exports()), &c.symbolExtraArena) + result.SetMembers(symbol.Members().Clone(), &c.symbolExtraArena) + result.SetExports(symbol.Exports().Clone(), &c.symbolExtraArena) result.SetParent(symbol.Parent()) links := c.exportTypeLinks.Get(result) links.target = symbol @@ -16327,7 +16327,7 @@ func (c *Checker) tryGetQualifiedNameAsValue(node *ast.Node) *ast.Symbol { } func (c *Checker) getSuggestedSymbolForNonexistentModule(name *ast.Node, targetModule *ast.Symbol) *ast.Symbol { - return c.getSpellingSuggestionForName(name.Text(), maps.Values(c.getExportsOfModule(targetModule)), ast.SymbolFlagsModuleMember) + return c.getSpellingSuggestionForName(name.Text(), c.getExportsOfModule(targetModule).Values(), ast.SymbolFlagsModuleMember) } func (c *Checker) getFullyQualifiedName(symbol *ast.Symbol, containingLocation *ast.Node) string { @@ -16367,12 +16367,12 @@ func (c *Checker) getResolvedMembersOrExportsOfSymbol(symbol *ast.Symbol, resolu switch { case c.hasLateBindableName(member): if lateSymbols == nil { - lateSymbols = make(ast.SymbolTable) + lateSymbols = ast.NewSymbolTable(0) } c.lateBindMember(symbol, earlySymbols, lateSymbols, member) case c.hasLateBindableIndexSignature(member): if lateSymbols == nil { - lateSymbols = make(ast.SymbolTable) + lateSymbols = ast.NewSymbolTable(0) } c.lateBindIndexSignature(symbol, earlySymbols, lateSymbols, member.AsNode() /* as LateBoundDeclaration | LateBoundBinaryExpressionDeclaration */) } @@ -16380,11 +16380,11 @@ func (c *Checker) getResolvedMembersOrExportsOfSymbol(symbol *ast.Symbol, resolu } } if isStatic { - if assignmentSymbol := symbol.Exports()[ast.InternalSymbolNameAssignmentDeclaration]; assignmentSymbol != nil { + if assignmentSymbol := symbol.Exports().Get(ast.InternalSymbolNameAssignmentDeclaration); assignmentSymbol != nil { for _, member := range assignmentSymbol.Declarations() { if c.hasLateBindableName(member) { if lateSymbols == nil { - lateSymbols = make(ast.SymbolTable) + lateSymbols = ast.NewSymbolTable(0) } c.lateBindMember(symbol, earlySymbols, lateSymbols, member) } @@ -16445,13 +16445,13 @@ func (c *Checker) lateBindMember(parent *ast.Symbol, earlySymbols ast.SymbolTabl memberName := getPropertyNameFromType(t) symbolFlags := decl.Symbol().Flags() // Get or add a late-bound symbol for the member. This allows us to merge late-bound accessor declarations. - lateSymbol := lateSymbols[memberName] + lateSymbol := lateSymbols.Get(memberName) if lateSymbol == nil { lateSymbol = c.newSymbolEx(ast.SymbolFlagsNone, memberName, ast.CheckFlagsLate) - lateSymbols[memberName] = lateSymbol + lateSymbols.Set(memberName, lateSymbol) } // Report an error if there's a symbol declaration with the same name and conflicting flags. - earlySymbol := earlySymbols[memberName] + earlySymbol := earlySymbols.Get(memberName) if lateSymbol.Flags()&getExcludedSymbolFlags(symbolFlags) != 0 { // If we have an existing early-bound member, combine its declarations so that we can // report an error at each declaration. @@ -16487,16 +16487,16 @@ func (c *Checker) lateBindMember(parent *ast.Symbol, earlySymbols ast.SymbolTabl func (c *Checker) lateBindIndexSignature(parent *ast.Symbol, earlySymbols ast.SymbolTable, lateSymbols ast.SymbolTable, decl *ast.Node) { // First, late bind the index symbol itself, if needed - indexSymbol := lateSymbols[ast.InternalSymbolNameIndex] + indexSymbol := lateSymbols.Get(ast.InternalSymbolNameIndex) if indexSymbol == nil { - early := earlySymbols[ast.InternalSymbolNameIndex] + early := earlySymbols.Get(ast.InternalSymbolNameIndex) if early == nil { indexSymbol = c.newSymbolEx(ast.SymbolFlagsNone, ast.InternalSymbolNameIndex, ast.CheckFlagsLate) } else { indexSymbol = c.cloneSymbol(early) indexSymbol.SetCheckFlags(indexSymbol.CheckFlags() | ast.CheckFlagsLate) } - lateSymbols[ast.InternalSymbolNameIndex] = indexSymbol + lateSymbols.Set(ast.InternalSymbolNameIndex, indexSymbol) } // Then just add the computed name as a late bound declaration // (note: unlike `addDeclarationToLateBoundSymbol` we do not set up a `.lateSymbol` on `decl`'s links, @@ -16567,16 +16567,17 @@ type ExportCollisionTable = map[string]*ExportCollision func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports ast.SymbolTable, typeOnlyExportStarMap map[string]*ast.Node) { var visitedSymbols []*ast.Symbol - nonTypeOnlyNames := collections.NewSetWithSizeHint[string](len(moduleSymbol.Exports())) + nonTypeOnlyNames := collections.NewSetWithSizeHint[string](moduleSymbol.Exports().Len()) // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example, // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error. + var visit func(*ast.Symbol, *ast.Node, bool) ast.SymbolTable visit = func(symbol *ast.Symbol, exportStar *ast.Node, isTypeOnly bool) ast.SymbolTable { if !isTypeOnly && symbol != nil { // Add non-type-only names before checking if we've visited this module, // because we might have visited it via an 'export type *', and visiting // again with 'export *' will override the type-onlyness of its exports. - for name := range symbol.Exports() { + for name := range symbol.Exports().All() { nonTypeOnlyNames.Add(name) } } @@ -16584,11 +16585,11 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as return nil } visitedSymbols = append(visitedSymbols, symbol) - symbols := maps.Clone(symbol.Exports()) + symbols := symbol.Exports().Clone() // All export * declarations are collected in an __export symbol by the binder - exportStars := symbol.Exports()[ast.InternalSymbolNameExportStar] + exportStars := symbol.Exports().Get(ast.InternalSymbolNameExportStar) if exportStars != nil { - nestedSymbols := make(ast.SymbolTable) + nestedSymbols := ast.NewSymbolTable(0) lookupTable := make(ExportCollisionTable) for _, node := range exportStars.Declarations() { resolvedModule := c.resolveExternalModuleName(node, node.ModuleSpecifier(), false /*ignoreErrors*/, c.getTypeFromImportAttributes(ast.GetImportAttributes(node))) @@ -16597,7 +16598,7 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as } for id, s := range lookupTable { // It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself - if id == ast.InternalSymbolNameExportEquals || len(s.exportsWithDuplicate) == 0 || symbols[id] != nil { + if id == ast.InternalSymbolNameExportEquals || len(s.exportsWithDuplicate) == 0 || symbols.Get(id) != nil { continue } for _, node := range s.exportsWithDuplicate { @@ -16610,7 +16611,7 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as if typeOnlyExportStarMap == nil { typeOnlyExportStarMap = make(map[string]*ast.Node) } - for name := range symbols { + for name := range symbols.All() { typeOnlyExportStarMap[name] = exportStar } } @@ -16618,7 +16619,7 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as } var originalModule *ast.Symbol if moduleSymbol != nil { - if c.resolveSymbolEx(moduleSymbol.Exports()[ast.InternalSymbolNameExportEquals], false /*dontResolveAlias*/) != nil { + if c.resolveSymbolEx(moduleSymbol.Exports().Get(ast.InternalSymbolNameExportEquals), false /*dontResolveAlias*/) != nil { originalModule = moduleSymbol } } @@ -16626,10 +16627,10 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as moduleSymbol = c.resolveExternalModuleSymbol(moduleSymbol, false /*dontResolveAlias*/) exports = visit(moduleSymbol, nil, false) if exports == nil { - exports = make(ast.SymbolTable) + exports = ast.NewSymbolTable(0) } // A CommonJS module defined by an 'export=' might also export typedefs, stored on the original module - if originalModule != nil && len(originalModule.Exports()) > 1 { + if originalModule != nil && originalModule.Exports().Len() > 1 { c.forEachSymbolTableEntry(originalModule.Exports(), func(_ string, symbol *ast.Symbol) bool { if symbol.Name() == ast.InternalSymbolNameExportEquals || symbol.Name() == ast.InternalSymbolNameExportStar { return false @@ -16637,8 +16638,8 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as flags := c.getSymbolFlags(symbol) if flags&(ast.SymbolFlagsType|ast.SymbolFlagsNamespace) != 0 && flags&ast.SymbolFlagsValue == 0 && - exports[symbol.Name()] == nil { - exports[symbol.Name()] = symbol + exports.Get(symbol.Name()) == nil { + exports.Set(symbol.Name(), symbol) } return false }) @@ -16659,13 +16660,13 @@ func (c *Checker) extendExportSymbols(target ast.SymbolTable, source ast.SymbolT symbol *ast.Symbol } var collisions []collision - for id, sourceSymbol := range source { + for id, sourceSymbol := range source.All() { if id == ast.InternalSymbolNameDefault { continue } - targetSymbol := target[id] + targetSymbol := target.Get(id) if targetSymbol == nil { - target[id] = sourceSymbol + target.Set(id, sourceSymbol) if lookupTable != nil && exportNode != nil { lookupTable[id] = &ExportCollision{ specifierText: scanner.GetTextOfNode(exportNode.ModuleSpecifier()), @@ -16684,7 +16685,7 @@ func (c *Checker) extendExportSymbols(target ast.SymbolTable, source ast.SymbolT return strings.Compare(a.id, b.id) }) for _, collision := range collisions { - if c.resolveSymbol(target[collision.id]) != c.resolveSymbol(collision.symbol) { + if c.resolveSymbol(target.Get(collision.id)) != c.resolveSymbol(collision.symbol) { s := lookupTable[collision.id] s.exportsWithDuplicate = append(s.exportsWithDuplicate, exportNode) } @@ -17273,14 +17274,14 @@ func (c *Checker) padObjectLiteralType(t *Type, pattern *ast.Node) *Type { if len(missingElements) == 0 { return t } - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) for _, prop := range c.getPropertiesOfObjectType(t) { - members[prop.Name()] = prop + members.Set(prop.Name(), prop) } for _, e := range missingElements { symbol := c.newSymbol(ast.SymbolFlagsProperty|ast.SymbolFlagsOptional, c.getPropertyNameFromBindingElement(e)) c.valueSymbolLinks.Get(symbol).resolvedType = c.getTypeFromBindingElement(e, false /*includePatternInType*/, true /*reportErrors*/) - members[symbol.Name()] = symbol + members.Set(symbol.Name(), symbol) } result := c.newAnonymousType(t.symbol, members, nil, nil, c.getIndexInfosOfType(t)) result.objectFlags = t.objectFlags @@ -18289,9 +18290,9 @@ func (c *Checker) getRestType(source *Type, properties []*ast.Node, symbol *ast. } return c.getTypeAliasInstantiation(omitTypeAlias, []*Type{source, omitKeyType}, nil) } - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) for _, prop := range spreadableProperties { - members[prop.Name()] = c.getSpreadSymbol(prop, false /*readonly*/) + members.Set(prop.Name(), c.getSpreadSymbol(prop, false /*readonly*/)) } result := c.newAnonymousType(symbol, members, nil, nil, c.getIndexInfosOfType(source)) result.objectFlags |= ObjectFlagsObjectRestType @@ -18382,7 +18383,7 @@ func (c *Checker) getTypeFromBindingPattern(pattern *ast.Node, includePatternInT // Return the type implied by an object binding pattern func (c *Checker) getTypeFromObjectBindingPattern(pattern *ast.Node, includePatternInType bool, reportErrors bool) *Type { - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) var stringIndexInfo *IndexInfo objectFlags := ObjectFlagsObjectLiteral | ObjectFlagsContainsObjectOrArrayLiteral for _, e := range pattern.Elements() { @@ -18401,7 +18402,7 @@ func (c *Checker) getTypeFromObjectBindingPattern(pattern *ast.Node, includePatt flags := ast.SymbolFlagsProperty | core.IfElse(e.Initializer() != nil, ast.SymbolFlagsOptional, 0) symbol := c.newSymbol(flags, text) c.valueSymbolLinks.Get(symbol).resolvedType = c.getTypeFromBindingElement(e, includePatternInType, reportErrors) - members[symbol.Name()] = symbol + members.Set(symbol.Name(), symbol) } var indexInfos []*IndexInfo if stringIndexInfo != nil { @@ -18870,14 +18871,14 @@ func (c *Checker) getWidenedTypeOfObjectLiteral(t *Type, context *WideningContex return cached } } - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) for _, prop := range c.getPropertiesOfObjectType(t) { - members[prop.Name()] = c.getWidenedProperty(prop, context) + members.Set(prop.Name(), c.getWidenedProperty(prop, context)) } if context != nil { for _, prop := range c.getPropertiesOfContext(context) { - if _, ok := members[prop.Name()]; !ok { - members[prop.Name()] = c.getUndefinedProperty(prop) + if _, ok := members.Lookup(prop.Name()); !ok { + members.Set(prop.Name(), c.getUndefinedProperty(prop)) } } } @@ -19368,7 +19369,7 @@ func (c *Checker) getPropertyOfTypeEx(t *Type, name string, skipObjectFunctionPr switch { case t.flags&TypeFlagsObject != 0: resolved := c.resolveStructuredTypeMembers(t) - symbol := resolved.members[name] + symbol := resolved.members.Get(name) if symbol != nil { if !includeTypeOnlyMembers && t.symbol != nil && t.symbol.Flags()&ast.SymbolFlagsValueModule != 0 && c.moduleSymbolLinks.Get(t.symbol).typeOnlyExportStarMap[name] != nil { // If this is the type of a module, `resolved.members.get(name)` might have effectively skipped over @@ -19597,7 +19598,7 @@ func (c *Checker) resolveObjectTypeMembers(t *Type, source *Type, typeParameters baseTypes := c.getBaseTypes(source) if len(baseTypes) != 0 { if !instantiated { - members = maps.Clone(members) + members = members.Clone() } thisArgument := core.LastOrNil(typeArguments) for _, baseType := range baseTypes { @@ -20065,11 +20066,11 @@ func (c *Checker) getTypeWithThisArgument(t *Type, thisArgument *Type, needAppar func (c *Checker) addInheritedMembers(symbols ast.SymbolTable, baseSymbols []*ast.Symbol) ast.SymbolTable { for _, base := range baseSymbols { if !isStaticPrivateIdentifierProperty(base) { - if s, ok := symbols[base.Name()]; !ok || s.Flags()&ast.SymbolFlagsValue == 0 { + if s, ok := symbols.Lookup(base.Name()); !ok || s.Flags()&ast.SymbolFlagsValue == 0 { if symbols == nil { - symbols = make(ast.SymbolTable) + symbols = ast.NewSymbolTable(0) } - symbols[base.Name()] = base + symbols.Set(base.Name(), base) } } } @@ -20082,8 +20083,8 @@ func (c *Checker) resolveDeclaredMembers(t *Type) *InterfaceType { members := c.getMembersOfSymbol(t.symbol) d.declaredMembersResolved = true d.declaredMembers = members - d.declaredCallSignatures = c.getSignaturesOfSymbol(d.declaredMembers[ast.InternalSymbolNameCall]) - d.declaredConstructSignatures = c.getSignaturesOfSymbol(d.declaredMembers[ast.InternalSymbolNameNew]) + d.declaredCallSignatures = c.getSignaturesOfSymbol(d.declaredMembers.Get(ast.InternalSymbolNameCall)) + d.declaredConstructSignatures = c.getSignaturesOfSymbol(d.declaredMembers.Get(ast.InternalSymbolNameNew)) d.declaredIndexInfos = c.getIndexInfosOfSymbol(t.symbol) } return d @@ -20094,7 +20095,7 @@ func (c *Checker) getIndexInfosOfSymbol(symbol *ast.Symbol) []*IndexInfo { if indexSymbol != nil { // The types of the siblings are created in this order, so sort them rather than using the random iteration // order of the symbol table. - siblingSymbols := slices.Collect(maps.Values(c.getMembersOfSymbol(symbol))) + siblingSymbols := slices.Collect(c.getMembersOfSymbol(symbol).Values()) c.sortSymbols(siblingSymbols) return c.getIndexInfosOfIndexSymbol(indexSymbol, siblingSymbols) } @@ -20271,7 +20272,7 @@ func (c *Checker) findIndexInfo(indexInfos []*IndexInfo, keyType *Type) *IndexIn } func (c *Checker) getIndexSymbol(symbol *ast.Symbol) *ast.Symbol { - return c.getMembersOfSymbol(symbol)[ast.InternalSymbolNameIndex] + return c.getMembersOfSymbol(symbol).Get(ast.InternalSymbolNameIndex) } func (c *Checker) getSignaturesOfSymbol(symbol *ast.Symbol) []*Signature { @@ -21133,8 +21134,8 @@ func (c *Checker) resolveAnonymousTypeMembers(t *Type) { if symbol.Flags()&ast.SymbolFlagsTypeLiteral != 0 { c.setStructuredTypeMembers(t, nil, nil, nil, nil) members := c.getMembersOfSymbol(symbol) - callSignatures := c.getSignaturesOfSymbol(members[ast.InternalSymbolNameCall]) - constructSignatures := c.getSignaturesOfSymbol(members[ast.InternalSymbolNameNew]) + callSignatures := c.getSignaturesOfSymbol(members.Get(ast.InternalSymbolNameCall)) + constructSignatures := c.getSignaturesOfSymbol(members.Get(ast.InternalSymbolNameNew)) indexInfos := c.getIndexInfosOfSymbol(symbol) c.setStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos) return @@ -21143,10 +21144,10 @@ func (c *Checker) resolveAnonymousTypeMembers(t *Type) { members := c.getExportsOfSymbol(symbol) var indexInfos []*IndexInfo if symbol == c.globalThisSymbol { - varsOnly := make(ast.SymbolTable) - for _, p := range members { + varsOnly := ast.NewSymbolTable(0) + for _, p := range members.All() { if p.Flags()&ast.SymbolFlagsBlockScoped == 0 && !(p.Flags()&ast.SymbolFlagsValueModule != 0 && len(p.Declarations()) != 0 && core.Every(p.Declarations(), ast.IsAmbientModule)) { - varsOnly[p.Name()] = p + varsOnly.Set(p.Name(), p) } } members = varsOnly @@ -21157,18 +21158,18 @@ func (c *Checker) resolveAnonymousTypeMembers(t *Type) { classType := c.getDeclaredTypeOfClassOrInterface(symbol) baseConstructorType := c.getBaseConstructorTypeOfClass(classType) if baseConstructorType.flags&(TypeFlagsObject|TypeFlagsIntersection|TypeFlagsTypeVariable) != 0 { - members = maps.Clone(members) + members = members.Clone() c.addInheritedMembers(members, c.getPropertiesOfType(baseConstructorType)) c.setStructuredTypeMembers(t, members, nil, nil, nil) } else if baseConstructorType == c.anyType { baseConstructorIndexInfo = c.anyBaseTypeIndexInfo } } - indexSymbol := members[ast.InternalSymbolNameIndex] + indexSymbol := members.Get(ast.InternalSymbolNameIndex) if indexSymbol != nil { // The types of the siblings are created in this order, so sort them rather than using the random iteration // order of the symbol table. - siblingSymbols := slices.Collect(maps.Values(members)) + siblingSymbols := slices.Collect(members.Values()) c.sortSymbols(siblingSymbols) indexInfos = c.getIndexInfosOfIndexSymbol(indexSymbol, siblingSymbols) } else { @@ -21199,7 +21200,7 @@ func (c *Checker) resolveAnonymousTypeMembers(t *Type) { // And likewise for construct signatures for classes if symbol.Flags()&ast.SymbolFlagsClass != 0 { classType := c.getDeclaredTypeOfClassOrInterface(symbol) - constructSignatures := c.getSignaturesOfSymbol(symbol.Members()[ast.InternalSymbolNameConstructor]) + constructSignatures := c.getSignaturesOfSymbol(symbol.Members().Get(ast.InternalSymbolNameConstructor)) if len(constructSignatures) == 0 { constructSignatures = c.getDefaultConstructSignatures(classType) } @@ -21214,21 +21215,21 @@ func (c *Checker) createInstantiatedSymbolTable(symbols []*ast.Symbol, m *TypeMa if len(symbols) == 0 { return nil } - result := make(ast.SymbolTable, len(symbols)) + result := ast.NewSymbolTable(len(symbols)) for _, symbol := range symbols { - result[symbol.Name()] = c.instantiateSymbol(symbol, m) + result.Set(symbol.Name(), c.instantiateSymbol(symbol, m)) } return result } func (c *Checker) instantiateSymbolTable(symbols ast.SymbolTable, m *TypeMapper) ast.SymbolTable { - if len(symbols) == 0 { + if symbols.Len() == 0 { return nil } - result := make(ast.SymbolTable, len(symbols)) - for id, symbol := range symbols { + result := ast.NewSymbolTable(symbols.Len()) + for id, symbol := range symbols.All() { if c.isNamedMember(symbol, id) { - result[id] = c.instantiateSymbol(symbol, m) + result.Set(id, c.instantiateSymbol(symbol, m)) } } return result @@ -21372,7 +21373,7 @@ func (c *Checker) getDefaultConstructSignatures(classType *Type) []*Signature { } func (c *Checker) resolveMappedTypeMembers(t *Type) { - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) var indexInfos []*IndexInfo // Resolve upfront such that recursive references see an empty object type. c.setStructuredTypeMembers(t, nil, nil, nil, nil) @@ -21396,7 +21397,7 @@ func (c *Checker) resolveMappedTypeMembers(t *Type) { // String enum members from separate enums with identical values // are distinct types with the same property name. Make the resulting // property symbol's name type be the union of those enum member types. - if existingProp := members[propName]; existingProp != nil { + if existingProp := members.Get(propName); existingProp != nil { valueLinks := c.valueSymbolLinks.Get(existingProp) valueLinks.setNameType(c, c.getUnionType([]*Type{valueLinks.getNameType(), propNameType})) mappedLinks := c.mappedSymbolLinks.Get(existingProp) @@ -21426,7 +21427,7 @@ func (c *Checker) resolveMappedTypeMembers(t *Type) { prop.SetDeclarations(modifiersProp.Declarations()) } } - members[propName] = prop + members.Set(propName, prop) } } else if c.isValidIndexKeyType(propNameType) || propNameType.flags&(TypeFlagsAny|TypeFlagsEnum) != 0 { indexKeyType := propNameType @@ -21883,7 +21884,7 @@ func (c *Checker) includeMixinType(t *Type, types []*Type, mixinFlags []bool, in func (c *Checker) getPropertyOfObjectType(t *Type, name string) *ast.Symbol { if t.flags&TypeFlagsObject != 0 { resolved := c.resolveStructuredTypeMembers(t) - symbol := resolved.members[name] + symbol := resolved.members.Get(name) if symbol != nil && c.symbolIsValue(symbol) { return symbol } @@ -21912,17 +21913,17 @@ func (c *Checker) getUnionOrIntersectionProperty(t *Type, name string, skipObjec } else { cache = ast.GetSymbolTable(&t.AsUnionOrIntersectionType().propertyCache) } - if prop := cache[name]; prop != nil { + if prop := cache.Get(name); prop != nil { return prop } prop := c.createUnionOrIntersectionProperty(t, name, skipObjectFunctionPropertyAugment) if prop != nil { - cache[name] = prop + cache.Set(name, prop) // Propagate an entry from the non-augmented cache to the augmented cache unless the property is partial. if skipObjectFunctionPropertyAugment && prop.CheckFlags()&ast.CheckFlagsPartial == 0 { augmentedCache := ast.GetSymbolTable(&t.AsUnionOrIntersectionType().propertyCache) - if augmentedCache[name] == nil { - augmentedCache[name] = prop + if augmentedCache.Get(name) == nil { + augmentedCache.Set(name, prop) } } } @@ -22583,13 +22584,13 @@ func (c *Checker) getDefaultOrUnknownFromTypeParameter(t *Type) *Type { } func (c *Checker) getNamedMembers(members ast.SymbolTable, container *ast.Symbol) []*ast.Symbol { - if len(members) == 0 { + if members.Len() == 0 { return nil } // For classes and interfaces, we store explicitly declared members ahead of inherited members. This ensures we process // explicitly declared members first in type relations, which is beneficial because explicitly declared members are more // likely to contain discriminating differences. See for example https://github.com/microsoft/TypeScript/tsc/issues/1968. - result := make([]*ast.Symbol, 0, len(members)) + result := make([]*ast.Symbol, 0, members.Len()) c.forEachSymbolTableEntry(members, func(id string, symbol *ast.Symbol) bool { if c.isNamedMember(symbol, id) { result = append(result, symbol) @@ -23507,7 +23508,7 @@ func (c *Checker) getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node *as if links.resolvedType == nil { // Deferred resolution of members is handled by resolveObjectTypeMembers alias := c.getAliasForTypeNode(node) - if sym := node.Symbol(); sym == nil || len(c.getMembersOfSymbol(sym)) == 0 && alias == nil { + if sym := node.Symbol(); sym == nil || c.getMembersOfSymbol(sym).Len() == 0 && alias == nil { links.resolvedType = c.emptyTypeLiteralType } else { t := c.newObjectType(ObjectFlagsAnonymous, node.Symbol()) @@ -24410,7 +24411,7 @@ func (c *Checker) getOuterTypeParameters(node *ast.Node, includeThisTypes bool) func (c *Checker) getInferTypeParameters(node *ast.Node) []*Type { var symbols []*ast.Symbol - for _, symbol := range node.Locals() { + for _, symbol := range node.Locals().All() { if symbol.Flags()&ast.SymbolFlagsTypeParameter != 0 { symbols = append(symbols, symbol) } @@ -24685,7 +24686,7 @@ func (c *Checker) evaluateEntity(expr *ast.Node, location *ast.Node) evaluator.R rootSymbol := c.resolveEntityName(root, ast.SymbolFlagsValue, true /*ignoreErrors*/, false, nil) if rootSymbol != nil && rootSymbol.Flags()&ast.SymbolFlagsEnum != 0 { name := expr.AsElementAccessExpression().ArgumentExpression.Text() - member := rootSymbol.Exports()[name] + member := rootSymbol.Exports().Get(name) if member != nil { if location != nil { return c.evaluateEnumMember(expr, member, location) @@ -25403,7 +25404,7 @@ func (c *Checker) createTupleTargetType(elementInfos []TupleElementInfo, readonl return e.flags&(ElementFlagsRequired|ElementFlagsVariadic) != 0 }) var typeParameters []*Type - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) combinedFlags := ElementFlagsNone if arity != 0 { typeParameters = make([]*Type, 0, arity) @@ -25416,11 +25417,11 @@ func (c *Checker) createTupleTargetType(elementInfos []TupleElementInfo, readonl property := c.newSymbolEx(ast.SymbolFlagsProperty|core.IfElse(flags&ElementFlagsOptional != 0, ast.SymbolFlagsOptional, 0), strconv.Itoa(i), core.IfElse(readonly, ast.CheckFlagsReadonly, 0)) c.valueSymbolLinks.Get(property).resolvedType = typeParameter // c.valueSymbolLinks.get(property).tupleLabelDeclaration = elementInfos[i].labeledDeclaration - members[property.Name()] = property + members.Set(property.Name(), property) } } } - fixedLength := len(members) + fixedLength := members.Len() lengthSymbol := c.newSymbolEx(ast.SymbolFlagsProperty, "length", core.IfElse(readonly, ast.CheckFlagsReadonly, 0)) if combinedFlags&ElementFlagsVariable != 0 { c.valueSymbolLinks.Get(lengthSymbol).resolvedType = c.numberType @@ -25431,7 +25432,7 @@ func (c *Checker) createTupleTargetType(elementInfos []TupleElementInfo, readonl } c.valueSymbolLinks.Get(lengthSymbol).resolvedType = c.getUnionType(literalTypes) } - members[lengthSymbol.Name()] = lengthSymbol + members.Set(lengthSymbol.Name(), lengthSymbol) t := c.newObjectType(ObjectFlagsTuple|ObjectFlagsReference, nil) d := t.AsTupleType() d.thisType = c.newTypeParameter(nil) @@ -27129,7 +27130,7 @@ func (c *Checker) filterTypes(types []*Type, predicate func(*Type) bool) { func (c *Checker) IsEmptyAnonymousObjectType(t *Type) bool { return t.objectFlags&ObjectFlagsAnonymous != 0 && (t.objectFlags&ObjectFlagsMembersResolved != 0 && c.isEmptyResolvedType(t.AsStructuredType()) || - t.symbol != nil && t.symbol.Flags()&ast.SymbolFlagsTypeLiteral != 0 && len(c.getMembersOfSymbol(t.symbol)) == 0) + t.symbol != nil && t.symbol.Flags()&ast.SymbolFlagsTypeLiteral != 0 && c.getMembersOfSymbol(t.symbol).Len() == 0) } func (c *Checker) isEmptyResolvedType(t *StructuredType) bool { @@ -27800,7 +27801,7 @@ func (c *Checker) getPropertyTypeForIndexType(originalObjectType *Type, objectTy return c.getUnionType(append(types, c.undefinedType)) } } - if objectType.symbol == c.globalThisSymbol && hasPropName && c.globalThisSymbol.Exports()[propName] != nil && c.globalThisSymbol.Exports()[propName].Flags()&ast.SymbolFlagsBlockScoped != 0 { + if objectType.symbol == c.globalThisSymbol && hasPropName && c.globalThisSymbol.Exports().Get(propName) != nil && c.globalThisSymbol.Exports().Get(propName).Flags()&ast.SymbolFlagsBlockScoped != 0 { c.error(accessExpression, diagnostics.Property_0_does_not_exist_on_type_1, propName, c.TypeToString(objectType)) } else if c.noImplicitAny && accessFlags&AccessFlagsSuppressNoImplicitAnyError == 0 { if hasPropName && c.typeHasStaticProperty(propName, objectType) { @@ -28784,7 +28785,7 @@ func (c *Checker) getSingleBaseForNonAugmentingSubtype(t *Type) *Type { if len(bases) != 1 { return nil } - if len(c.getMembersOfSymbol(t.symbol)) != 0 { + if c.getMembersOfSymbol(t.symbol).Len() != 0 { // If the interface has any members, they may subtype members in the base, so we should do a full structural comparison return nil } @@ -28852,14 +28853,14 @@ func (c *Checker) getRegularTypeOfObjectLiteral(t *Type) *Type { } func (c *Checker) transformTypeOfMembers(t *Type, f func(propertyType *Type) *Type) ast.SymbolTable { - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) for _, property := range c.getPropertiesOfObjectType(t) { original := c.getTypeOfSymbol(property) updated := f(original) if updated != original { property = c.createSymbolWithType(property, updated) } - members[property.Name()] = property + members.Set(property.Name(), property) } return members } @@ -31137,10 +31138,10 @@ func (c *Checker) getClassMemberDecoratorContextOverrideType(nameType *Type, isP if overrideType := c.cachedTypes[key]; overrideType != nil { return overrideType } - members := make(ast.SymbolTable) - members["name"] = c.newProperty("name", nameType) - members["private"] = c.newProperty("private", core.IfElse(isPrivate, c.trueType, c.falseType)) - members["static"] = c.newProperty("static", core.IfElse(isStatic, c.trueType, c.falseType)) + members := ast.NewSymbolTable(0) + members.Set("name", c.newProperty("name", nameType)) + members.Set("private", c.newProperty("private", core.IfElse(isPrivate, c.trueType, c.falseType))) + members.Set("static", c.newProperty("static", core.IfElse(isStatic, c.trueType, c.falseType))) overrideType := c.newAnonymousType(nil, members, nil, nil, nil) c.cachedTypes[key] = overrideType return overrideType @@ -31470,7 +31471,7 @@ func (c *Checker) discriminateContextualTypeByObjectMembers(node *ast.Node, cont return false }) discriminantMembers := core.Filter(c.getPropertiesOfType(contextualType), func(s *ast.Symbol) bool { - return s.Flags()&ast.SymbolFlagsOptional != 0 && node.Symbol().Members()[s.Name()] == nil && c.isDiscriminantProperty(contextualType, s.Name()) + return s.Flags()&ast.SymbolFlagsOptional != 0 && node.Symbol().Members().Get(s.Name()) == nil && c.isDiscriminantProperty(contextualType, s.Name()) }) discriminator := &ObjectLiteralDiscriminator{c: c, props: discriminantProperties, members: discriminantMembers} discriminated = c.discriminateTypeByDiscriminableItems(contextualType, discriminator) @@ -31841,7 +31842,7 @@ func (c *Checker) isFunctionObjectType(t *Type) bool { // We do a quick check for a "bind" property before performing the more expensive subtype // check. This gives us a quicker out in the common case where an object type is not a function. resolved := c.resolveStructuredTypeMembers(t) - return len(resolved.getSignatures()) != 0 || resolved.members["bind"] != nil && c.isTypeSubtypeOf(t, c.globalFunctionType) + return len(resolved.getSignatures()) != 0 || resolved.members.Get("bind") != nil && c.isTypeSubtypeOf(t, c.globalFunctionType) } func (c *Checker) getTypeWithFacts(t *Type, include TypeFacts) *Type { @@ -32337,7 +32338,7 @@ func (c *Checker) getSymbolAtLocation(node *ast.Node, ignoreErrors bool) *ast.Sy // member should more exactly be the kind of (declarationless) symbol we want. // (See #44364 and #45031 for relevant implementation PRs) if metaProp.KeywordToken == ast.KindImportKeyword && node.Text() == "meta" { - return c.getGlobalImportMetaExpressionType().AsObjectType().members["meta"] + return c.getGlobalImportMetaExpressionType().AsObjectType().members.Get("meta") } // no other meta properties are valid syntax, thus no others should have symbols return nil diff --git a/tsc/internal/checker/emitresolver.go b/tsc/internal/checker/emitresolver.go index 619e8ec645fda..cb0f9f6cf9741 100644 --- a/tsc/internal/checker/emitresolver.go +++ b/tsc/internal/checker/emitresolver.go @@ -1,7 +1,6 @@ package checker import ( - "maps" "slices" "sync" @@ -269,7 +268,7 @@ func (r *EmitResolver) IsImportRequiredByAugmentation(decl *ast.ImportDeclaratio r.checkerMu.Lock() defer r.checkerMu.Unlock() exports := r.checker.getExportsOfModule(file.Symbol) - for s := range maps.Values(exports) { + for s := range exports.Values() { merged := r.checker.getMergedSymbol(s) if merged != s { if len(merged.Declarations()) > 0 { @@ -753,7 +752,7 @@ func (r *EmitResolver) CreateLateBoundIndexSignatures(container *ast.Node, enclo instanceIndexSymbol := r.checker.getIndexSymbol(sym) var instanceInfos []*IndexInfo if instanceIndexSymbol != nil { - siblingSymbols := slices.Collect(maps.Values(r.checker.getMembersOfSymbol(sym))) + siblingSymbols := slices.Collect(r.checker.getMembersOfSymbol(sym).Values()) r.checker.sortSymbols(siblingSymbols) instanceInfos = r.checker.getIndexInfosOfIndexSymbol(instanceIndexSymbol, siblingSymbols) } diff --git a/tsc/internal/checker/inference.go b/tsc/internal/checker/inference.go index 02c7d009b9ec5..602facca7ee25 100644 --- a/tsc/internal/checker/inference.go +++ b/tsc/internal/checker/inference.go @@ -1117,7 +1117,7 @@ func (c *Checker) resolveReverseMappedTypeMembers(t *Type) { if indexInfo != nil { indexInfos = []*IndexInfo{c.newIndexInfo(c.stringType, core.OrElse(c.inferReverseMappedType(indexInfo.valueType, r.mappedType, r.constraintType), c.unknownType), readonlyMask && indexInfo.isReadonly, nil, nil)} } - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) limitedConstraint := c.getLimitedConstraint(t) for _, prop := range c.getPropertiesOfType(r.source) { // In case of a reverse mapped type with an intersection constraint, if we were able to @@ -1148,7 +1148,7 @@ func (c *Checker) resolveReverseMappedTypeMembers(t *Type) { links.mappedType = r.mappedType links.constraintType = r.constraintType } - members[prop.Name()] = inferredProp + members.Set(prop.Name(), inferredProp) } c.setStructuredTypeMembers(t, members, nil, nil, indexInfos) } @@ -1238,7 +1238,7 @@ func (c *Checker) isTypeCloselyMatchedBy(s *Type, t *Type) bool { // Create an object with properties named in the string literal type. Every property has type `any`. func (c *Checker) createEmptyObjectTypeFromStringLiteral(t *Type) *Type { - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) for _, t := range t.Distributed() { if t.flags&TypeFlagsStringLiteral == 0 { continue @@ -1250,7 +1250,7 @@ func (c *Checker) createEmptyObjectTypeFromStringLiteral(t *Type) *Type { literalProp.SetDeclarations(t.symbol.Declarations()) literalProp.SetValueDeclaration(t.symbol.ValueDeclaration()) } - members[name] = literalProp + members.Set(name, literalProp) } var indexInfos []*IndexInfo if t.flags&TypeFlagsString != 0 { diff --git a/tsc/internal/checker/jsx.go b/tsc/internal/checker/jsx.go index 7f35f796957cf..1294d6fde9a9d 100644 --- a/tsc/internal/checker/jsx.go +++ b/tsc/internal/checker/jsx.go @@ -285,7 +285,7 @@ func (c *Checker) discriminateContextualTypeByJSXAttributes(node *ast.Node, cont if s.Name() == jsxChildrenPropertyName && ast.IsJsxElement(element) && len(ast.GetSemanticJsxChildren(element.Children().Nodes)) != 0 { return false } - return node.Symbol().Members()[s.Name()] == nil && c.isDiscriminantProperty(contextualType, s.Name()) + return node.Symbol().Members().Get(s.Name()) == nil && c.isDiscriminantProperty(contextualType, s.Name()) }) discriminator := &ObjectLiteralDiscriminator{c: c, props: discriminantProperties, members: discriminantMembers} discriminated := c.discriminateTypeByDiscriminableItems(contextualType, discriminator) @@ -710,9 +710,9 @@ func (c *Checker) checkApplicableSignatureForJsxCallLikeElement(node *ast.Node, func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeElement *ast.Node, checkMode CheckMode) *Type { var allAttributesTable ast.SymbolTable if c.strictNullChecks { - allAttributesTable = make(ast.SymbolTable) + allAttributesTable = ast.NewSymbolTable(0) } - attributesTable := make(ast.SymbolTable) + attributesTable := ast.NewSymbolTable(0) var attributesSymbol *ast.Symbol attributeParent := openingLikeElement spread := c.emptyJsxObjectType @@ -750,9 +750,9 @@ func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeEleme links := c.valueSymbolLinks.Get(attributeSymbol) links.resolvedType = exprType links.target = member - attributesTable[attributeSymbol.Name()] = attributeSymbol + attributesTable.Set(attributeSymbol.Name(), attributeSymbol) if allAttributesTable != nil { - allAttributesTable[attributeSymbol.Name()] = attributeSymbol + allAttributesTable.Set(attributeSymbol.Name(), attributeSymbol) } if attributeDecl.Name().Text() == jsxChildrenPropertyName { explicitlySpecifyChildrenAttribute = true @@ -766,9 +766,9 @@ func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeEleme } } else { debug.Assert(attributeDecl.Kind == ast.KindJsxSpreadAttribute) - if len(attributesTable) != 0 { + if attributesTable.Len() != 0 { spread = c.getSpreadType(spread, createJsxAttributesType(), attributesSymbol, objectFlags, false /*readonly*/) - attributesTable = make(ast.SymbolTable) + attributesTable = ast.NewSymbolTable(0) } exprType := c.getReducedType(c.checkExpressionEx(attributeDecl.Expression(), checkMode&CheckModeInferential)) if IsTypeAny(exprType) { @@ -790,7 +790,7 @@ func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeEleme } } if !hasSpreadAnyType { - if len(attributesTable) != 0 { + if attributesTable.Len() != 0 { spread = c.getSpreadType(spread, createJsxAttributesType(), attributesSymbol, objectFlags, false /*readonly*/) } } @@ -846,8 +846,8 @@ func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeEleme childrenPropSymbol.SetValueDeclaration(c.factory.NewPropertySignatureDeclaration(nil, c.factory.NewIdentifier(jsxChildrenPropertyName), nil /*postfixToken*/, nil /*type*/, nil /*initializer*/)) childrenPropSymbol.ValueDeclaration().Parent = attributeParent childrenPropSymbol.ValueDeclaration().AsPropertySignatureDeclaration().Symbol = childrenPropSymbol - childPropMap := make(ast.SymbolTable) - childPropMap[jsxChildrenPropertyName] = childrenPropSymbol + childPropMap := ast.NewSymbolTable(0) + childPropMap.Set(jsxChildrenPropertyName, childrenPropSymbol) spread = c.getSpreadType(spread, c.newAnonymousType(attributesSymbol, childPropMap, nil, nil, nil), attributesSymbol, objectFlags|c.getPropagatingFlagsOfTypes(childTypes, TypeFlagsNone), false /*readonly*/) } } diff --git a/tsc/internal/checker/nodebuilder_hover.go b/tsc/internal/checker/nodebuilder_hover.go index b048c5d1618c6..6edb0380ca13f 100644 --- a/tsc/internal/checker/nodebuilder_hover.go +++ b/tsc/internal/checker/nodebuilder_hover.go @@ -413,7 +413,7 @@ func (b *NodeBuilderImpl) serializeNamespaceMember(resolved *ast.Symbol, name st func (b *NodeBuilderImpl) expandModuleDecl(symbol *ast.Symbol) *ast.Node { exports := b.ch.getExportsOfSymbol(symbol) var members []*ast.Symbol - for _, sym := range exports { + for _, sym := range exports.All() { // Filter to namespace-relevant members if !b.isNamespaceMember(sym) { continue @@ -498,7 +498,7 @@ func (b *NodeBuilderImpl) expandModuleDecl(symbol *ast.Symbol) *ast.Node { } // If the function also has namespace characteristics, emit an empty namespace. merged := b.ch.getMergedSymbol(resolved) - hasModuleExports := merged.Flags()&(ast.SymbolFlagsValueModule|ast.SymbolFlagsNamespaceModule) != 0 && merged.Exports() != nil && len(merged.Exports()) != 0 + hasModuleExports := merged.Flags()&(ast.SymbolFlagsValueModule|ast.SymbolFlagsNamespaceModule) != 0 && merged.Exports() != nil && merged.Exports().Len() != 0 if !hasModuleExports { bodyStmts = append(bodyStmts, hoverStatement{node: b.f.NewModuleDeclaration(nil, ast.KindNamespaceKeyword, b.f.NewIdentifier(m.Name()), nil /*attributes*/, b.f.NewModuleBlock(b.f.NewNodeList(nil)))}) } diff --git a/tsc/internal/checker/nodebuilderimpl.go b/tsc/internal/checker/nodebuilderimpl.go index dbb356e06c1ab..155a973d4a73b 100644 --- a/tsc/internal/checker/nodebuilderimpl.go +++ b/tsc/internal/checker/nodebuilderimpl.go @@ -773,7 +773,7 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index exports := b.ch.getExportsOfSymbol(parent) if exports != nil { // avoid exhaustive iteration in the common case - res, ok := exports[symbol.Name()] + res, ok := exports.Lookup(symbol.Name()) if symbol.Name() != ast.InternalSymbolNameExportEquals && !isLateBoundName(symbol.Name()) && ok && res != nil && b.ch.getSymbolIfSameReference(res, symbol) != nil { symbolName = symbol.Name() } else { @@ -818,8 +818,8 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index b.ctx.approximateLength += len(symbolName) + 1 if (b.ctx.flags&nodebuilder.FlagsForbidIndexedAccessSymbolReferences == 0) && parent != nil && - b.ch.getMembersOfSymbol(parent) != nil && b.ch.getMembersOfSymbol(parent)[symbol.Name()] != nil && - b.ch.getSymbolIfSameReference(b.ch.getMembersOfSymbol(parent)[symbol.Name()], symbol) != nil { + b.ch.getMembersOfSymbol(parent) != nil && b.ch.getMembersOfSymbol(parent).Get(symbol.Name()) != nil && + b.ch.getSymbolIfSameReference(b.ch.getMembersOfSymbol(parent).Get(symbol.Name()), symbol) != nil { // Should use an indexed access lhs := b.createAccessFromSymbolChain(chain, index-1, stopper, overrideTypeArguments) if ast.IsIndexedAccessTypeNode(lhs) { @@ -1113,7 +1113,7 @@ func (b *NodeBuilderImpl) getSymbolChain(symbol *ast.Symbol, meaning ast.SymbolF parentChain := b.getSymbolChain(parent, getQualifiedLeftMeaning(meaning), false, yieldModuleSymbol) if len(parentChain) > 0 { if parent.Exports() != nil { - exported, ok := parent.Exports()[ast.InternalSymbolNameExportEquals] + exported, ok := parent.Exports().Lookup(ast.InternalSymbolNameExportEquals) if ok && b.ch.getSymbolIfSameReference(exported, symbol) != nil { // parentChain root _is_ symbol - symbol is a module export=, so it kinda looks like it's own parent // No need to lookup an alias for the symbol in itself diff --git a/tsc/internal/checker/nodebuilderscopes.go b/tsc/internal/checker/nodebuilderscopes.go index 05f033bf05b7d..0c1b52a289f46 100644 --- a/tsc/internal/checker/nodebuilderscopes.go +++ b/tsc/internal/checker/nodebuilderscopes.go @@ -119,21 +119,21 @@ func (b *NodeBuilderImpl) enterNewScope(declaration *ast.Node, expandedParams [] locals = existingFakeScope.Locals() } if locals == nil { - locals = make(ast.SymbolTable) + locals = ast.NewSymbolTable(0) } newLocals := []string{} oldLocals := []localsRecord{} addAll(func(name string, symbol *ast.Symbol) { // Add cleanup information only if we don't own the fake scope if existingFakeScope != nil { - oldSymbol, ok := locals[name] + oldSymbol, ok := locals.Lookup(name) if !ok || oldSymbol == nil { newLocals = append(newLocals, name) } else { oldLocals = append(oldLocals, localsRecord{name, oldSymbol}) } } - locals[name] = symbol + locals.Set(name, symbol) }) if existingFakeScope == nil { @@ -150,10 +150,10 @@ func (b *NodeBuilderImpl) enterNewScope(declaration *ast.Node, expandedParams [] // We did not create the current scope, so we have to clean it up undo := func() { for _, s := range newLocals { - delete(locals, s) + locals.Delete(s) } for _, s := range oldLocals { - locals[s.name] = s.oldSymbol + locals.Set(s.name, s.oldSymbol) } } return undo diff --git a/tsc/internal/checker/services.go b/tsc/internal/checker/services.go index 90f3f2f901844..a52d779a38264 100644 --- a/tsc/internal/checker/services.go +++ b/tsc/internal/checker/services.go @@ -1,7 +1,6 @@ package checker import ( - "maps" "slices" "strings" @@ -23,7 +22,7 @@ func (c *Checker) getSymbolsInScope(location *ast.Node, meaning ast.SymbolFlags) return nil } - symbols := make(ast.SymbolTable) + symbols := ast.NewSymbolTable(0) isStaticSymbol := false // Copy the given symbol into symbol tables if the symbol has the given meaning @@ -34,15 +33,15 @@ func (c *Checker) getSymbolsInScope(location *ast.Node, meaning ast.SymbolFlags) // We will copy all symbol regardless of its reserved name because // symbolsToArray will check whether the key is a reserved name and // it will not copy symbol with reserved name to the array - if _, ok := symbols[id]; !ok { - symbols[id] = symbol + if _, ok := symbols.Lookup(id); !ok { + symbols.Set(id, symbol) } } } copySymbols := func(source ast.SymbolTable, meaning ast.SymbolFlags) { if meaning != 0 { - for _, symbol := range source { + for _, symbol := range source.All() { copySymbol(symbol, meaning) } } @@ -50,7 +49,7 @@ func (c *Checker) getSymbolsInScope(location *ast.Node, meaning ast.SymbolFlags) copyLocallyVisibleExportSymbols := func(source ast.SymbolTable, meaning ast.SymbolFlags) { if meaning != 0 { - for _, symbol := range source { + for _, symbol := range source.All() { // Similar condition as in `resolveNameHelper` if ast.GetDeclarationOfKind(symbol, ast.KindExportSpecifier) == nil && ast.GetDeclarationOfKind(symbol, ast.KindNamespaceExport) == nil && @@ -124,7 +123,7 @@ func (c *Checker) getSymbolsInScope(location *ast.Node, meaning ast.SymbolFlags) populateSymbols() - delete(symbols, ast.InternalSymbolNameThis) // Not a symbol, a keyword + symbols.Delete(ast.InternalSymbolNameThis) // Not a symbol, a keyword return symbolsToArray(symbols) } @@ -133,7 +132,7 @@ func (c *Checker) GetExportsOfModule(symbol *ast.Symbol) []*ast.Symbol { } func (c *Checker) ForEachExportAndPropertyOfModule(moduleSymbol *ast.Symbol, cb func(*ast.Symbol, string)) { - for key, exportedSymbol := range c.getExportsOfModule(moduleSymbol) { + for key, exportedSymbol := range c.getExportsOfModule(moduleSymbol).All() { if !isReservedMemberName(key) { cb(exportedSymbol, key) } @@ -154,7 +153,7 @@ func (c *Checker) ForEachExportAndPropertyOfModule(moduleSymbol *ast.Symbol, cb if reducedType.flags&TypeFlagsStructuredType == 0 { return } - for name, symbol := range c.resolveStructuredTypeMembers(reducedType).members { + for name, symbol := range c.resolveStructuredTypeMembers(reducedType).members.All() { if c.isNamedMember(symbol, name) { cb(symbol, name) } @@ -212,20 +211,20 @@ func (c *Checker) GetAllPossiblePropertiesOfTypes(types []*Type) []*ast.Symbol { return c.getAugmentedPropertiesOfType(unionType) } - props := make(ast.SymbolTable) + props := ast.NewSymbolTable(0) for _, memberType := range types { augmentedProps := c.getAugmentedPropertiesOfType(memberType) for _, p := range augmentedProps { - if _, ok := props[p.Name()]; !ok { + if _, ok := props.Lookup(p.Name()); !ok { prop := c.createUnionOrIntersectionProperty(unionType, p.Name(), false /*skipObjectFunctionPropertyAugment*/) // May be undefined if the property is private if prop != nil { - props[p.Name()] = prop + props.Set(p.Name(), prop) } } } } - return slices.Collect(maps.Values(props)) + return slices.Collect(props.Values()) } func (c *Checker) IsUnknownSymbol(symbol *ast.Symbol) bool { @@ -280,12 +279,12 @@ func (c *Checker) getAugmentedPropertiesOfType(t *Type) []*ast.Symbol { } if propsByName == nil { - propsByName = make(ast.SymbolTable) + propsByName = ast.NewSymbolTable(0) } if functionType != nil { for _, p := range c.getPropertiesOfType(functionType) { - if _, ok := propsByName[p.Name()]; !ok { - propsByName[p.Name()] = p + if _, ok := propsByName.Lookup(p.Name()); !ok { + propsByName.Set(p.Name(), p) } } } @@ -312,7 +311,7 @@ func (c *Checker) TryGetMemberInModuleExportsAndProperties(memberName string, mo func (c *Checker) TryGetMemberInModuleExports(memberName string, moduleSymbol *ast.Symbol) *ast.Symbol { symbolTable := c.getExportsOfModule(moduleSymbol) - return symbolTable[memberName] + return symbolTable.Get(memberName) } func (c *Checker) shouldTreatPropertiesOfExternalModuleAsExports(resolvedExternalModuleType *Type) bool { diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index 44e6f2db36cc4..ec88f92b9118e 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -152,7 +152,7 @@ func (c *Checker) getWithAlternativeContainers(container *ast.Symbol, symbol *as } } var unresolved []*ast.Symbol - for _, s := range t { + for _, s := range t.All() { if s.Flags()&leftMeaning == 0 { continue } @@ -284,7 +284,7 @@ func (c *Checker) buildExternalModuleContainerIndex() { index.add(c.getResolvedTarget(exported), container) return false }) - if exportEquals := container.Exports()[ast.InternalSymbolNameExportEquals]; exportEquals != nil { + if exportEquals := container.Exports().Get(ast.InternalSymbolNameExportEquals); exportEquals != nil { index.add(c.getResolvedTarget(exportEquals), container) } } @@ -305,7 +305,7 @@ func (c *Checker) forEachSymbolTableEntry(symbols ast.SymbolTable, f func(name s symbol *ast.Symbol } var unresolved []entry - for name, symbol := range symbols { + for name, symbol := range symbols.All() { if !c.isAliasChainResolved(symbol) { unresolved = append(unresolved, entry{name, symbol}) continue @@ -404,7 +404,7 @@ func (c *Checker) getFileSymbolIfFileSymbolExportEqualsContainer(d *ast.Node, co if fileSymbol == nil || fileSymbol.Exports() == nil { return nil } - exported, ok := fileSymbol.Exports()[ast.InternalSymbolNameExportEquals] + exported, ok := fileSymbol.Exports().Lookup(ast.InternalSymbolNameExportEquals) if !ok || exported == nil { return nil } @@ -488,13 +488,13 @@ func (c *Checker) getAliasForSymbolInContainer(container *ast.Symbol, symbol *as // Check if container is a thing with an `export=` which points directly at `symbol`, and if so, return // the container itself as the alias for the symbol if container.Exports() != nil { - exportEquals, ok := container.Exports()[ast.InternalSymbolNameExportEquals] + exportEquals, ok := container.Exports().Lookup(ast.InternalSymbolNameExportEquals) if ok && exportEquals != nil && c.getSymbolIfSameReference(exportEquals, symbol) != nil { return container } } exports := c.getExportsOfSymbol(container) - quick, ok := exports[symbol.Name()] + quick, ok := exports.Lookup(symbol.Name()) if ok && quick != nil && c.getSymbolIfSameReference(quick, symbol) != nil { return quick } @@ -660,7 +660,7 @@ func (c *Checker) getSymbolTableAliases(symbols ast.SymbolTable, tableId symbolT } } var aliases []*ast.Symbol - for _, sym := range symbols { + for _, sym := range symbols.All() { if sym.Flags()&ast.SymbolFlagsAlias != 0 { aliases = append(aliases, sym) } @@ -686,7 +686,7 @@ func (c *Checker) trySymbolTable( ) []*ast.Symbol { isGlobals := tableId == stKindGlobals // If symbol is directly available by its name in the symbol table - res, ok := symbols[ctx.symbol.Name()] + res, ok := symbols.Lookup(ctx.symbol.Name()) if ok && res != nil && c.isAccessible(ctx, res /*resolvedAliasSymbol*/, nil, ignoreQualification) { return []*ast.Symbol{ctx.symbol} } @@ -845,7 +845,7 @@ func (c *Checker) needsQualification(symbol *ast.Symbol, enclosingDeclaration *a qualify := false c.someSymbolTableInScope(enclosingDeclaration, func(symbolTable ast.SymbolTable, _ symbolTableID, _ bool, _ bool, _ *ast.Node) bool { // If symbol of this name is not available in the symbol table we are ok - res, ok := symbolTable[symbol.Name()] + res, ok := symbolTable.Lookup(symbol.Name()) if !ok || res == nil { return false } @@ -930,12 +930,12 @@ func (c *Checker) someSymbolTableInScope( var table ast.SymbolTable sym := c.getSymbolOfDeclaration(location) // TODO: Should this filtered table be cached in some way? - for key, memberSymbol := range sym.Members() { + for key, memberSymbol := range sym.Members().All() { if memberSymbol.Flags()&(ast.SymbolFlagsType & ^ast.SymbolFlagsAssignment) != 0 { if table == nil { - table = make(ast.SymbolTable) + table = ast.NewSymbolTable(0) } - table[key] = memberSymbol + table.Set(key, memberSymbol) } } if table != nil && callback(table, symbolTableIDFromMembers(sym), false, false, location) { @@ -975,7 +975,7 @@ func (c *Checker) getClassExpressionNameTable(location *ast.Node) ast.SymbolTabl if len(nameText) == 0 || classSymbol == nil { return nil } - table := ast.SymbolTable{nameText: classSymbol} + table := ast.SymbolTableOf(nameText, classSymbol) if c.classExpressionNameTables == nil { c.classExpressionNameTables = make(map[ast.NodeId]ast.SymbolTable) } diff --git a/tsc/internal/checker/types_test.go b/tsc/internal/checker/types_test.go index 86de2b089e06e..66fd050a2cd03 100644 --- a/tsc/internal/checker/types_test.go +++ b/tsc/internal/checker/types_test.go @@ -291,10 +291,10 @@ func TestIntersectionReductionAllocations(t *testing.T) { //nolint:paralleltest t.Skip("race instrumentation changes hashing allocations") } c, _ := newCompositeTestChecker() - members := make(ast.SymbolTable) + members := ast.NewSymbolTable(0) for i := range 128 { name := strconv.Itoa(i) - members[name] = c.newSymbol(ast.SymbolFlagsProperty, name) + members.Set(name, c.newSymbol(ast.SymbolFlagsProperty, name)) } object := c.newAnonymousType(nil, members, nil, nil, nil) intersection := c.newIntersectionType(ObjectFlagsNone, []*Type{object, object}) @@ -349,7 +349,7 @@ func TestIntersectionReductionReentrancy(t *testing.T) { t.Parallel() c, _ := newCompositeTestChecker() property := c.newSymbol(ast.SymbolFlagsProperty, "value") - object := c.newAnonymousType(nil, ast.SymbolTable{"value": property}, nil, nil, nil) + object := c.newAnonymousType(nil, ast.SymbolTableOf("value", property), nil, nil, nil) inner := c.newIntersectionType(ObjectFlagsNone, []*Type{object, object}) outer := c.newIntersectionType(ObjectFlagsNone, []*Type{inner, object}) assert.Equal(t, c.getReducedType(outer), outer) @@ -359,7 +359,7 @@ func TestIntersectionReductionReentrancy(t *testing.T) { assert.Assert(t, c.freePropertyCounts.next != nil) workspace := c.freePropertyCounts conflicting := c.newSymbolEx(ast.SymbolFlagsProperty, "value", ast.CheckFlagsContainsPrivate) - outer.AsUnionOrIntersectionType().propertyCacheWithoutFunctionPropertyAugment["value"] = conflicting + outer.AsUnionOrIntersectionType().propertyCacheWithoutFunctionPropertyAugment.Set("value", conflicting) assert.Assert(t, c.somePropertyReducesToNever(outer)) assert.Equal(t, c.freePropertyCounts, workspace) for counts := c.freePropertyCounts; counts != nil; counts = counts.next { diff --git a/tsc/internal/checker/utilities.go b/tsc/internal/checker/utilities.go index 3a7e9993ba879..eb2a7ce1142cc 100644 --- a/tsc/internal/checker/utilities.go +++ b/tsc/internal/checker/utilities.go @@ -255,7 +255,7 @@ func isSyntacticDefault(node *ast.Node) bool { } func hasExportAssignmentSymbol(moduleSymbol *ast.Symbol) bool { - return moduleSymbol.Exports()[ast.InternalSymbolNameExportEquals] != nil + return moduleSymbol.Exports().Get(ast.InternalSymbolNameExportEquals) != nil } func isTypeAlias(node *ast.Node) bool { @@ -352,9 +352,9 @@ func createSymbolTable(symbols []*ast.Symbol) ast.SymbolTable { if len(symbols) == 0 { return nil } - result := make(ast.SymbolTable) + result := ast.NewSymbolTable(0) for _, symbol := range symbols { - result[symbol.Name()] = symbol + result.Set(symbol.Name(), symbol) } return result } @@ -1274,7 +1274,7 @@ func isInNameOfExpressionWithTypeArgumentsOrHeritageTypeReference(node *ast.Node } func getIndexSymbolFromSymbolTable(symbolTable ast.SymbolTable) *ast.Symbol { - return symbolTable[ast.InternalSymbolNameIndex] + return symbolTable.Get(ast.InternalSymbolNameIndex) } // Indicates whether the result of an `Expression` will be unused. @@ -1768,7 +1768,7 @@ func introducesArgumentsExoticObject(node *ast.Node) bool { func symbolsToArray(symbols ast.SymbolTable) []*ast.Symbol { var result []*ast.Symbol - for id, symbol := range symbols { + for id, symbol := range symbols.All() { if !isReservedMemberName(id) { result = append(result, symbol) } diff --git a/tsc/internal/execute/incremental/affectedfileshandler.go b/tsc/internal/execute/incremental/affectedfileshandler.go index 50ca58e8f676b..b3828155ed197 100644 --- a/tsc/internal/execute/incremental/affectedfileshandler.go +++ b/tsc/internal/execute/incremental/affectedfileshandler.go @@ -230,7 +230,7 @@ func (h *affectedFilesHandler) handleDtsMayChangeOfAffectedFile(dtsMayChange dts var done func() // If exported const enum, we need to ensure that js files are emitted as well since the const enum value changed if affectedFile.Symbol != nil { - for _, exported := range affectedFile.Symbol.Exports() { + for _, exported := range affectedFile.Symbol.Exports().All() { if exported.Flags()&ast.SymbolFlagsConstEnum != 0 { invalidateJsFiles = true break diff --git a/tsc/internal/ls/autoimport/extract.go b/tsc/internal/ls/autoimport/extract.go index 12ea044255167..8a6f98ef6fcd3 100644 --- a/tsc/internal/ls/autoimport/extract.go +++ b/tsc/internal/ls/autoimport/extract.go @@ -111,7 +111,7 @@ func (e *exportExtractor) extractFromFile(file *ast.SourceFile) []*Export { var exportCount int for _, statement := range file.Statements.Nodes { if ast.IsModuleWithStringLiteralName(statement) && isNonPatternAmbientModuleDeclaration(file, statement.AsModuleDeclaration()) { - exportCount += len(statement.AsModuleDeclaration().Symbol.Exports()) + exportCount += statement.AsModuleDeclaration().Symbol.Exports().Len() } } exports := make([]*Export, 0, exportCount) @@ -144,11 +144,11 @@ func (e *exportExtractor) extractFromModule(file *ast.SourceFile) []*Export { }) var augmentationExportCount int for _, decl := range moduleAugmentations { - augmentationExportCount += len(decl.Symbol.Exports()) + augmentationExportCount += decl.Symbol.Exports().Len() } moduleID := e.getModuleID(file) - exports := make([]*Export, 0, len(file.Symbol.Exports())+augmentationExportCount) - for name, symbol := range file.Symbol.Exports() { + exports := make([]*Export, 0, file.Symbol.Exports().Len()+augmentationExportCount) + for name, symbol := range file.Symbol.Exports().All() { e.extractFromSymbol(name, symbol, moduleID, file.FileName(), file, &exports) } for _, decl := range moduleAugmentations { @@ -176,7 +176,7 @@ func (e *exportExtractor) extractFromModule(file *ast.SourceFile) []*Export { } func (e *exportExtractor) extractFromModuleDeclaration(decl *ast.ModuleDeclaration, file *ast.SourceFile, moduleID ModuleID, moduleFileName tspath.RootedFilePath, exports *[]*Export) { - for name, symbol := range decl.Symbol.Exports() { + for name, symbol := range decl.Symbol.Exports().All() { e.extractFromSymbol(name, symbol, moduleID, moduleFileName, file, exports) } } @@ -191,7 +191,7 @@ func (e *symbolExtractor) extractFromSymbol(name string, symbol *ast.Symbol, mod allExports := e.checker.GetExportsOfModule(symbol.Parent()) // allExports includes named exports from the file that will be processed separately; // we want to add only the ones that come from the star - for name, namedExport := range symbol.Parent().Exports() { + for name, namedExport := range symbol.Parent().Exports().All() { if name != ast.InternalSymbolNameExportStar { idx := slices.Index(allExports, namedExport) if idx >= 0 || shouldIgnoreSymbol(namedExport) { @@ -231,8 +231,8 @@ func (e *symbolExtractor) extractFromSymbol(name string, symbol *ast.Symbol, mod if target != nil { if syntax == ExportSyntaxEquals && target.Flags()&ast.SymbolFlagsNamespace != 0 { - *exports = slices.Grow(*exports, len(target.Exports())) - for innerName, namedExport := range target.Exports() { + *exports = slices.Grow(*exports, target.Exports().Len()) + for innerName, namedExport := range target.Exports().All() { if innerName != ast.InternalSymbolNameExportStar { export, _ := e.createExport(namedExport, moduleID, moduleFileName, syntax, file, checkerLease) if export != nil { @@ -251,7 +251,7 @@ func (e *symbolExtractor) extractFromSymbol(name string, symbol *ast.Symbol, mod *exports = slices.Grow(*exports, len(expression.AsObjectLiteralExpression().Properties.Nodes)) for _, prop := range expression.AsObjectLiteralExpression().Properties.Nodes { if ast.IsShorthandPropertyAssignment(prop) || ast.IsPropertyAssignment(prop) && prop.AsPropertyAssignment().Name().Kind == ast.KindIdentifier { - export, _ := e.createExport(expression.Symbol().Members()[prop.Name().Text()], moduleID, moduleFileName, syntax, file, checkerLease) + export, _ := e.createExport(expression.Symbol().Members().Get(prop.Name().Text()), moduleID, moduleFileName, syntax, file, checkerLease) if export != nil { export.through = name *exports = append(*exports, export) diff --git a/tsc/internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go b/tsc/internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go index b91cc1b1c44b4..50194b6c8dfc7 100644 --- a/tsc/internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go +++ b/tsc/internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go @@ -190,10 +190,10 @@ func getMissingMembers(typeChecker *checker.Checker, classDeclaration *ast.Node, if symbol == nil { continue } - if classMembers != nil && classMembers[symbol.Name()] != nil { + if classMembers != nil && classMembers.Get(symbol.Name()) != nil { continue } - if inheritedMembers[symbol.Name()] != nil || seenMembers[symbol.Name()] != nil { + if inheritedMembers.Get(symbol.Name()) != nil || seenMembers[symbol.Name()] != nil { continue } flags := checker.GetDeclarationModifierFlagsFromSymbol(symbol) @@ -209,22 +209,22 @@ func getMissingMembers(typeChecker *checker.Checker, classDeclaration *ast.Node, func getInheritedMembers(typeChecker *checker.Checker, classDeclaration *ast.Node) ast.SymbolTable { typeNode := ast.GetClassExtendsHeritageElement(classDeclaration) if typeNode == nil { - return ast.SymbolTable{} + return ast.NewSymbolTable(0) } baseType := typeChecker.GetTypeAtLocation(typeNode.AsNode()) if baseType == nil { - return ast.SymbolTable{} + return ast.NewSymbolTable(0) } - inheritedMembers := make(ast.SymbolTable) + inheritedMembers := ast.NewSymbolTable(0) for _, symbol := range typeChecker.GetPropertiesOfType(baseType) { if symbol == nil { continue } flags := checker.GetDeclarationModifierFlagsFromSymbol(symbol) if flags&ast.ModifierFlagsPrivate == 0 { - inheritedMembers[symbol.Name()] = symbol + inheritedMembers.Set(symbol.Name(), symbol) } } return inheritedMembers diff --git a/tsc/internal/ls/completions.go b/tsc/internal/ls/completions.go index 62564fbbd2f7e..5d0987f101c44 100644 --- a/tsc/internal/ls/completions.go +++ b/tsc/internal/ls/completions.go @@ -1408,9 +1408,9 @@ func (l *LanguageService) getCompletionData( if localSymbol != nil { localExports = localSymbol.Exports() } - for name, symbol := range localsContainer.Locals() { + for name, symbol := range localsContainer.Locals().All() { symbols = append(symbols, symbol) - if _, ok := localExports[name]; ok { + if _, ok := localExports.Lookup(name); ok { symbolId := ast.GetSymbolId(symbol) symbolToSortTextMap[symbolId] = SortTextOptionalMember } diff --git a/tsc/internal/ls/definition.go b/tsc/internal/ls/definition.go index eb1761a6d98d2..0a1279d767c65 100644 --- a/tsc/internal/ls/definition.go +++ b/tsc/internal/ls/definition.go @@ -352,7 +352,7 @@ func getDeclarationsFromLocation(c *checker.Checker, node *ast.Node) []*ast.Node node = getDeclarationNameForKeyword(node) if symbol := c.GetSymbolAtLocation(node); symbol != nil { if symbol.Flags()&ast.SymbolFlagsClass != 0 && symbol.Flags()&(ast.SymbolFlagsFunction|ast.SymbolFlagsVariable) == 0 && node.Kind == ast.KindConstructorKeyword { - if constructor := symbol.Members()[ast.InternalSymbolNameConstructor]; constructor != nil { + if constructor := symbol.Members().Get(ast.InternalSymbolNameConstructor); constructor != nil { symbol = constructor } } diff --git a/tsc/internal/ls/findallreferences.go b/tsc/internal/ls/findallreferences.go index 6e40e4aa1211c..ec77cebfc46fb 100644 --- a/tsc/internal/ls/findallreferences.go +++ b/tsc/internal/ls/findallreferences.go @@ -1408,7 +1408,7 @@ func (l *LanguageService) getReferencedSymbolsForModuleIfDeclaredBySourceFile(ct } else { return nil } - exportEquals := symbol.Exports()[ast.InternalSymbolNameExportEquals] + exportEquals := symbol.Exports().Get(ast.InternalSymbolNameExportEquals) // If exportEquals != nil, we're about to add references to `import("mod")` anyway, so don't double-count them. moduleReferences := l.getReferencedSymbolsForModule(checker, program, symbol, exportEquals != nil, sourceFiles, sourceFilesSet) if exportEquals == nil || exportEquals.Flags()&ast.SymbolFlagsAlias == 0 || !sourceFilesSet.Has(moduleSourceFileName) { @@ -1798,7 +1798,7 @@ func (l *LanguageService) getReferencedSymbolsForModule(checker *checker.Checker } // Handle export equals declarations - exported := symbol.Exports()[ast.InternalSymbolNameExportEquals] + exported := symbol.Exports().Get(ast.InternalSymbolNameExportEquals) if exported != nil && len(exported.Declarations()) > 0 { for _, decl := range exported.Declarations() { sourceFile := ast.GetSourceFileOfNode(decl) @@ -2041,7 +2041,7 @@ func getClassConstructorSymbol(classSymbol *ast.Symbol) *ast.Symbol { if classSymbol.Members() == nil { return nil } - return classSymbol.Members()[ast.InternalSymbolNameConstructor] + return classSymbol.Members().Get(ast.InternalSymbolNameConstructor) } func hasOwnConstructor(classDeclaration *ast.ClassLikeDeclaration) bool { @@ -2061,7 +2061,7 @@ func findOwnConstructorReferences(classSymbol *ast.Symbol, sourceFile *ast.Sourc } if classSymbol.Exports() != nil { - for _, member := range classSymbol.Exports() { + for _, member := range classSymbol.Exports().All() { decl := member.ValueDeclaration() if decl != nil && decl.Kind == ast.KindMethodDeclaration { body := decl.Body() diff --git a/tsc/internal/modulespecifiers/specifiers.go b/tsc/internal/modulespecifiers/specifiers.go index 261c26755a640..2518d4c00ca2f 100644 --- a/tsc/internal/modulespecifiers/specifiers.go +++ b/tsc/internal/modulespecifiers/specifiers.go @@ -136,7 +136,7 @@ func tryGetModuleNameFromAmbientModule(moduleSymbol *ast.Symbol, checker Checker continue } - sym, ok := possibleContainer.Symbol().Exports()[ast.InternalSymbolNameExportEquals] + sym, ok := possibleContainer.Symbol().Exports().Lookup(ast.InternalSymbolNameExportEquals) if !ok || sym == nil { continue } diff --git a/tsc/internal/printer/namegenerator.go b/tsc/internal/printer/namegenerator.go index 81078f087a3bd..efcec92f05e0b 100644 --- a/tsc/internal/printer/namegenerator.go +++ b/tsc/internal/printer/namegenerator.go @@ -366,7 +366,7 @@ func isUniqueLocalName(name string, container *ast.Node) bool { locals := node.Locals() if locals != nil { // We conservatively include alias symbols to cover cases where they're emitted as locals - if local, ok := locals[name]; ok && local.Flags()&(ast.SymbolFlagsValue|ast.SymbolFlagsExportValue|ast.SymbolFlagsAlias) != 0 { + if local, ok := locals.Lookup(name); ok && local.Flags()&(ast.SymbolFlagsValue|ast.SymbolFlagsExportValue|ast.SymbolFlagsAlias) != 0 { return false } } diff --git a/tsc/internal/transformers/declarations/transform.go b/tsc/internal/transformers/declarations/transform.go index 7e362d9fb1660..41456f0c2a2b1 100644 --- a/tsc/internal/transformers/declarations/transform.go +++ b/tsc/internal/transformers/declarations/transform.go @@ -355,7 +355,7 @@ func (tx *DeclarationTransformer) transformSourceFile(node *ast.SourceFile) *ast combinedStatements.Loc = statements.Loc // setTextRange if ast.IsExternalOrCommonJSModule(node) { if ast.IsInJSFile(node.AsNode()) { - if exportEquals := node.Symbol.Exports()[ast.InternalSymbolNameExportEquals]; exportEquals != nil && len(exportEquals.Declarations()) > 1 { + if exportEquals := node.Symbol.Exports().Get(ast.InternalSymbolNameExportEquals); exportEquals != nil && len(exportEquals.Declarations()) > 1 { for _, node := range exportEquals.Declarations() { tx.state.addDiagnostic(createDiagnosticForNode(node, diagnostics.Multiple_module_exports_assignments_cannot_be_serialized_for_declaration_emit)) } @@ -2846,8 +2846,8 @@ func (tx *DeclarationTransformer) transformExpandoAssignment(node *ast.BinaryExp declarationData := synthesizedNamespace.DeclarationData() declarationData.Symbol = host containerData := synthesizedNamespace.LocalsContainerData() - containerData.Locals = make(ast.SymbolTable, 0) - containerData.Locals[localName.Text()] = symbol + containerData.Locals = ast.NewSymbolTable(0) + containerData.Locals.Set(localName.Text(), symbol) oldEnclosing := tx.enclosingDeclaration tx.enclosingDeclaration = synthesizedNamespace From 4a86f9b5e1793e68fed5a9fa9f6cb0ef89fa49bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 10:54:07 +0200 Subject: [PATCH 23/35] Rely on symbol table insertion order instead of sorting --- tsc/internal/checker/checker.go | 54 ++------ tsc/internal/checker/emitresolver.go | 1 - tsc/internal/checker/symbolaccessibility.go | 79 +----------- ...embersResolutionOrderExportStar.errors.txt | 6 +- ...mespaceMembersResolutionOrderExportStar.js | 28 ++-- ...ceMembersResolutionOrderExportStar.symbols | 4 +- ...paceMembersResolutionOrderExportStar.types | 120 +++++++++--------- 7 files changed, 93 insertions(+), 199 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index be42451b57e4f..977c151328431 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -15223,17 +15223,14 @@ func (c *Checker) reportNonExportedMember(name *ast.Node, declarationName string c.error(name, diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName) } } else { - // Looking for the export resolves aliases, which creates types, so do it in a stable order rather than - // in the random iteration order of the symbol table. - var exportedSymbols []*ast.Symbol + var exportedSymbol *ast.Symbol c.forEachSymbolTableEntry(exports, func(_ string, symbol *ast.Symbol) bool { if c.getSymbolIfSameReference(symbol, localSymbol) != nil { - exportedSymbols = append(exportedSymbols, symbol) + exportedSymbol = symbol + return true } return false }) - c.sortSymbols(exportedSymbols) - exportedSymbol := core.FirstOrNil(exportedSymbols) var diagnostic *ast.Diagnostic if exportedSymbol != nil { diagnostic = c.error(name, diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, c.symbolToString(exportedSymbol)) @@ -16655,11 +16652,6 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables */ func (c *Checker) extendExportSymbols(target ast.SymbolTable, source ast.SymbolTable, lookupTable ExportCollisionTable, exportNode *ast.Node) { - type collision struct { - id string - symbol *ast.Symbol - } - var collisions []collision for id, sourceSymbol := range source.All() { if id == ast.InternalSymbolNameDefault { continue @@ -16672,21 +16664,8 @@ func (c *Checker) extendExportSymbols(target ast.SymbolTable, source ast.SymbolT specifierText: scanner.GetTextOfNode(exportNode.ModuleSpecifier()), } } - } else if lookupTable != nil && exportNode != nil { - collisions = append(collisions, collision{id, sourceSymbol}) - } - } - // Checking a collision resolves the aliases on both sides, which creates types, so do it in a stable order rather - // than in the random iteration order of the symbol table. - slices.SortFunc(collisions, func(a, b collision) int { - if r := c.compareSymbols(a.symbol, b.symbol); r != 0 { - return r - } - return strings.Compare(a.id, b.id) - }) - for _, collision := range collisions { - if c.resolveSymbol(target.Get(collision.id)) != c.resolveSymbol(collision.symbol) { - s := lookupTable[collision.id] + } else if lookupTable != nil && exportNode != nil && c.resolveSymbol(targetSymbol) != c.resolveSymbol(sourceSymbol) { + s := lookupTable[id] s.exportsWithDuplicate = append(s.exportsWithDuplicate, exportNode) } } @@ -20093,11 +20072,7 @@ func (c *Checker) resolveDeclaredMembers(t *Type) *InterfaceType { func (c *Checker) getIndexInfosOfSymbol(symbol *ast.Symbol) []*IndexInfo { indexSymbol := c.getIndexSymbol(symbol) if indexSymbol != nil { - // The types of the siblings are created in this order, so sort them rather than using the random iteration - // order of the symbol table. - siblingSymbols := slices.Collect(c.getMembersOfSymbol(symbol).Values()) - c.sortSymbols(siblingSymbols) - return c.getIndexInfosOfIndexSymbol(indexSymbol, siblingSymbols) + return c.getIndexInfosOfIndexSymbol(indexSymbol, slices.Collect(c.getMembersOfSymbol(symbol).Values())) } return nil } @@ -21167,11 +21142,7 @@ func (c *Checker) resolveAnonymousTypeMembers(t *Type) { } indexSymbol := members.Get(ast.InternalSymbolNameIndex) if indexSymbol != nil { - // The types of the siblings are created in this order, so sort them rather than using the random iteration - // order of the symbol table. - siblingSymbols := slices.Collect(members.Values()) - c.sortSymbols(siblingSymbols) - indexInfos = c.getIndexInfosOfIndexSymbol(indexSymbol, siblingSymbols) + indexInfos = c.getIndexInfosOfIndexSymbol(indexSymbol, slices.Collect(members.Values())) } else { if baseConstructorIndexInfo != nil { indexInfos = append(indexInfos, baseConstructorIndexInfo) @@ -24410,19 +24381,12 @@ func (c *Checker) getOuterTypeParameters(node *ast.Node, includeThisTypes bool) } func (c *Checker) getInferTypeParameters(node *ast.Node) []*Type { - var symbols []*ast.Symbol + var result []*Type for _, symbol := range node.Locals().All() { if symbol.Flags()&ast.SymbolFlagsTypeParameter != 0 { - symbols = append(symbols, symbol) + result = append(result, c.getDeclaredTypeOfSymbol(symbol)) } } - // Getting the declared types creates them, so do it in a stable order rather than in the random iteration order - // of the symbol table. - c.sortSymbols(symbols) - var result []*Type - for _, symbol := range symbols { - result = append(result, c.getDeclaredTypeOfSymbol(symbol)) - } slices.SortFunc(result, CompareTypes) return result } diff --git a/tsc/internal/checker/emitresolver.go b/tsc/internal/checker/emitresolver.go index cb0f9f6cf9741..e4fad5c3f5b1f 100644 --- a/tsc/internal/checker/emitresolver.go +++ b/tsc/internal/checker/emitresolver.go @@ -753,7 +753,6 @@ func (r *EmitResolver) CreateLateBoundIndexSignatures(container *ast.Node, enclo var instanceInfos []*IndexInfo if instanceIndexSymbol != nil { siblingSymbols := slices.Collect(r.checker.getMembersOfSymbol(sym).Values()) - r.checker.sortSymbols(siblingSymbols) instanceInfos = r.checker.getIndexInfosOfIndexSymbol(instanceIndexSymbol, siblingSymbols) } diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index ec88f92b9118e..ecf440670d20e 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -3,7 +3,6 @@ package checker import ( "cmp" "slices" - "strings" "github.com/microsoft/TypeScript/tsc/internal/ast" "github.com/microsoft/TypeScript/tsc/internal/collections" @@ -145,29 +144,12 @@ func (c *Checker) getWithAlternativeContainers(container *ast.Symbol, symbol *as c.getDeclaredTypeOfSymbol(container).flags&TypeFlagsObject != 0 { c.someSymbolTableInScope(enclosingDeclaration, func(t ast.SymbolTable, _ symbolTableID, _ bool, _ bool, _ *ast.Node) bool { found := false - check := func(s *ast.Symbol) { - if c.getTypeOfSymbol(s) == c.getDeclaredTypeOfSymbol(container) { + for _, s := range t.All() { + if s.Flags()&leftMeaning != 0 && c.getTypeOfSymbol(s) == c.getDeclaredTypeOfSymbol(container) { variableMatches = append(variableMatches, s) found = true } } - var unresolved []*ast.Symbol - for _, s := range t.All() { - if s.Flags()&leftMeaning == 0 { - continue - } - if links := c.valueSymbolLinks.TryGet(s); links != nil && links.resolvedType != nil { - check(s) - } else { - unresolved = append(unresolved, s) - } - } - // Getting the types that are not resolved yet can create types and resolve aliases, so do it in a stable - // order rather than in the random iteration order of the symbol table. - c.sortSymbols(unresolved) - for _, s := range unresolved { - check(s) - } return found }) c.sortSymbols(variableMatches) @@ -291,63 +273,15 @@ func (c *Checker) buildExternalModuleContainerIndex() { index.complete = true } -// forEachSymbolTableEntry calls f for each entry of a symbol table so that any types f creates are created -// in an order that does not depend on the table's random iteration order. That holds as long as f has no side -// effects for a symbol that is not an alias, or for an alias whose whole chain of aliases is already resolved: those -// come first, in table order. Resolving an alias can create types, so the other aliases come last, sorted. f must -// not depend on the order it sees entries in for its result: collect and sort what it finds instead. f returns true -// to stop, which is only allowed when the answer does not depend on which entry stopped it (such as whether any -// entry matches), and forEachSymbolTableEntry then returns true. f gets each symbol's key in the table, which is -// not always the symbol's name (a default export is keyed "default"). +// forEachSymbolTableEntry calls f for each entry of a symbol table, in the table's insertion order. f returns true to +// stop, and forEachSymbolTableEntry then returns true. f gets each symbol's key in the table, which is not always the +// symbol's name (a default export is keyed "default"). func (c *Checker) forEachSymbolTableEntry(symbols ast.SymbolTable, f func(name string, symbol *ast.Symbol) bool) bool { - type entry struct { - name string - symbol *ast.Symbol - } - var unresolved []entry for name, symbol := range symbols.All() { - if !c.isAliasChainResolved(symbol) { - unresolved = append(unresolved, entry{name, symbol}) - continue - } if f(name, symbol) { return true } } - slices.SortFunc(unresolved, func(a, b entry) int { - if r := c.compareSymbols(a.symbol, b.symbol); r != 0 { - return r - } - return strings.Compare(a.name, b.name) - }) - for _, alias := range unresolved { - if f(alias.name, alias.symbol) { - return true - } - } - return false -} - -// isAliasChainResolved reports whether symbol is not an alias, or every alias in its chain is resolved. Resolving an -// alias stops at a target with a meaning of its own even when that target is also an alias, so getSymbolFlags and -// getTypeOnlyAliasDeclaration can still resolve later aliases of a chain whose first alias is resolved. -func (c *Checker) isAliasChainResolved(symbol *ast.Symbol) bool { - // A circular chain resolves to the unknown symbol, so the bound only guards against a chain that never ends, which - // then counts as unresolved. - for range 100 { - if symbol.Flags()&ast.SymbolFlagsAlias == 0 { - return true - } - links := c.aliasSymbolLinks.TryGet(symbol) - if links == nil || links.aliasTarget == nil { - return false - } - target := c.getExportSymbolOfValueSymbolIfExported(links.aliasTarget) - if target == symbol || target == c.unknownSymbol { - return true - } - symbol = target - } return false } @@ -665,9 +599,6 @@ func (c *Checker) getSymbolTableAliases(symbols ast.SymbolTable, tableId symbolT aliases = append(aliases, sym) } } - // The aliases are resolved in this order, which creates types, so sort them rather than using the random - // iteration order of the symbol table. - c.sortSymbols(aliases) if kind == stKindGlobals || kind == stKindExports || kind == stKindResolvedExports { if c.symbolTableAliasCache == nil { c.symbolTableAliasCache = make(map[symbolTableID][]*ast.Symbol) diff --git a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.errors.txt b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.errors.txt index bff4827ef673c..f9e0d6ab4eac5 100644 --- a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.errors.txt +++ b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.errors.txt @@ -1,4 +1,4 @@ -/main.ts(8,32): error TS2339: Property 'ma' does not exist on type '{}'. +/main.ts(7,32): error TS2339: Property 'mb' does not exist on type '{}'. ==== /main.ts (1 errors) ==== @@ -9,9 +9,9 @@ export const fromA = MA.pa; export const fromB = MB.pb; export const checkA: 1 = MA.pa.mb; - export const checkB: 1 = MB.pb.ma; ~~ -!!! error TS2339: Property 'ma' does not exist on type '{}'. +!!! error TS2339: Property 'mb' does not exist on type '{}'. + export const checkB: 1 = MB.pb.ma; ==== /ma.js (0 errors) ==== export { v as pa } from "./xa"; diff --git a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.js b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.js index e7f345491f402..b99218d5bfd65 100644 --- a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.js +++ b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.js @@ -185,10 +185,7 @@ exports.checkB = MB.pb.ma; //// [xa.d.ts] export = o; declare const o: { - v: { - pb: {}; - mb: 1; - }; + v: {}; }; //// [ma.d.ts] export { v as pa } from "./xa"; @@ -196,7 +193,10 @@ export declare const ma = 1; //// [xb.d.ts] export = o; declare const o: { - v: {}; + v: { + pa: {}; + ma: 1; + }; }; //// [mb.d.ts] export { v as pb } from "./xb"; @@ -205,7 +205,10 @@ export declare const mb = 1; export = o; declare const o: { v: { - pb: {}; + pb: { + pa: {}; + ma: 1; + }; mb: 1; }; }; @@ -213,10 +216,7 @@ declare const o: { export = o; declare const o: { v: { - pa: { - pb: {}; - mb: 1; - }; + pa: {}; ma: 1; }; }; @@ -236,10 +236,10 @@ export declare const f8 = 8; export declare const f9 = 9; export declare const f10 = 10; //// [main.d.ts] -export declare const fromA: { - pb: {}; - mb: 1; +export declare const fromA: {}; +export declare const fromB: { + pa: {}; + ma: 1; }; -export declare const fromB: {}; export declare const checkA: 1; export declare const checkB: 1; diff --git a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.symbols b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.symbols index 6997e4d5a273d..4f7c5a9b9f1d4 100644 --- a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.symbols +++ b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.symbols @@ -28,17 +28,17 @@ export const fromB = MB.pb; export const checkA: 1 = MA.pa.mb; >checkA : Symbol(checkA, Decl(main.ts, 6, 12)) ->MA.pa.mb : Symbol(mb, Decl(mb.js, 1, 12)) >MA.pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) >MA : Symbol(MA, Decl(main.ts, 2, 6)) >pa : Symbol(MA.pa, Decl(ma.js, 0, 8)) ->mb : Symbol(mb, Decl(mb.js, 1, 12)) export const checkB: 1 = MB.pb.ma; >checkB : Symbol(checkB, Decl(main.ts, 7, 12)) +>MB.pb.ma : Symbol(ma, Decl(ma.js, 1, 12)) >MB.pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) >MB : Symbol(MB, Decl(main.ts, 3, 6)) >pb : Symbol(MB.pb, Decl(mb.js, 0, 8)) +>ma : Symbol(ma, Decl(ma.js, 1, 12)) === /ma.js === export { v as pa } from "./xa"; diff --git a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.types b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.types index 49f1de0b3ac44..179ce8b0ee07e 100644 --- a/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.types +++ b/tsc/testdata/baselines/reference/compiler/namespaceMembersResolutionOrderExportStar.types @@ -5,8 +5,8 @@ import * as idx from "./index"; >idx : typeof idx const all = { ...idx }; ->all : { a: { pa: { pb: {}; mb: 1; }; ma: 1; }; b: { pb: {}; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } ->{ ...idx } : { a: { pa: { pb: {}; mb: 1; }; ma: 1; }; b: { pb: {}; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } +>all : { a: { pa: {}; ma: 1; }; b: { pb: { pa: {}; ma: 1; }; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } +>{ ...idx } : { a: { pa: {}; ma: 1; }; b: { pb: { pa: {}; ma: 1; }; mb: 1; }; f1: 1; f2: 2; f3: 3; f4: 4; f5: 5; f6: 6; f7: 7; f8: 8; f9: 9; f10: 10; } >idx : typeof idx import * as MA from "./ma"; @@ -16,37 +16,37 @@ import * as MB from "./mb"; >MB : typeof MB export const fromA = MA.pa; ->fromA : { pb: {}; mb: 1; } ->MA.pa : { pb: {}; mb: 1; } +>fromA : {} +>MA.pa : {} >MA : typeof MA ->pa : { pb: {}; mb: 1; } +>pa : {} export const fromB = MB.pb; ->fromB : {} ->MB.pb : {} +>fromB : { pa: {}; ma: 1; } +>MB.pb : { pa: {}; ma: 1; } >MB : typeof MB ->pb : {} +>pb : { pa: {}; ma: 1; } export const checkA: 1 = MA.pa.mb; >checkA : 1 ->MA.pa.mb : 1 ->MA.pa : { pb: {}; mb: 1; } +>MA.pa.mb : any +>MA.pa : {} >MA : typeof MA ->pa : { pb: {}; mb: 1; } ->mb : 1 +>pa : {} +>mb : any export const checkB: 1 = MB.pb.ma; >checkB : 1 ->MB.pb.ma : any ->MB.pb : {} +>MB.pb.ma : 1 +>MB.pb : { pa: {}; ma: 1; } >MB : typeof MB ->pb : {} ->ma : any +>pb : { pa: {}; ma: 1; } +>ma : 1 === /ma.js === export { v as pa } from "./xa"; ->v : { pb: {}; mb: 1; } ->pa : { pb: {}; mb: 1; } +>v : {} +>pa : {} export const ma = 1; >ma : 1 @@ -54,8 +54,8 @@ export const ma = 1; === /mb.js === export { v as pb } from "./xb"; ->v : {} ->pb : {} +>v : { pa: {}; ma: 1; } +>pb : { pa: {}; ma: 1; } export const mb = 1; >mb : 1 @@ -68,18 +68,18 @@ const M = /** @type {any} */ (null); >(null) : any const o = { v: { ...M } }; ->o : { v: { pb: {}; mb: 1; }; } ->{ v: { ...M } } : { v: { pb: {}; mb: 1; }; } ->v : { pb: {}; mb: 1; } ->{ ...M } : { pb: {}; mb: 1; } +>o : { v: {}; } +>{ v: { ...M } } : { v: { pb: { pa: {}; ma: 1; }; mb: 1; }; } +>v : { pb: { pa: {}; ma: 1; }; mb: 1; } +>{ ...M } : { pb: { pa: {}; ma: 1; }; mb: 1; } >M : typeof import("./mb") module.exports = o; ->module.exports = o : { v: { pb: {}; mb: 1; }; } ->module.exports : { v: { pb: {}; mb: 1; }; } ->module : { exports: { v: { pb: {}; mb: 1; }; }; } ->exports : { v: { pb: {}; mb: 1; }; } ->o : { v: { pb: {}; mb: 1; }; } +>module.exports = o : { v: {}; } +>module.exports : { v: {}; } +>module : { exports: { v: {}; }; } +>exports : { v: {}; } +>o : { v: {}; } === /xb.js === /** @type {typeof import("./ma")} */ @@ -88,18 +88,18 @@ const M = /** @type {any} */ (null); >(null) : any const o = { v: { ...M } }; ->o : { v: {}; } ->{ v: { ...M } } : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } ->v : { pa: { pb: {}; mb: 1; }; ma: 1; } ->{ ...M } : { pa: { pb: {}; mb: 1; }; ma: 1; } +>o : { v: { pa: {}; ma: 1; }; } +>{ v: { ...M } } : { v: { pa: {}; ma: 1; }; } +>v : { pa: {}; ma: 1; } +>{ ...M } : { pa: {}; ma: 1; } >M : typeof import("./ma") module.exports = o; ->module.exports = o : { v: {}; } ->module.exports : { v: {}; } ->module : { exports: { v: {}; }; } ->exports : { v: {}; } ->o : { v: {}; } +>module.exports = o : { v: { pa: {}; ma: 1; }; } +>module.exports : { v: { pa: {}; ma: 1; }; } +>module : { exports: { v: { pa: {}; ma: 1; }; }; } +>exports : { v: { pa: {}; ma: 1; }; } +>o : { v: { pa: {}; ma: 1; }; } === /ia.js === /** @type {typeof import("./ma")} */ @@ -108,18 +108,18 @@ const M = /** @type {any} */ (null); >(null) : any const o = { v: { ...M } }; ->o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } ->{ v: { ...M } } : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } ->v : { pa: { pb: {}; mb: 1; }; ma: 1; } ->{ ...M } : { pa: { pb: {}; mb: 1; }; ma: 1; } +>o : { v: { pa: {}; ma: 1; }; } +>{ v: { ...M } } : { v: { pa: {}; ma: 1; }; } +>v : { pa: {}; ma: 1; } +>{ ...M } : { pa: {}; ma: 1; } >M : typeof import("./ma") module.exports = o; ->module.exports = o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } ->module.exports : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } ->module : { exports: { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; }; } ->exports : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } ->o : { v: { pa: { pb: {}; mb: 1; }; ma: 1; }; } +>module.exports = o : { v: { pa: {}; ma: 1; }; } +>module.exports : { v: { pa: {}; ma: 1; }; } +>module : { exports: { v: { pa: {}; ma: 1; }; }; } +>exports : { v: { pa: {}; ma: 1; }; } +>o : { v: { pa: {}; ma: 1; }; } === /ib.js === /** @type {typeof import("./mb")} */ @@ -128,28 +128,28 @@ const M = /** @type {any} */ (null); >(null) : any const o = { v: { ...M } }; ->o : { v: { pb: {}; mb: 1; }; } ->{ v: { ...M } } : { v: { pb: {}; mb: 1; }; } ->v : { pb: {}; mb: 1; } ->{ ...M } : { pb: {}; mb: 1; } +>o : { v: { pb: { pa: {}; ma: 1; }; mb: 1; }; } +>{ v: { ...M } } : { v: { pb: { pa: {}; ma: 1; }; mb: 1; }; } +>v : { pb: { pa: {}; ma: 1; }; mb: 1; } +>{ ...M } : { pb: { pa: {}; ma: 1; }; mb: 1; } >M : typeof import("./mb") module.exports = o; ->module.exports = o : { v: { pb: {}; mb: 1; }; } ->module.exports : { v: { pb: {}; mb: 1; }; } ->module : { exports: { v: { pb: {}; mb: 1; }; }; } ->exports : { v: { pb: {}; mb: 1; }; } ->o : { v: { pb: {}; mb: 1; }; } +>module.exports = o : { v: { pb: { pa: {}; ma: 1; }; mb: 1; }; } +>module.exports : { v: { pb: { pa: {}; ma: 1; }; mb: 1; }; } +>module : { exports: { v: { pb: { pa: {}; ma: 1; }; mb: 1; }; }; } +>exports : { v: { pb: { pa: {}; ma: 1; }; mb: 1; }; } +>o : { v: { pb: { pa: {}; ma: 1; }; mb: 1; }; } === /star.js === export { v as a } from "./ia"; ->v : { pa: { pb: {}; mb: 1; }; ma: 1; } ->a : { pa: { pb: {}; mb: 1; }; ma: 1; } +>v : { pa: {}; ma: 1; } +>a : { pa: {}; ma: 1; } === /index.js === export { v as b } from "./ib"; ->v : { pb: {}; mb: 1; } ->b : { pb: {}; mb: 1; } +>v : { pb: { pa: {}; ma: 1; }; mb: 1; } +>b : { pb: { pa: {}; ma: 1; }; mb: 1; } export * from "./star"; export const f1 = 1; From 84b8af31facebe302153b22b80da59c3668c3cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 11:07:01 +0200 Subject: [PATCH 24/35] Index large symbol tables by entry position --- tsc/internal/ast/symbol.go | 46 +++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/tsc/internal/ast/symbol.go b/tsc/internal/ast/symbol.go index 702554ff0a16a..cdc2d139b9ce5 100644 --- a/tsc/internal/ast/symbol.go +++ b/tsc/internal/ast/symbol.go @@ -1,6 +1,7 @@ package ast import ( + "hash/maphash" "iter" "maps" "slices" @@ -183,10 +184,12 @@ const symbolTableLinearMax = 16 type SymbolMap struct { entries []symbolMapEntry - index map[string]int32 + index []int32 // open addressing table of entry positions plus one (0 is empty), only past symbolTableLinearMax oddKeys map[int32]string } +var symbolTableSeed = maphash.MakeSeed() + type symbolMapEntry struct { symbol *Symbol keyLen int32 @@ -198,7 +201,7 @@ func NewSymbolTable(capacity int) SymbolTable { if capacity > 0 { m.entries = make([]symbolMapEntry, 0, capacity) if capacity > symbolTableLinearMax { - m.index = make(map[string]int32, capacity) + m.index = make([]int32, indexSizeFor(capacity)) } } return m @@ -223,10 +226,16 @@ func (m *SymbolMap) find(key string) int { return -1 } if m.index != nil { - if i, ok := m.index[key]; ok { - return int(i) + mask := uint64(len(m.index) - 1) + for slot := maphash.String(symbolTableSeed, key) & mask; ; slot = (slot + 1) & mask { + p := m.index[slot] + if p == 0 { + return -1 + } + if i := int(p - 1); m.entries[i].keyLen == int32(len(key)) && m.keyAt(i, m.oddKeys) == key { + return i + } } - return -1 } keyLen := int32(len(key)) for i := range m.entries { @@ -272,8 +281,8 @@ func (m *SymbolMap) Set(key string, symbol *Symbol) { if symbol == nil || symbol.Name() != key { m.setOddKey(i, key) } - if m.index != nil { - m.index[key] = i + if m.index != nil && len(m.entries)*4 <= len(m.index)*3 { + m.insertIndex(key, i) } else if len(m.entries) > symbolTableLinearMax { m.buildIndex() } @@ -287,10 +296,27 @@ func (m *SymbolMap) setOddKey(i int32, key string) { m.oddKeys[i] = key } +func indexSizeFor(n int) int { + size := 32 + for size*3 < n*4 { + size *= 2 + } + return size +} + +func (m *SymbolMap) insertIndex(key string, i int32) { + mask := uint64(len(m.index) - 1) + slot := maphash.String(symbolTableSeed, key) & mask + for m.index[slot] != 0 { + slot = (slot + 1) & mask + } + m.index[slot] = i + 1 +} + func (m *SymbolMap) buildIndex() { - m.index = make(map[string]int32, len(m.entries)) + m.index = make([]int32, indexSizeFor(len(m.entries)*2)) for i := range m.entries { - m.index[m.keyAt(i, m.oddKeys)] = int32(i) + m.insertIndex(m.keyAt(i, m.oddKeys), int32(i)) } } @@ -364,7 +390,7 @@ func (m *SymbolMap) Clone() SymbolTable { if m == nil { return nil } - clone := &SymbolMap{entries: slices.Clone(m.entries), index: maps.Clone(m.index), oddKeys: maps.Clone(m.oddKeys)} + clone := &SymbolMap{entries: slices.Clone(m.entries), index: slices.Clone(m.index), oddKeys: maps.Clone(m.oddKeys)} return clone } From a8a691550d9877c95c2ed84bb835a0a728fffdc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 15:13:36 +0200 Subject: [PATCH 25/35] Do not handle nil symbols in symbol tables --- tsc/internal/ast/symbol.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tsc/internal/ast/symbol.go b/tsc/internal/ast/symbol.go index cdc2d139b9ce5..11fc98005e7cd 100644 --- a/tsc/internal/ast/symbol.go +++ b/tsc/internal/ast/symbol.go @@ -271,14 +271,14 @@ func (m *SymbolMap) Lookup(key string) (*Symbol, bool) { func (m *SymbolMap) Set(key string, symbol *Symbol) { if i := m.find(key); i >= 0 { m.entries[i].symbol = symbol - if !m.entries[i].oddKey && (symbol == nil || symbol.Name() != key) { + if !m.entries[i].oddKey && symbol.Name() != key { m.setOddKey(int32(i), key) } return } i := int32(len(m.entries)) m.entries = append(m.entries, symbolMapEntry{symbol: symbol, keyLen: int32(len(key))}) - if symbol == nil || symbol.Name() != key { + if symbol.Name() != key { m.setOddKey(i, key) } if m.index != nil && len(m.entries)*4 <= len(m.index)*3 { From 193faf43baa1aee1343c885937c6049542d606cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 15:14:50 +0200 Subject: [PATCH 26/35] Delete symbol table entries in place --- tsc/internal/ast/symbol.go | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tsc/internal/ast/symbol.go b/tsc/internal/ast/symbol.go index 11fc98005e7cd..88b6796566c0d 100644 --- a/tsc/internal/ast/symbol.go +++ b/tsc/internal/ast/symbol.go @@ -177,7 +177,7 @@ func (s *Symbol) CombinedLocalAndExportSymbolFlags() SymbolFlags { // it has more than symbolTableLinearMax entries, and only then gets a hash index of entry positions. An entry does not // store its key: the key is almost always the symbol's own name, so an entry holds the symbol and the key's length, // which rejects most non-matching entries without reading the symbol. A key with other text than its symbol's name -// is kept in oddKeys. Delete builds a new entry slice, so an iteration in progress keeps seeing a snapshot. +// is kept in oddKeys. type SymbolTable = *SymbolMap const symbolTableLinearMax = 16 @@ -325,22 +325,23 @@ func (m *SymbolMap) Delete(key string) { if d < 0 { return } - entries := make([]symbolMapEntry, 0, len(m.entries)-1) - var oddKeys map[int32]string - for i := range m.entries { - if i == d { - continue - } - if m.entries[i].oddKey { + m.entries = slices.Delete(m.entries, d, d+1) + if m.oddKeys != nil { + var oddKeys map[int32]string + for i, oddKey := range m.oddKeys { + if i == int32(d) { + continue + } + if i > int32(d) { + i-- + } if oddKeys == nil { - oddKeys = make(map[int32]string) + oddKeys = make(map[int32]string, len(m.oddKeys)) } - oddKeys[int32(len(entries))] = m.oddKeys[int32(i)] + oddKeys[i] = oddKey } - entries = append(entries, m.entries[i]) + m.oddKeys = oddKeys } - m.entries = entries - m.oddKeys = oddKeys m.index = nil if len(m.entries) > symbolTableLinearMax { m.buildIndex() From 7c10f462b0d73a6a49f056d20e6e6b98d9a3d5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 15:15:17 +0200 Subject: [PATCH 27/35] Document symbol table invariants --- tsc/internal/ast/symbol.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tsc/internal/ast/symbol.go b/tsc/internal/ast/symbol.go index 88b6796566c0d..3e1b47ce8b8e4 100644 --- a/tsc/internal/ast/symbol.go +++ b/tsc/internal/ast/symbol.go @@ -177,7 +177,12 @@ func (s *Symbol) CombinedLocalAndExportSymbolFlags() SymbolFlags { // it has more than symbolTableLinearMax entries, and only then gets a hash index of entry positions. An entry does not // store its key: the key is almost always the symbol's own name, so an entry holds the symbol and the key's length, // which rejects most non-matching entries without reading the symbol. A key with other text than its symbol's name -// is kept in oddKeys. +// is kept in oddKeys. Because of that, a symbol's name must not change after the symbol is added to a table. +// +// This is not a collections.OrderedMap[string, *Symbol]: that stores every key in its key slice and again in its +// map, and gives every table a hash map, while symbol tables are numerous, long-lived and mostly tiny. +// +// A table must not be changed with Set or Delete while it is being iterated. type SymbolTable = *SymbolMap const symbolTableLinearMax = 16 From 2080da6b5e77ac3f463a3b3e9a8ec4d8443e5dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 15:21:36 +0200 Subject: [PATCH 28/35] Iterate symbol tables directly instead of through forEachSymbolTableEntry --- tsc/internal/checker/checker.go | 37 +++++++++------------ tsc/internal/checker/nodebuilderimpl.go | 5 ++- tsc/internal/checker/symbolaccessibility.go | 22 +++--------- 3 files changed, 21 insertions(+), 43 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 977c151328431..6cc04be0308cd 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -1848,14 +1848,7 @@ func (c *Checker) getSuggestionForSymbolNameLookup(symbols ast.SymbolTable, name if meaning&ast.SymbolFlagsGlobalLookup != 0 { extras = getPrimitiveTypeAliasSuggestions(symbols) } - // Checking a candidate alias resolves it, which creates types, so visit aliases last and in a stable order - // rather than in the random iteration order of the symbol table. - candidates := make([]*ast.Symbol, 0, symbols.Len()) - c.forEachSymbolTableEntry(symbols, func(_ string, symbol *ast.Symbol) bool { - candidates = append(candidates, symbol) - return false - }) - return c.getSpellingSuggestionForName(name, core.ConcatenateSeq(slices.Values(candidates), extras), meaning) + return c.getSpellingSuggestionForName(name, core.ConcatenateSeq(symbols.Values(), extras), meaning) } // Given a name and a list of symbols whose names are *not* equal to the name, return a spelling suggestion if there is @@ -5926,9 +5919,12 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) { } func (c *Checker) hasExportedMembersOfKind(moduleSymbol *ast.Symbol, kind ast.SymbolFlags) bool { - return c.forEachSymbolTableEntry(moduleSymbol.Exports(), func(_ string, symbol *ast.Symbol) bool { - return symbol.Name() != ast.InternalSymbolNameExportEquals && c.getSymbolFlags(symbol)&kind != 0 - }) + for _, symbol := range moduleSymbol.Exports().All() { + if symbol.Name() != ast.InternalSymbolNameExportEquals && c.getSymbolFlags(symbol)&kind != 0 { + return true + } + } + return false } func (c *Checker) hasShadowedNamespace(symbol *ast.Symbol) bool { @@ -15224,13 +15220,12 @@ func (c *Checker) reportNonExportedMember(name *ast.Node, declarationName string } } else { var exportedSymbol *ast.Symbol - c.forEachSymbolTableEntry(exports, func(_ string, symbol *ast.Symbol) bool { + for _, symbol := range exports.All() { if c.getSymbolIfSameReference(symbol, localSymbol) != nil { exportedSymbol = symbol - return true + break } - return false - }) + } var diagnostic *ast.Diagnostic if exportedSymbol != nil { diagnostic = c.error(name, diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, c.symbolToString(exportedSymbol)) @@ -16628,9 +16623,9 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as } // A CommonJS module defined by an 'export=' might also export typedefs, stored on the original module if originalModule != nil && originalModule.Exports().Len() > 1 { - c.forEachSymbolTableEntry(originalModule.Exports(), func(_ string, symbol *ast.Symbol) bool { + for _, symbol := range originalModule.Exports().All() { if symbol.Name() == ast.InternalSymbolNameExportEquals || symbol.Name() == ast.InternalSymbolNameExportStar { - return false + continue } flags := c.getSymbolFlags(symbol) if flags&(ast.SymbolFlagsType|ast.SymbolFlagsNamespace) != 0 && @@ -16638,8 +16633,7 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as exports.Get(symbol.Name()) == nil { exports.Set(symbol.Name(), symbol) } - return false - }) + } } for name := range nonTypeOnlyNames.Keys() { delete(typeOnlyExportStarMap, name) @@ -22562,12 +22556,11 @@ func (c *Checker) getNamedMembers(members ast.SymbolTable, container *ast.Symbol // explicitly declared members first in type relations, which is beneficial because explicitly declared members are more // likely to contain discriminating differences. See for example https://github.com/microsoft/TypeScript/tsc/issues/1968. result := make([]*ast.Symbol, 0, members.Len()) - c.forEachSymbolTableEntry(members, func(id string, symbol *ast.Symbol) bool { + for id, symbol := range members.All() { if c.isNamedMember(symbol, id) { result = append(result, symbol) } - return false - }) + } if container == nil || container.Flags()&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) == 0 { c.sortSymbols(result) return result diff --git a/tsc/internal/checker/nodebuilderimpl.go b/tsc/internal/checker/nodebuilderimpl.go index 155a973d4a73b..bd0feb2b4acff 100644 --- a/tsc/internal/checker/nodebuilderimpl.go +++ b/tsc/internal/checker/nodebuilderimpl.go @@ -778,13 +778,12 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index symbolName = symbol.Name() } else { results := make(map[*ast.Symbol]string, 1) - b.ch.forEachSymbolTableEntry(exports, func(name string, ex *ast.Symbol) bool { + for name, ex := range exports.All() { if b.ch.getSymbolIfSameReference(ex, symbol) != nil && !isLateBoundName(name) && name != ast.InternalSymbolNameExportEquals { results[ex] = name // break // must collect all results and sort them - exports are randomly iterated } - return false - }) + } resultSymbols := slices.Collect(maps.Keys(results)) if len(resultSymbols) > 0 { b.ch.sortSymbols(resultSymbols) diff --git a/tsc/internal/checker/symbolaccessibility.go b/tsc/internal/checker/symbolaccessibility.go index ecf440670d20e..e848d431f2a8d 100644 --- a/tsc/internal/checker/symbolaccessibility.go +++ b/tsc/internal/checker/symbolaccessibility.go @@ -262,10 +262,9 @@ func (c *Checker) buildExternalModuleContainerIndex() { } container := c.getSymbolOfDeclaration(file.AsNode()) index.moduleOrder[container] = len(index.moduleOrder) - c.forEachSymbolTableEntry(c.getExportsOfSymbol(container), func(_ string, exported *ast.Symbol) bool { + for _, exported := range c.getExportsOfSymbol(container).All() { index.add(c.getResolvedTarget(exported), container) - return false - }) + } if exportEquals := container.Exports().Get(ast.InternalSymbolNameExportEquals); exportEquals != nil { index.add(c.getResolvedTarget(exportEquals), container) } @@ -273,18 +272,6 @@ func (c *Checker) buildExternalModuleContainerIndex() { index.complete = true } -// forEachSymbolTableEntry calls f for each entry of a symbol table, in the table's insertion order. f returns true to -// stop, and forEachSymbolTableEntry then returns true. f gets each symbol's key in the table, which is not always the -// symbol's name (a default export is keyed "default"). -func (c *Checker) forEachSymbolTableEntry(symbols ast.SymbolTable, f func(name string, symbol *ast.Symbol) bool) bool { - for name, symbol := range symbols.All() { - if f(name, symbol) { - return true - } - } - return false -} - func (c *Checker) scanExternalModuleContainers(symbol *ast.Symbol) []*ast.Symbol { var containers []*ast.Symbol for _, file := range c.program.SourceFiles() { @@ -433,12 +420,11 @@ func (c *Checker) getAliasForSymbolInContainer(container *ast.Symbol, symbol *as return quick } var candidates []*ast.Symbol - c.forEachSymbolTableEntry(exports, func(_ string, exported *ast.Symbol) bool { + for _, exported := range exports.All() { if c.getSymbolIfSameReference(exported, symbol) != nil { candidates = append(candidates, exported) } - return false - }) + } if len(candidates) > 0 { c.sortSymbols(candidates) // _must_ sort exports for stable results - symbol table is randomly iterated return candidates[0] From 33748194faecf64fb66cdabc46df2152b4019b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 15:21:37 +0200 Subject: [PATCH 29/35] Remove the unused SymbolMap.CopyFrom --- tsc/internal/ast/symbol.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tsc/internal/ast/symbol.go b/tsc/internal/ast/symbol.go index 3e1b47ce8b8e4..b3e3f8800f994 100644 --- a/tsc/internal/ast/symbol.go +++ b/tsc/internal/ast/symbol.go @@ -400,12 +400,6 @@ func (m *SymbolMap) Clone() SymbolTable { return clone } -func (m *SymbolMap) CopyFrom(source SymbolTable) { - for key, symbol := range source.All() { - m.Set(key, symbol) - } -} - const InternalSymbolNamePrefix = "\xFE" // Invalid UTF8 sequence, will never occur as IdentifierName const ( From 1423283c113f3390a4a824f217496cf5d87c999a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 15:24:27 +0200 Subject: [PATCH 30/35] Size a rebuilt symbol table index for its entries --- tsc/internal/ast/symbol.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsc/internal/ast/symbol.go b/tsc/internal/ast/symbol.go index b3e3f8800f994..7ca275c59903d 100644 --- a/tsc/internal/ast/symbol.go +++ b/tsc/internal/ast/symbol.go @@ -319,7 +319,7 @@ func (m *SymbolMap) insertIndex(key string, i int32) { } func (m *SymbolMap) buildIndex() { - m.index = make([]int32, indexSizeFor(len(m.entries)*2)) + m.index = make([]int32, indexSizeFor(len(m.entries))) for i := range m.entries { m.insertIndex(m.keyAt(i, m.oddKeys), int32(i)) } From abcdada915dc3a91c32c01e5b7664b2e370bb0da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 15:33:57 +0200 Subject: [PATCH 31/35] Start symbol tables with room for two entries --- tsc/internal/ast/symbol.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tsc/internal/ast/symbol.go b/tsc/internal/ast/symbol.go index 7ca275c59903d..15b1e929cf4e3 100644 --- a/tsc/internal/ast/symbol.go +++ b/tsc/internal/ast/symbol.go @@ -282,6 +282,10 @@ func (m *SymbolMap) Set(key string, symbol *Symbol) { return } i := int32(len(m.entries)) + if cap(m.entries) == 0 { + // Most tables hold one or two entries, so start with room for two rather than growing from one. + m.entries = make([]symbolMapEntry, 0, 2) + } m.entries = append(m.entries, symbolMapEntry{symbol: symbol, keyLen: int32(len(key))}) if symbol.Name() != key { m.setOddKey(i, key) From 8f8b066b558ca92913c09a17a88e7a9729673c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Oct 2026 17:03:27 +0200 Subject: [PATCH 32/35] Split declared and inherited members in place in getNamedMembers --- tsc/internal/checker/checker.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 6cc04be0308cd..f5fd596c7780a 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -22565,17 +22565,15 @@ func (c *Checker) getNamedMembers(members ast.SymbolTable, container *ast.Symbol c.sortSymbols(result) return result } - var inherited []*ast.Symbol + // Move the members declared in the container to the front. Both parts are sorted below, so the order the split + // leaves them in does not matter. containedCount := 0 - for _, symbol := range result { + for i, symbol := range result { if c.isDeclarationContainedBy(symbol, container) { - result[containedCount] = symbol + result[containedCount], result[i] = result[i], result[containedCount] containedCount++ - } else { - inherited = append(inherited, symbol) } } - copy(result[containedCount:], inherited) c.sortSymbols(result[:containedCount]) c.sortSymbols(result[containedCount:]) return result From a8d7f4e9b264d9c3d5026457bd7015a33c63fdaa Mon Sep 17 00:00:00 2001 From: Dimitri Mitropoulos Date: Wed, 21 Oct 2026 19:19:02 -0400 Subject: [PATCH 33/35] Iterate symbol tables directly in GetIndexInfosOfIndexSymbol --- tsc/internal/checker/exports.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tsc/internal/checker/exports.go b/tsc/internal/checker/exports.go index bce0ba48cfa20..f03be066141dc 100644 --- a/tsc/internal/checker/exports.go +++ b/tsc/internal/checker/exports.go @@ -1,7 +1,6 @@ package checker import ( - "maps" "slices" "github.com/microsoft/TypeScript/tsc/internal/ast" @@ -365,8 +364,7 @@ func (c *Checker) GetIndexInfosOfType(t *Type) []*IndexInfo { func (c *Checker) GetIndexInfosOfIndexSymbol(symbol *ast.Symbol) []*IndexInfo { var siblingSymbols []*ast.Symbol if symbol.Parent() != nil { - siblingSymbols = slices.Collect(maps.Values(c.getMembersOfSymbol(symbol.Parent()))) - c.sortSymbols(siblingSymbols) + siblingSymbols = slices.Collect(c.getMembersOfSymbol(symbol.Parent()).Values()) } return c.getIndexInfosOfIndexSymbol(symbol, siblingSymbols) } From c141b6ca093fac1b4c04d86035834d1fc2d32563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 22 Oct 2026 09:30:22 +0200 Subject: [PATCH 34/35] Run namespace member resolution order tests single-threaded --- .../cases/compiler/namespaceMembersResolutionOrderExportStar.ts | 1 + .../noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts | 1 + ...yDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/tsc/testdata/tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts b/tsc/testdata/tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts index 47f869222be63..9361fe9f688d0 100644 --- a/tsc/testdata/tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts +++ b/tsc/testdata/tests/cases/compiler/namespaceMembersResolutionOrderExportStar.ts @@ -6,6 +6,7 @@ // @declaration: true // @outDir: /out // @noImplicitReferences: true +// @singleThreaded: true // @Filename: /ma.js export { v as pa } from "./xa"; diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts index 14f8c0ed89cf4..337c7236fb5a8 100644 --- a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrder.ts @@ -6,6 +6,7 @@ // @declaration: true // @outDir: /out // @noImplicitReferences: true +// @singleThreaded: true // @Filename: /ma.js export { v as pa } from "./xa"; diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts index 86fe41104d7dd..604156e3e4433 100644 --- a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsNamespaceMembersResolutionOrderReexportedTypes.ts @@ -7,6 +7,7 @@ // @declaration: true // @outDir: /out // @noImplicitReferences: true +// @singleThreaded: true // @Filename: /ma.js export { v as pa } from "./xa"; From fa5d2fcbf898f1893ddd1d4fbd85e66131045923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 22 Oct 2026 09:34:38 +0200 Subject: [PATCH 35/35] Drop the redundant oddKeys parameter from keyAt --- tsc/internal/ast/symbol.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tsc/internal/ast/symbol.go b/tsc/internal/ast/symbol.go index 15b1e929cf4e3..5273aa8e8d955 100644 --- a/tsc/internal/ast/symbol.go +++ b/tsc/internal/ast/symbol.go @@ -219,9 +219,9 @@ func SymbolTableOf(name string, symbol *Symbol) SymbolTable { return m } -func (m *SymbolMap) keyAt(i int, oddKeys map[int32]string) string { +func (m *SymbolMap) keyAt(i int) string { if m.entries[i].oddKey { - return oddKeys[int32(i)] + return m.oddKeys[int32(i)] } return m.entries[i].symbol.Name() } @@ -237,14 +237,14 @@ func (m *SymbolMap) find(key string) int { if p == 0 { return -1 } - if i := int(p - 1); m.entries[i].keyLen == int32(len(key)) && m.keyAt(i, m.oddKeys) == key { + if i := int(p - 1); m.entries[i].keyLen == int32(len(key)) && m.keyAt(i) == key { return i } } } keyLen := int32(len(key)) for i := range m.entries { - if m.entries[i].keyLen == keyLen && m.keyAt(i, m.oddKeys) == key { + if m.entries[i].keyLen == keyLen && m.keyAt(i) == key { return i } } @@ -325,7 +325,7 @@ func (m *SymbolMap) insertIndex(key string, i int32) { func (m *SymbolMap) buildIndex() { m.index = make([]int32, indexSizeFor(len(m.entries))) for i := range m.entries { - m.insertIndex(m.keyAt(i, m.oddKeys), int32(i)) + m.insertIndex(m.keyAt(i), int32(i)) } }