feat: compile-check checks only the changed files after a body edit in a large assembly
Merged
HA
2d ago+2266+2266+0123456789012345678901234567890123456789-58-58-01234567890123456789
Summary
- After a method-body edit in a large assembly,
uloop compile-checknow checks only the changed files against the last successful full compile instead of recompiling the whole assembly, and carries the other files' diagnostics over. - Anything the check cannot vouch for still compiles in full, and the output says why.
--fullturns the check off for one run.
User Impact
- Before: a one-line body edit in an assembly of about 3,000 files took 17–22 seconds, because csc recompiled and re-analyzed every file.
- After: the same edit is checked on the changed file only (the prototype took 2.7 seconds). The output lists which assemblies were checked this way and which rules only a full compile runs, and asks for
--fullbefore finishing.
Changes
- Input key:
computeInputKeyreturns the content hash of each source it read, and a new non-source key digests every input except source contents (with the source path list instead). - Full compiles: csc saves generator output to
<Assembly>.generated/. After a successful full compile of an assembly with at least 300 sources, a baseline<Assembly>.fastcheck.jsonrecords each source's content hash (the one the input key read) and declaration fingerprint (from the worker), the non-source key read before the compile, the worker key, and the content hash of each saved generated file. A source or any other input edited during the compile leaves no baseline, and a baseline that cannot be recorded is reported inFastPathBaselineNoteswithout failing the run.--fullruns record too. - Fast path in
reuseOrCompile, after reuse and before the full compile: it falls back to a full compile, with a reason, when there is no usable baseline, an input other than source contents changed, the saved generator output is missing or changed, more than 30 files changed, a declaration changed, or the worker cannot build, run, or support the assembly.--all, units picked only as dependents, units without an input key, and assemblies with fewer than 300 sources never try it, and are not listed as fallbacks. A used fast check touches no outputs, manifest, or baseline. Diagnostics of unchanged files are carried over from the baseline compile's manifest and merged with the worker's, without duplicates by (normalized path, line, column, code). - Reasons the worker gives spell file paths relative to the project root, like the diagnostics, so no local path reaches the output.
- The worker is built at most once per run and shared by the units that compile in parallel.
- Response:
FastCheckedAssemblies,FastChecks(ChangedFiles,UncheckedCodes,GeneratorsNotRerun),FastPathFallbacks(Assembly,Reason), andFastPathBaselineNotes(Assembly,Reason), all[]when empty. The summary counts fast-checked assemblies, so a run answered only by the check no longer says nothing changed, and the message asks for--fullbefore finishing. --fulloption, help line, docs (docs/compile-check.md), and the compile-check skill.
Verification
cli/dispatcher:golangci-lint fmt --diff,go vet ./...,golangci-lint run ./...(0 issues), the complexity config (0 issues), andgo test ./...all pass.scripts/check-go-cli.shrefuses to run with the local Go 1.26.6 (CI uses 1.26.9), so its steps were run per module;cli/commonis unchanged.- File length check: no file over 500 SLOC. Skill size check and
scripts/sync-tool-docs.sh --checkpass. - Dispatcher coverage measured locally with the CI exclusions: 94.22% (baseline 94.2).
- The input-space table of the plan has one test per row, each driving the real scheduler with a fake csc and a fake worker. Mutation checks, each restored afterwards and each failing the test that pins it:
--fullstill trying,--alltrying, the source-changed-during-compile check, the carried-diagnostic filter, the deduplication, recording for dependents, the cancellation check, the size limit, the changed-file limit, the worker key check, the non-source key re-check before recording, and the generator output check. - The Unity 2022.3 csc accepts the added
-generatedfilesoutline. - Measured on a real project, in an assembly of 3,081 source files:
- The first full compile took 12.7 s and recorded the baseline.
- A body edit was fast-checked in 2.96 s, against 14.98 s for
--fullon the same state, with identical Errors and Warnings. - An injected type error was fast-checked in 3.70 s, against 9.87 s for
--full. It reported CS0029 at the right line and column, and the diagnostics matched--full. - Adding a method fell back with
DeclarationChangedand compiled the 18 dependents. UncheckedCodeslisted CS0067, CS0414, and three analyzer rules, andGeneratorsNotRerunwas true.
- The Unity 2022.3 csc creates the per-generator folders under
-generatedfilesoutbut not the directory itself, so compile-check now creates it before csc runs. - Repository CI that triggers only for
mainmay not run on this pull request into the integration branch; the commands above are the local equivalent.