feat: make rcases use the custom Nat eliminator (#3747)

As a special case, makes the `rcases` machinery use `Nat.casesAuxOn` so
that goal states see `0` and `n + 1` rather than `Nat.zero` and
`Nat.succ n`. This is a followup to enabling custom eliminators for
`cases` and `induction`.

This doesn't use custom eliminators in general since `rcases` uses
`Lean.MVarId.cases`, which is completely different from what `cases` and
`induction` use.
This commit is contained in:
Kyle Miller 2024-04-13 09:55:48 -07:00 committed by GitHub
parent 3d24c68347
commit c4bfe25d18
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 19 additions and 12 deletions

View file

@ -348,7 +348,7 @@ partial def rcasesCore (g : MVarId) (fs : FVarSubst) (clears : Array FVarId) (e
pure ([(n, ps)], #[⟨⟨g, #[mkFVar v], fs'⟩, n⟩])
| ConstantInfo.inductInfo info, _ => do
let (altVarNames, r) ← processConstructors pat.ref info.numParams #[] info.ctors pat.asAlts
(r, ·) <$> g.cases e.fvarId! altVarNames
(r, ·) <$> g.cases e.fvarId! altVarNames (useNatCasesAuxOn := true)
| _, _ => failK ()
(·.2) <$> subgoals.foldlM (init := (r, a)) fun (r, a) ⟨goal, ctorName⟩ => do
let rec

View file

@ -222,15 +222,17 @@ private def unifyCasesEqs (numEqs : Nat) (subgoals : Array CasesSubgoal) : MetaM
}
private def inductionCasesOn (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNames) (ctx : Context)
: MetaM (Array CasesSubgoal) := mvarId.withContext do
(useNatCasesAuxOn : Bool := false) : MetaM (Array CasesSubgoal) := mvarId.withContext do
let majorType ← inferType (mkFVar majorFVarId)
let (us, params) ← getInductiveUniverseAndParams majorType
let casesOn := mkCasesOnName ctx.inductiveVal.name
let mut casesOn := mkCasesOnName ctx.inductiveVal.name
if useNatCasesAuxOn && ctx.inductiveVal.name == ``Nat && (← getEnv).contains ``Nat.casesAuxOn then
casesOn := ``Nat.casesAuxOn
let ctors := ctx.inductiveVal.ctors.toArray
let s ← mvarId.induction majorFVarId casesOn givenNames
return toCasesSubgoals s ctors majorFVarId us params
def cases (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNames := #[]) : MetaM (Array CasesSubgoal) := do
def cases (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNames := #[]) (useNatCasesAuxOn : Bool := false) : MetaM (Array CasesSubgoal) := do
try
mvarId.withContext do
mvarId.checkNotAssigned `cases
@ -243,7 +245,7 @@ def cases (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNam
allow callers to specify whether they want the `FVarSubst` or not. -/
if ctx.inductiveVal.numIndices == 0 then
-- Simple case
inductionCasesOn mvarId majorFVarId givenNames ctx
inductionCasesOn mvarId majorFVarId givenNames ctx (useNatCasesAuxOn := useNatCasesAuxOn)
else
let s₁ ← generalizeIndices mvarId majorFVarId
trace[Meta.Tactic.cases] "after generalizeIndices\n{MessageData.ofGoal s₁.mvarId}"
@ -258,9 +260,14 @@ end Cases
/--
Apply `casesOn` using the free variable `majorFVarId` as the major premise (aka discriminant).
`givenNames` contains user-facing names for each alternative.
- `useNatCasesAuxOn` is a temporary hack for the `rcases` family of tactics.
Do not use it, as it is subject to removal.
It enables using `Nat.casesAuxOn` instead of `Nat.casesOn`,
which causes case splits on `n : Nat` to be represented as `0` and `n' + 1` rather than as `Nat.zero` and `Nat.succ n'`.
-/
def _root_.Lean.MVarId.cases (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNames := #[]) : MetaM (Array CasesSubgoal) :=
Cases.cases mvarId majorFVarId givenNames
def _root_.Lean.MVarId.cases (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNames := #[]) (useNatCasesAuxOn : Bool := false) : MetaM (Array CasesSubgoal) :=
Cases.cases mvarId majorFVarId givenNames (useNatCasesAuxOn := useNatCasesAuxOn)
@[deprecated MVarId.cases]
def cases (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNames := #[]) : MetaM (Array CasesSubgoal) :=

View file

@ -38,10 +38,10 @@ example : cond false Nat Int → cond true Int Nat → Nat ⊕ Unit → True :=
example (x y : Nat) (h : x = y) : True := by
rcases x with _|⟨⟩|z
· guard_hyp h : Nat.zero = y; trivial
· guard_hyp h : Nat.succ Nat.zero = y; trivial
· guard_hyp h :ₛ 0 = y; trivial
· guard_hyp h :ₛ 0 + 1 = y; trivial
· guard_hyp z : Nat
guard_hyp h : Nat.succ (Nat.succ z) = y; trivial
guard_hyp h :ₛ z + 1 + 1 = y; trivial
example (h : x = 3) (h₂ : x < 4) : x < 4 := by
rcases h with ⟨⟩
@ -188,8 +188,8 @@ example (h : a ≤ 2 2 < a) : True := by
example (a : Nat) : True := by
rcases h : a with _ | n
· guard_hyp h : a = 0; trivial
· guard_hyp h : a = n + 1; trivial
· guard_hyp h : a = 0; trivial
· guard_hyp h : a = n + 1; trivial
inductive BaseType : Type where
| one