mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-17 10:24:07 +00:00
feat: apply @[mvcgen_invariant_type] to Invariant, StringInvariant, StringSliceInvariant (#12880)
This PR applies `@[mvcgen_invariant_type]` to `Std.Do.Invariant` and removes the hard-coded fallback in `isMVCGenInvariantType` that was needed for bootstrapping (cf. #12874). It also extracts `StringInvariant` and `StringSliceInvariant` as named abbreviations tagged with `@[mvcgen_invariant_type]`, so that `mvcgen` classifies string and string slice loop invariants correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -262,10 +262,9 @@ builtin_initialize mvcgenInvariantAttr : TagAttribute ←
|
||||
|
||||
/--
|
||||
Returns `true` if `ty` is an application of a type tagged with `@[mvcgen_invariant_type]`.
|
||||
Falls back to checking for `Std.Do.Invariant` for bootstrapping purposes.
|
||||
-/
|
||||
def isMVCGenInvariantType (env : Environment) (ty : Expr) : Bool :=
|
||||
if let .const name .. := ty.getAppFn then
|
||||
mvcgenInvariantAttr.hasTag env name || name == ``Std.Do.Invariant
|
||||
mvcgenInvariantAttr.hasTag env name
|
||||
else
|
||||
false
|
||||
|
||||
@@ -688,6 +688,7 @@ After leaving the loop, the cursor's prefix is `xs` and the suffix is empty.
|
||||
During the induction step, the invariant holds for a suffix with head element `x`.
|
||||
After running the loop body, the invariant then holds after shifting `x` to the prefix.
|
||||
-/
|
||||
@[mvcgen_invariant_type]
|
||||
abbrev Invariant {α : Type u₁} (xs : List α) (β : Type u₂) (ps : PostShape.{max u₁ u₂}) :=
|
||||
PostCond (List.Cursor xs × β) ps
|
||||
|
||||
@@ -1997,6 +1998,18 @@ theorem Spec.foldlM_array {α β : Type u} {m : Type u → Type v} {ps : PostSha
|
||||
simp
|
||||
apply Spec.foldlM_list inv step
|
||||
|
||||
/--
|
||||
The type of loop invariants used by the specifications of `for ... in ...` loops over strings.
|
||||
A loop invariant is a `PostCond` that takes as parameters
|
||||
|
||||
* A `String.Pos` representing the current position in the string `s`.
|
||||
* A state tuple of type `β`, which will be a nesting of `MProd`s representing the elaboration of
|
||||
`let mut` variables and early return.
|
||||
-/
|
||||
@[mvcgen_invariant_type]
|
||||
abbrev StringInvariant (s : String) (β : Type u) (ps : PostShape.{u}) :=
|
||||
PostCond (s.Pos × β) ps
|
||||
|
||||
/--
|
||||
Helper definition for specifying loop invariants for loops with early return.
|
||||
|
||||
@@ -2019,7 +2032,7 @@ abbrev StringInvariant.withEarlyReturn {s : String}
|
||||
(onContinue : s.Pos → β → Assertion ps)
|
||||
(onReturn : γ → β → Assertion ps)
|
||||
(onExcept : ExceptConds ps := ExceptConds.false) :
|
||||
PostCond (s.Pos × MProd (Option γ) β) ps
|
||||
StringInvariant s (MProd (Option γ) β) ps
|
||||
:=
|
||||
⟨fun ⟨pos, x, b⟩ => spred(
|
||||
(⌜x = none⌝ ∧ onContinue pos b)
|
||||
@@ -2029,7 +2042,7 @@ abbrev StringInvariant.withEarlyReturn {s : String}
|
||||
@[spec]
|
||||
theorem Spec.forIn_string
|
||||
{s : String} {init : β} {f : Char → β → m (ForInStep β)}
|
||||
(inv : PostCond (s.Pos × β) ps)
|
||||
(inv : StringInvariant s β ps)
|
||||
(step : ∀ pos b (h : pos ≠ s.endPos),
|
||||
Triple
|
||||
(f (pos.get h) b)
|
||||
@@ -2057,6 +2070,18 @@ theorem Spec.forIn_string
|
||||
next b => simp [ih _ _ hsp.next]
|
||||
| endPos => simpa using Triple.pure _ (by simp)
|
||||
|
||||
/--
|
||||
The type of loop invariants used by the specifications of `for ... in ...` loops over string slices.
|
||||
A loop invariant is a `PostCond` that takes as parameters
|
||||
|
||||
* A `String.Slice.Pos` representing the current position in the string slice `s`.
|
||||
* A state tuple of type `β`, which will be a nesting of `MProd`s representing the elaboration of
|
||||
`let mut` variables and early return.
|
||||
-/
|
||||
@[mvcgen_invariant_type]
|
||||
abbrev StringSliceInvariant (s : String.Slice) (β : Type u) (ps : PostShape.{u}) :=
|
||||
PostCond (s.Pos × β) ps
|
||||
|
||||
/--
|
||||
Helper definition for specifying loop invariants for loops with early return.
|
||||
|
||||
@@ -2079,7 +2104,7 @@ abbrev StringSliceInvariant.withEarlyReturn {s : String.Slice}
|
||||
(onContinue : s.Pos → β → Assertion ps)
|
||||
(onReturn : γ → β → Assertion ps)
|
||||
(onExcept : ExceptConds ps := ExceptConds.false) :
|
||||
PostCond (s.Pos × MProd (Option γ) β) ps
|
||||
StringSliceInvariant s (MProd (Option γ) β) ps
|
||||
:=
|
||||
⟨fun ⟨pos, x, b⟩ => spred(
|
||||
(⌜x = none⌝ ∧ onContinue pos b)
|
||||
@@ -2089,7 +2114,7 @@ abbrev StringSliceInvariant.withEarlyReturn {s : String.Slice}
|
||||
@[spec]
|
||||
theorem Spec.forIn_stringSlice
|
||||
{s : String.Slice} {init : β} {f : Char → β → m (ForInStep β)}
|
||||
(inv : PostCond (s.Pos × β) ps)
|
||||
(inv : StringSliceInvariant s β ps)
|
||||
(step : ∀ pos b (h : pos ≠ s.endPos),
|
||||
Triple
|
||||
(f (pos.get h) b)
|
||||
|
||||
Reference in New Issue
Block a user