-
Notifications
You must be signed in to change notification settings - Fork 52
feat: ieval, isimp and iunfold #490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
39c2694
Start implementing `ieval`, `isimp` and `iunfold`
alvinylt 27ab402
Require non-empty selection pattern
alvinylt 5c784fa
Introduce `iEvalHyps` and `iEvalGoal`
alvinylt 7d2a875
Towards implementing `iEvalGoal`, add a relevant test
alvinylt 46cebf6
Introduce `EvalState` for iterative handling of selection targets
alvinylt 9115175
Towards implementing `iEvalHypsOne`
alvinylt e986d83
Complete `ieval` implementation
alvinylt 1997635
Add tests for `ieval` and `isimp`
alvinylt f9ea46d
Add a test for `iunfold`
alvinylt f782157
More specific error messages with `ieval` for invalid inputs
alvinylt a898fe7
Code refactoring: integrate `iEvalHypsOne` into `iEvalHyps` inline
alvinylt 7d1b229
Code refactoring: comments
alvinylt d877845
Bug fix: use `pure` instead of `return`
alvinylt 05bceae
Eliminate trivial theorem `eval_refl`
alvinylt 43ff334
Factor out repetitive parts of the code as a helper function
alvinylt be5817a
Refactor code to avoid repetition
alvinylt 9bd5d0a
Add docstring comments to `iEvalCore` and the tactics
alvinylt 89a12d7
Update `Porting.lean`
alvinylt aeb11f7
Update `tactics.md`
alvinylt fb43f8c
Refine error message
alvinylt 994fe63
`isimp`: support variants of `simp`
alvinylt 52b172c
Simplify `isimp`
alvinylt 21b8a09
Merge remote-tracking branch 'upstream/master' into iEval
alvinylt ceeabfe
Add Qq type annotation
alvinylt 417bb84
Fix Qq problem
alvinylt 0d2086b
Qq fix attempt
alvinylt 5706db8
Remove redundant helper function
alvinylt f153c5a
Fix outdated comment for `iEvalOne`
alvinylt d573e30
Update `tactics.md`
alvinylt e339335
Merge remote-tracking branch 'upstream/master' into iEval
alvinylt 6ba2875
Use if-then-else instead of pattern matching on `Bool`
alvinylt bb98893
Explicit `isGoal : Bool` argument for `iEvalOne`
alvinylt eefe5a9
Simplify `iEvalOne`
alvinylt f3a160c
Update Iris/Iris/ProofMode/Tactics/Eval.lean
MackieLoeffel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| /- | ||
| Copyright (c) 2026 Alvin Tang. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Michael Sammler, Alvin Tang | ||
| -/ | ||
| module | ||
|
|
||
| public meta import Iris.ProofMode.Patterns.SelPattern | ||
| public meta import Iris.ProofMode.ProofModeM | ||
|
|
||
| namespace Iris.ProofMode | ||
|
|
||
| public meta section | ||
| open Lean Elab Tactic Meta Qq BI Lean.Parser.Tactic | ||
|
|
||
| /-- For iteratively applying the tactic sequences to selection targets in the context -/ | ||
| private structure EvalState {u} {prop : Q(Type u)} {bi : Q(BI $prop)} (e : Q($prop)) where | ||
| {newE : Q($prop)} | ||
| (newHyps : Hyps bi newE) | ||
| (pf : Q($e ⊢ $newE)) | ||
|
|
||
| /-- | ||
| Apply the tactic sequence `tac` to transform `ty`, which is strengthened when | ||
| it is the goal or weakened when it is a hypothesis in the context. | ||
|
|
||
| When `isGoal` is `true`, the tactic sequence results in the proof goal being *strengthened*. | ||
| When `isGoal` is `false`, the tactic sequence results in the hypothesis being *weakened*. | ||
|
|
||
| The function returns the new expression and a proof that the expression | ||
| is strengthened/weakened. | ||
| -/ | ||
| private def iEvalOne {u} {prop : Q(Type u)} (bi : Q(BI $prop)) | ||
| (tac : TSyntax `Lean.Parser.Tactic.tacticSeq) (isGoal : Bool) (ty : Q($prop)) : | ||
| ProofModeM <| Q($prop) × Expr := do | ||
| let m : Q($prop) ← mkFreshExprMVar q($prop) | ||
| let pf ← mkFreshExprSyntheticOpaqueMVar <| if isGoal then q($m ⊢ $ty) else q($ty ⊢ $m) | ||
| let [g] ← evalTacticAt tac pf.mvarId! | ||
| | throwError "ieval: the supplied tactic does not produce exactly one subgoal" | ||
| let some #[_, _, lhs, rhs] ← g.getType <&> (·.appM? ``Entails) | ||
| | throwError "ieval: the goal is not Iris entailment upon applying the supplied tactic" | ||
| let newTy : Q($prop) := if isGoal then rhs else lhs | ||
| m.mvarId!.assign newTy | ||
| g.assign (q(.rfl) : Q($newTy ⊢ $newTy)) | ||
| return ⟨m, pf⟩ | ||
|
|
||
| /-- | ||
| Apply the tactic sequence `tac` to either the proof goal (when `selTargets` | ||
| is `none`) or the hypotheses in the context specified by the selection targets. | ||
| -/ | ||
| private def iEvalCore {u} {prop : Q(Type u)} {bi : Q(BI $prop)} {e} | ||
| (hyps : Hyps bi e) (goal : Q($prop)) (tac : TSyntax `Lean.Parser.Tactic.tacticSeq) | ||
| (selTargets : Option <| List SelTarget) : ProofModeM Q($e ⊢ $goal) := do | ||
| match selTargets with | ||
| -- No selection pattern given, apply the tactics to the proof goal | ||
| | none => | ||
| let ⟨newGoal, (pf : Q($newGoal ⊢ $goal))⟩ ← iEvalOne (isGoal := true) bi tac goal | ||
| let pf' ← addBIGoal hyps newGoal | ||
| return q($(pf').trans $pf) | ||
| -- Selection patterns given, apply the tactics to the chosen hypotheses | ||
| | some selTargets => | ||
| let mut evalState : EvalState e := { newHyps := hyps, pf := q(.rfl) } | ||
| -- Iteratively apply the supplied tactic sequence to the selection targets | ||
| for selTarget in selTargets do | ||
| evalState ← match selTarget.kind with | ||
| | .pure _ => | ||
| throwError "ieval: pure hypotheses in the selection pattern is not supported" | ||
| | .ipm ivar => | ||
| let some ⟨newE, newHyps, pf⟩ ← evalState.newHyps.evalReplace ivar fun ty => do | ||
| let ⟨newTy, pf⟩ ← iEvalOne (isGoal := false) bi tac ty | ||
| return ⟨newTy, (pf : Q($ty ⊢ $newTy))⟩ | ||
| | throwError m!"ieval: unable to find the hypothesis {ivar.name} in the context" | ||
| pure { newE, newHyps, pf := q($(evalState.pf).trans $pf) } | ||
| let pf' ← addBIGoal evalState.newHyps goal | ||
| return q($(evalState.pf).trans $pf') | ||
|
|
||
| /-- | ||
| `ieval (tac)` applies the tactic sequence `tac` to the proof goal. | ||
| -/ | ||
| elab "ieval " "(" tac:tacticSeq ")" : tactic => do | ||
| ProofModeM.runTactic λ mvar { hyps, goal, .. } => do | ||
| let pf ← iEvalCore hyps goal tac none | ||
| mvar.assign pf | ||
|
|
||
| /-- | ||
| `ieval (tac) in spats` applies the tactic sequence `tac` to the Iris | ||
| hypotheses chosen by the selection pattern `spats`. Pure hypotheses are not | ||
| supported by this tactic. | ||
| -/ | ||
| elab "ieval " "(" tacs:tacticSeq ")" " in " spats:(colGt ppSpace selPat)+ : tactic => do | ||
| let selPats ← liftMacroM <| SelPat.parse spats | ||
|
|
||
| ProofModeM.runTactic λ mvar { hyps, goal, .. } => do | ||
| let selTargets ← SelPat.resolve hyps selPats | ||
| let pf ← iEvalCore hyps goal tacs selTargets | ||
| mvar.assign pf | ||
|
|
||
| /-- | ||
| `isimp` applies `simp` to the proof goal. This is shorthand for `ieval (simp)`. | ||
|
|
||
| `isimp in spats` applies `simp` to the Iris hypotheses chosen by the | ||
| selection pattern `spats`. Pure hypotheses are not supported by this tactic. | ||
| This is shorthand for `ieval (simp) in spats`. | ||
|
|
||
| One can also use `isimp [h₁, h₂, …, hₙ]`, `isimp [*]` and | ||
| `isimp only [h₁, h₂, …, hₙ]` for the tactic behaviour corresponding to | ||
| `simp [h₁, h₂, …, hₙ]`, `simp [*]` and `simp only [h₁, h₂, …, hₙ]`, | ||
| respectively. | ||
| -/ | ||
| syntax "isimp" optConfig (discharger)? (&" only")? (simpArgs)? | ||
| (" in " (colGt ppSpace selPat)+)? : tactic | ||
|
|
||
| private def elabSimp (simp : TSyntax `tactic) | ||
| (spats : Option (TSyntaxArray `selPat)) : TacticM Unit := | ||
| match spats with | ||
| | none => do evalTactic (← `(tactic| ieval ($simp:tactic))) | ||
| | some spats => do evalTactic (← `(tactic| ieval ($simp:tactic) in $spats*)) | ||
|
|
||
| elab_rules : tactic | ||
| | `(tactic| isimp $cfg* $[$disch]? $[[$args,*]]? $[in $spats*]?) => do | ||
| elabSimp (← `(tactic| simp $cfg* $[$disch]? $[[$args,*]]?)) spats | ||
| | `(tactic| isimp $cfg* $[$disch]? only $[[$args,*]]? $[in $spats*]?) => do | ||
| elabSimp (← `(tactic| simp $cfg* $[$disch]? only $[[$args,*]]?)) spats | ||
|
|
||
| /-- `iunfold hs` applies `unfold hs` to the proof goal. This is shorthand for `ieval (unfold)`. -/ | ||
| macro "iunfold " hs:ident,+ : tactic => `(tactic| ieval (unfold $hs*)) | ||
|
|
||
| /-- | ||
| `iunfold hs in spats` applies `unfold hs` to the Iris hypotheses chosen by | ||
| the selection pattern `spats`. Pure hypotheses are not supported by this tactic. | ||
| This is shorthand for `ieval (unfold hs) in spats`. | ||
| -/ | ||
| macro "iunfold " hs:ident,+ " in " spats:(colGt ppSpace selPat)* : tactic => | ||
| `(tactic| ieval (unfold $hs*) in $spats*) | ||
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
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
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.
Uh oh!
There was an error while loading. Please reload this page.