File tree Expand file tree Collapse file tree 5 files changed +136
-57
lines changed
Expand file tree Collapse file tree 5 files changed +136
-57
lines changed Original file line number Diff line number Diff line change @@ -160,9 +160,16 @@ but adds the `hx : x = v` hypothesis first. Having a `with` binding associated t
160160syntax (name := clearValue) "clear_value" (ppSpace colGt (clearValueStar <|> term:max))+ (" with" (ppSpace colGt binderIdent)+)? : tactic
161161
162162/--
163- `subst x...` substitutes each `x` with `e` in the goal if there is a hypothesis
164- of type `x = e` or `e = x`.
165- If `x` is itself a hypothesis of type `y = e` or `e = y`, `y` is substituted instead.
163+ `subst x...` substitutes each hypothesis `x` with a definition found in the local context,
164+ then eliminates the hypothesis.
165+ - If `x` is a local definition, then its definition is used.
166+ - Otherwise, if there is a hypothesis of the form `x = e` or `e = x`,
167+ then `e` is used for the definition of `x`.
168+
169+ If `h : a = b`, then `subst h` may be used if either `a` or `b` unfolds to a local hypothesis.
170+ This is similar to the `cases h` tactic.
171+
172+ See also: `subst_vars` for substituting all local hypotheses that have a defining equation.
166173-/
167174syntax (name := subst) "subst" (ppSpace colGt term:max)+ : tactic
168175
Original file line number Diff line number Diff line change @@ -403,7 +403,20 @@ def forEachVar (hs : Array Syntax) (tac : MVarId → FVarId → MetaM MVarId) :
403403
404404@[builtin_tactic Lean.Parser.Tactic.subst] def evalSubst : Tactic := fun stx =>
405405 match stx with
406- | `(tactic| subst $hs*) => forEachVar hs Meta.subst
406+ | `(tactic| subst $hs*) => forEachVar hs fun mvarId fvarId => do
407+ let decl ← fvarId.getDecl
408+ if decl.isLet then
409+ -- Zeta delta reduce the let and eliminate it.
410+ let (_, mvarId) ← mvarId.withReverted #[fvarId] fun mvarId' fvars => mvarId'.withContext do
411+ let tgt ← mvarId'.getType
412+ assert! tgt.isLet
413+ let mvarId'' ← mvarId'.replaceTargetDefEq (tgt.letBody!.instantiate1 tgt.letValue!)
414+ -- Dropped the let fvar
415+ let aliasing := (fvars.extract 1 ).map some
416+ return ((), aliasing, mvarId'')
417+ return mvarId
418+ else
419+ Meta.subst mvarId fvarId
407420 | _ => throwUnsupportedSyntax
408421
409422@[builtin_tactic Lean.Parser.Tactic.substVars] def evalSubstVars : Tactic := fun _ =>
Original file line number Diff line number Diff line change 1+ /-!
2+ # Tests of the `subst` tactic when `let`s are present.
3+ -/
4+
5+ /-!
6+ Eliminates `a` even though `e : id a = m`.
7+ -/
8+ /--
9+ trace: case intro
10+ n : Nat
11+ m : Nat := n
12+ a : Nat
13+ e : id a = m
14+ ⊢ 0 + n = n
15+ ---
16+ trace: case intro
17+ a : Nat
18+ m : Nat := id a
19+ ⊢ 0 + id a = id a
20+ -/
21+ #guard_msgs in
22+ theorem ex1 (n : Nat) : 0 + n = n := by
23+ let m := n
24+ have h : ∃ k, id k = m := ⟨m, rfl⟩
25+ cases h with
26+ | intro a e =>
27+ trace_state
28+ subst e
29+ trace_state
30+ apply Nat.zero_add
31+
32+ /-!
33+ Eliminates `a` even though `e : m = id a`.
34+ -/
35+ /--
36+ trace: case intro
37+ n : Nat
38+ m : Nat := n
39+ a : Nat
40+ e : m = id a
41+ ⊢ 0 + n = n
42+ ---
43+ trace: case intro
44+ n : Nat
45+ m : Nat := n
46+ ⊢ 0 + n = n
47+ -/
48+ #guard_msgs in
49+ theorem ex2 (n : Nat) : 0 + n = n := by
50+ let m := n
51+ have h : ∃ k, m = id k := ⟨m, rfl⟩
52+ cases h with
53+ | intro a e =>
54+ trace_state
55+ subst e
56+ trace_state
57+ apply Nat.zero_add
58+
59+ /-!
60+ Since `v` is a let binding, the `subst v` tactic instead
61+ zeta delta reduces it everywhere and then clears it.
62+ -/
63+ /--
64+ trace: n : Nat
65+ h : n = 0
66+ m : Nat := n + 1
67+ v : Nat := m + 1
68+ this : v = n + 2
69+ ⊢ 0 + n = 0
70+ ---
71+ trace: n : Nat
72+ h : n = 0
73+ m : Nat := n + 1
74+ this : m + 1 = n + 2
75+ ⊢ 0 + n = 0
76+ ---
77+ trace: m : Nat := 0 + 1
78+ this : m + 1 = 0 + 2
79+ ⊢ 0 + 0 = 0
80+ -/
81+ #guard_msgs in
82+ theorem ex3 (n : Nat) (h : n = 0 ) : 0 + n = 0 := by
83+ let m := n + 1
84+ let v := m + 1
85+ have : v = n + 2 := rfl
86+ trace_state
87+ subst v
88+ trace_state
89+ subst n
90+ trace_state
91+ rfl
92+
93+ /-!
94+ Can't do `subst this` with `this : v = n + 2` since `v` is a let binding.
95+ The tactic sees `m + 1 = n + 2` and fails.
96+ -/
97+ /--
98+ error: tactic 'subst' failed, invalid equality proof, it is not of the form (x = t) or (t = x)
99+ v = n + 2
100+ n : Nat
101+ h : n = 0
102+ m : Nat := n + 1
103+ v : Nat := m + 1
104+ this : v = n + 2
105+ ⊢ 0 + n = 0
106+ -/
107+ #guard_msgs in
108+ theorem ex4 (n : Nat) (h : n = 0 ) : 0 + n = 0 := by
109+ let m := n + 1
110+ let v := m + 1
111+ have : v = n + 2 := rfl
112+ subst this
Load Diff This file was deleted.
Load Diff This file was deleted.
You can’t perform that action at this time.
0 commit comments