From 253c2fb3c6bfadeafc9dfde330142ea5823628a8 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:20:47 -0800 Subject: [PATCH 1/2] Never create more checkers than files in a program --- internal/compiler/checkerpool.go | 11 ++++++++++- internal/compiler/fileloader.go | 2 ++ internal/compiler/program.go | 14 ++++++-------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/internal/compiler/checkerpool.go b/internal/compiler/checkerpool.go index 50025dd7ed..e6bb85b62b 100644 --- a/internal/compiler/checkerpool.go +++ b/internal/compiler/checkerpool.go @@ -32,7 +32,16 @@ type checkerPool struct { var _ CheckerPool = (*checkerPool)(nil) -func newCheckerPool(checkerCount int, program *Program) *checkerPool { +func newCheckerPool(program *Program) *checkerPool { + checkerCount := 4 + if program.SingleThreaded() { + checkerCount = 1 + } else if c := program.Options().Checkers; c != nil { + checkerCount = *c + } + + checkerCount = min(max(checkerCount, 1), len(program.files), 256) + pool := &checkerPool{ program: program, checkerCount: checkerCount, diff --git a/internal/compiler/fileloader.go b/internal/compiler/fileloader.go index ef866d1921..29e9a5851f 100644 --- a/internal/compiler/fileloader.go +++ b/internal/compiler/fileloader.go @@ -69,6 +69,7 @@ type processedFiles struct { // if file was included using source file and its output is actually part of program // this contains mapping from output to source file outputFileToProjectReferenceSource map[tspath.Path]string + finishedProcessing bool } type jsxRuntimeImportSpecifier struct { @@ -236,6 +237,7 @@ func processAllProgramFiles( } return processedFiles{ + finishedProcessing: true, resolver: loader.resolver, files: allFiles, filesByPath: filesByPath, diff --git a/internal/compiler/program.go b/internal/compiler/program.go index f25efc404d..bf2f64b948 100644 --- a/internal/compiler/program.go +++ b/internal/compiler/program.go @@ -222,8 +222,8 @@ func (p *Program) GetSourceFileFromReference(origin *ast.SourceFile, ref *ast.Fi func NewProgram(opts ProgramOptions) *Program { p := &Program{opts: opts} - p.initCheckerPool() p.processedFiles = processAllProgramFiles(p.opts, p.SingleThreaded()) + p.initCheckerPool() p.verifyCompilerOptions() return p } @@ -259,16 +259,14 @@ func (p *Program) UpdateProgram(changedFilePath tspath.Path, newHost CompilerHos } func (p *Program) initCheckerPool() { + if !p.finishedProcessing { + panic("Program must finish processing files before initializing checker pool") + } + if p.opts.CreateCheckerPool != nil { p.checkerPool = p.opts.CreateCheckerPool(p) } else { - checkers := 4 - if p.SingleThreaded() { - checkers = 1 - } else if p.Options().Checkers != nil { - checkers = min(max(*p.Options().Checkers, 1), 256) - } - p.checkerPool = newCheckerPool(checkers, p) + p.checkerPool = newCheckerPool(p) } } From 0210eabecf58643d9e37605c90b8070a46229582 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:27:32 -0800 Subject: [PATCH 2/2] Apply suggestion from @jakebailey --- internal/compiler/checkerpool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/compiler/checkerpool.go b/internal/compiler/checkerpool.go index e6bb85b62b..88b22a6ac1 100644 --- a/internal/compiler/checkerpool.go +++ b/internal/compiler/checkerpool.go @@ -40,7 +40,7 @@ func newCheckerPool(program *Program) *checkerPool { checkerCount = *c } - checkerCount = min(max(checkerCount, 1), len(program.files), 256) + checkerCount = max(min(checkerCount, len(program.files), 256), 1) pool := &checkerPool{ program: program,