@@ -6,6 +6,7 @@ Authors: Lua Viana Reis, Kyle Miller, Gareth Ma
66module
77
88public meta import Mathlib.Tactic.Set
9+ public meta import Mathlib.Tactic.Core
910public meta import Lean.Elab.BuiltinTerm
1011public meta import Batteries.Tactic.Exact
1112
@@ -17,26 +18,26 @@ This module defines the `setm` tactic.
1718
1819meta section
1920
20- open Lean Elab Tactic Meta Term Syntax
21+ open Lean Mathlib Elab Tactic Meta Term Syntax
2122
22- abbrev SetMReplaceM := StateT (AssocList Name MVarId) TermElabM
23+ abbrev SetMReplaceM := StateT (List ( Name × MVarId) ) TermElabM
2324
2425/-- Collect all synthetic holes and replace them with fresh metavariables. -/
2526partial def replaceWithMVars (stx : Term) : SetMReplaceM Term := do
2627 let stx ← stx.raw.replaceM fun stx ↦ do
27- if let `(?$n:ident) := stx then
28- let mvar ← ((← get).find? n.getId).getDM do
29- let name ← mkFreshUserName n.getId
30- let mvar := (← mkFreshExprMVar none (userName := name)).mvarId!
31- modify (.cons n.getId mvar)
32- pure mvar
33- return ← withRef stx <| `(? $(mkIdent (← mvar.getTag)))
34- else if let `(?_) := stx then
35- let mvar ← mkFreshExprMVar none
36- let name ← mkFreshUserName .anonymous
37- modify (.cons name mvar.mvarId!)
38- return ← withRef stx <| `(? $(mkIdent name) )
39- else pure none
28+ let pair ←
29+ if let `(?$n:ident) := stx then
30+ (← get).find? (·. 1 == n.getId) |>.getDM do
31+ let name ← mkFreshUserName n.getId
32+ let mvar ← mkFreshExprMVar none (userName := name )
33+ pure (n.getId, mvar.mvarId!)
34+ else if let `(?_) := stx then
35+ let name ← mkFreshUserName `x
36+ let mvar ← mkFreshExprMVar none (userName := name)
37+ pure (name, mvar.mvarId!)
38+ else return none
39+ modify (.cons pair )
40+ return ← withRef stx <| `(? $(mkIdent (← pair. 2 .getTag)))
4041 return ⟨stx⟩
4142
4243/--
@@ -45,41 +46,41 @@ local declaration (using the `at h` syntax) or the main goal, and introduces `le
4546representing subexpressions whose location corresponds to the given named hole. These variables are
4647also substituted into the type of declaration (or main goal).
4748-/
48- syntax (name := setM) "setm " term (Parser.Tactic.location)? : tactic
49+ syntax (name := setM) "setm " term ("using" ident)? ( Parser.Tactic.location)? : tactic
4950
50- @ [ tactic setM]
51- public def evalSetM : Tactic
52- | `(tactic| setm $pat:term $[$loc:location]?) => withReducibleAndInstances do
53- let locations := expandOptLocation (Lean.mkOptionalNode loc)
54- withMainContext do
55- let (pat, mvars) ← (replaceWithMVars pat).run {}
56- let pat ← Term.elabTerm pat none
57- let mut g ← getMainGoal
58- for (name, mvar) in mvars.toList.reverse do
59- let mvar' ← mkFreshExprMVar none
60- g ← g.define name (← mvar'.mvarId!.getType) mvar'
61- let (fvar, g') ← g.intro1P
62- mvar.assign (.fvar fvar)
63- g := g'
64- replaceMainGoal [g]
65- withLocation locations
66- (atLocal := fun loc ↦ do
67- if ← isDefEq pat (← loc.getType) then
68- liftMetaTactic fun g ↦ do
69- return [← g.replaceLocalDeclDefEq loc pat]
70- else
71- defeqError pat (← loc.getType))
72- (atTarget := do
73- liftMetaTactic fun g ↦ do
74- if ← isDefEq pat (← g.getType) then
75- return [← g.replaceTargetDefEq pat]
76- else
77- defeqError pat (← g.getType))
78- (failed := fun _ ↦ throwError "tactic `setm` failed" )
79- | _ => throwUnsupportedSyntax
80- where
81- defeqError {α} (p e : Expr) : MetaM α :=
82- throwError MessageData.ofLazyM (es := #[p, e]) do
83- let (p, tgt) ← addPPExplicitToExposeDiff p e
84- return m! "setm pattern { indentExpr p } \n is not definitionally equal {
85- "" } to the target { indentExpr tgt } "
51+ def defeqError {α} (p e : Expr) : MetaM α :=
52+ throwError MessageData.ofLazyM (es := #[p, e]) do
53+ let (p, tgt) ← addPPExplicitToExposeDiff p e
54+ return m! "setm pattern { indentExpr p } \n is not definitionally equal {
55+ "" } to the target { indentExpr tgt } "
56+
57+ elab_rules : tactic
58+ | `(tactic| setm $pat:term $[ using $usingArg]? $[$loc:location]?) =>
59+ withMainContext do
60+ let (pat, mvars) ← (replaceWithMVars pat).run {}
61+ let pat ← Term.elabTerm pat none
62+ let mut g ← getMainGoal
63+ for (name, mvar) in mvars.reverse do
64+ let mvar' ← mkFreshExprMVar none
65+ g ← g.define name (← mvar'.mvarId!.getType) mvar'
66+ let (fvar, g') ← g.intro1P
67+ mvar.assign (.fvar fvar)
68+ g := g'
69+ replaceMainGoal [g]
70+ withMainContext <| withReducibleAndInstances do
71+ if let some place := usingArg.map getId then
72+ let loc := (← getLocalDeclFromUserName place).fvarId
73+ if ← isDefEq pat (← loc.getType) then
74+ replaceMainGoal [← g.changeLocalDecl loc pat false ]
75+ else
76+ defeqError pat (← loc.getType)
77+ else
78+ if ← isDefEq pat (← g.getType) then
79+ replaceMainGoal [← g.replaceTargetDefEq pat]
80+ else
81+ defeqError pat (← g.getType)
82+ if let some loc := loc then
83+ for (name, _) in mvars do
84+ let expr := (← getLocalDeclFromUserName name).value
85+ evalTactic (← `(tactic| try
86+ rewrite [ show $(← Term.exprToSyntax expr) = $(mkIdent name) from rfl] $loc))
0 commit comments