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:
parent
4450ff8995
commit
17807e1cbe
2 changed files with 30 additions and 6 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue