-
Notifications
You must be signed in to change notification settings - Fork 259
/
Cases.lean
110 lines (99 loc) · 4.39 KB
/
Cases.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/-
Copyright (c) 2022 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
import Lean
import Std.Tactic.OpenPrivate
import Std.Data.List.Basic
/-!
# Backward compatible implementation of lean 3 `cases` tactic
This tactic is similar to the `cases` tactic in lean 4 core, but the syntax for giving
names is different:
```
example (h : p ∨ q) : q ∨ p := by
cases h with
| inl hp => exact Or.inr hp
| inr hq => exact Or.inl hq
example (h : p ∨ q) : q ∨ p := by
cases' h with hp hq
· exact Or.inr hp
· exact Or.inl hq
example (h : p ∨ q) : q ∨ p := by
rcases h with hp | hq
· exact Or.inr hp
· exact Or.inl hq
```
Prefer `cases` or `rcases` when possible, because these tactics promote structured proofs.
-/
namespace Lean.Parser.Tactic
open Meta Elab Elab.Tactic
open private getAltNumFields in evalCases ElimApp.evalAlts.go in
def ElimApp.evalNames (elimInfo : ElimInfo) (alts : Array ElimApp.Alt) (withArg : Syntax)
(numEqs := 0) (numGeneralized := 0) (toClear : Array FVarId := #[]) :
TermElabM (Array MVarId) := do
let mut names := if withArg.isNone then [] else
withArg[1].getArgs.map (getNameOfIdent' ·[0]) |>.toList
let mut subgoals := #[]
for { name := altName, mvarId := g, .. } in alts do
let numFields ← getAltNumFields elimInfo altName
let (altVarNames, names') := names.splitAtD numFields `_
names := names'
let (_, g) ← g.introN numFields altVarNames
let some (g, _) ← Cases.unifyEqs? numEqs g {} | pure ()
let (_, g) ← g.introNP numGeneralized
let g ← liftM $ toClear.foldlM (·.tryClear) g
subgoals := subgoals.push g
pure subgoals
open private getElimNameInfo generalizeTargets generalizeVars in evalInduction in
elab (name := induction') "induction' " tgts:(casesTarget,+)
usingArg:((" using " ident)?)
withArg:((" with " (colGt binderIdent)+)?)
genArg:((" generalizing " (colGt ident)+)?) : tactic => do
let targets ← elabCasesTargets tgts.1.getSepArgs
let g ← getMainGoal
g.withContext do
let elimInfo ← getElimNameInfo usingArg targets (induction := true)
let targets ← addImplicitTargets elimInfo targets
evalInduction.checkTargets targets
let targetFVarIds := targets.map (·.fvarId!)
g.withContext do
let genArgs ← if genArg.1.isNone then pure #[] else getFVarIds genArg.1[1].getArgs
let forbidden ← mkGeneralizationForbiddenSet targets
let mut s ← getFVarSetToGeneralize targets forbidden
for v in genArgs do
if forbidden.contains v then
throwError ("variable cannot be generalized " ++
"because target depends on it{indentExpr (mkFVar v)}")
if s.contains v then
throwError ("unnecessary 'generalizing' argument, " ++
"variable '{mkFVar v}' is generalized automatically")
s := s.insert v
let (fvarIds, g) ← g.revert (← sortFVarIds s.toArray)
let result ← withRef tgts <| ElimApp.mkElimApp elimInfo targets (← g.getTag)
let elimArgs := result.elimApp.getAppArgs
ElimApp.setMotiveArg g elimArgs[elimInfo.motivePos]!.mvarId! targetFVarIds
g.assign result.elimApp
let subgoals ← ElimApp.evalNames elimInfo result.alts withArg
(numGeneralized := fvarIds.size) (toClear := targetFVarIds)
setGoals (subgoals ++ result.others).toList
open private getElimNameInfo in evalCases in
elab (name := cases') "cases' " tgts:(casesTarget,+) usingArg:((" using " ident)?)
withArg:((" with " (colGt binderIdent)+)?) : tactic => do
let targets ← elabCasesTargets tgts.1.getSepArgs
let g ← getMainGoal
g.withContext do
let elimInfo ← getElimNameInfo usingArg targets (induction := false)
let targets ← addImplicitTargets elimInfo targets
let result ← withRef tgts <| ElimApp.mkElimApp elimInfo targets (← g.getTag)
let elimArgs := result.elimApp.getAppArgs
let targets ← elimInfo.targetsPos.mapM (instantiateMVars elimArgs[·]!)
let motive := elimArgs[elimInfo.motivePos]!
let g ← generalizeTargetsEq g (← inferType motive) targets
let (targetsNew, g) ← g.introN targets.size
g.withContext do
ElimApp.setMotiveArg g motive.mvarId! targetsNew
g.assign result.elimApp
let subgoals ← ElimApp.evalNames elimInfo result.alts withArg
(numEqs := targets.size) (toClear := targetsNew)
setGoals subgoals.toList