Repository navigation
Fix compiler option invalidation in incremental builds - #64712
Open
Jake Bailey (jakebailey) wants to merge 24 commits into
Open
Jake Bailey (jakebailey) wants to merge 24 commits into
Jake Bailey (jakebailey) wants to merge 24 commits into
Conversation
Option-only edits can leave declarations, diagnostics, and dependent projects inconsistent with a fresh build. These baselines capture the existing behavior before correcting invalidation. A subsequent source edit also demonstrates that option-only declaration emit can leave stale shape signatures, even for an option already classified as affecting emit.
Compiler option changes can affect declaration types and diagnostics without altering source text or the dependency graph. Emit invalidation must include these options and retain their values across build-info round trips, including ordered resolution settings and strict defaults. Option-only declaration writes must also refresh shape signatures. Otherwise a later source edit can appear unchanged and leave dependent files with stale types and diagnostics.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
paths invalidation omits its effective PathsBasePath, allowing stale incremental results for inherited configurations.
1 open finding
What changed in this PR
Improves incremental compiler-option invalidation and build-info serialization so option changes correctly refresh diagnostics and emitted declarations.
Changes:
- Expands option invalidation and build-info metadata.
- Preserves structured compiler options during build-info round trips.
- Adds comparison tests and updates affected baselines.
| File | Description |
|---|---|
tsc/testdata/baselines/reference/tscWatch/commandLineWatch/watch-handles-tsconfig-with-extends-base-modified.js |
Updates watch emit baseline. |
tsc/testdata/baselines/reference/tsc/projectReferences/issues-a-nice-error-when-the-input-file-is-missing-when-module-reference-is-not-relative.js |
Records paths in build info. |
tsc/testdata/baselines/reference/tsc/libraryResolution/with-config.js |
Records typeRoots. |
tsc/testdata/baselines/reference/tsc/libraryResolution/with-config-with-libReplacement.js |
Records typeRoots with lib replacement. |
tsc/testdata/baselines/reference/tsc/declarationEmit/reports-dts-generation-errors-with-incremental.js |
Records module resolution mode. |
tsc/testdata/baselines/reference/tsc/compilerOptionChanges/strict-default-incremental-direction-1.js |
Covers strict-default invalidation. |
tsc/testdata/baselines/reference/tsc/compilerOptionChanges/strict-default-incremental-direction-0.js |
Covers reverse strict-default transition. |
tsc/testdata/baselines/reference/tsbuildWatch/roots/when-root-file-is-from-referenced-project.js |
Updates watched referenced-project behavior. |
tsc/testdata/baselines/reference/tsbuildWatch/roots/when-root-file-is-from-referenced-project-and-shared-is-first.js |
Updates alternate project ordering. |
tsc/testdata/baselines/reference/tsbuildWatch/programUpdates/works-with-extended-source-files.js |
Updates rebuild output tracking. |
tsc/testdata/baselines/reference/tsbuildWatch/moduleResolution/handles-the-cache-correctly-when-two-projects-use-different-module-resolution-settings.js |
Persists resolution-sensitive options. |
tsc/testdata/baselines/reference/tsbuildWatch/libraryResolution/with-config.js |
Records watched typeRoots. |
tsc/testdata/baselines/reference/tsbuildWatch/libraryResolution/with-config-with-libReplacement.js |
Records watched replacement-library roots. |
tsc/testdata/baselines/reference/tsbuildWatch/dependencyUpdate/watches-absolute-non-root-dependency-updates.js |
Persists absolute path mappings. |
tsc/testdata/baselines/reference/tsbuild/transitiveReferences/builds-correctly.js |
Records transitive path mappings. |
tsc/testdata/baselines/reference/tsbuild/roots/when-root-file-is-from-referenced-project.js |
Updates referenced-root build info. |
tsc/testdata/baselines/reference/tsbuild/roots/when-root-file-is-from-referenced-project-and-shared-is-first.js |
Updates alternate referenced-root order. |
tsc/testdata/baselines/reference/tsbuild/projectReferenceRedirect/uses-correct-project-reference-redirect-when-file-belongs-to-multiple-sub-projects.js |
Records redirect resolution settings. |
tsc/testdata/baselines/reference/tsbuild/moduleResolution/type-reference-resolution-uses-correct-options-for-different-resolution-options-referenced-project.js |
Persists per-project type roots. |
tsc/testdata/baselines/reference/tsbuild/moduleResolution/resolves-specifier-in-output-declaration-file-from-referenced-project-correctly.js |
Records declaration path mappings. |
tsc/testdata/baselines/reference/tsbuild/moduleResolution/resolves-specifier-in-output-declaration-file-from-referenced-project-correctly-with-preserveSymlinks.js |
Updates symlink-resolution baseline. |
tsc/testdata/baselines/reference/tsbuild/moduleResolution/resolution-from-d.ts-of-referenced-project.js |
Persists module resolution and paths. |
tsc/testdata/baselines/reference/tsbuild/libraryResolution/with-config.js |
Records build-mode typeRoots. |
tsc/testdata/baselines/reference/tsbuild/libraryResolution/with-config-with-libReplacement.js |
Records replacement-library type roots. |
tsc/testdata/baselines/reference/tsbuild/inferredTypeFromMonorepoReference/inferred-type-from-referenced-project-that-references-another-project-in-monorepo.js |
Persists monorepo resolution mode. |
tsc/testdata/baselines/reference/tsbuild/dependencyUpdate/rebuilds-when-absolute-non-root-dependency-is-updated.js |
Records absolute dependency mappings. |
tsc/testdata/baselines/reference/tsbuild/declarationEmitForReferencedProjectTypesSubpath/declaration-emit-names-referenced-project-type-via-types-subpath.js |
Persists declaration resolution mode. |
tsc/testdata/baselines/reference/tsbuild/declarationEmit/when-declaration-file-used-inferred-type-from-referenced-project.js |
Records declaration path mappings. |
tsc/testdata/baselines/reference/tsbuild/declarationEmit/reports-dts-generation-errors-with-incremental.js |
Records resolution mode for diagnostics. |
tsc/testdata/baselines/reference/fourslash/state/findAllRefsRootOfReferencedProjectDeclarationMaps.baseline |
Updates fourslash build-info state. |
tsc/internal/tsoptions/rawcompileroptions.go |
Extracts reusable raw-option decoding. |
tsc/internal/tsoptions/options_generated.go |
Expands generated invalidation and persistence logic. |
tsc/internal/tsoptions/compileroptions_test.go |
Tests deep and strict-default comparisons. |
tsc/internal/execute/tsctests/readablebuildinfo.go |
Adapts readable build-info options. |
tsc/internal/execute/incremental/snapshottobuildinfo.go |
Uses structured build-info options. |
tsc/internal/execute/incremental/emitfileshandler.go |
Recomputes signatures after option changes. |
tsc/internal/execute/incremental/buildInfo.go |
Adds typed compiler-option build info. |
tsc/internal/execute/incremental/buildinfo_path_test.go |
Tests option JSON round trips. |
tools/scripts/tsc/options.ts |
Marks additional invalidating options. |
tools/scripts/tsc/options.test.ts |
Tests metadata and deep comparisons. |
tools/scripts/tsc/options-model.ts |
Documents invalidation metadata. |
tools/scripts/tsc/generate-options.ts |
Generates deep comparisons and validation. |
Files not reviewed (1)
- tsc/internal/tsoptions/options_generated.go: Generated file
🧠 Review effort: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Identical paths mappings mean different things when inherited from configs in different directories. Switching only the extended config can leave declarations naming an alias that no longer resolves to the inferred type. Capture both directions in build and incremental modes before fixing invalidation and persistence of the inherited base directory.
Paths mappings depend on the directory of the config that defines them. Comparing the mapping alone misses changes to that inherited directory and can leave declarations naming aliases for the wrong inferred type. Persist the derived base relative to build info and compare it whenever paths participates in invalidation. Ignore unused bases when mappings are absent or empty.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
moduleDetection remains absent from invalidation metadata, allowing stale diagnostics and emitted module markers.
1 open finding
1 resolved since last review
Files not reviewed (1)
- tsc/internal/tsoptions/options_generated.go: Generated file
🧠 Review effort: Balanced
| return field; | ||
| }; | ||
| return [`${value("oldOptions")} != ${value("newOptions")}`]; | ||
| const expressions = [optionValuesDiffer(goType(option), value("oldOptions"), value("newOptions"))]; |
Module status can change without changing global-scope classification. Cover files where graph-based invalidation cannot detect that change.
Graph comparisons cannot detect every external-module status change. Persist and compare module detection to refresh diagnostics and output.
Replacement libraries can change overload order without changing their contents or membership. Reuse the existing build-info file ordering to invalidate stale state without persisting a duplicate library list.
All option-change regressions now match fresh compilation without known-bug allowances. Refresh remaining trace baselines for the new invalidation behavior.
Jake Bailey (jakebailey)
force-pushed
the
compiler-option-invalidation
branch
from
October 10, 2026 05:08
a221e69 to
4d48fcf
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

This started off as an off hand remark in a session where it mentioned that EOPT was not correctly handled as an emit-affecting option.
I had copilot vet every option, and it came up with a lot of cases where we were not correctly invalidating during incremental mode, did not store enough in
tsbuildinfo, stored nonderministic data, etc.The second commit contains the actual fixes.
Fixes #63223