@@ -26,7 +26,6 @@ type ProgramOptions struct {
26
26
Host CompilerHost
27
27
Config * tsoptions.ParsedCommandLine
28
28
UseSourceOfProjectReference bool
29
- SingleThreaded core.Tristate
30
29
CreateCheckerPool func (* Program ) CheckerPool
31
30
TypingsLocation string
32
31
ProjectName string
@@ -39,7 +38,11 @@ func (p *ProgramOptions) canUseProjectReferenceSource() bool {
39
38
type Program struct {
40
39
opts ProgramOptions
41
40
nodeModules map [string ]* ast.SourceFile
42
- checkerPool CheckerPool
41
+
42
+ concurrency concurrency
43
+ concurrencyOnce sync.Once
44
+ checkerPool CheckerPool
45
+ checkerPoolOnce sync.Once
43
46
44
47
comparePathsOptions tspath.ComparePathsOptions
45
48
@@ -191,9 +194,6 @@ func NewProgram(opts ProgramOptions) *Program {
191
194
if p .opts .Host == nil {
192
195
panic ("host required" )
193
196
}
194
- p .initCheckerPool ()
195
-
196
- // p.maxNodeModuleJsDepth = p.options.MaxNodeModuleJsDepth
197
197
198
198
// TODO(ercornel): !!! tracing?
199
199
// tracing?.push(tracing.Phase.Program, "createProgram", { configFilePath: options.configFilePath, rootDir: options.rootDir }, /*separateBeginAndEnd*/ true);
@@ -239,7 +239,6 @@ func (p *Program) UpdateProgram(changedFilePath tspath.Path) (*Program, bool) {
239
239
currentNodeModulesDepth : p .currentNodeModulesDepth ,
240
240
usesUriStyleNodeCoreModules : p .usesUriStyleNodeCoreModules ,
241
241
}
242
- result .initCheckerPool ()
243
242
index := core .FindIndex (result .files , func (file * ast.SourceFile ) bool { return file .Path () == newFile .Path () })
244
243
result .files = slices .Clone (result .files )
245
244
result .files [index ] = newFile
@@ -248,14 +247,6 @@ func (p *Program) UpdateProgram(changedFilePath tspath.Path) (*Program, bool) {
248
247
return result , true
249
248
}
250
249
251
- func (p * Program ) initCheckerPool () {
252
- if p .opts .CreateCheckerPool != nil {
253
- p .checkerPool = p .opts .CreateCheckerPool (p )
254
- } else {
255
- p .checkerPool = newCheckerPool (core .IfElse (p .singleThreaded (), 1 , 4 ), p )
256
- }
257
- }
258
-
259
250
func canReplaceFileInProgram (file1 * ast.SourceFile , file2 * ast.SourceFile ) bool {
260
251
// TODO(jakebailey): metadata??
261
252
return file2 != nil &&
@@ -299,8 +290,26 @@ func (p *Program) GetConfigFileParsingDiagnostics() []*ast.Diagnostic {
299
290
return slices .Clip (p .opts .Config .GetConfigFileParsingDiagnostics ())
300
291
}
301
292
293
+ func (p * Program ) getConcurrency () concurrency {
294
+ p .concurrencyOnce .Do (func () {
295
+ p .concurrency = parseConcurrency (p .Options (), len (p .files ))
296
+ })
297
+ return p .concurrency
298
+ }
299
+
302
300
func (p * Program ) singleThreaded () bool {
303
- return p .opts .SingleThreaded .DefaultIfUnknown (p .Options ().SingleThreaded ).IsTrue ()
301
+ return p .getConcurrency ().isSingleThreaded ()
302
+ }
303
+
304
+ func (p * Program ) getCheckerPool () CheckerPool {
305
+ p .checkerPoolOnce .Do (func () {
306
+ if p .opts .CreateCheckerPool != nil {
307
+ p .checkerPool = p .opts .CreateCheckerPool (p )
308
+ } else {
309
+ p .checkerPool = newCheckerPool (p .getConcurrency ().getCheckerCount (len (p .files )), p )
310
+ }
311
+ })
312
+ return p .checkerPool
304
313
}
305
314
306
315
func (p * Program ) BindSourceFiles () {
@@ -317,11 +326,11 @@ func (p *Program) BindSourceFiles() {
317
326
318
327
func (p * Program ) CheckSourceFiles (ctx context.Context ) {
319
328
wg := core .NewWorkGroup (p .singleThreaded ())
320
- checkers , done := p .checkerPool .GetAllCheckers (ctx )
329
+ checkers , done := p .getCheckerPool () .GetAllCheckers (ctx )
321
330
defer done ()
322
331
for _ , checker := range checkers {
323
332
wg .Queue (func () {
324
- for file := range p .checkerPool .Files (checker ) {
333
+ for file := range p .getCheckerPool () .Files (checker ) {
325
334
checker .CheckSourceFile (ctx , file )
326
335
}
327
336
})
@@ -331,19 +340,19 @@ func (p *Program) CheckSourceFiles(ctx context.Context) {
331
340
332
341
// Return the type checker associated with the program.
333
342
func (p * Program ) GetTypeChecker (ctx context.Context ) (* checker.Checker , func ()) {
334
- return p .checkerPool .GetChecker (ctx )
343
+ return p .getCheckerPool () .GetChecker (ctx )
335
344
}
336
345
337
346
func (p * Program ) GetTypeCheckers (ctx context.Context ) ([]* checker.Checker , func ()) {
338
- return p .checkerPool .GetAllCheckers (ctx )
347
+ return p .getCheckerPool () .GetAllCheckers (ctx )
339
348
}
340
349
341
350
// Return a checker for the given file. We may have multiple checkers in concurrent scenarios and this
342
351
// method returns the checker that was tasked with checking the file. Note that it isn't possible to mix
343
352
// types obtained from different checkers, so only non-type data (such as diagnostics or string
344
353
// representations of types) should be obtained from checkers returned by this method.
345
354
func (p * Program ) GetTypeCheckerForFile (ctx context.Context , file * ast.SourceFile ) (* checker.Checker , func ()) {
346
- return p .checkerPool .GetCheckerForFile (ctx , file )
355
+ return p .getCheckerPool () .GetCheckerForFile (ctx , file )
347
356
}
348
357
349
358
func (p * Program ) GetResolvedModule (file ast.HasFileName , moduleReference string , mode core.ResolutionMode ) * module.ResolvedModule {
@@ -385,7 +394,7 @@ func (p *Program) GetSuggestionDiagnostics(ctx context.Context, sourceFile *ast.
385
394
386
395
func (p * Program ) GetGlobalDiagnostics (ctx context.Context ) []* ast.Diagnostic {
387
396
var globalDiagnostics []* ast.Diagnostic
388
- checkers , done := p .checkerPool .GetAllCheckers (ctx )
397
+ checkers , done := p .getCheckerPool () .GetAllCheckers (ctx )
389
398
defer done ()
390
399
for _ , checker := range checkers {
391
400
globalDiagnostics = append (globalDiagnostics , checker .GetGlobalDiagnostics ()... )
@@ -432,11 +441,11 @@ func (p *Program) getSemanticDiagnosticsForFile(ctx context.Context, sourceFile
432
441
var fileChecker * checker.Checker
433
442
var done func ()
434
443
if sourceFile != nil {
435
- fileChecker , done = p .checkerPool .GetCheckerForFile (ctx , sourceFile )
444
+ fileChecker , done = p .getCheckerPool () .GetCheckerForFile (ctx , sourceFile )
436
445
defer done ()
437
446
}
438
447
diags := slices .Clip (sourceFile .BindDiagnostics ())
439
- checkers , closeCheckers := p .checkerPool .GetAllCheckers (ctx )
448
+ checkers , closeCheckers := p .getCheckerPool () .GetAllCheckers (ctx )
440
449
defer closeCheckers ()
441
450
442
451
// Ask for diags from all checkers; checking one file may add diagnostics to other files.
@@ -523,13 +532,13 @@ func (p *Program) getSuggestionDiagnosticsForFile(ctx context.Context, sourceFil
523
532
var fileChecker * checker.Checker
524
533
var done func ()
525
534
if sourceFile != nil {
526
- fileChecker , done = p .checkerPool .GetCheckerForFile (ctx , sourceFile )
535
+ fileChecker , done = p .getCheckerPool () .GetCheckerForFile (ctx , sourceFile )
527
536
defer done ()
528
537
}
529
538
530
539
diags := slices .Clip (sourceFile .BindSuggestionDiagnostics )
531
540
532
- checkers , closeCheckers := p .checkerPool .GetAllCheckers (ctx )
541
+ checkers , closeCheckers := p .getCheckerPool () .GetAllCheckers (ctx )
533
542
defer closeCheckers ()
534
543
535
544
// Ask for diags from all checkers; checking one file may add diagnostics to other files.
@@ -640,7 +649,7 @@ func (p *Program) SymbolCount() int {
640
649
for _ , file := range p .files {
641
650
count += file .SymbolCount
642
651
}
643
- checkers , done := p .checkerPool .GetAllCheckers (context .Background ())
652
+ checkers , done := p .getCheckerPool () .GetAllCheckers (context .Background ())
644
653
defer done ()
645
654
for _ , checker := range checkers {
646
655
count += int (checker .SymbolCount )
@@ -650,7 +659,7 @@ func (p *Program) SymbolCount() int {
650
659
651
660
func (p * Program ) TypeCount () int {
652
661
var count int
653
- checkers , done := p .checkerPool .GetAllCheckers (context .Background ())
662
+ checkers , done := p .getCheckerPool () .GetAllCheckers (context .Background ())
654
663
defer done ()
655
664
for _ , checker := range checkers {
656
665
count += int (checker .TypeCount )
@@ -660,7 +669,7 @@ func (p *Program) TypeCount() int {
660
669
661
670
func (p * Program ) InstantiationCount () int {
662
671
var count int
663
- checkers , done := p .checkerPool .GetAllCheckers (context .Background ())
672
+ checkers , done := p .getCheckerPool () .GetAllCheckers (context .Background ())
664
673
defer done ()
665
674
for _ , checker := range checkers {
666
675
count += int (checker .TotalInstantiationCount )
0 commit comments