Skip to content

Commit 91070c4

Browse files
Merge branch 'main' into fix-linked-package-dts-state
2 parents 64ca02c + 97aedd3 commit 91070c4

165 files changed

Lines changed: 12119 additions & 390 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎packages/typescript/enums/symbolFlags.d.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export declare enum SymbolFlags {
3333
ConstEnumOnlyModule = 1 << 28,
3434
ReplaceableByMethod = 1 << 29,
3535
GlobalLookup = 1 << 30,
36+
NameProxy = 1 << 30,
3637
All = (1 << 30) - 1,
3738
Enum = RegularEnum | ConstEnum,
3839
Variable = FunctionScopedVariable | BlockScopedVariable,

‎packages/typescript/enums/symbolFlags.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export var SymbolFlags;
3333
SymbolFlags[SymbolFlags["ConstEnumOnlyModule"] = 268435456] = "ConstEnumOnlyModule";
3434
SymbolFlags[SymbolFlags["ReplaceableByMethod"] = 536870912] = "ReplaceableByMethod";
3535
SymbolFlags[SymbolFlags["GlobalLookup"] = 1073741824] = "GlobalLookup";
36+
SymbolFlags[SymbolFlags["NameProxy"] = 1073741824] = "NameProxy";
3637
SymbolFlags[SymbolFlags["All"] = 1073741823] = "All";
3738
SymbolFlags[SymbolFlags["Enum"] = 384] = "Enum";
3839
SymbolFlags[SymbolFlags["Variable"] = 3] = "Variable";

‎tsc/internal/api/enum_values_generated.go‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎tsc/internal/api/session.go‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func getSourceFileSymbolIndex(sourceFile *ast.SourceFile) map[SymbolID]*ast.Symb
7070
addSymbol(symbol.Parent())
7171
addSymbol(symbol.ExportSymbol())
7272
for _, table := range []ast.SymbolTable{symbol.Members(), symbol.Exports()} {
73-
for _, child := range table {
73+
for _, child := range table.All() {
7474
addSymbol(child)
7575
}
7676
}
@@ -81,11 +81,11 @@ func getSourceFileSymbolIndex(sourceFile *ast.SourceFile) map[SymbolID]*ast.Symb
8181
}
8282
addSymbol(node.Symbol())
8383
addSymbol(node.LocalSymbol())
84-
for _, symbol := range node.Locals() {
84+
for _, symbol := range node.Locals().All() {
8585
addSymbol(symbol)
8686
}
8787
}
88-
for _, symbol := range file.GlobalExports {
88+
for _, symbol := range file.GlobalExports.All() {
8989
addSymbol(symbol)
9090
}
9191
for _, module := range file.PatternAmbientModules {
@@ -3451,20 +3451,20 @@ func (s *Session) resolveSymbolTablePropertyOfSymbol(ctx context.Context, params
34513451
defer release()
34523452

34533453
symbolTable := getter(symbol)
3454-
if len(symbolTable) == 0 {
3454+
if symbolTable.Len() == 0 {
34553455
return nil, nil
34563456
}
3457-
if len(symbolTable) == 1 {
3458-
for _, sub := range symbolTable {
3457+
if symbolTable.Len() == 1 {
3458+
for _, sub := range symbolTable.All() {
34593459
if sd == nil {
34603460
return []*SymbolResponse{newFileSymbolResponse(sub)}, nil
34613461
}
34623462
return []*SymbolResponse{sd.newSymbolResponse(sub, projectID)}, nil
34633463
}
34643464
}
34653465

3466-
symbols := make([]*ast.Symbol, 0, len(symbolTable))
3467-
for _, sub := range symbolTable {
3466+
symbols := make([]*ast.Symbol, 0, symbolTable.Len())
3467+
for _, sub := range symbolTable.All() {
34683468
symbols = append(symbols, sub)
34693469
}
34703470
if sd == nil {

‎tsc/internal/api/session_symbolresponse_test.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func TestSymbolReferencesIdentifyOwnerWithoutDescriptor(t *testing.T) {
8686
assert.Assert(t, !strings.Contains(string(encoded), "contentHash"))
8787

8888
// A file-owned symbol's relationships are references into the same file.
89-
member := class.Members()["property"]
89+
member := class.Members().Get("property")
9090
response := newFileSymbolResponse(member)
9191
assert.DeepEqual(t, response.Parent, reference)
9292
}
@@ -110,6 +110,6 @@ func TestContentMappedSymbolsAreSnapshotOwned(t *testing.T) {
110110
assert.NilError(t, err)
111111
assert.Equal(t, resolved, class)
112112

113-
reference := newSymbolReference(class.Members()["property"])
113+
reference := newSymbolReference(class.Members().Get("property"))
114114
assert.Equal(t, reference.File, "")
115115
}

‎tsc/internal/ast/symbol.go‎

Lines changed: 207 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package ast
22

33
import (
4+
"hash/maphash"
5+
"iter"
6+
"slices"
47
"strings"
58
"sync/atomic"
69

@@ -164,8 +167,211 @@ func (s *Symbol) CombinedLocalAndExportSymbolFlags() SymbolFlags {
164167
}
165168

166169
// SymbolTable
170+
//
171+
// A SymbolTable maps names to symbols and iterates in insertion order, like Strada's Map, so that iterating a table
172+
// is deterministic and visits symbols in the order the binder and checker added them. A nil SymbolTable is an empty
173+
// table that can be read and iterated but not written, like a nil map.
174+
//
175+
// The entries are kept in insertion order in one slice. Most tables are small, so a table is searched linearly until
176+
// it has more than symbolTableLinearMax entries, and only then gets a hash index of entry positions. An entry does not
177+
// store its key as the key is almost always the symbol's own name. In the rare cases when a symbol has a different name,
178+
// the table stores a proxy symbol with the new name and a reference to the original symbol in the parent field.
179+
//
180+
// A table must not be changed with Set or Delete while it is being iterated.
181+
type SymbolTable = *SymbolMap
167182

168-
type SymbolTable map[string]*Symbol
183+
const symbolTableLinearMax = 16
184+
185+
type SymbolMap struct {
186+
entries []*Symbol
187+
index []int32 // open addressing table of entry positions plus one (0 is empty), only past symbolTableLinearMax
188+
}
189+
190+
var symbolTableSeed = maphash.MakeSeed()
191+
192+
func NewSymbolTable() SymbolTable {
193+
return NewSymbolTableWithCapacity(0)
194+
}
195+
196+
func NewSymbolTableWithCapacity(capacity int) SymbolTable {
197+
m := &SymbolMap{}
198+
if capacity > 0 {
199+
m.entries = make([]*Symbol, 0, capacity)
200+
if capacity > symbolTableLinearMax {
201+
m.index = make([]int32, indexSizeFor(capacity))
202+
}
203+
}
204+
return m
205+
}
206+
207+
// SymbolTableOf returns a new table holding symbol under name.
208+
func SymbolTableOf(name string, symbol *Symbol) SymbolTable {
209+
m := NewSymbolTableWithCapacity(1)
210+
m.Set(name, symbol)
211+
return m
212+
}
213+
214+
func (m *SymbolMap) keyAt(i int) string {
215+
return m.entries[i].Name()
216+
}
217+
218+
func (m *SymbolMap) symbolAt(i int) *Symbol {
219+
symbol := m.entries[i]
220+
if symbol.flags == SymbolFlagsNameProxy {
221+
symbol = symbol.data.parent
222+
}
223+
return symbol
224+
}
225+
226+
func (m *SymbolMap) find(key string) int {
227+
if m == nil {
228+
return -1
229+
}
230+
if m.index != nil {
231+
mask := uint64(len(m.index) - 1)
232+
for slot := maphash.String(symbolTableSeed, key) & mask; ; slot = (slot + 1) & mask {
233+
p := m.index[slot]
234+
if p == 0 {
235+
return -1
236+
}
237+
if i := int(p - 1); m.keyAt(i) == key {
238+
return i
239+
}
240+
}
241+
}
242+
for i := range m.entries {
243+
if m.keyAt(i) == key {
244+
return i
245+
}
246+
}
247+
return -1
248+
}
249+
250+
func (m *SymbolMap) Len() int {
251+
if m == nil {
252+
return 0
253+
}
254+
return len(m.entries)
255+
}
256+
257+
func (m *SymbolMap) Get(key string) *Symbol {
258+
if i := m.find(key); i >= 0 {
259+
return m.symbolAt(i)
260+
}
261+
return nil
262+
}
263+
264+
func (m *SymbolMap) Lookup(key string) (*Symbol, bool) {
265+
if i := m.find(key); i >= 0 {
266+
return m.symbolAt(i), true
267+
}
268+
return nil, false
269+
}
270+
271+
// Set replaces the symbol of an existing key in place, keeping its position, or adds the key at the end.
272+
func (m *SymbolMap) Set(key string, symbol *Symbol) {
273+
if key != symbol.Name() {
274+
proxy := NewSymbol()
275+
proxy.flags = SymbolFlagsNameProxy
276+
proxy.data.name = key
277+
proxy.data.parent = symbol
278+
symbol = proxy
279+
}
280+
if i := m.find(key); i >= 0 {
281+
m.entries[i] = symbol
282+
return
283+
}
284+
i := int32(len(m.entries))
285+
if cap(m.entries) == 0 {
286+
// Most tables hold one or two entries, so start with room for two rather than growing from one.
287+
m.entries = make([]*Symbol, 0, 2)
288+
}
289+
m.entries = append(m.entries, symbol)
290+
if m.index != nil && len(m.entries)*4 <= len(m.index)*3 {
291+
m.insertIndex(key, i)
292+
} else if len(m.entries) > symbolTableLinearMax {
293+
m.buildIndex()
294+
}
295+
}
296+
297+
func indexSizeFor(n int) int {
298+
size := 32
299+
for size*3 < n*4 {
300+
size *= 2
301+
}
302+
return size
303+
}
304+
305+
func (m *SymbolMap) insertIndex(key string, i int32) {
306+
mask := uint64(len(m.index) - 1)
307+
slot := maphash.String(symbolTableSeed, key) & mask
308+
for m.index[slot] != 0 {
309+
slot = (slot + 1) & mask
310+
}
311+
m.index[slot] = i + 1
312+
}
313+
314+
func (m *SymbolMap) buildIndex() {
315+
m.index = make([]int32, indexSizeFor(len(m.entries)))
316+
for i := range m.entries {
317+
m.insertIndex(m.keyAt(i), int32(i))
318+
}
319+
}
320+
321+
func (m *SymbolMap) Delete(key string) {
322+
d := m.find(key)
323+
if d < 0 {
324+
return
325+
}
326+
m.entries = slices.Delete(m.entries, d, d+1)
327+
m.index = nil
328+
if len(m.entries) > symbolTableLinearMax {
329+
m.buildIndex()
330+
}
331+
}
332+
333+
// All iterates over the keys and symbols of the table in insertion order.
334+
func (m *SymbolMap) All() iter.Seq2[string, *Symbol] {
335+
return func(yield func(string, *Symbol) bool) {
336+
if m == nil {
337+
return
338+
}
339+
entries := m.entries
340+
for i := range entries {
341+
if !yield(m.keyAt(i), m.symbolAt(i)) {
342+
return
343+
}
344+
}
345+
}
346+
}
347+
348+
func (m *SymbolMap) Keys() iter.Seq[string] {
349+
return func(yield func(string) bool) {
350+
for key := range m.All() {
351+
if !yield(key) {
352+
return
353+
}
354+
}
355+
}
356+
}
357+
358+
func (m *SymbolMap) Values() iter.Seq[*Symbol] {
359+
return func(yield func(*Symbol) bool) {
360+
for _, symbol := range m.All() {
361+
if !yield(symbol) {
362+
return
363+
}
364+
}
365+
}
366+
}
367+
368+
func (m *SymbolMap) Clone() SymbolTable {
369+
if m == nil {
370+
return nil
371+
}
372+
clone := &SymbolMap{entries: slices.Clone(m.entries), index: slices.Clone(m.index)}
373+
return clone
374+
}
169375

170376
const InternalSymbolNamePrefix = "\xFE" // Invalid UTF8 sequence, will never occur as IdentifierName
171377

0 commit comments

Comments
 (0)