Conversation
There was a problem hiding this comment.
Pull request overview
This PR removes the GetOptionsDiagnostics method, which redundantly combined config file diagnostics and global diagnostics. The code now directly uses GetConfigFileParsingDiagnostics and GetGlobalDiagnostics instead, eliminating unnecessary duplication and improving diagnostic handling clarity.
Key changes:
- Removed
GetOptionsDiagnosticsmethod and its helper from theProgramstruct - Updated diagnostic collection logic to call
GetConfigFileParsingDiagnosticsandGetGlobalDiagnosticsdirectly - Added a safety check in
GetGlobalDiagnosticsto handle editor scenarios
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| testdata/baselines/reference/tsbuildWatch/configFileErrors/reports-syntax-errors-in-config-file.js | Updated test baseline to reflect removal of semanticDiagnosticsPerFile field and changes to diagnostic caching behavior |
| testdata/baselines/reference/tsbuild/configFileErrors/reports-syntax-errors-in-config-file.js | Updated test baseline with same changes as watch variant |
| internal/execute/incremental/program.go | Removed GetOptionsDiagnostics method wrapper and its usage in error state checking |
| internal/compiler/program.go | Removed GetOptionsDiagnostics and helper methods, added type assertion safety check, updated GetDiagnosticsOfAnyProgram to call diagnostics methods directly |
| pool := p.checkerPool.(*checkerPool) | ||
| pool, ok := p.checkerPool.(*checkerPool) | ||
| if !ok { | ||
| return nil // !!! Global diagnostics in the editor? |
There was a problem hiding this comment.
Whenever we get around to revamping how the checkers are allocated, I think the fix is going to be to (in the editor) collect global diags from diagnostic-producing checkers, and then re-collect them whenever we check a new file, then expose those diags there.
| } | ||
|
|
||
| func (p *Program) getOptionsDiagnosticsOfConfigFile() []*ast.Diagnostic { | ||
| if p.Options() == nil || p.Options().ConfigFilePath == "" { |
There was a problem hiding this comment.
This used to be here because we could fail to get file parsing diags. But then we made ParsedCommandLine mandatory, so this call always succeeds, so there's no reason to special case anything.
| // Do binding early so we can track the time. | ||
| getBindDiagnostics(ctx, file) | ||
|
|
||
| allDiagnostics = append(allDiagnostics, program.GetOptionsDiagnostics(ctx)...) |
There was a problem hiding this comment.
Note above how we get config file diags, then get options diags, and then get global diags. This means we could have the same diags repeated twice!
(This func does not sort and dedupe, for some reason)
There was a problem hiding this comment.
Yes before this the duplicae config parsing diagnostics is why we didnt report semantic errors which we are doing now (that is when there are no syntax errors in source files and program options are ok.
| len(program.GetConfigFileParsingDiagnostics()) > 0 || | ||
| len(program.GetSyntacticDiagnostics(ctx, nil)) > 0 || | ||
| len(program.GetProgramDiagnostics()) > 0 || | ||
| len(program.GetOptionsDiagnostics(ctx)) > 0 || |
There was a problem hiding this comment.
This list already contains GetConfigFileParsingDiagnostics and GetGlobalDiagnostics, so this is a noop.
| if len(allDiagnostics) == configFileParsingDiagnosticsLength { | ||
| allDiagnostics = append(allDiagnostics, getSemanticDiagnostics(ctx, file)...) | ||
| // Ask for the global diagnostics again (they were empty above); we may have found new during checking, e.g. missing globals. | ||
| allDiagnostics = append(allDiagnostics, program.GetGlobalDiagnostics(ctx)...) |
There was a problem hiding this comment.
Strada use to add them to semantic Diagnostics - this ensured that all callers of this API didnt have to worry about it?
There was a problem hiding this comment.
We can do that, if and only if the caller passes in a nil file, theoretically.
There was a problem hiding this comment.
Pushed a change which I think works to delete GetGlobalDiagnostics too.
There was a problem hiding this comment.
well - strada did the exact opposite. It added to "per file semanticDiagnostics" because thats how editor gets diagnostics and it shouldnt miss them?
function getDiagnosticsWorker(sourceFile: SourceFile, nodesToCheck: Node[] | undefined): Diagnostic[] {
if (sourceFile) {
ensurePendingDiagnosticWorkComplete();
// Some global diagnostics are deferred until they are needed and
// may not be reported in the first call to getGlobalDiagnostics.
// We should catch these changes and report them.
const previousGlobalDiagnostics = diagnostics.getGlobalDiagnostics();
const previousGlobalDiagnosticsSize = previousGlobalDiagnostics.length;
checkSourceFileWithEagerDiagnostics(sourceFile, nodesToCheck);
const semanticDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName);
if (nodesToCheck) {
// No need to get global diagnostics.
return semanticDiagnostics;
}
const currentGlobalDiagnostics = diagnostics.getGlobalDiagnostics();
if (currentGlobalDiagnostics !== previousGlobalDiagnostics) {
// If the arrays are not the same reference, new diagnostics were added.
const deferredGlobalDiagnostics = relativeComplement(previousGlobalDiagnostics, currentGlobalDiagnostics, compareDiagnostics);
return concatenate(deferredGlobalDiagnostics, semanticDiagnostics);
}
else if (previousGlobalDiagnosticsSize === 0 && currentGlobalDiagnostics.length > 0) {
// If the arrays are the same reference, but the length has changed, a single
// new diagnostic was added as DiagnosticCollection attempts to reuse the
// same array.
return concatenate(currentGlobalDiagnostics, semanticDiagnostics);
}
return semanticDiagnostics;
}
// Global diagnostics are always added when a file is not provided to
// getDiagnostics
forEach(host.getSourceFiles(), file => checkSourceFileWithEagerDiagnostics(file));
return diagnostics.getDiagnostics();
}There was a problem hiding this comment.
Not suire if we have enough coverage for diagnostics in fourslash but all this logic was for editor to not miss reporting errors as for command line you can always get all semantic diagnostics and then global diagnsotics?
There was a problem hiding this comment.
Not suire if we have enough coverage for diagnostics in fourslash but all this logic was for editor to not miss reporting errors as for command line you can always get all semantic diagnostics and then global diagnsotics?
The current LS can miss these global diagnostics, yes. Though, that isn't new...
There was a problem hiding this comment.
The last commit I did was bad, though, because it locks off ever asking for global diags in the LS where we never ask for all files, so I'll undo that
There was a problem hiding this comment.
Not suire if we have enough coverage for diagnostics in fourslash but all this logic was for editor to not miss reporting errors as for command line you can always get all semantic diagnostics and then global diagnsotics?
The current LS can miss these global diagnostics, yes. Though, that isn't new...
It is new right, given we use to add the new diagnostics to semantic diagnostics and send it back to client ?
getBindAndCheckDiagnosticsForFile
It shouldnt be part of this as these are the ones that are cached in buildInfo and need to be consistent
There was a problem hiding this comment.
I'm confused enough with how to make this work that I wish we just didn't have global diags at all, they just really do depend on whether or not a file was checked and in which order, which does not feel reasonable to manage?
There was a problem hiding this comment.
Havent checked how diagnostics are handled in corsa but with push diagnostics we can control the order but not sure how to handle that as part of pull diagnostics esp since global diagnostics are checker diagnostics without any file info. (may be we just need to make sure that checker cannot generate global diagnostics) ?
"Options diagnostics" were just config file diagnostics + global diagnostics.
This was odd, because we then took that in places and combined it with... config file diags and global diags. And then not deduping it, sometimes.
This PR just removes
GetOptionsDiagnosticsaltogether, instead leaving behind justGetConfigFileParsingDiagnosticsandGetGlobalDiagnostics.The language server still does not ever call
GetGlobalDiagnostics. I am not sure where such a thing would go, since global diagnostics are generated as a side effect of doing checking (e.g., when we figure out thatAsyncIterablewas never declared or something).There's a baseline change, but I think it's correct and positive.