Zulip Chat Archive
Stream: iris-lean
Topic: Iris-Lean demos
Markus de Medeiros (Jan 26 2026 at 18:44):
With all of the recent changes, we can now define a points-to connective in the usual Iris way. Great work to all the recent contributors!
/- Parameterize by a type of UFractions. This example also shows how to deal with this
kind of polymorphism, which can be tricky. -/
variable {F} [UFraction F]
/- Define an OFunctor for the heap. -/
abbrev F1 : OFunctorPre := constOF <| HeapView F Nat (Agree (LeibnizO String)) AssocList
/- Our OFunctor is present in the global list of OFunctors. -/
variable {GF} [ElemG GF (F1 (F := F))]
/- Allow the types of GF and F, and the UFraction instance for F, to be inferred by γ
alone. Doing it this way allows us to define a notation for the points-to that does not
require explicit type parameters. Curiously, I don't need to instantiate this; having it
in the context is enough for typeclass inference to make this shortcut. I sort of doubt
that we would want to do this globally for ElemG, but I'm not sure about that. -/
set_option synthInstance.checkSynthOrder false in
class abbrev HasPointsToF1 (γ : GName) (GF : outParam _) (F : outParam (Type _)) [UFraction F] :=
ElemG GF (F1 (F := F))
/- Define notation for the heap. -/
def points_to (γ : GName) [HasPointsToF1 γ GF F] (k : Nat) (v : String) :=
iOwn (GF := GF) (F := F1 (F := F)) γ (Frag k (own one) (toAgree ⟨v⟩))
notation k:50 " ↦[" γ:50 "] " v:50 => points_to γ k v
/- In this example, we assume that the setup is complete and a GName has already been
allocated. -/
example {γ : GName} : 5 ↦[γ] "A" ∗ 5 ↦[γ] "B" ⊢ False := by
refine iOwn_op.mpr.trans ?_
refine iOwn_cmraValid.trans ?_
refine (UPred.cmraValid_elim _).trans ?_
iintro %H
have _ := dist_inj <| toAgree_op_validN_iff_dist.mp <|
(frag_op_validN_iff.mp H).2
grind
Markus de Medeiros (Jan 27 2026 at 16:13):
One more thing to show off: an example of defining a weakest precondition, and proving some proof rules with it. The code is still a little rough around the edges but it works!
/-! Example: a typical step-indexed weakest precondition -/
section Example3
open OFE
/- In this example, we are given a type of expressions and a type of states, as well as a
single-stepping function from an operational semantics. -/
class OperationalSemantics (Expr State Value : Type _) where
step : Expr × State → Expr × State
to_value : Expr → Option Value
export OperationalSemantics (step to_value)
variable (Expr State Value : Type _) [OperationalSemantics Expr State Value]
/- Let's say that we are also given two OFunctors, and an interpretation of the state into
state using these resources. -/
variable (F3 F4 : OFunctorPre) [RFunctorContractive F3] [RFunctorContractive F4]
variable {GF} [ElemG GF F3] [ElemG GF F4]
class StateInterpretation (State : Type _) (GF : BundledGFunctors) where
state_interp : State → IProp GF
export StateInterpretation (state_interp)
variable [StateInterpretation State GF]
/- Again, doing this trick so that we can write WP notations that don't explicitly include
Expr State and Value. -/
set_option synthInstance.checkSynthOrder false in
class abbrev Ex3WP {Expr : Type _} {State Value : outParam (Type _)} {GF : outParam BundledGFunctors} :=
OperationalSemantics Expr State Value,
StateInterpretation State GF
/- Now, we can define a contractive functor for the weakest precondition. -/
def wp_F (wp : Expr → (Value → IProp GF) → IProp GF) (e : Expr) (Φ : Value → IProp GF) :
IProp GF := iprop(
(∃ v : Value, ⌜@to_value _ State _ _ e = some v⌝ ∗ |==> Φ v) ∨
∀ s, @state_interp State _ _ s -∗
∃ e' s', ⌜@step _ _ Value _ (e, s) = (e', s') ⌝ ∗ ▷ |==> (@state_interp _ _ _ s' ∗ wp e' Φ))
instance wp_F_contractive : Contractive (@wp_F Expr State Value _ GF _) where
distLater_dist {n x y HL} e Φ := by
refine or_ne.ne (.of_eq rfl) ?_
refine forall_ne (fun _ => ?_)
refine wand_ne.ne (.of_eq rfl) ?_
refine exists_ne (fun v => ?_)
refine exists_ne (fun _ => ?_)
refine sep_ne.ne (.of_eq rfl) ?_
refine Contractive.distLater_dist fun m Hm => ?_
refine BIUpdate.bupd_ne.ne ?_
refine sep_ne.ne (.of_eq rfl) ?_
exact HL m Hm v Φ
def wp {Expr State Value : Type _} [@Ex3WP Expr State Value GF] (e : Expr) (Φ : Value → IProp GF) : IProp GF :=
(fixpoint <| @wp_F Expr State Value _ GF _) e Φ
theorem wp_unfold (e : Expr) (Φ : Value → IProp GF) :
wp e Φ ≡ iprop(
(∃ v : Value, ⌜@to_value _ State _ _ e = some v⌝ ∗ |==> Φ v) ∨
∀ s, @state_interp State _ _ s -∗
∃ e' s', ⌜@step _ _ Value _ (e, s) = (e', s') ⌝ ∗
▷ |==> (@state_interp _ _ _ s' ∗ wp e' Φ)) := by
apply fixpoint_unfold (f := ⟨(@wp_F Expr State Value _ GF _),
@OFE.ne_of_contractive _ _ _ _ (@wp_F Expr State Value _ GF _) _⟩)
/- Now, we can derive some example proof rules. First let's prove a rule for pure deterministic steps: -/
example (e e' : Expr) Φ (Hstep : ∀ {s : State}, @step _ _ Value _ (e, s) = (e', s)) :
wp e' Φ ⊢ wp e Φ := by
refine .trans ?_ (equiv_iff.mp (@wp_unfold Expr State Value _ GF _ _ _).symm).mp
iintro Hspec
iright
iintro %s Hs
iexists e', s
isplitr
· ipure_intro
exact Hstep
· refine .trans ?_ later_intro -- FIXME: once iNext is implemented
refine .trans ?_ BIUpdate.intro -- FIXME: once iModIntro is implemented
iintro ⟨Hspec, Hs⟩
isplitl [Hs]
· iexact Hs
· iexact Hspec
/- The pattern of rules for stateful steps, for example, writing to a piece of memory.
This style of rule applies when ownership over a resource P (eg. k ↦[γ] v) ensures that the state
can step the expression e to some new expression e', and can be updated to a new resource P'
in the stepped-to state.
Then, it suffies to have access to P, and show that access to P' is enough to verify e'. -/
example (e e' : Expr) (P P' : IProp GF) Φ
(Hstep : ∀ s, iprop(P ∗ @state_interp State GF _ s ⊢ ∃ s',
⌜@step _ _ Value _ (e, s) = (e', s')⌝ ∗ |==> (P' ∗ @state_interp State GF _ s'))) :
P ∗ (P' -∗ wp e' Φ) ⊢ wp e Φ := by
refine .trans ?_ (equiv_iff.mp (@wp_unfold Expr State Value _ GF _ _ _).symm).mp
iintro ⟨HP, Hspec⟩
iright
iintro %s Hs
istop -- FIXME: iHave bug?
refine .trans (sep_mono (sep_mono (wand_intro (Hstep s)) .rfl) .rfl) ?_
iintro ⟨⟨Hcont, Hspec⟩, HP⟩
icases Hcont $$ HP with ⟨%s', %Hstep, Hupd⟩
iexists e', s'
isplitr
· ipure_intro; exact Hstep
refine .trans ?_ later_intro -- FIXME: once iNext is implemented
refine .trans bupd_frame_l ?_ -- FIXME: once iMod is implemented
refine BIUpdate.mono ?_ -- FIXME: once iMod is implemented
iintro ⟨Hspec, HP', Hs⟩
isplitl [Hs]
· iexact Hs
· iapply Hspec $$ HP'
end Example3
Markus de Medeiros (Jan 27 2026 at 16:15):
Improvements to these examples are very welcome, by the way
Markus de Medeiros (Feb 05 2026 at 14:15):
Example proof rule for infinitely looping programs, using Löb induction
/- Looping programs, by Löb induction -/
example (e : Expr) Φ (Hloop : ∀ σ : State, step Value (e, σ) = (e, σ)) :
⊢ wp e Φ := by
iapply BILoeb.loeb_weak
iintro HLöb
iapply wp_unfold
iright
iintro %s Hs
iexists e, s
isplitr
· ipure_intro; exact Hloop s
iintro !> !>
isplitl [Hs]
· iassumption
· iassumption
· exact true_intro
Markus de Medeiros (Feb 05 2026 at 14:16):
All the improvements to the frontend are awesome, it feels so much more like writing Iris-Rocq these days
Last updated: Feb 28 2026 at 14:05 UTC