From c96bad7ea2f33dfbc3b675954416b26f7319929f Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 10 Jun 2025 14:39:17 -0700 Subject: [PATCH 1/2] Cache CompilerOptions.SourceFileAffecting --- internal/compiler/fileloader.go | 2 +- internal/compiler/program.go | 14 ++-------- internal/core/compileroptions.go | 29 ++++++++++++-------- internal/tsoptions/commandlineparser_test.go | 3 +- internal/tsoptions/tsconfigparsing_test.go | 3 +- 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/internal/compiler/fileloader.go b/internal/compiler/fileloader.go index 075d9f0660..df728f1a60 100644 --- a/internal/compiler/fileloader.go +++ b/internal/compiler/fileloader.go @@ -278,7 +278,7 @@ func (p *fileLoader) loadSourceFileMetaData(fileName string) *ast.SourceFileMeta func (p *fileLoader) parseSourceFile(t *parseTask) *ast.SourceFile { path := p.toPath(t.normalizedFilePath) - sourceFile := p.opts.Host.GetSourceFile(t.normalizedFilePath, path, p.projectReferenceFileMapper.getCompilerOptionsForFile(t).SourceFileAffecting(), t.metadata) // TODO(jakebailey): cache :( + sourceFile := p.opts.Host.GetSourceFile(t.normalizedFilePath, path, p.projectReferenceFileMapper.getCompilerOptionsForFile(t).SourceFileAffecting(), t.metadata) return sourceFile } diff --git a/internal/compiler/program.go b/internal/compiler/program.go index aa66e69f13..202d002c92 100644 --- a/internal/compiler/program.go +++ b/internal/compiler/program.go @@ -41,9 +41,6 @@ type Program struct { nodeModules map[string]*ast.SourceFile checkerPool CheckerPool - sourceAffectingCompilerOptionsOnce sync.Once - sourceAffectingCompilerOptions *core.SourceFileAffectingCompilerOptions - comparePathsOptions tspath.ComparePathsOptions processedFiles @@ -302,19 +299,12 @@ func (p *Program) singleThreaded() bool { return p.opts.SingleThreaded.DefaultIfUnknown(p.Options().SingleThreaded).IsTrue() } -func (p *Program) getSourceAffectingCompilerOptions() *core.SourceFileAffectingCompilerOptions { - p.sourceAffectingCompilerOptionsOnce.Do(func() { - p.sourceAffectingCompilerOptions = p.Options().SourceFileAffecting() - }) - return p.sourceAffectingCompilerOptions -} - func (p *Program) BindSourceFiles() { wg := core.NewWorkGroup(p.singleThreaded()) for _, file := range p.files { if !file.IsBound() { wg.Queue(func() { - binder.BindSourceFile(file, p.getSourceAffectingCompilerOptions()) + binder.BindSourceFile(file, p.Options().SourceFileAffecting()) }) } } @@ -605,7 +595,7 @@ func compactAndMergeRelatedInfos(diagnostics []*ast.Diagnostic) []*ast.Diagnosti func (p *Program) getDiagnosticsHelper(ctx context.Context, sourceFile *ast.SourceFile, ensureBound bool, ensureChecked bool, getDiagnostics func(context.Context, *ast.SourceFile) []*ast.Diagnostic) []*ast.Diagnostic { if sourceFile != nil { if ensureBound { - binder.BindSourceFile(sourceFile, p.getSourceAffectingCompilerOptions()) + binder.BindSourceFile(sourceFile, p.Options().SourceFileAffecting()) } return SortAndDeduplicateDiagnostics(getDiagnostics(ctx, sourceFile)) } diff --git a/internal/core/compileroptions.go b/internal/core/compileroptions.go index 3001df1ea8..e6c7f859e9 100644 --- a/internal/core/compileroptions.go +++ b/internal/core/compileroptions.go @@ -3,6 +3,7 @@ package core import ( "reflect" "strings" + "sync" "github.com/microsoft/typescript-go/internal/collections" "github.com/microsoft/typescript-go/internal/tspath" @@ -146,6 +147,9 @@ type CompilerOptions struct { PprofDir string `json:"pprofDir,omitzero"` SingleThreaded Tristate `json:"singleThreaded,omitzero"` Quiet Tristate `json:"quiet,omitzero"` + + sourceFileAffectingCompilerOptionsOnce sync.Once + sourceFileAffectingCompilerOptions *SourceFileAffectingCompilerOptions } // noCopy may be embedded into structs which must not be copied @@ -360,17 +364,20 @@ type SourceFileAffectingCompilerOptions struct { } func (options *CompilerOptions) SourceFileAffecting() *SourceFileAffectingCompilerOptions { - return &SourceFileAffectingCompilerOptions{ - AllowUnreachableCode: options.AllowUnreachableCode, - AllowUnusedLabels: options.AllowUnusedLabels, - BindInStrictMode: options.AlwaysStrict.IsTrue() || options.Strict.IsTrue(), - EmitModuleDetectionKind: options.GetEmitModuleDetectionKind(), - EmitModuleKind: options.GetEmitModuleKind(), - EmitScriptTarget: options.GetEmitScriptTarget(), - JsxEmit: options.Jsx, - NoFallthroughCasesInSwitch: options.NoFallthroughCasesInSwitch, - ShouldPreserveConstEnums: options.ShouldPreserveConstEnums(), - } + options.sourceFileAffectingCompilerOptionsOnce.Do(func() { + options.sourceFileAffectingCompilerOptions = &SourceFileAffectingCompilerOptions{ + AllowUnreachableCode: options.AllowUnreachableCode, + AllowUnusedLabels: options.AllowUnusedLabels, + BindInStrictMode: options.AlwaysStrict.IsTrue() || options.Strict.IsTrue(), + EmitModuleDetectionKind: options.GetEmitModuleDetectionKind(), + EmitModuleKind: options.GetEmitModuleKind(), + EmitScriptTarget: options.GetEmitScriptTarget(), + JsxEmit: options.Jsx, + NoFallthroughCasesInSwitch: options.NoFallthroughCasesInSwitch, + ShouldPreserveConstEnums: options.ShouldPreserveConstEnums(), + } + }) + return options.sourceFileAffectingCompilerOptions } type ModuleDetectionKind int32 diff --git a/internal/tsoptions/commandlineparser_test.go b/internal/tsoptions/commandlineparser_test.go index 019e890768..c1cc66e622 100644 --- a/internal/tsoptions/commandlineparser_test.go +++ b/internal/tsoptions/commandlineparser_test.go @@ -7,6 +7,7 @@ import ( "strings" "testing" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/diagnostics" "github.com/microsoft/typescript-go/internal/diagnosticwriter" @@ -173,7 +174,7 @@ func (f commandLineSubScenario) assertParseResult(t *testing.T) { newParsedCompilerOptions := &core.CompilerOptions{} e := json.Unmarshal(o, newParsedCompilerOptions) assert.NilError(t, e) - assert.DeepEqual(t, tsBaseline.options, newParsedCompilerOptions) + assert.DeepEqual(t, tsBaseline.options, newParsedCompilerOptions, cmpopts.IgnoreUnexported(core.CompilerOptions{})) newParsedWatchOptions := core.WatchOptions{} e = json.Unmarshal(o, &newParsedWatchOptions) diff --git a/internal/tsoptions/tsconfigparsing_test.go b/internal/tsoptions/tsconfigparsing_test.go index 7c99d8252f..36fcb9b6d0 100644 --- a/internal/tsoptions/tsconfigparsing_test.go +++ b/internal/tsoptions/tsconfigparsing_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/diagnosticwriter" "github.com/microsoft/typescript-go/internal/parser" @@ -863,7 +864,7 @@ func TestParseSrcCompiler(t *testing.T) { SourceMap: core.TSTrue, UseUnknownInCatchVariables: core.TSFalse, Pretty: core.TSTrue, - }) + }, cmpopts.IgnoreUnexported(core.CompilerOptions{})) fileNames := parseConfigFileContent.ParsedConfig.FileNames relativePaths := make([]string, 0, len(fileNames)) From a8f1d7b61f7a73e2013fd68805c06cf6e5dbe647 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 11 Jun 2025 11:29:33 -0700 Subject: [PATCH 2/2] use correct options --- internal/compiler/program.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/compiler/program.go b/internal/compiler/program.go index 202d002c92..b2c5b1db67 100644 --- a/internal/compiler/program.go +++ b/internal/compiler/program.go @@ -304,7 +304,7 @@ func (p *Program) BindSourceFiles() { for _, file := range p.files { if !file.IsBound() { wg.Queue(func() { - binder.BindSourceFile(file, p.Options().SourceFileAffecting()) + binder.BindSourceFile(file, p.projectReferenceFileMapper.getCompilerOptionsForFile(file).SourceFileAffecting()) }) } } @@ -595,7 +595,7 @@ func compactAndMergeRelatedInfos(diagnostics []*ast.Diagnostic) []*ast.Diagnosti func (p *Program) getDiagnosticsHelper(ctx context.Context, sourceFile *ast.SourceFile, ensureBound bool, ensureChecked bool, getDiagnostics func(context.Context, *ast.SourceFile) []*ast.Diagnostic) []*ast.Diagnostic { if sourceFile != nil { if ensureBound { - binder.BindSourceFile(sourceFile, p.Options().SourceFileAffecting()) + binder.BindSourceFile(sourceFile, p.projectReferenceFileMapper.getCompilerOptionsForFile(sourceFile).SourceFileAffecting()) } return SortAndDeduplicateDiagnostics(getDiagnostics(ctx, sourceFile)) }