This PR adds the tactic implementation for #7830, before changing the syntax after a stage0 update. It will allow optional RHSs in induction cases.
This commit is contained in:
parent
48a9bfb73d
commit
de25524dd6
1 changed files with 62 additions and 29 deletions
|
|
@ -49,36 +49,55 @@ private def altHasExplicitModifier (alt : Syntax) : Bool :=
|
|||
private def getAltVars (alt : Syntax) : Array Syntax :=
|
||||
let lhs := getFirstAltLhs alt
|
||||
lhs[2].getArgs
|
||||
private def hasAltRHS (alt : Syntax) : Bool :=
|
||||
if !alt[1].isOfKind nullKind then
|
||||
-- TODO(kmill) Bootstrapping workaround. Delete case in #7830.
|
||||
true
|
||||
else
|
||||
alt[1].getNumArgs > 0
|
||||
private def getAltRHS (alt : Syntax) : Syntax :=
|
||||
alt[2]
|
||||
if !alt[1].isOfKind nullKind then
|
||||
-- TODO(kmill) Bootstrapping workaround. Delete case in #7830.
|
||||
alt[2]
|
||||
else
|
||||
alt[1][1]
|
||||
private def getAltDArrow (alt : Syntax) : Syntax :=
|
||||
alt[1]
|
||||
if !alt[1].isOfKind nullKind then
|
||||
-- TODO(kmill) Bootstrapping workaround. Delete case in #7830.
|
||||
alt[1]
|
||||
else
|
||||
alt[1][0]
|
||||
|
||||
-- Return true if `stx` is a term occurring in the RHS of the induction/cases tactic
|
||||
def isHoleRHS (rhs : Syntax) : Bool :=
|
||||
rhs.isOfKind ``Parser.Term.syntheticHole || rhs.isOfKind ``Parser.Term.hole
|
||||
|
||||
def evalAlt (mvarId : MVarId) (alt : Syntax) (addInfo : TermElabM Unit) : TacticM Unit :=
|
||||
let rhs := getAltRHS alt
|
||||
withCaseRef (getAltDArrow alt) rhs do
|
||||
if isHoleRHS rhs then
|
||||
addInfo
|
||||
mvarId.withContext <| withTacticInfoContext rhs do
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let val ← elabTermEnsuringType rhs mvarDecl.type
|
||||
mvarId.assign val
|
||||
let gs' ← getMVarsNoDelayed val
|
||||
tagUntaggedGoals mvarDecl.userName `induction gs'.toList
|
||||
setGoals <| (← getGoals) ++ gs'.toList
|
||||
else
|
||||
let goals ← getGoals
|
||||
try
|
||||
def evalAlt (mvarId : MVarId) (alt : Syntax) (addInfo : TermElabM Unit) : TacticM Unit := do
|
||||
if !hasAltRHS alt then
|
||||
throwErrorAt alt "(internal error) RHS was not expanded"
|
||||
else
|
||||
let rhs := getAltRHS alt
|
||||
withCaseRef (getAltDArrow alt) rhs do
|
||||
if isHoleRHS rhs then
|
||||
addInfo
|
||||
let goals ← getGoals
|
||||
setGoals [mvarId]
|
||||
closeUsingOrAdmit <|
|
||||
withTacticInfoContext (mkNullNode #[getAltLhses alt, getAltDArrow alt]) <|
|
||||
(addInfo *> evalTactic rhs)
|
||||
finally
|
||||
setGoals goals
|
||||
mvarId.withContext <| withTacticInfoContext (mkNullNode #[getAltLhses alt, rhs]) do
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let val ← elabTermEnsuringType rhs mvarDecl.type
|
||||
mvarId.assign val
|
||||
let gs' ← getMVarsNoDelayed val
|
||||
tagUntaggedGoals mvarDecl.userName `induction gs'.toList
|
||||
setGoals <| goals ++ gs'.toList
|
||||
else
|
||||
let goals ← getGoals
|
||||
try
|
||||
setGoals [mvarId]
|
||||
closeUsingOrAdmit <|
|
||||
withTacticInfoContext (mkNullNode #[getAltLhses alt, getAltDArrow alt]) <|
|
||||
(addInfo *> evalTactic rhs)
|
||||
finally
|
||||
setGoals goals
|
||||
|
||||
/-!
|
||||
Helper method for creating an user-defined eliminator/recursor application.
|
||||
|
|
@ -531,12 +550,26 @@ private def withAltsOfOptInductionAlts (optInductionAlts : Syntax)
|
|||
private def getOptPreTacOfOptInductionAlts (optInductionAlts : Syntax) : Syntax :=
|
||||
if optInductionAlts.isNone then mkNullNode else optInductionAlts[0][1]
|
||||
|
||||
private def isMultiAlt (alt : Syntax) : Bool :=
|
||||
alt[0].getNumArgs > 1
|
||||
/--
|
||||
Returns true if the `Lean.Parser.Tactic.inductionAlt` either has more than one alternative
|
||||
or has no RHS.
|
||||
-/
|
||||
private def shouldExpandAlt (alt : Syntax) : Bool :=
|
||||
-- TODO(kmill) enable second case in #7830
|
||||
alt[0].getNumArgs > 1 || (false && 1 < alt.getNumArgs && alt[1].getNumArgs == 0)
|
||||
|
||||
/-- Return `some #[alt_1, ..., alt_n]` if `alt` has multiple LHSs. -/
|
||||
private def expandMultiAlt? (alt : Syntax) : Option (Array Syntax) := Id.run do
|
||||
if isMultiAlt alt then
|
||||
/--
|
||||
Returns `some #[alt_1, ..., alt_n]` if `alt` has multiple LHSs or if `alt` has no RHS.
|
||||
If there is no RHS, it is filled in with a hole.
|
||||
-/
|
||||
private def expandAlt? (alt : Syntax) : Option (Array Syntax) := Id.run do
|
||||
if shouldExpandAlt alt then
|
||||
let alt :=
|
||||
-- TODO(kmill) enable case in #7830
|
||||
if false && 1 < alt.getNumArgs && alt[1].getNumArgs == 0 then
|
||||
alt.setArg 1 <| mkNullNode #[mkAtomFrom alt "=>", mkHole alt]
|
||||
else
|
||||
alt
|
||||
some <| alt[0].getArgs.map fun lhs => alt.setArg 0 (mkNullNode #[lhs])
|
||||
else
|
||||
none
|
||||
|
|
@ -553,10 +586,10 @@ Remark: the `RHS` of alternatives with multi LHSs is copied.
|
|||
-/
|
||||
private def expandInductionAlts? (inductionAlts : Syntax) : Option Syntax := Id.run do
|
||||
let alts := getAltsOfInductionAlts inductionAlts
|
||||
if alts.any isMultiAlt then
|
||||
if alts.any shouldExpandAlt then
|
||||
let mut altsNew := #[]
|
||||
for alt in alts do
|
||||
if let some alt' := expandMultiAlt? alt then
|
||||
if let some alt' := expandAlt? alt then
|
||||
altsNew := altsNew ++ alt'
|
||||
else
|
||||
altsNew := altsNew.push alt
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue