Skip to content

Commit 36be503

Browse files
jakebaileyCopilot
andauthored
Make SourceFileAffectingCompilerOptions hold fully computed values, use in binder (microsoft#788)
Co-authored-by: Copilot <[email protected]>
1 parent 1849e6b commit 36be503

12 files changed

+81
-72
lines changed

internal/binder/binder.go

+11-11
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const (
4040

4141
type Binder struct {
4242
file *ast.SourceFile
43-
options *core.CompilerOptions
43+
options *core.SourceFileAffectingCompilerOptions
4444
languageVersion core.ScriptTarget
4545
bindFunc func(*ast.Node) bool
4646
unreachableFlow *ast.FlowNode
@@ -86,7 +86,7 @@ type ActiveLabel struct {
8686
func (label *ActiveLabel) BreakTarget() *ast.FlowNode { return label.breakTarget }
8787
func (label *ActiveLabel) ContinueTarget() *ast.FlowNode { return label.continueTarget }
8888

89-
func BindSourceFile(file *ast.SourceFile, options *core.CompilerOptions) {
89+
func BindSourceFile(file *ast.SourceFile, options *core.SourceFileAffectingCompilerOptions) {
9090
// This is constructed this way to make the compiler "out-line" the function,
9191
// avoiding most work in the common case where the file has already been bound.
9292
if !file.IsBound() {
@@ -111,14 +111,14 @@ func putBinder(b *Binder) {
111111
binderPool.Put(b)
112112
}
113113

114-
func bindSourceFile(file *ast.SourceFile, options *core.CompilerOptions) {
114+
func bindSourceFile(file *ast.SourceFile, options *core.SourceFileAffectingCompilerOptions) {
115115
file.BindOnce(func() {
116116
b := getBinder()
117117
defer putBinder(b)
118118
b.file = file
119119
b.options = options
120-
b.languageVersion = options.GetEmitScriptTarget()
121-
b.inStrictMode = (options.AlwaysStrict.IsTrue() || options.Strict.IsTrue()) && !file.IsDeclarationFile || ast.IsExternalModule(file)
120+
b.languageVersion = options.EmitScriptTarget
121+
b.inStrictMode = options.BindInStrictMode && !file.IsDeclarationFile || ast.IsExternalModule(file)
122122
b.unreachableFlow = b.newFlowNode(ast.FlowFlagsUnreachable)
123123
b.reportedUnreachableFlow = b.newFlowNode(ast.FlowFlagsUnreachable)
124124
b.bind(file.AsNode())
@@ -1331,7 +1331,7 @@ func (b *Binder) checkStrictModeWithStatement(node *ast.Node) {
13311331

13321332
func (b *Binder) checkStrictModeLabeledStatement(node *ast.Node) {
13331333
// Grammar checking for labeledStatement
1334-
if b.inStrictMode && b.options.Target >= core.ScriptTargetES2015 {
1334+
if b.inStrictMode && b.options.EmitScriptTarget >= core.ScriptTargetES2015 {
13351335
data := node.AsLabeledStatement()
13361336
if ast.IsDeclarationStatement(data.Statement) || ast.IsVariableStatement(data.Statement) {
13371337
b.errorOnFirstToken(data.Label, diagnostics.A_label_is_not_allowed_here)
@@ -1665,7 +1665,7 @@ func (b *Binder) checkUnreachable(node *ast.Node) bool {
16651665

16661666
func (b *Binder) shouldReportErrorOnModuleDeclaration(node *ast.Node) bool {
16671667
instanceState := ast.GetModuleInstanceState(node)
1668-
return instanceState == ast.ModuleInstanceStateInstantiated || (instanceState == ast.ModuleInstanceStateConstEnumOnly && b.options.ShouldPreserveConstEnums())
1668+
return instanceState == ast.ModuleInstanceStateInstantiated || (instanceState == ast.ModuleInstanceStateConstEnumOnly && b.options.ShouldPreserveConstEnums)
16691669
}
16701670

16711671
func (b *Binder) errorOnEachUnreachableRange(node *ast.Node, isError bool) {
@@ -2421,8 +2421,8 @@ func (b *Binder) bindInitializer(node *ast.Node) {
24212421
b.currentFlow = b.finishFlowLabel(exitFlow)
24222422
}
24232423

2424-
func isEnumDeclarationWithPreservedEmit(node *ast.Node, options *core.CompilerOptions) bool {
2425-
return node.Kind == ast.KindEnumDeclaration && (!ast.IsEnumConst(node) || options.ShouldPreserveConstEnums())
2424+
func isEnumDeclarationWithPreservedEmit(node *ast.Node, options *core.SourceFileAffectingCompilerOptions) bool {
2425+
return node.Kind == ast.KindEnumDeclaration && (!ast.IsEnumConst(node) || options.ShouldPreserveConstEnums)
24262426
}
24272427

24282428
func setFlowNode(node *ast.Node, flowNode *ast.FlowNode) {
@@ -2746,11 +2746,11 @@ func isFunctionSymbol(symbol *ast.Symbol) bool {
27462746
return false
27472747
}
27482748

2749-
func unreachableCodeIsError(options *core.CompilerOptions) bool {
2749+
func unreachableCodeIsError(options *core.SourceFileAffectingCompilerOptions) bool {
27502750
return options.AllowUnreachableCode == core.TSFalse
27512751
}
27522752

2753-
func unusedLabelIsError(options *core.CompilerOptions) bool {
2753+
func unusedLabelIsError(options *core.SourceFileAffectingCompilerOptions) bool {
27542754
return options.AllowUnusedLabels == core.TSFalse
27552755
}
27562756

internal/binder/binder_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func BenchmarkBind(b *testing.B) {
2828
}
2929

3030
compilerOptions := &core.CompilerOptions{Target: core.ScriptTargetESNext, ModuleKind: core.ModuleKindNodeNext}
31+
sourceAffecting := compilerOptions.SourceFileAffecting()
3132

3233
// The above parses do a lot of work; ensure GC is finished before we start collecting performance data.
3334
// GC must be called twice to allow things to settle.
@@ -36,7 +37,7 @@ func BenchmarkBind(b *testing.B) {
3637

3738
b.ResetTimer()
3839
for i := range b.N {
39-
BindSourceFile(sourceFiles[i], compilerOptions)
40+
BindSourceFile(sourceFiles[i], sourceAffecting)
4041
}
4142
})
4243
}

internal/compiler/program.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ type Program struct {
4141
currentDirectory string
4242
configFileParsingDiagnostics []*ast.Diagnostic
4343

44+
sourceAffectingCompilerOptionsOnce sync.Once
45+
sourceAffectingCompilerOptions *core.SourceFileAffectingCompilerOptions
46+
4447
resolver *module.Resolver
4548

4649
comparePathsOptions tspath.ComparePathsOptions
@@ -184,12 +187,19 @@ func (p *Program) GetConfigFileParsingDiagnostics() []*ast.Diagnostic {
184187
return slices.Clip(p.configFileParsingDiagnostics)
185188
}
186189

190+
func (p *Program) getSourceAffectingCompilerOptions() *core.SourceFileAffectingCompilerOptions {
191+
p.sourceAffectingCompilerOptionsOnce.Do(func() {
192+
p.sourceAffectingCompilerOptions = p.compilerOptions.SourceFileAffecting()
193+
})
194+
return p.sourceAffectingCompilerOptions
195+
}
196+
187197
func (p *Program) BindSourceFiles() {
188198
wg := core.NewWorkGroup(p.programOptions.SingleThreaded)
189199
for _, file := range p.files {
190200
if !file.IsBound() {
191201
wg.Queue(func() {
192-
binder.BindSourceFile(file, p.compilerOptions)
202+
binder.BindSourceFile(file, p.getSourceAffectingCompilerOptions())
193203
})
194204
}
195205
}
@@ -388,7 +398,7 @@ func SortAndDeduplicateDiagnostics(diagnostics []*ast.Diagnostic) []*ast.Diagnos
388398
func (p *Program) getDiagnosticsHelper(sourceFile *ast.SourceFile, ensureBound bool, ensureChecked bool, getDiagnostics func(*ast.SourceFile) []*ast.Diagnostic) []*ast.Diagnostic {
389399
if sourceFile != nil {
390400
if ensureBound {
391-
binder.BindSourceFile(sourceFile, p.compilerOptions)
401+
binder.BindSourceFile(sourceFile, p.getSourceAffectingCompilerOptions())
392402
}
393403
return SortAndDeduplicateDiagnostics(getDiagnostics(sourceFile))
394404
}

internal/core/compileroptions.go

+16-25
Original file line numberDiff line numberDiff line change
@@ -269,34 +269,25 @@ func (options *CompilerOptions) HasJsonModuleEmitEnabled() bool {
269269
return true
270270
}
271271

272-
// SourceFileAffectingCompilerOptions are the CompilerOptions values that when
273-
// changed require a new SourceFile be created.
272+
// SourceFileAffectingCompilerOptions are the precomputed CompilerOptions values which
273+
// affect the parse and bind of a source file.
274274
type SourceFileAffectingCompilerOptions struct {
275-
// !!! generate this
276-
Target ScriptTarget
277-
Jsx JsxEmit
278-
JsxImportSource string
279-
ImportHelpers Tristate
280-
AlwaysStrict Tristate
281-
ModuleDetection ModuleDetectionKind
282-
AllowUnreachableCode Tristate
283-
AllowUnusedLabels Tristate
284-
PreserveConstEnums Tristate
285-
IsolatedModules Tristate
275+
AllowUnreachableCode Tristate
276+
AllowUnusedLabels Tristate
277+
BindInStrictMode bool
278+
EmitScriptTarget ScriptTarget
279+
NoFallthroughCasesInSwitch Tristate
280+
ShouldPreserveConstEnums bool
286281
}
287282

288-
func (options *CompilerOptions) SourceFileAffecting() SourceFileAffectingCompilerOptions {
289-
return SourceFileAffectingCompilerOptions{
290-
Target: options.Target,
291-
Jsx: options.Jsx,
292-
JsxImportSource: options.JsxImportSource,
293-
ImportHelpers: options.ImportHelpers,
294-
AlwaysStrict: options.AlwaysStrict,
295-
ModuleDetection: options.ModuleDetection,
296-
AllowUnreachableCode: options.AllowUnreachableCode,
297-
AllowUnusedLabels: options.AllowUnusedLabels,
298-
PreserveConstEnums: options.PreserveConstEnums,
299-
IsolatedModules: options.IsolatedModules,
283+
func (options *CompilerOptions) SourceFileAffecting() *SourceFileAffectingCompilerOptions {
284+
return &SourceFileAffectingCompilerOptions{
285+
AllowUnreachableCode: options.AllowUnreachableCode,
286+
AllowUnusedLabels: options.AllowUnusedLabels,
287+
BindInStrictMode: options.AlwaysStrict.IsTrue() || options.Strict.IsTrue(),
288+
EmitScriptTarget: options.GetEmitScriptTarget(),
289+
NoFallthroughCasesInSwitch: options.NoFallthroughCasesInSwitch,
290+
ShouldPreserveConstEnums: options.ShouldPreserveConstEnums(),
300291
}
301292
}
302293

internal/printer/namegenerator_test.go

+23-21
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"gotest.tools/v3/assert"
1212
)
1313

14+
var defaultSourceFileAffectingOptions = (&core.CompilerOptions{}).SourceFileAffecting()
15+
1416
func TestTempVariable1(t *testing.T) {
1517
t.Parallel()
1618

@@ -257,7 +259,7 @@ func TestGeneratedNameForIdentifier1(t *testing.T) {
257259
ec := printer.NewEmitContext()
258260

259261
file := parsetestutil.ParseTypeScript("function f() {}", false /*jsx*/)
260-
binder.BindSourceFile(file, &core.CompilerOptions{})
262+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
261263

262264
n := file.Statements.Nodes[0].Name()
263265
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -274,7 +276,7 @@ func TestGeneratedNameForIdentifier2(t *testing.T) {
274276
ec := printer.NewEmitContext()
275277

276278
file := parsetestutil.ParseTypeScript("function f() {}", false /*jsx*/)
277-
binder.BindSourceFile(file, &core.CompilerOptions{})
279+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
278280

279281
n := file.Statements.Nodes[0].Name()
280282
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{
@@ -294,7 +296,7 @@ func TestGeneratedNameForIdentifier3(t *testing.T) {
294296
ec := printer.NewEmitContext()
295297

296298
file := parsetestutil.ParseTypeScript("function f() {}", false /*jsx*/)
297-
binder.BindSourceFile(file, &core.CompilerOptions{})
299+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
298300

299301
n := file.Statements.Nodes[0].Name()
300302
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{
@@ -316,7 +318,7 @@ func TestGeneratedNameForNamespace1(t *testing.T) {
316318
ec := printer.NewEmitContext()
317319

318320
file := parsetestutil.ParseTypeScript("namespace foo { }", false /*jsx*/)
319-
binder.BindSourceFile(file, &core.CompilerOptions{})
321+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
320322

321323
ns1 := file.Statements.Nodes[0]
322324
name1 := ec.NewGeneratedNameForNode(ns1, printer.AutoGenerateOptions{})
@@ -334,7 +336,7 @@ func TestGeneratedNameForNamespace2(t *testing.T) {
334336
ec := printer.NewEmitContext()
335337

336338
file := parsetestutil.ParseTypeScript("namespace foo { var foo; }", false /*jsx*/)
337-
binder.BindSourceFile(file, &core.CompilerOptions{})
339+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
338340

339341
ns1 := file.Statements.Nodes[0]
340342
name1 := ec.NewGeneratedNameForNode(ns1, printer.AutoGenerateOptions{})
@@ -352,7 +354,7 @@ func TestGeneratedNameForNamespace3(t *testing.T) {
352354
ec := printer.NewEmitContext()
353355

354356
file := parsetestutil.ParseTypeScript("namespace ns1 { namespace foo { var foo; } } namespace ns2 { namespace foo { var foo; } }", false /*jsx*/)
355-
binder.BindSourceFile(file, &core.CompilerOptions{})
357+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
356358

357359
ns1 := file.Statements.Nodes[0].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0]
358360
ns2 := file.Statements.Nodes[1].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0]
@@ -374,7 +376,7 @@ func TestGeneratedNameForNamespace4(t *testing.T) {
374376
ec := printer.NewEmitContext()
375377

376378
file := parsetestutil.ParseTypeScript("namespace ns1 { namespace foo { var foo; } } namespace ns2 { namespace foo { var foo; } }", false /*jsx*/)
377-
binder.BindSourceFile(file, &core.CompilerOptions{})
379+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
378380

379381
ns1 := file.Statements.Nodes[0].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0]
380382
ns2 := file.Statements.Nodes[1].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0]
@@ -400,7 +402,7 @@ func TestGeneratedNameForNodeCached(t *testing.T) {
400402
ec := printer.NewEmitContext()
401403

402404
file := parsetestutil.ParseTypeScript("namespace foo { var foo; }", false /*jsx*/)
403-
binder.BindSourceFile(file, &core.CompilerOptions{})
405+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
404406

405407
ns1 := file.Statements.Nodes[0]
406408
name1 := ec.NewGeneratedNameForNode(ns1, printer.AutoGenerateOptions{})
@@ -420,7 +422,7 @@ func TestGeneratedNameForImport(t *testing.T) {
420422
ec := printer.NewEmitContext()
421423

422424
file := parsetestutil.ParseTypeScript("import * as foo from 'foo'", false /*jsx*/)
423-
binder.BindSourceFile(file, &core.CompilerOptions{})
425+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
424426

425427
n := file.Statements.Nodes[0]
426428
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -437,7 +439,7 @@ func TestGeneratedNameForExport(t *testing.T) {
437439
ec := printer.NewEmitContext()
438440

439441
file := parsetestutil.ParseTypeScript("export * as foo from 'foo'", false /*jsx*/)
440-
binder.BindSourceFile(file, &core.CompilerOptions{})
442+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
441443

442444
n := file.Statements.Nodes[0]
443445
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -454,7 +456,7 @@ func TestGeneratedNameForFunctionDeclaration1(t *testing.T) {
454456
ec := printer.NewEmitContext()
455457

456458
file := parsetestutil.ParseTypeScript("export function f() {}", false /*jsx*/)
457-
binder.BindSourceFile(file, &core.CompilerOptions{})
459+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
458460

459461
n := file.Statements.Nodes[0]
460462
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -471,7 +473,7 @@ func TestGeneratedNameForFunctionDeclaration2(t *testing.T) {
471473
ec := printer.NewEmitContext()
472474

473475
file := parsetestutil.ParseTypeScript("export default function () {}", false /*jsx*/)
474-
binder.BindSourceFile(file, &core.CompilerOptions{})
476+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
475477

476478
n := file.Statements.Nodes[0]
477479
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -488,7 +490,7 @@ func TestGeneratedNameForClassDeclaration1(t *testing.T) {
488490
ec := printer.NewEmitContext()
489491

490492
file := parsetestutil.ParseTypeScript("export class C {}", false /*jsx*/)
491-
binder.BindSourceFile(file, &core.CompilerOptions{})
493+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
492494

493495
n := file.Statements.Nodes[0]
494496
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -505,7 +507,7 @@ func TestGeneratedNameForClassDeclaration2(t *testing.T) {
505507
ec := printer.NewEmitContext()
506508

507509
file := parsetestutil.ParseTypeScript("export default class {}", false /*jsx*/)
508-
binder.BindSourceFile(file, &core.CompilerOptions{})
510+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
509511

510512
n := file.Statements.Nodes[0]
511513
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -522,7 +524,7 @@ func TestGeneratedNameForExportAssignment(t *testing.T) {
522524
ec := printer.NewEmitContext()
523525

524526
file := parsetestutil.ParseTypeScript("export default 0", false /*jsx*/)
525-
binder.BindSourceFile(file, &core.CompilerOptions{})
527+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
526528

527529
n := file.Statements.Nodes[0]
528530
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -539,7 +541,7 @@ func TestGeneratedNameForClassExpression(t *testing.T) {
539541
ec := printer.NewEmitContext()
540542

541543
file := parsetestutil.ParseTypeScript("(class {})", false /*jsx*/)
542-
binder.BindSourceFile(file, &core.CompilerOptions{})
544+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
543545

544546
n := file.Statements.Nodes[0].AsExpressionStatement().Expression.AsParenthesizedExpression().Expression
545547
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -556,7 +558,7 @@ func TestGeneratedNameForMethod1(t *testing.T) {
556558
ec := printer.NewEmitContext()
557559

558560
file := parsetestutil.ParseTypeScript("class C { m() {} }", false /*jsx*/)
559-
binder.BindSourceFile(file, &core.CompilerOptions{})
561+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
560562

561563
n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0]
562564
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -573,7 +575,7 @@ func TestGeneratedNameForMethod2(t *testing.T) {
573575
ec := printer.NewEmitContext()
574576

575577
file := parsetestutil.ParseTypeScript("class C { 0() {} }", false /*jsx*/)
576-
binder.BindSourceFile(file, &core.CompilerOptions{})
578+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
577579

578580
n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0]
579581
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -590,7 +592,7 @@ func TestGeneratedPrivateNameForMethod(t *testing.T) {
590592
ec := printer.NewEmitContext()
591593

592594
file := parsetestutil.ParseTypeScript("class C { m() {} }", false /*jsx*/)
593-
binder.BindSourceFile(file, &core.CompilerOptions{})
595+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
594596

595597
n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0]
596598
name1 := ec.NewGeneratedPrivateNameForNode(n, printer.AutoGenerateOptions{})
@@ -607,7 +609,7 @@ func TestGeneratedNameForComputedPropertyName(t *testing.T) {
607609
ec := printer.NewEmitContext()
608610

609611
file := parsetestutil.ParseTypeScript("class C { [x] }", false /*jsx*/)
610-
binder.BindSourceFile(file, &core.CompilerOptions{})
612+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
611613

612614
n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0].Name()
613615
name1 := ec.NewGeneratedNameForNode(n, printer.AutoGenerateOptions{})
@@ -624,7 +626,7 @@ func TestGeneratedNameForOther(t *testing.T) {
624626
ec := printer.NewEmitContext()
625627

626628
file := parsetestutil.ParseTypeScript("class C { [x] }", false /*jsx*/)
627-
binder.BindSourceFile(file, &core.CompilerOptions{})
629+
binder.BindSourceFile(file, defaultSourceFileAffectingOptions)
628630

629631
n := ec.Factory.NewObjectLiteralExpression(
630632
ec.Factory.NewNodeList([]*ast.Node{}),

internal/project/documentregistry.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type registryKey struct {
1919

2020
func newRegistryKey(options *core.CompilerOptions, path tspath.Path, scriptKind core.ScriptKind) registryKey {
2121
return registryKey{
22-
SourceFileAffectingCompilerOptions: options.SourceFileAffecting(),
22+
SourceFileAffectingCompilerOptions: *options.SourceFileAffecting(),
2323
path: path,
2424
scriptKind: scriptKind,
2525
}

0 commit comments

Comments
 (0)