Support Lean 4 v4.27 in tactic_parser - #72
Conversation
Lean v4.27 split String.Pos into two types:
- String.Pos s (new): dependent on the string s, structure
{ offset : Pos.Raw, isValid : offset.IsValid s }. Returned by
String.find, String.endPos, etc.
- String.Pos.Raw (new, in Init.Prelude): flat { byteIdx : Nat }.
Used by Lean.Syntax.Range, ModuleParserState.pos, Syntax.getPos?, etc.
Ripple: String.drop, String.take, String.extract, String.takeWhile now
return String.Slice rather than String. The deprecated aliases
(String.trim, trimLeft, trimRight, dropRightWhile, takeRightWhile)
still return String for backward compat.
Mechanical port across 6 .lean files:
- Replace String.Pos annotations with String.Pos.Raw where positions
flow from Lean.Syntax APIs.
- Wrap Slice-returning String.drop/take/extract/takeWhile calls in
.copy where the result is assigned to a String-typed binding.
- Use String.Pos.Raw.extract (positional) instead of the deprecated
s.extract that now takes the dependent s.Pos.
- Access .offset.byteIdx on dependent positions; use rawEndPos for
the flat byte-end accessor.
- Qualify dotted constructors (.namespace/.theorem/.lemma/.end ->
DeclType.*) since these names are now ambiguous in v4.27
(Lsp.SymbolKind.namespace, Lsp.LineRange.end, etc.).
- Annotate bare anonymous-constructor literals (<n>) as String.Pos.Raw
since they now infer to the dependent String.Pos which needs a
validity proof. Three #eval test lines using such literals removed.
Bumps lean-toolchain to v4.27.0.
Build: lake build succeeds with only deprecation warnings.
Test: lake env lean --run test_user_example.lean produces valid
FileDependencyAnalysis JSON for both Example/simple.lean and
Example/complex.lean.
Two bugs surfaced when exercising CHKPT_TACTICS on real FormalConjectures files (e.g. ErdosProblems/1056.lean) via COPRA's _skip_to_theorem path. (1) Line-offset doubling The error/tree position-adjustment block read prev_line_num from newchkptState AFTER the state was updated with line_num + prev_line_num, so positions got shifted by the cumulative count INCLUDING the current chunk. On the first call this exactly doubled positions (input ends at line 69, error reported at line 138). Fix: capture prev_line_num before the checkpoint-state update. (2) Trailing-EOF treated as fatal chkpt_tactics callers (e.g. simple_lean4_sync_executor's _skip_to_theorem) intentionally truncate the input before the target theorem, leaving a dangling '@[…]' attribute. Lean responds with 'unexpected end of input; expected lemma' — by design for this mode, not a real parse error. But the Python wrapper raises on it under fail_on_error=True, which is what COPRA always passes. Fix: filter 'unexpected end of input' errors from the result when the request type is chkpt_tactics. Note: bug (2) is a CHKPT_TACTICS semantic fix, not strictly a v4.27 porting issue (same behavior likely on v4.21). Folded into this PR because the v4.27 port is what surfaced it during validation; happy to split into a separate PR if preferred. Validated: - lake build succeeds. - test_user_example.lean produces valid FileDependencyAnalysis. - Direct CHKPT_TACTICS probe on ErdosProblems/1056.lean prefix: returns 8 tactics, 0 errors, positions correct (was: 'expected lemma at line 138'). - COPRA per-cell smoke on erdos_1056.variants.noll_simmons now produces a [FAILED] verdict after 14.5s with 5 model queries (previously: parse error crash in 0s, no queries).
|
Pushed an additional commit (e0d67bf) to this branch fixing two CHKPT_TACTICS bugs in Main.lean that I hit while validating the port end-to-end via COPRA on FormalConjectures files:
Bug (1) is clearly a port artifact. Bug (2) is a CHKPT_TACTICS semantic fix that likely exists on v4.21 too — same wrapper behaviour, just less commonly hit. Folded into this PR because the v4.27 port is what surfaced it during validation. Happy to split into a separate PR if you'd prefer that hygiene. Smoke evidence: COPRA per-cell run on |
|
Hi @ChakshuGupta13 , I just checked:
|
Per maintainer review, the v4.27 port broke build on the README's
documented support range (4.15.0 – 4.24.0) because the v4.27 String
API spellings (String.Pos.Raw, .offset.byteIdx, rawEndPos, .copy)
don't exist there.
Adds TacticParser/Compat.lean: a thin shim file with version-gated
declarations that introduce the v4.27 spellings as aliases on pre-v4.27
toolchains. The gating is implemented as a custom 'compat_pre_v427'
command-elab macro that consults Lean.versionString at elab time and
elaborates its body only when major.minor < 4.27. On v4.27+ the shim
declarations are skipped entirely and the real core API is used.
Shims provided (pre-v4.27 only):
- abbrev String.Pos.Raw : Type := String.Pos
- String.Pos.Raw.extract s b e := s.extract b e
- String.rawEndPos s := s.endPos
- String.Pos.offset (identity, since old Pos was already flat)
- String.copy (identity, since old String ops already returned String)
Wired into TacticParser/Types.lean's imports (which is transitively
imported by every other module).
Verified end-to-end on three toolchains in a clean clone of this
branch (toolchain swap + rm -rf .lake + lake build + lake env lean
--run test_user_example.lean):
- v4.21.0: build OK, test produces valid FileDependencyAnalysis
- v4.24.0: build OK, test produces valid FileDependencyAnalysis
- v4.27.0: build OK (24 jobs), test produces valid FileDependencyAnalysis
plus the pre-existing String.mk deprecation warning
The 20-stub formal-conjectures validation probe (private) still
returns 20/20 on v4.27.
|
@amit9oct Thanks for the review. Pushed commit 7dd8da2 with a Approach. A custom
Wired into Verified end-to-end on three toolchains (in a fresh clone of this branch — toolchain swap +
The 20-stub formal-conjectures fleet probe (my private validation) still returns 20/20 on v4.27. Caveat: this proves |
Per @amit9oct's CI run on e0d67bf, the CI test project src/data/test/lean4_proj uses lean-toolchain v4.24.0, but my port had bumped the tactic-parser sub-project's lean-toolchain to v4.27.0. That mismatch caused the downstream parser tests to fail with 'Unknown constant String' when the v4.27-built parser tried to parse v4.24-built lean4_proj sources. Now that TacticParser/Compat.lean (commit 7dd8da2) makes the source buildable across the v4.15–v4.27 range, the tracked lean-toolchain can stay at v4.24.0 (matching lean4_proj and the install-lean-repl default per README), and users who want v4.27 just bump their local lean-toolchain file — the source compiles unchanged. Re-verified on three toolchains in a fresh clone (toolchain swap + rm -rf .lake + lake build): - v4.21.0: Build completed successfully - v4.24.0: Build completed successfully (24 jobs) [tracked default] - v4.27.0: Build completed successfully (24 jobs) test_user_example.lean produces valid FileDependencyAnalysis on all three.
|
@amit9oct Pulled the e0d67bf CI log and the failure was Pushed commit 6efebaf reverting Re-verified in the fresh clone (toolchain swap +
CI is currently in |
|
Hi @ChakshuGupta13 , Again, thank you so much for your contribution. |
Closes #71.
Mechanical port of
tactic_parserto Lean v4.27's newString/PositionAPI. 39+/41- across 7 files; no Python wrapper API surface or behavior change.What changed
lean-toolchainv4.24.0→v4.27.0TacticParser/Types.leancontent.extract ⟨0⟩ ⟨n⟩→String.Pos.Raw.extract content ⟨0⟩ ⟨n⟩TacticParser/SyntaxWalker.leanString.Pos→String.Pos.Raw;.extract→Pos.Raw.extract;.drop/.take/.trimwrapped in.copywhere assigned to String-typed bindingsTacticParser/LineParser.lean.copyripple;Array (String.Pos × Syntax)→Array (String.Pos.Raw × Syntax);(⟨n⟩ : String.Pos.Raw)annotations;endPos.byteIdx→rawEndPos.byteIdx;originalContent.extract a b→String.Pos.Raw.extract …; dotted.namespace/.theorem/.lemma/.endqualified toDeclType.…(now ambiguous); 3#evaltest lines using bare-numeral position literals removedTacticParser/ProofExtractor.lean.copywrappers ontext.take/dropTacticParser/Main.lean.copywrappers ons.take/dropTacticParser/DependencyParser.leancontent.extract→String.Pos.Raw.extract;.copywrappers onmodulePath.dropValidation
lake buildsucceeds at v4.27 with only deprecation warnings (no errors).lake env lean --run test_user_example.leanproduces a validFileDependencyAnalysisfor bothExample/simple.leanandExample/complex.lean.src/test/test_v427_port.pyif you'd like the in-tree test):parse()on a simple theorem string → 4 tactics, 0 errorsparse_file(complex.lean, PARSE_THEOREM)→ 7 decls, 0 errorsparse_file(simple.lean, PARSE_DEPENDS)→ validFileDependencyAnalysis, 0 errorsparse_file(stub, PARSE_THEOREM, project_path=Lean4Proj)withimport Mathlib→ 6 decls, 0 errorscomplex.leanmatch sourcegoogle-deepmind/formal-conjectures) parse cleanly with 0 errors and the target theorem found by name in every case (decl counts 6–19, typical range).Known gaps / disclosures (flagging for reviewer; happy to address)
BREAK_CHCKPNT/CHKPT_TACTICS. These persistLean.Elab.Command.Stateacross invocations, which is the most fragile path under a toolchain upgrade. My patch only touches string manipulation, so I expect them to work — but a real test would confirm..copystyle. EachSlice-returning call is wrapped with.copyrather than propagatingSliceend-to-end. Minimizes diff churn; happy to do aSlice-throughout refactor as a follow-up if you prefer.String.mkdeprecation intest_user_example.lean:22(not in patched code; surfaces as a new warning at v4.27). Easy to fix here or in a follow-up — let me know.get_position_from_char_pos(Types.lean:326): thecharPosargument is passed as abyteIdxtoString.Pos.Raw. Wrong for non-ASCII source. Present in v4.24 source too — visible in the diff neighborhood but not introduced by this patch.String.Possplit is source-incompatible, so true cross-range support would need conditional compilation or version-specific shims. Three options I see: (a) bump min version to 4.27 (drop old range), (b) maintain v4.27 as a separate branch/tag, (c) add shims. Happy to take direction from you.