-
Notifications
You must be signed in to change notification settings - Fork 26
feat: iapply tactic #80
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
markusdemedeiros
merged 124 commits into
leanprover-community:master
from
oliversoeser:iapply
Dec 4, 2025
Merged
Changes from all commits
Commits
Show all changes
124 commits
Select commit
Hold shift + click to select a range
a735c02
basic iapply setup
oliversoeser cc90064
basic iapply case distinction
oliversoeser d940602
iapply structure
oliversoeser 8583f03
comment out sorrys
oliversoeser 4f0b356
comment out failing tests
oliversoeser 6725231
iapply simple wand (n=1 case)
oliversoeser a100c8a
iApplyCore
oliversoeser 72a67ba
move hypothesis removal
oliversoeser c4870cd
recursion
oliversoeser 1430f9f
identify hypotheses
oliversoeser 70c81cb
Revert
oliversoeser f293704
basic spec patterns
oliversoeser 33591dc
induction step apply theorem
oliversoeser 3e7cab4
apply' forward direction only
oliversoeser 3b0f2d6
apply' type classes
oliversoeser abceb0e
proof refactor
oliversoeser 795b55d
simple spec patterns success
oliversoeser d10ff64
specpat constructor
oliversoeser 39d76ce
complex spec pat progress
oliversoeser d9ffddb
recursive hypothesis removal
oliversoeser 62453b4
hypothesis removal outputs
oliversoeser c37a1fc
restructure
oliversoeser f7178bf
make apply reflect tac_apply
oliversoeser 5e78fff
hyps split
oliversoeser 96ab470
hyp split refactor
oliversoeser 4ff5961
goal tracking refactor
oliversoeser 5168049
simplify iApplyCore signature
oliversoeser cd95a81
PmTerms
oliversoeser 671efb3
complete pmterm syntax
oliversoeser 449575e
pmterm parser
oliversoeser 8b40de9
fix pmterm ident type
oliversoeser 2d51609
structure for recursive case
oliversoeser c0bf5c5
construction outline
oliversoeser a641db9
implement outline
oliversoeser 0729e71
reworked iApply recursion
oliversoeser 1b2ab36
experimental implementation
oliversoeser 84ff33e
explicit instance construction
oliversoeser dc190de
working prototype
oliversoeser ed7eaee
goal tracker
oliversoeser f470641
weaken assumption theorem hypotheses
oliversoeser 67a12a1
refactoring
oliversoeser f2c3aff
Merge branch 'master' into iapply
oliversoeser 7e03b87
Revert "Merge branch 'master' into iapply"
oliversoeser 013ad81
combine IntoWand and IntoWand'
oliversoeser daae14c
Merge branch 'leanprover-community:master' into iapply
oliversoeser 5bb5655
get rid of RemoveHyp'
oliversoeser 575122c
simplify iApplyCore and revert assumption
oliversoeser ea0815d
update lean
oliversoeser 2d70845
fix pmterm parser
oliversoeser 0decafa
simplify
oliversoeser 1a12aa3
rec_apply
oliversoeser a2d75d3
additional test case
oliversoeser 5d33ec0
more tests
oliversoeser a0803eb
restructure
oliversoeser 6e7e912
lean lemma structure
oliversoeser 51f67ce
prototype finished
oliversoeser c98b528
lean lemma exact case
oliversoeser 2876ae7
comments
oliversoeser 6954bdc
rename variables
oliversoeser 4cd0647
lean lemma general case
oliversoeser 3aed4ae
simplify
oliversoeser 983d0fd
simplify
oliversoeser 7961a91
add tests for lean lemma apply
oliversoeser 8771eb7
rename temp
oliversoeser 2629d95
eliminate trivial goals
oliversoeser fb38fd7
move goal elimination to core
oliversoeser 3bb0d9b
adjust behaviour
oliversoeser 52f2fe6
control goal elimination using with
oliversoeser 5138d0d
nameable goals
oliversoeser 8905208
add fromAssumption instances
oliversoeser 2e93d34
headName
oliversoeser 798da91
revert extra automation
oliversoeser 9e3bac4
improve specpats
oliversoeser 69c2b13
distinguish [H] and H
oliversoeser 4e19bc2
restructure iApplyCore
oliversoeser ac460ba
proper error message
oliversoeser 124e41d
ipose structure
oliversoeser 9459f50
document iapply
oliversoeser f174afe
document specPat and pmTerm
oliversoeser b3e5307
fix test
oliversoeser d6a0adc
ipose prototype
oliversoeser 2438131
ipose working
oliversoeser 1c363fc
ipose emp case
oliversoeser 9d1dca8
iPoseCore
oliversoeser 0a76d07
ipose explicit types
oliversoeser ed00cbf
processSpecPats
oliversoeser 8f3f32a
factor processSpecPats out of iApplyCore
oliversoeser 9ffc891
more factoring
oliversoeser ba9eb70
specPatGoal
oliversoeser 3270440
simplify recursive case
oliversoeser a8501a3
restructure ipose
oliversoeser dd7ff75
integrate ipose in iapply
oliversoeser d5fbfe3
simplify iApply
oliversoeser 6d4a8ec
ipose refactor
oliversoeser fe13897
document ipose
oliversoeser dba0e6f
pmTerm syntax replace idents with terms
oliversoeser b5d9cc4
term cases and test
oliversoeser c2be0a7
fix
oliversoeser 7f92909
Revert "fix"
oliversoeser 0ac46ae
Revert "term cases and test"
oliversoeser ebc7bb6
blunt lean lemma application
oliversoeser b1c6760
combine and simplify
oliversoeser a4794c7
use of apply
oliversoeser f4d6c63
simplify
oliversoeser 9cd8ae3
simplify
oliversoeser d88ffa0
exact term application
oliversoeser 920b47f
working apply test
oliversoeser 38c5ebb
refactor
oliversoeser bbd8c1e
ipose use identifiers
oliversoeser f897976
minor changes
oliversoeser 30f0290
forall test
oliversoeser 471877b
$! tests
oliversoeser 2ab1377
basic $! functionality
oliversoeser 62d30a5
Use IntoForall typeclass
oliversoeser e331f53
minor cleanup
oliversoeser a265544
update ipose description
oliversoeser 1232e3e
$! working for iris hypotheses
oliversoeser d8addaf
IntoEmpValid
oliversoeser 7e02499
refactor iPoseCore with IntoEmpValid
oliversoeser 462048c
simplify single specPat
oliversoeser 94479c2
handle top-level foralls
oliversoeser b6c4625
fully handle dependent arrows
oliversoeser e9f71b6
use iCasesCore in iPose
oliversoeser e050e0f
idents for goal naming
oliversoeser 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,3 @@ | ||
| import Iris.ProofMode.Patterns.CasesPattern | ||
| import Iris.ProofMode.Patterns.ProofModeTerm | ||
| import Iris.ProofMode.Patterns.SpecPattern |
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,34 @@ | ||
| /- | ||
| Copyright (c) 2025 Oliver Soeser. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Oliver Soeser | ||
| -/ | ||
| import Iris.ProofMode.Patterns.SpecPattern | ||
|
|
||
| namespace Iris.ProofMode | ||
| open Lean | ||
|
|
||
| declare_syntax_cat pmTerm | ||
|
|
||
| syntax term : pmTerm | ||
| syntax term "with" specPat,+ : pmTerm | ||
| syntax term "$!" term,+ : pmTerm | ||
| syntax term "$!" term,+ "with" specPat,+ : pmTerm | ||
|
|
||
| structure PMTerm where | ||
| term : Term | ||
| terms : List Term | ||
| spats : List SpecPat | ||
| deriving Repr, Inhabited | ||
|
|
||
| partial def PMTerm.parse (term : Syntax) : MacroM PMTerm := do | ||
| match ← expandMacros term with | ||
| | `(pmTerm| $trm:term) => return ⟨trm, [], []⟩ | ||
| | `(pmTerm| $trm:term with $spats,*) => return ⟨trm, [], ← parseSpats spats⟩ | ||
| | `(pmTerm| $trm:term $! $ts,*) => return ⟨trm, ts.getElems.toList, []⟩ | ||
| | `(pmTerm| $trm:term $! $ts,* with $spats,*) => | ||
| return ⟨trm, ts.getElems.toList, ← parseSpats spats⟩ | ||
| | _ => Macro.throwUnsupported | ||
| where | ||
| parseSpats (spats : Syntax.TSepArray `specPat ",") : MacroM (List SpecPat) := | ||
| return (← spats.getElems.toList.mapM fun pat => SpecPat.parse pat.raw) | ||
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,36 @@ | ||
| /- | ||
| Copyright (c) 2025 Oliver Soeser. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Oliver Soeser | ||
| -/ | ||
| namespace Iris.ProofMode | ||
| open Lean | ||
|
|
||
| declare_syntax_cat specPat | ||
|
|
||
| syntax binderIdent : specPat | ||
| syntax "[" binderIdent,* "]" optional(" as " ident) : specPat | ||
|
|
||
| inductive SpecPat | ||
| | ident (name : TSyntax ``binderIdent) | ||
| | idents (names : List (TSyntax ``binderIdent)) (goalName : Name) | ||
| deriving Repr, Inhabited | ||
|
|
||
| partial def SpecPat.parse (pat : Syntax) : MacroM SpecPat := do | ||
| match go ⟨← expandMacros pat⟩ with | ||
| | none => Macro.throwUnsupported | ||
| | some pat => return pat | ||
| where | ||
| go : TSyntax `specPat → Option SpecPat | ||
| | `(specPat| $name:binderIdent) => some <| .ident name | ||
| | `(specPat| [$[$names:binderIdent],*]) => some <| .idents names.toList .anonymous | ||
| | `(specPat| [$[$names:binderIdent],*] as $goal:ident) => match goal.raw with | ||
| | .ident _ _ val _ => some <| .idents names.toList val | ||
| | _ => none | ||
| | _ => none | ||
|
|
||
| def headName (spats : List SpecPat) : Name := | ||
| match spats.head? with | ||
| | some <| .ident _ => .anonymous | ||
| | some <| .idents _ name => name | ||
| | _ => .anonymous |
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,126 @@ | ||
| /- | ||
| Copyright (c) 2025 Oliver Soeser. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Oliver Soeser | ||
| -/ | ||
| import Iris.ProofMode.Patterns.ProofModeTerm | ||
| import Iris.ProofMode.Tactics.Split | ||
| import Iris.ProofMode.Tactics.Pose | ||
|
|
||
| namespace Iris.ProofMode | ||
| open Lean Elab Tactic Meta Qq BI Std | ||
|
|
||
| theorem apply [BI PROP] {P Q1 Q2 R : PROP} | ||
| (h : P ⊢ Q1) [inst : IntoWand false false R Q1 Q2] : P ∗ R ⊢ Q2 := | ||
| (sep_mono h inst.1).trans wand_elim_r | ||
|
|
||
| theorem rec_apply [BI PROP] {P Q P' Q' Q1 Q2 R : PROP} | ||
| (h1 : P ⊣⊢ P' ∗ Q') (h2 : Q' ⊢ Q1) (h3 : P' ∗ Q2 ⊢ R) | ||
| [IntoWand false false Q Q1 Q2] : P ∗ Q ⊢ R := | ||
| (sep_congr h1 .rfl).mp.trans <| sep_assoc.mp.trans <| (sep_mono_r <| apply h2).trans h3 | ||
|
|
||
| theorem apply_lean [BI PROP] {P Q R : PROP} (h1 : ⊢ Q) (h2 : P ∗ Q ⊢ R) : P ⊢ R := | ||
| sep_emp.mpr.trans <| (sep_mono_r h1).trans h2 | ||
|
|
||
| variable {prop : Q(Type u)} {bi : Q(BI $prop)} in | ||
| def specPatGoal | ||
| (A1 : Q($prop)) (hyps : Hyps bi e) (spats : List SpecPat) | ||
| (addGoal : ∀ {e}, Name → Hyps bi e → (goal : Q($prop)) → MetaM Q($e ⊢ $goal)) : | ||
| MetaM Q($e ⊢ $A1) := do | ||
| return ← if let (some <| .ident _, some inst) := (spats.head?, | ||
| ← try? (synthInstanceQ q(FromAssumption false $e $A1))) then | ||
| pure q(($inst).from_assumption) | ||
| else | ||
| addGoal (headName spats) hyps A1 | ||
|
|
||
| variable {prop : Q(Type u)} {bi : Q(BI $prop)} in | ||
| def processSpecPats | ||
| (A1 : Q($prop)) (hypsl : Hyps bi el) (spats : List SpecPat) | ||
| (addGoal : ∀ {e}, Name → Hyps bi e → (goal : Q($prop)) → MetaM Q($e ⊢ $goal)) : | ||
| MetaM ((el' er' : Q($prop)) × Q($er' ⊢ $A1) × Hyps bi el' × Q($el ⊣⊢ $el' ∗ $er')) := do | ||
| let splitPat := fun name _ => match spats.head? with | ||
| | some <| .ident bIdent => binderIdentHasName name bIdent | ||
| | some <| .idents bIdents _ => bIdents.any <| binderIdentHasName name | ||
| | _ => false | ||
|
|
||
| let ⟨el', er', hypsl', hypsr', h'⟩ := Hyps.split bi splitPat hypsl | ||
| let m ← specPatGoal A1 hypsr' spats addGoal | ||
| return ⟨el', er', m, hypsl', h'⟩ | ||
|
|
||
| variable {prop : Q(Type u)} {bi : Q(BI $prop)} in | ||
| partial def iApplyCore | ||
| (goal el er : Q($prop)) (hypsl : Hyps bi el) (spats : List SpecPat) | ||
| (addGoal : ∀ {e}, Name → Hyps bi e → (goal : Q($prop)) → MetaM Q($e ⊢ $goal)) : | ||
| MetaM (Q($el ∗ $er ⊢ $goal)) := do | ||
| let A1 ← mkFreshExprMVarQ q($prop) | ||
| let A2 ← mkFreshExprMVarQ q($prop) | ||
|
|
||
| let _ ← isDefEq er goal | ||
| if let (some _, some _) := (← try? <| synthInstanceQ q(FromAssumption false $er $goal), | ||
| ← try? <| synthInstanceQ q(TCOr (Affine $el) (Absorbing $goal))) then | ||
| -- iexact case | ||
| return q(assumption (p := false) .rfl) | ||
| else if let some _ ← try? <| synthInstanceQ q(IntoWand false false $er $A1 $goal) then | ||
| -- iapply base case | ||
| let m ← specPatGoal A1 hypsl spats addGoal | ||
| return q(apply $m) | ||
| else if let some _ ← try? <| synthInstanceQ q(IntoWand false false $er $A1 $A2) then | ||
| -- iapply recursive case | ||
| let ⟨el', _, m, hypsl', h'⟩ ← processSpecPats A1 hypsl spats addGoal | ||
| let res : Q($el' ∗ $A2 ⊢ $goal) ← iApplyCore goal el' A2 hypsl' spats.tail addGoal | ||
| return q(rec_apply $h' $m $res) | ||
| else | ||
| throwError "iapply: cannot apply {er} to {goal}" | ||
|
|
||
| theorem apply_forall [BI PROP] (x : α) (P : α → PROP) {Q : PROP} | ||
| [H1 : IntoForall Q P] (H2 : E ⊢ E' ∗ Q) : E ⊢ E' ∗ P x := | ||
| Entails.trans H2 <| sep_mono_r <| H1.into_forall.trans <| forall_elim x | ||
|
|
||
| partial def instantiateForalls' {prop : Q(Type u)} (e e' : Q($prop)) (bi : Q(BI $prop)) | ||
| (out : Q($prop)) (pf : Q($e ⊢ $e' ∗ $out)) (terms : List Term) : | ||
| TacticM (Expr × Expr) := do | ||
| if let some t := terms.head? then | ||
| let texpr ← mkAppM' (← elabTerm t none) #[] | ||
| let ⟨_, ttype, texpr⟩ ← inferTypeQ texpr | ||
| let Φ ← mkFreshExprMVarQ q($ttype → $prop) | ||
| let _ ← synthInstanceQ q(IntoForall $out $Φ) | ||
| let res ← mkAppM' Φ #[texpr] | ||
| let pf' ← mkAppM ``apply_forall #[texpr, Φ, pf] | ||
| return ← instantiateForalls' e e' bi res pf' terms.tail | ||
| else | ||
| return ⟨out, pf⟩ | ||
|
|
||
| elab "iapply" colGt pmt:pmTerm : tactic => do | ||
| let pmt ← liftMacroM <| PMTerm.parse pmt | ||
| let mvar ← getMainGoal | ||
|
|
||
| mvar.withContext do | ||
| let g ← instantiateMVars <| ← mvar.getType | ||
| let some { u, prop, e, bi, hyps, goal, .. } := parseIrisGoal? g | throwError "not in proof mode" | ||
| if let some uniq ← try? do pure (← hyps.findWithInfo ⟨pmt.term⟩) then | ||
| -- lemma from iris context | ||
| let ⟨e', hyps', out, _, _, _, pf⟩ := hyps.remove false uniq | ||
|
|
||
| let ⟨out, pf⟩ := ← instantiateForalls' e e' bi out q(($pf).mp) pmt.terms | ||
|
|
||
| let goals ← IO.mkRef #[] | ||
| let res ← iApplyCore goal e' out hyps' pmt.spats <| goalTracker goals | ||
| mvar.assign <| ← mkAppM ``Entails.trans #[pf, res] | ||
| replaceMainGoal (← goals.get).toList | ||
| else | ||
| -- lemma from lean context | ||
| let A1 ← mkFreshExprMVarQ q($prop) | ||
| let A2 ← mkFreshExprMVarQ q($prop) | ||
|
|
||
| let expected : Q(Prop) := if let some _ := ← try? <| | ||
| synthInstanceQ q(IntoWand false false $goal $A1 $A2) | ||
| then q($e ⊢ $A1 -∗ $A2) else q($e ⊢ $goal) | ||
|
|
||
| let expr ← mkAppM' (← elabTerm pmt.term (some expected)) #[] | ||
|
|
||
| let goals ← IO.mkRef #[] | ||
| let ⟨hyp, pf⟩ ← iPoseCore bi expr pmt.terms goals | ||
|
|
||
| let res ← iApplyCore goal e hyp hyps pmt.spats <| goalTracker goals | ||
| mvar.assign <| ← mkAppM ``apply_lean #[pf, res] | ||
| replaceMainGoal (← goals.get).toList |
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to leave this for now but I think it's worth putting on the todo list to improve this syntax, I think we can do better with a more curry howard application-like syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving this to an issue.