Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/vscode-typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,36 @@
],
"description": "%native-preview.trackFlakyDiagnostics.description%",
"scope": "window"
},
"js/ts.experimental.workspaceDiagnostics.scope": {
"type": "string",
"enum": [
"off",
"openProjects",
"openProjectsAndDependents",
"allProjects"
],
"enumDescriptions": [
"%native-preview.workspaceDiagnostics.off%",
"%native-preview.workspaceDiagnostics.openProjects%",
"%native-preview.workspaceDiagnostics.openProjectsAndDependents%",
"%native-preview.workspaceDiagnostics.allProjects%"
],
"default": "off",
"tags": [
"experimental"
],
"description": "%native-preview.workspaceDiagnostics.description%",
"scope": "window"
},
"js/ts.experimental.workspaceDiagnostics.serverDiagnosticsDeDuplication": {
"type": "boolean",
"default": true,
"tags": [
"experimental"
],
"description": "%native-preview.workspaceDiagnostics.serverDiagnosticsDeDuplication.description%",
"scope": "window"
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions packages/vscode-typescript/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,11 @@
"native-preview.trackFlakyDiagnostics.log": "Log an error when a flaky diagnostic is detected.",
"native-preview.trackFlakyDiagnostics.never": "Never perform flaky diagnostic checking and logging.",
"native-preview.trackFlakyDiagnostics.auto": "Perform flaky diagnostic logging only on VS Code Insiders.",
"native-preview.workspaceDiagnostics.description": "Controls how much of the workspace is checked for errors, including files that are not open. Checking whole projects is expensive.",
"native-preview.workspaceDiagnostics.serverDiagnosticsDeDuplication.description": "Leave a file out of workspace diagnostics while it is open, because the editor reports open files separately and would otherwise show every problem in them twice. Turn this off only for a client that does not request diagnostics per document.",
"native-preview.workspaceDiagnostics.off": "Only report errors in open files.",
"native-preview.workspaceDiagnostics.openProjects": "Report errors in every file of the projects that contain an open file.",
"native-preview.workspaceDiagnostics.openProjectsAndDependents": "Also report errors in the projects that reference those projects.",
"native-preview.workspaceDiagnostics.allProjects": "Report errors in every project in the workspace.",
"developer": "Developer"
}
18 changes: 16 additions & 2 deletions tsc/internal/compiler/checkerpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,22 @@ import (
// The returned checker must not be accessed concurrently; each acquisition is exclusive.
// If file is non-nil, the pool may use it as an affinity hint to return the same
// checker for the same file across calls.
// CheckerPool owns the checkers a program is checked with: one per the program's `checkers` option,
// with the program's files partitioned across them. Which checker sees a file is part of how a
// program is checked, so anything wanting to check one the way the command line does has to check
// it through this.
type CheckerPool interface {
GetChecker(ctx context.Context, file *ast.SourceFile) (*checker.Checker, func())
// ForEachCheckerGroupDo runs one task per checker rather than one per file, so each checker is
// taken once for the whole group of files assigned to it.
ForEachCheckerGroupDo(ctx context.Context, files []*ast.SourceFile, singleThreaded bool, cb func(c *checker.Checker, fileIndex int, file *ast.SourceFile))
GetGlobalDiagnostics() []*ast.Diagnostic
}

// NewCheckerPool returns the pool the compiler would check this program with. A Program builds its
// own, so this is for callers that supply a pool of their own and need the compiler's for checking.
func NewCheckerPool(program *Program) CheckerPool {
return newCheckerPool(program)
}

type checkerPool struct {
Expand Down Expand Up @@ -466,10 +480,10 @@ func (p *checkerPool) GetGlobalDiagnostics() []*ast.Diagnostic {
return SortAndDeduplicateDiagnostics(slices.Concat(globalDiagnostics...))
}

// forEachCheckerGroupDo runs one task per checker in parallel. Each task iterates
// ForEachCheckerGroupDo runs one task per checker in parallel. Each task iterates
// the provided files, processing only those assigned to its checker. Within each
// checker's set, files are visited in their original order.
func (p *checkerPool) forEachCheckerGroupDo(ctx context.Context, files []*ast.SourceFile, singleThreaded bool, cb func(c *checker.Checker, fileIndex int, file *ast.SourceFile)) {
func (p *checkerPool) ForEachCheckerGroupDo(ctx context.Context, files []*ast.SourceFile, singleThreaded bool, cb func(c *checker.Checker, fileIndex int, file *ast.SourceFile)) {
p.createCheckers()

checkerCount := len(p.checkers)
Expand Down
23 changes: 5 additions & 18 deletions tsc/internal/compiler/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -698,24 +698,11 @@ func filterAndSortDiagnostics(diags []*ast.Diagnostic) []*ast.Diagnostic {
// collectCheckerDiagnosticsFromFiles collects checker diagnostics for a list of files.
func (p *Program) collectCheckerDiagnosticsFromFiles(ctx context.Context, sourceFiles []*ast.SourceFile, collect func(context.Context, *checker.Checker, *ast.SourceFile) []*ast.Diagnostic) [][]*ast.Diagnostic {
diagnostics := make([][]*ast.Diagnostic, len(sourceFiles))
if p.compilerCheckerPool != nil {
p.compilerCheckerPool.forEachCheckerGroupDo(ctx, sourceFiles, p.SingleThreaded(), func(c *checker.Checker, fileIndex int, file *ast.SourceFile) {
diagnostics[fileIndex] = collect(ctx, c, file)
})
} else {
wg := core.NewWorkGroup(p.SingleThreaded())
for i, file := range sourceFiles {
if p.SkipTypeChecking(file, false) {
continue
}
wg.Queue(func() {
c, done := p.checkerPool.GetChecker(ctx, file)
diagnostics[i] = collect(ctx, c, file)
done()
})
}
wg.RunAndWait()
}
// A file is checked by the checker its pool assigned it, and each checker is taken once for its
// whole group rather than once per file.
p.checkerPool.ForEachCheckerGroupDo(ctx, sourceFiles, p.SingleThreaded(), func(c *checker.Checker, fileIndex int, file *ast.SourceFile) {
diagnostics[fileIndex] = collect(ctx, c, file)
})
return diagnostics
}

Expand Down
1 change: 1 addition & 0 deletions tsc/internal/core/compileroptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type CompilerOptions struct {
ForceConsistentCasingInFileNames Tristate `json:"forceConsistentCasingInFileNames,omitzero"`
IsolatedModules Tristate `json:"isolatedModules,omitzero"`
IsolatedDeclarations Tristate `json:"isolatedDeclarations,omitzero"`
ExperimentalWorkspaceDiagnosticsExclude []string `json:"experimentalWorkspaceDiagnosticsExclude,omitzero"`
IgnoreConfig Tristate `json:"ignoreConfig,omitzero"`
IgnoreDeprecations string `json:"ignoreDeprecations,omitzero"`
ImportHelpers Tristate `json:"importHelpers,omitzero"`
Expand Down
8 changes: 8 additions & 0 deletions tsc/internal/diagnostics/diagnostics_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions tsc/internal/diagnostics/extraDiagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -338,5 +338,13 @@
"Diagnostic directive {0} returned by the content mapper has an invalid 'unusedExpectDirectiveIndex'.": {
"category": "Message",
"code": 100068
},
"Checking workspace": {
"category": "Message",
"code": 100069
},
"Paths that workspace-wide diagnostics in the editor should not report on.": {
"category": "Message",
"code": 100070
}
}
30 changes: 30 additions & 0 deletions tsc/internal/execute/incremental/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,36 @@ type TestingData struct {
UpdatedSignatureKinds map[tspath.Path]SignatureUpdateKind
}

// PriorState is what one program leaves for the next to work out what a change reached: the file
// hashes, references and cached diagnostics it built, and none of the program they came from. A
// caller that keeps a whole Program for this keeps its program too, and every type reachable from
// it, for as long as it holds on.
type PriorState struct {
snapshot *snapshot
}

// PriorState returns what this program has worked out, without the program itself.
func (p *Program) PriorState() *PriorState {
if p == nil {
return nil
}
return &PriorState{snapshot: p.snapshot}
}

// NewProgramFromPriorState is NewProgram for a caller that kept only what the previous program
// worked out, rather than the program itself.
func NewProgramFromPriorState(program *compiler.Program, prior *PriorState, host Host) *Program {
var oldSnapshot *snapshot
if prior != nil {
oldSnapshot = prior.snapshot
}
return &Program{
snapshot: buildSnapshot(program, oldSnapshot, false /*hashWithText*/),
program: program,
host: host,
}
}

func (p *Program) GetTestingData() *TestingData {
return p.testingData
}
Expand Down
Loading