From 8031654a82f2d1e983c3fdc2939ef3df3ce50884 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 13 Nov 2025 12:08:33 -0800 Subject: [PATCH 1/2] Unify locks used on checkers between exclusive pool borrows and emitResolver scopes --- internal/checker/checker.go | 7 +++++-- internal/checker/emitresolver.go | 3 ++- internal/compiler/checkerpool.go | 6 +++--- internal/project/checkerpool.go | 2 +- internal/transformers/tstransforms/importelision_test.go | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index ccade6b56f..7acb842061 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -857,12 +857,15 @@ type Checker struct { activeTypeMappersCaches []map[string]*Type ambientModulesOnce sync.Once ambientModules []*ast.Symbol + + lock *sync.Mutex } -func NewChecker(program Program) *Checker { +func NewChecker(program Program) (*Checker, *sync.Mutex) { program.BindSourceFiles() c := &Checker{} + c.lock = &sync.Mutex{} c.id = nextCheckerID.Add(1) c.program = program c.compilerOptions = program.Options() @@ -1071,7 +1074,7 @@ func NewChecker(program Program) *Checker { c.initializeClosures() c.initializeIterationResolvers() c.initializeChecker() - return c + return c, c.lock } func createFileIndexMap(files []*ast.SourceFile) map[*ast.SourceFile]int { diff --git a/internal/checker/emitresolver.go b/internal/checker/emitresolver.go index a40d49b2a9..2ca8d8b8e4 100644 --- a/internal/checker/emitresolver.go +++ b/internal/checker/emitresolver.go @@ -34,7 +34,7 @@ type DeclarationFileLinks struct { type EmitResolver struct { checker *Checker - checkerMu sync.Mutex + checkerMu *sync.Mutex isValueAliasDeclaration func(node *ast.Node) bool aliasMarkingVisitor func(node *ast.Node) bool referenceResolver binder.ReferenceResolver @@ -47,6 +47,7 @@ func newEmitResolver(checker *Checker) *EmitResolver { e := &EmitResolver{checker: checker} e.isValueAliasDeclaration = e.isValueAliasDeclarationWorker e.aliasMarkingVisitor = e.aliasMarkingVisitorWorker + e.checkerMu = checker.lock return e } diff --git a/internal/compiler/checkerpool.go b/internal/compiler/checkerpool.go index f7594696f9..50025dd7ed 100644 --- a/internal/compiler/checkerpool.go +++ b/internal/compiler/checkerpool.go @@ -26,7 +26,7 @@ type checkerPool struct { createCheckersOnce sync.Once checkers []*checker.Checker - locks []sync.Mutex + locks []*sync.Mutex fileAssociations map[*ast.SourceFile]*checker.Checker } @@ -37,7 +37,7 @@ func newCheckerPool(checkerCount int, program *Program) *checkerPool { program: program, checkerCount: checkerCount, checkers: make([]*checker.Checker, checkerCount), - locks: make([]sync.Mutex, checkerCount), + locks: make([]*sync.Mutex, checkerCount), } return pool @@ -74,7 +74,7 @@ func (p *checkerPool) createCheckers() { wg := core.NewWorkGroup(p.program.SingleThreaded()) for i := range p.checkerCount { wg.Queue(func() { - p.checkers[i] = checker.NewChecker(p.program) + p.checkers[i], p.locks[i] = checker.NewChecker(p.program) }) } diff --git a/internal/project/checkerpool.go b/internal/project/checkerpool.go index a83a2e833f..0e1ba1cd04 100644 --- a/internal/project/checkerpool.go +++ b/internal/project/checkerpool.go @@ -218,7 +218,7 @@ func (p *CheckerPool) isFullLocked() bool { func (p *CheckerPool) createCheckerLocked() (*checker.Checker, int) { for i, existing := range p.checkers { if existing == nil { - checker := checker.NewChecker(p.program) + checker, _ := checker.NewChecker(p.program) p.checkers[i] = checker return checker, i } diff --git a/internal/transformers/tstransforms/importelision_test.go b/internal/transformers/tstransforms/importelision_test.go index 3dc5c227cd..5e57db5a6c 100644 --- a/internal/transformers/tstransforms/importelision_test.go +++ b/internal/transformers/tstransforms/importelision_test.go @@ -213,7 +213,7 @@ func TestImportElision(t *testing.T) { compilerOptions := &core.CompilerOptions{} - c := checker.NewChecker(&fakeProgram{ + c, _ := checker.NewChecker(&fakeProgram{ singleThreaded: true, compilerOptions: compilerOptions, files: files, From d97650272263b25c8eda657d6f5c5f051ae9a136 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 13 Nov 2025 13:22:21 -0800 Subject: [PATCH 2/2] Embed and rename lock --- internal/checker/checker.go | 5 ++--- internal/checker/emitresolver.go | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 7acb842061..69a4f7c7f7 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -858,14 +858,13 @@ type Checker struct { ambientModulesOnce sync.Once ambientModules []*ast.Symbol - lock *sync.Mutex + mu sync.Mutex } func NewChecker(program Program) (*Checker, *sync.Mutex) { program.BindSourceFiles() c := &Checker{} - c.lock = &sync.Mutex{} c.id = nextCheckerID.Add(1) c.program = program c.compilerOptions = program.Options() @@ -1074,7 +1073,7 @@ func NewChecker(program Program) (*Checker, *sync.Mutex) { c.initializeClosures() c.initializeIterationResolvers() c.initializeChecker() - return c, c.lock + return c, &c.mu } func createFileIndexMap(files []*ast.SourceFile) map[*ast.SourceFile]int { diff --git a/internal/checker/emitresolver.go b/internal/checker/emitresolver.go index 2ca8d8b8e4..877f2d1831 100644 --- a/internal/checker/emitresolver.go +++ b/internal/checker/emitresolver.go @@ -47,7 +47,7 @@ func newEmitResolver(checker *Checker) *EmitResolver { e := &EmitResolver{checker: checker} e.isValueAliasDeclaration = e.isValueAliasDeclarationWorker e.aliasMarkingVisitor = e.aliasMarkingVisitorWorker - e.checkerMu = checker.lock + e.checkerMu = &checker.mu return e }