Skip to content

Commit 27f0239

Browse files
authored
Set parents during parse, not bind (#1251)
1 parent a8d79ee commit 27f0239

File tree

9 files changed

+69
-121
lines changed

9 files changed

+69
-121
lines changed

internal/ast/utilities.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -904,8 +904,7 @@ func newParentInChildrenSetter() func(node *Node) bool {
904904
}
905905

906906
state.visit = func(node *Node) bool {
907-
if state.parent != nil && node.Parent != state.parent {
908-
// Avoid data races on no-ops
907+
if state.parent != nil {
909908
node.Parent = state.parent
910909
}
911910
saveParent := state.parent

internal/binder/binder.go

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ type Binder struct {
4646
unreachableFlow *ast.FlowNode
4747
reportedUnreachableFlow *ast.FlowNode
4848

49-
parent *ast.Node
5049
container *ast.Node
5150
thisContainer *ast.Node
5251
blockScopeContainer *ast.Node
@@ -211,9 +210,6 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol
211210
} else if !(includes&ast.SymbolFlagsVariable != 0 && symbol.Flags&ast.SymbolFlagsAssignment != 0 ||
212211
includes&ast.SymbolFlagsAssignment != 0 && symbol.Flags&ast.SymbolFlagsVariable != 0) {
213212
// Assignment declarations are allowed to merge with variables, no matter what other flags they have.
214-
if node.Name() != nil {
215-
setParent(node.Name(), node)
216-
}
217213
// Report errors every position with duplicate declaration
218214
// Report errors on previous encountered declarations
219215
var message *diagnostics.Message
@@ -584,9 +580,6 @@ func (b *Binder) bind(node *ast.Node) bool {
584580
if node == nil {
585581
return false
586582
}
587-
if node.Parent == nil || node.Parent.Flags&ast.NodeFlagsReparsed != 0 {
588-
node.Parent = b.parent
589-
}
590583
saveInStrictMode := b.inStrictMode
591584
// Even though in the AST the jsdoc @typedef node belongs to the current node,
592585
// its symbol might be in the same scope with the current node's symbol. Consider:
@@ -731,9 +724,7 @@ func (b *Binder) bind(node *ast.Node) bool {
731724
// children, as an optimization we don't process those.
732725
thisNodeOrAnySubnodesHasError := node.Flags&ast.NodeFlagsThisNodeHasError != 0
733726
if node.Kind > ast.KindLastToken {
734-
saveParent := b.parent
735727
saveSeenParseError := b.seenParseError
736-
b.parent = node
737728
b.seenParseError = false
738729
containerFlags := GetContainerFlags(node)
739730
if containerFlags == ContainerFlagsNone {
@@ -744,15 +735,7 @@ func (b *Binder) bind(node *ast.Node) bool {
744735
if b.seenParseError {
745736
thisNodeOrAnySubnodesHasError = true
746737
}
747-
b.parent = saveParent
748738
b.seenParseError = saveSeenParseError
749-
} else {
750-
saveParent := b.parent
751-
if node.Kind == ast.KindEndOfFile {
752-
b.parent = node
753-
}
754-
b.setJSDocParents(node)
755-
b.parent = saveParent
756739
}
757740
if thisNodeOrAnySubnodesHasError {
758741
node.Flags |= ast.NodeFlagsThisNodeOrAnySubNodesHasError
@@ -762,16 +745,6 @@ func (b *Binder) bind(node *ast.Node) bool {
762745
return false
763746
}
764747

765-
func (b *Binder) setJSDocParents(node *ast.Node) {
766-
for _, jsdoc := range node.JSDoc(b.file) {
767-
setParent(jsdoc, node)
768-
if jsdoc.Kind != ast.KindJSDocImportTag {
769-
// JSDocImportTag children have parents set during parsing for module resolution purposes.
770-
ast.SetParentInChildren(jsdoc)
771-
}
772-
}
773-
}
774-
775748
func (b *Binder) bindPropertyWorker(node *ast.Node) {
776749
isAutoAccessor := ast.IsAutoAccessorPropertyDeclaration(node)
777750
includes := core.IfElse(isAutoAccessor, ast.SymbolFlagsAccessor, ast.SymbolFlagsProperty)
@@ -868,9 +841,6 @@ func (b *Binder) bindExportDeclaration(node *ast.Node) {
868841
// All export * declarations are collected in an __export symbol
869842
b.declareSymbol(ast.GetExports(b.container.Symbol()), b.container.Symbol(), node, ast.SymbolFlagsExportStar, ast.SymbolFlagsNone)
870843
} else if ast.IsNamespaceExport(decl.ExportClause) {
871-
// declareSymbol walks up parents to find name text, parent _must_ be set
872-
// but won't be set by the normal binder walk until `bindChildren` later on.
873-
setParent(decl.ExportClause, node)
874844
b.declareSymbol(ast.GetExports(b.container.Symbol()), b.container.Symbol(), decl.ExportClause, ast.SymbolFlagsAlias, ast.SymbolFlagsAliasExcludes)
875845
}
876846
}
@@ -981,7 +951,6 @@ func (b *Binder) bindClassLikeDeclaration(node *ast.Node) {
981951
prototypeSymbol := b.newSymbol(ast.SymbolFlagsProperty|ast.SymbolFlagsPrototype, "prototype")
982952
symbolExport := ast.GetExports(symbol)[prototypeSymbol.Name]
983953
if symbolExport != nil {
984-
setParent(name, node)
985954
b.errorOnNode(symbolExport.Declarations[0], diagnostics.Duplicate_identifier_0, ast.SymbolName(prototypeSymbol))
986955
}
987956
ast.GetExports(symbol)[prototypeSymbol.Name] = prototypeSymbol
@@ -1026,9 +995,6 @@ func (b *Binder) bindExpandoPropertyAssignment(node *ast.Node) {
1026995
symbol = b.lookupEntity(parent, b.container)
1027996
}
1028997
if symbol = getInitializerSymbol(symbol); symbol != nil {
1029-
// Fix up parent pointers since we're going to use these nodes before we bind into them
1030-
setParent(expr.Left, node)
1031-
setParent(expr.Right, node)
1032998
if ast.HasDynamicName(node) {
1033999
b.bindAnonymousDeclaration(node, ast.SymbolFlagsProperty|ast.SymbolFlagsAssignment, ast.InternalSymbolNameComputed)
10341000
addLateBoundAssignmentDeclarationToSymbol(node, symbol)
@@ -1599,7 +1565,6 @@ func (b *Binder) bindChildren(node *ast.Node) {
15991565
// and set it before we descend into nodes that could actually be part of an assignment pattern.
16001566
b.inAssignmentPattern = false
16011567
if b.checkUnreachable(node) {
1602-
b.setJSDocParents(node)
16031568
b.bindEachChild(node)
16041569
b.inAssignmentPattern = saveInAssignmentPattern
16051570
return
@@ -1611,7 +1576,6 @@ func (b *Binder) bindChildren(node *ast.Node) {
16111576
hasFlowNodeData.FlowNode = b.currentFlow
16121577
}
16131578
}
1614-
b.setJSDocParents(node)
16151579
switch node.Kind {
16161580
case ast.KindWhileStatement:
16171581
b.bindWhileStatement(node)
@@ -2800,12 +2764,6 @@ func (b *Binder) addDiagnostic(diagnostic *ast.Diagnostic) {
28002764
b.file.SetBindDiagnostics(append(b.file.BindDiagnostics(), diagnostic))
28012765
}
28022766

2803-
func setParent(child *ast.Node, parent *ast.Node) {
2804-
if child != nil {
2805-
child.Parent = parent
2806-
}
2807-
}
2808-
28092767
func isSignedNumericLiteral(node *ast.Node) bool {
28102768
if node.Kind == ast.KindPrefixUnaryExpression {
28112769
node := node.AsPrefixUnaryExpression()

internal/execute/tsc.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ func fmtMain(sys System, input, output string) ExitStatus {
7878
Path: pathified,
7979
JSDocParsingMode: ast.JSDocParsingModeParseAll,
8080
}, text, core.GetScriptKindFromFileName(string(pathified)))
81-
ast.SetParentInChildren(sourceFile.AsNode())
8281
edits := format.FormatDocument(ctx, sourceFile)
8382
newText := applyBulkEdits(text, edits)
8483

internal/format/api_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ func TestFormat(t *testing.T) {
5959
FileName: "/checker.ts",
6060
Path: "/checker.ts",
6161
}, text, core.ScriptKindTS)
62-
ast.SetParentInChildren(sourceFile.AsNode())
6362
edits := format.FormatDocument(ctx, sourceFile)
6463
newText := applyBulkEdits(text, edits)
6564
assert.Assert(t, len(newText) > 0)
@@ -89,7 +88,6 @@ func BenchmarkFormat(b *testing.B) {
8988
FileName: "/checker.ts",
9089
Path: "/checker.ts",
9190
}, text, core.ScriptKindTS)
92-
ast.SetParentInChildren(sourceFile.AsNode())
9391

9492
b.Run("format checker.ts", func(b *testing.B) {
9593
for b.Loop() {

internal/parser/jsdoc.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,6 @@ func (p *Parser) parseJSDocTypeExpression(mayOmitBraces bool) *ast.Node {
8282
}
8383

8484
result := p.factory.NewJSDocTypeExpression(t)
85-
// normally parent references are set during binding. However, for clients that only need
86-
// a syntax tree, and no semantic features, then the binding process is an unnecessary
87-
// overhead. This functions allows us to set all the parents, without all the expense of
88-
// binding.
89-
ast.SetParentInChildren(result)
9085
p.finishNode(result, pos)
9186
return result
9287
}
@@ -107,7 +102,6 @@ func (p *Parser) parseJSDocNameReference() *ast.Node {
107102
}
108103

109104
result := p.factory.NewJSDocNameReference(entityName)
110-
ast.SetParentInChildren(result)
111105
p.finishNode(result, pos)
112106
return result
113107
}
@@ -145,7 +139,6 @@ func (p *Parser) parseJSDocComment(parent *ast.Node, start int, end int, fullSta
145139
p.parsingContexts = p.parsingContexts | ParsingContexts(PCJSDocComment)
146140

147141
comment := p.parseJSDocCommentWorker(start, end, fullStart, initialIndent)
148-
comment.Parent = parent
149142
// move jsdoc diagnostics to jsdocDiagnostics -- for JS files only
150143
if p.contextFlags&ast.NodeFlagsJavaScriptFile != 0 {
151144
p.jsdocDiagnostics = append(p.jsdocDiagnostics, p.diagnostics[saveDiagnosticsLength:]...)
@@ -457,7 +450,6 @@ func (p *Parser) parseTag(tags []*ast.Node, margin int) *ast.Node {
457450
tag = p.parseSeeTag(start, tagName, margin, indentText)
458451
case "import":
459452
tag = p.parseImportTag(start, tagName, margin, indentText)
460-
ast.SetParentInChildren(tag)
461453
default:
462454
tag = p.parseUnknownTag(start, tagName, margin, indentText)
463455
}

internal/parser/parser.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,15 @@ func (p *Parser) finishSourceFile(result *ast.SourceFile, isDeclarationFile bool
352352
result.TextCount = p.factory.TextCount()
353353
result.IdentifierCount = p.identifierCount
354354
result.SetJSDocCache(p.jsdocCache)
355+
356+
ast.SetParentInChildren(result.AsNode())
357+
for parent, children := range p.jsdocCache {
358+
for _, child := range children {
359+
child.Parent = parent
360+
ast.SetParentInChildren(child)
361+
}
362+
}
363+
355364
ast.SetExternalModuleIndicator(result, p.opts.ExternalModuleIndicatorOptions)
356365
}
357366

internal/parser/references.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ func collectExternalModuleReferences(file *ast.SourceFile) {
1515

1616
if file.Flags&ast.NodeFlagsPossiblyContainsDynamicImport != 0 || ast.IsInJSFile(file.AsNode()) {
1717
ast.ForEachDynamicImportOrRequireCall(file /*includeTypeSpaceImports*/, true /*requireStringLiteralLikeArgument*/, true, func(node *ast.Node, moduleSpecifier *ast.Expression) bool {
18-
ast.SetParentInChildren(node) // we need parent data on imports before the program is fully bound, so we ensure it's set here
1918
ast.SetImportsOfSourceFile(file, append(file.Imports(), moduleSpecifier))
2019
return false
2120
})
@@ -31,9 +30,6 @@ func collectModuleReferences(file *ast.SourceFile, node *ast.Statement, inAmbien
3130
if moduleNameExpr != nil && ast.IsStringLiteral(moduleNameExpr) {
3231
moduleName := moduleNameExpr.AsStringLiteral().Text
3332
if moduleName != "" && (!inAmbientModule || !tspath.IsExternalModuleNameRelative(moduleName)) {
34-
if node.Kind != ast.KindJSImportDeclaration {
35-
ast.SetParentInChildren(node) // we need parent data on imports before the program is fully bound, so we ensure it's set here
36-
}
3733
ast.SetImportsOfSourceFile(file, append(file.Imports(), moduleNameExpr))
3834
// !!! removed `&& p.currentNodeModulesDepth == 0`
3935
if file.UsesUriStyleNodeCoreModules != core.TSTrue && !file.IsDeclarationFile {
@@ -50,7 +46,6 @@ func collectModuleReferences(file *ast.SourceFile, node *ast.Statement, inAmbien
5046
return
5147
}
5248
if ast.IsModuleDeclaration(node) && ast.IsAmbientModule(node) && (inAmbientModule || ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient) || file.IsDeclarationFile) {
53-
ast.SetParentInChildren(node)
5449
nameText := node.AsModuleDeclaration().Name().Text()
5550
// Ambient module declarations can be interpreted as augmentations for some existing external modules.
5651
// This will happen in two cases:

0 commit comments

Comments
 (0)