Skip to content

Remove AssignmentDeclarationMembers and GlobalExports from Symbol#3189

Open
ahejlsberg wants to merge 2 commits intomainfrom
reduce-symbol-size
Open

Remove AssignmentDeclarationMembers and GlobalExports from Symbol#3189
ahejlsberg wants to merge 2 commits intomainfrom
reduce-symbol-size

Conversation

@ahejlsberg
Copy link
Member

@ahejlsberg ahejlsberg commented Mar 21, 2026

This PR removes the rarely used AssignmentDeclarationMembers and GlobalExports fields from Symbol, shrinking it to the next size class down. Assignment declarations are now tracked in a symbol with an internal name and global exports (a.k.a. UMD namespace exports) are tracked in a map on the SourceFile object (only symbols associated with external modules would ever use the GlobalExports field, so a huge waste to have it in every symbol).

Copilot AI review requested due to automatic review settings March 21, 2026 17:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors internal symbol bookkeeping to reduce ast.Symbol size by removing AssignmentDeclarationMembers and GlobalExports, relocating that state to more targeted structures in the compiler/LS pipeline.

Changes:

  • Move UMD namespace (“global exports”) tracking from Symbol.GlobalExports to SourceFile.GlobalExports.
  • Replace Symbol.AssignmentDeclarationMembers with an internal export entry keyed by ast.InternalSymbolNameAssignmentDeclaration.
  • Update checker and language service logic to use the new storage locations.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
internal/ls/importTracker.go Updates UMD-global availability detection to consult SourceFile.GlobalExports via the module symbol’s ValueDeclaration.
internal/ls/findallreferences.go Adjusts symbol-scope logic for external modules/UMD globals, but introduces a scoping regression for ambient external modules.
internal/checker/checker.go Switches UMD export merging to SourceFile.GlobalExports and updates late-bound assignment handling to read from the new internal export symbol.
internal/binder/binder.go Writes namespace exports into SourceFile.GlobalExports and stores late-bound assignment declarations under an internal export symbol.
internal/ast/symbol.go Removes the two fields from Symbol and introduces InternalSymbolNameAssignmentDeclaration.
internal/ast/ast.go Adds GlobalExports SymbolTable to SourceFile.

Comment on lines 404 to 405
if exposedByParent && !(symbol.Parent.ValueDeclaration != nil && ast.IsSourceFile(symbol.Parent.ValueDeclaration) && symbol.Parent.ValueDeclaration.AsSourceFile().GlobalExports == nil) {
return nil
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new exposedByParent gate no longer checks whether symbol.Parent is an external module symbol; it only checks for a SourceFile value declaration. For ambient external modules (declare module "a" { ... }), the module symbol's ValueDeclaration is a ModuleDeclaration, so this condition will treat exports as globally visible and return nil scope, widening the reference search incorrectly. Consider restoring the external-module check (e.g. symbol.Parent.IsExternalModule() / checker.IsExternalModuleSymbol(symbol.Parent)) and then consulting GlobalExports only when the module symbol's ValueDeclaration is a SourceFile.

Suggested change
if exposedByParent && !(symbol.Parent.ValueDeclaration != nil && ast.IsSourceFile(symbol.Parent.ValueDeclaration) && symbol.Parent.ValueDeclaration.AsSourceFile().GlobalExports == nil) {
return nil
if exposedByParent {
// If the parent is not an external module symbol, the symbol is globally visible.
if !checker.IsExternalModuleSymbol(symbol.Parent) {
return nil
}
// For external modules, only treat exports as globally visible when the module
// is a SourceFile with `export as namespace` (non-nil GlobalExports).
if symbol.Parent.ValueDeclaration != nil && ast.IsSourceFile(symbol.Parent.ValueDeclaration) {
sourceFile := symbol.Parent.ValueDeclaration.AsSourceFile()
if sourceFile.GlobalExports != nil {
return nil
}
}

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the symbol's ValueDeclaration is a source file, we know we have an external module, so no need for other checks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even for declare module blocks?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

declare module blocks don't permit export as namespace declarations, so nothing to check there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyways, with the latest commit the code is now equivalent to what was there before.

@ahejlsberg ahejlsberg requested a review from jakebailey March 21, 2026 19:18
markSeenDirectImport := nodeSeenTracker()
markSeenIndirectUser := nodeSeenTracker()
isAvailableThroughGlobal := exportInfo.exportingModuleSymbol.GlobalExports != nil
isAvailableThroughGlobal := exportInfo.exportingModuleSymbol.ValueDeclaration != nil &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This func is the same as the one in findallreferences.go; worth pulling into a helper?

@ahejlsberg ahejlsberg requested a review from jakebailey March 22, 2026 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants