refactor(Tactic/Linter/Header): make the header linter stateful - #42201
Draft
marcelolynch wants to merge 9 commits into
Draft
refactor(Tactic/Linter/Header): make the header linter stateful#42201marcelolynch wants to merge 9 commits into
marcelolynch wants to merge 9 commits into
Conversation
Rewrite the minImports linter with the stateful linter API (leanprover/lean4#14357). The cumulative import data moves from a global IO.Ref into the linter state, which the elaborator threads through the commands of the file. The IO.Ref was unsafe under parallel elaboration, so `#import_bumps` had to set `Elab.async false`; the stateful state is safe and the option stays on. Linter behavior is unchanged: MathlibTest/MinImports.lean passes as is (validated on a nightly-2026-07-27 toolchain). NOTE: CI stays red until the toolchain bump to v4.34.0-rc1, which first provides `registerStatefulLinter`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The new section runs with Elab.async explicitly on: the linter state accumulates correctly across commands, and #import_bumps keeps parallel elaboration enabled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ionIn' Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ort_bumps Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PR summary a314edf962Import changes for modified filesNo significant changes to the import graph Import changes for all files
|
Rewrite the header linter with the stateful linter API (leanprover/lean4#14357). The linter state caches the library-root check, which replaces the Std.Mutex that guarded the cache against concurrent async linter runs, and records that the checks ran, so the linter checks the header of each module exactly once. A file without a module doc-string gets one set of warnings at its first command; the IO.Ref-era behavior repeated the full header parse and its warnings on every command of such a file. Linter behavior on well-formed files is unchanged; the header linter tests pass as is (validated on a nightly-2026-07-27 toolchain). NOTE: CI stays red until the toolchain bump to v4.34.0-rc1, which first provides `registerStatefulLinter`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The header linter state gains two things. The `headerSyntax` field stores the parsed module header, so other linters can read it instead of a re-parse of the file. The `settled` flag replaces `ran` and also covers exempt modules, so every command of an exempt file takes the same fast path as a checked file. The `withSetOptionIn'` helper moves to the `Mathlib.Linter` namespace and becomes public: the consumer linters share the single copy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eader linter state The end-of-file report positions its warnings with the parsed header from the state of the header linter. When the header checks did not run, the report falls back to the previous behavior: it reads the file and parses the header again. Two new tests pin both paths. MathlibTest/Linter/Header/MinImportsPayload.lean exercises the payload path, and a new section in MathlibTest/MinImports.lean exercises the fallback. A temporary throwError probe in the fallback verified that each test takes its intended path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… linter The longLine linter becomes a stateful linter with trivial state, so its end-of-file check can read the parsed header from the state of the header linter. When the header checks did not run, the check parses the header itself, as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
marcelolynch
force-pushed
the
2026/07/HeaderStateful
branch
from
July 28, 2026 20:51
263f312 to
a314edf
Compare
|
This PR/issue depends on: |
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 PR rewrites the header linter as a stateful linter (leanprover/lean4#14357). Linter behavior on well-formed files does not change. All four header linter test files pass without changes.
The linter state replaces two pieces of ad-hoc machinery:
Std.Mutexthat guarded the cache against concurrent async linter runs.One behavior improves on malformed files: a file without a module doc-string gets one set of warnings at its first command. The previous implementation repeated the full header parse and its warnings on every command of such a file. The repeated parse was the largest per-command cost of the linter, for example during edits of a new file that does not have its module doc-string yet.
Other performance effects are small. After the verdict, each command reads one state field, and the end-of-file checks of the consumer linters replace a header parse with a state read.
The state also stores the parsed module header, and the header linter becomes a producer. The
minImportsandlongLinelinters read the parsed header from the state for their end-of-file checks, instead of a re-parse of the file. When the header checks did not run, both linters fall back to the previous re-parse. Two new tests pin the payload path and the fallback path of theminImportsreport.🤖 Generated with Claude Code