11package checker
22
33import (
4- "reflect"
54 "slices"
6- "unsafe"
75
86 "github.com/microsoft/typescript-go/internal/ast"
97 "github.com/microsoft/typescript-go/internal/core"
@@ -143,7 +141,7 @@ func (ch *Checker) getWithAlternativeContainers(container *ast.Symbol, symbol *a
143141 container .Flags & leftMeaning == 0 ) &&
144142 container .Flags & ast .SymbolFlagsType != 0 &&
145143 ch .getDeclaredTypeOfSymbol (container ).flags & TypeFlagsObject != 0 {
146- ch .someSymbolTableInScope (enclosingDeclaration , func (t ast.SymbolTable , _ bool , _ bool , _ * ast.Node ) bool {
144+ ch .someSymbolTableInScope (enclosingDeclaration , func (t ast.SymbolTable , _ symbolTableID , _ bool , _ bool , _ * ast.Node ) bool {
147145 for _ , s := range t {
148146 if s .Flags & leftMeaning != 0 && ch .getTypeOfSymbol (s ) == ch .getDeclaredTypeOfSymbol (container ) {
149147 firstVariableMatch = s
@@ -378,7 +376,7 @@ func (ch *Checker) getAccessibleSymbolChain(
378376 meaning ast.SymbolFlags ,
379377 useOnlyExternalAliasing bool ,
380378) []* ast.Symbol {
381- return ch .getAccessibleSymbolChainEx (accessibleSymbolChainContext {symbol , enclosingDeclaration , meaning , useOnlyExternalAliasing , make (map [ast.SymbolId ]map [unsafe. Pointer ]struct {})})
379+ return ch .getAccessibleSymbolChainEx (accessibleSymbolChainContext {symbol , enclosingDeclaration , meaning , useOnlyExternalAliasing , make (map [ast.SymbolId ]map [symbolTableID ]struct {})})
382380}
383381
384382func (ch * Checker ) GetAccessibleSymbolChain (
@@ -395,7 +393,35 @@ type accessibleSymbolChainContext struct {
395393 enclosingDeclaration * ast.Node
396394 meaning ast.SymbolFlags
397395 useOnlyExternalAliasing bool
398- visitedSymbolTablesMap map [ast.SymbolId ]map [unsafe.Pointer ]struct {}
396+ visitedSymbolTablesMap map [ast.SymbolId ]map [symbolTableID ]struct {}
397+ }
398+
399+ // symbolTableID uniquely identifies a symbol table by encoding its source.
400+ // The high 2 bits encode the kind (locals, exports, members, globals),
401+ // and the remaining bits encode the NodeId or SymbolId of the source.
402+ type symbolTableID uint64
403+
404+ const (
405+ stKindLocals symbolTableID = iota << 62
406+ stKindExports
407+ stKindMembers
408+ stKindGlobals
409+ )
410+
411+ func symbolTableIDFromLocals (node * ast.Node ) symbolTableID {
412+ return stKindLocals | symbolTableID (ast .GetNodeId (node ))
413+ }
414+
415+ func symbolTableIDFromExports (sym * ast.Symbol ) symbolTableID {
416+ return stKindExports | symbolTableID (ast .GetSymbolId (sym ))
417+ }
418+
419+ func symbolTableIDFromMembers (sym * ast.Symbol ) symbolTableID {
420+ return stKindMembers | symbolTableID (ast .GetSymbolId (sym ))
421+ }
422+
423+ func symbolTableIDFromGlobals () symbolTableID {
424+ return stKindGlobals
399425}
400426
401427func (ch * Checker ) getAccessibleSymbolChainEx (ctx accessibleSymbolChainContext ) []* ast.Symbol {
@@ -407,7 +433,7 @@ func (ch *Checker) getAccessibleSymbolChainEx(ctx accessibleSymbolChainContext)
407433 }
408434 // Go from enclosingDeclaration to the first scope we check, so the cache is keyed off the scope and thus shared more
409435 var firstRelevantLocation * ast.Node
410- ch .someSymbolTableInScope (ctx .enclosingDeclaration , func (_ ast.SymbolTable , _ bool , _ bool , node * ast.Node ) bool {
436+ ch .someSymbolTableInScope (ctx .enclosingDeclaration , func (_ ast.SymbolTable , _ symbolTableID , _ bool , _ bool , node * ast.Node ) bool {
411437 firstRelevantLocation = node
412438 return true
413439 })
@@ -423,8 +449,8 @@ func (ch *Checker) getAccessibleSymbolChainEx(ctx accessibleSymbolChainContext)
423449
424450 var result []* ast.Symbol
425451
426- ch .someSymbolTableInScope (ctx .enclosingDeclaration , func (t ast.SymbolTable , ignoreQualification bool , isLocalNameLookup bool , _ * ast.Node ) bool {
427- res := ch .getAccessibleSymbolChainFromSymbolTable (ctx , t , ignoreQualification , isLocalNameLookup )
452+ ch .someSymbolTableInScope (ctx .enclosingDeclaration , func (t ast.SymbolTable , tableId symbolTableID , ignoreQualification bool , isLocalNameLookup bool , _ * ast.Node ) bool {
453+ res := ch .getAccessibleSymbolChainFromSymbolTable (ctx , t , tableId , ignoreQualification , isLocalNameLookup )
428454 if len (res ) > 0 {
429455 result = res
430456 return true
@@ -438,30 +464,30 @@ func (ch *Checker) getAccessibleSymbolChainEx(ctx accessibleSymbolChainContext)
438464/**
439465* @param {ignoreQualification} boolean Set when a symbol is being looked for through the exports of another symbol (meaning we have a route to qualify it already)
440466 */
441- func (ch * Checker ) getAccessibleSymbolChainFromSymbolTable (ctx accessibleSymbolChainContext , t ast.SymbolTable , ignoreQualification bool , isLocalNameLookup bool ) []* ast.Symbol {
467+ func (ch * Checker ) getAccessibleSymbolChainFromSymbolTable (ctx accessibleSymbolChainContext , t ast.SymbolTable , tableId symbolTableID , ignoreQualification bool , isLocalNameLookup bool ) []* ast.Symbol {
442468 symId := ast .GetSymbolId (ctx .symbol )
443469 visitedSymbolTables , ok := ctx .visitedSymbolTablesMap [symId ]
444470 if ! ok {
445- visitedSymbolTables = make (map [unsafe. Pointer ]struct {})
471+ visitedSymbolTables = make (map [symbolTableID ]struct {})
446472 ctx .visitedSymbolTablesMap [symId ] = visitedSymbolTables
447473 }
448474
449- id := reflect .ValueOf (t ).UnsafePointer () // TODO: Is this seriously the only way to check reference equality of maps?
450- _ , present := visitedSymbolTables [id ]
475+ _ , present := visitedSymbolTables [tableId ]
451476 if present {
452477 return nil
453478 }
454- visitedSymbolTables [id ] = struct {}{}
479+ visitedSymbolTables [tableId ] = struct {}{}
455480
456- res := ch .trySymbolTable (ctx , t , ignoreQualification , isLocalNameLookup )
481+ res := ch .trySymbolTable (ctx , t , tableId == stKindGlobals , ignoreQualification , isLocalNameLookup )
457482
458- delete (visitedSymbolTables , id )
483+ delete (visitedSymbolTables , tableId )
459484 return res
460485}
461486
462487func (ch * Checker ) trySymbolTable (
463488 ctx accessibleSymbolChainContext ,
464489 symbols ast.SymbolTable ,
490+ isGlobals bool ,
465491 ignoreQualification bool ,
466492 isLocalNameLookup bool ,
467493) []* ast.Symbol {
@@ -506,7 +532,7 @@ func (ch *Checker) trySymbolTable(
506532 }
507533
508534 // If there's no result and we're looking at the global symbol table, treat `globalThis` like an alias and try to lookup thru that
509- if reflect . ValueOf ( ch . globals ). UnsafePointer () == reflect . ValueOf ( symbols ). UnsafePointer () {
535+ if isGlobals {
510536 return ch .getCandidateListForSymbol (ctx , ch .globalThisSymbol , ch .globalThisSymbol , ignoreQualification )
511537 }
512538 return nil
@@ -553,7 +579,8 @@ func (ch *Checker) getCandidateListForSymbol(
553579 if candidateTable == nil {
554580 return nil
555581 }
556- accessibleSymbolsFromExports := ch .getAccessibleSymbolChainFromSymbolTable (ctx , candidateTable /*ignoreQualification*/ , true , false )
582+ candidateTableId := symbolTableIDFromExports (resolvedImportedSymbol )
583+ accessibleSymbolsFromExports := ch .getAccessibleSymbolChainFromSymbolTable (ctx , candidateTable , candidateTableId /*ignoreQualification*/ , true , false )
557584 if len (accessibleSymbolsFromExports ) == 0 {
558585 return nil
559586 }
@@ -606,7 +633,7 @@ func (ch *Checker) canQualifySymbol(
606633
607634func (ch * Checker ) needsQualification (symbol * ast.Symbol , enclosingDeclaration * ast.Node , meaning ast.SymbolFlags ) bool {
608635 qualify := false
609- ch .someSymbolTableInScope (enclosingDeclaration , func (symbolTable ast.SymbolTable , _ bool , _ bool , _ * ast.Node ) bool {
636+ ch .someSymbolTableInScope (enclosingDeclaration , func (symbolTable ast.SymbolTable , _ symbolTableID , _ bool , _ bool , _ * ast.Node ) bool {
610637 // If symbol of this name is not available in the symbol table we are ok
611638 res , ok := symbolTable [symbol .Name ]
612639 if ! ok || res == nil {
@@ -664,12 +691,12 @@ func isPropertyOrMethodDeclarationSymbol(symbol *ast.Symbol) bool {
664691
665692func (ch * Checker ) someSymbolTableInScope (
666693 enclosingDeclaration * ast.Node ,
667- callback func (symbolTable ast.SymbolTable , ignoreQualification bool , isLocalNameLookup bool , scopeNode * ast.Node ) bool ,
694+ callback func (symbolTable ast.SymbolTable , tableId symbolTableID , ignoreQualification bool , isLocalNameLookup bool , scopeNode * ast.Node ) bool ,
668695) bool {
669696 for location := enclosingDeclaration ; location != nil ; location = location .Parent {
670697 // Locals of a source file are not in scope (because they get merged into the global symbol table)
671698 if canHaveLocals (location ) && location .Locals () != nil && ! ast .IsGlobalSourceFile (location ) {
672- if callback (location .Locals (), false , true , location ) {
699+ if callback (location .Locals (), symbolTableIDFromLocals ( location . AsNode ()), false , true , location ) {
673700 return true
674701 }
675702 }
@@ -679,7 +706,7 @@ func (ch *Checker) someSymbolTableInScope(
679706 break
680707 }
681708 sym := ch .getSymbolOfDeclaration (location )
682- if callback (sym .Exports , false , true , location ) {
709+ if callback (sym .Exports , symbolTableIDFromExports ( sym ), false , true , location ) {
683710 return true
684711 }
685712 case ast .KindClassDeclaration , ast .KindClassExpression , ast .KindInterfaceDeclaration :
@@ -701,13 +728,13 @@ func (ch *Checker) someSymbolTableInScope(
701728 table [key ] = memberSymbol
702729 }
703730 }
704- if table != nil && callback (table , false , false , location ) {
731+ if table != nil && callback (table , symbolTableIDFromMembers ( sym ), false , false , location ) {
705732 return true
706733 }
707734 }
708735 }
709736
710- return callback (ch .globals , false , true , nil )
737+ return callback (ch .globals , symbolTableIDFromGlobals (), false , true , nil )
711738}
712739
713740/**
0 commit comments