fix: condition for selecting split target

Only discriminants must not have loose bound variables
This commit is contained in:
Leonardo de Moura 2021-09-10 14:55:16 -07:00
parent 1591bb1640
commit 0cf2c19fc2
3 changed files with 28 additions and 6 deletions

View file

@ -29,8 +29,12 @@ def MatcherInfo.numAlts (info : MatcherInfo) : Nat :=
def MatcherInfo.arity (info : MatcherInfo) : Nat :=
info.numParams + 1 + info.numDiscrs + info.numAlts
def MatcherInfo.getFirstDiscrPos (info : MatcherInfo) : Nat :=
info.numParams + 1
def MatcherInfo.getMotivePos (info : MatcherInfo) : Nat :=
info.numParams
namespace Extension
structure Entry where
@ -79,15 +83,18 @@ def isMatcherCore (env : Environment) (declName : Name) : Bool :=
def isMatcher [Monad m] [MonadEnv m] (declName : Name) : m Bool :=
return isMatcherCore (← getEnv) declName
def isMatcherAppCore (env : Environment) (e : Expr) : Bool :=
def isMatcherAppCore? (env : Environment) (e : Expr) : Option MatcherInfo :=
let fn := e.getAppFn
if fn.isConst then
if let some matcherInfo := getMatcherInfoCore? env fn.constName! then
e.getAppNumArgs ≥ matcherInfo.arity
if e.getAppNumArgs ≥ matcherInfo.arity then some matcherInfo else none
else
false
none
else
false
none
def isMatcherAppCore (env : Environment) (e : Expr) : Bool :=
isMatcherAppCore? env e |>.isSome
def isMatcherApp [Monad m] [MonadEnv m] (e : Expr) : m Bool :=
return isMatcherAppCore (← getEnv) e

View file

@ -100,7 +100,7 @@ def splitMatch (mvarId : MVarId) (e : Expr) : MetaM (List MVarId) := do
/-- Return an `if-then-else` or `match-expr` to split. -/
partial def findSplit? (env : Environment) (e : Expr) : Option Expr :=
if let some target := e.find? fun e => !e.hasLooseBVars && (e.isIte || e.isDIte || isMatcherAppCore env e) then
if let some target := e.find? isCandidate then
if e.isIte || e.isDIte then
let cond := target.getArg! 1 5
-- Try to find a nested `if` in `cond`
@ -109,6 +109,18 @@ partial def findSplit? (env : Environment) (e : Expr) : Option Expr :=
some target
else
none
where
isCandidate (e : Expr) : Bool := do
if e.isIte || e.isDIte then
!(e.getArg! 1 5).hasLooseBVars
else if let some info := isMatcherAppCore? env e then
let args := e.getAppArgs
for i in [info.getFirstDiscrPos : info.getFirstDiscrPos + info.numDiscrs] do
if args[i].hasLooseBVars then
return false
return true
else
false
end Split
@ -121,6 +133,7 @@ def splitTarget? (mvarId : MVarId) : MetaM (Option (List MVarId)) := commitWhenS
else
splitMatch mvarId e
else
trace[Meta.Tactic.split] "did not find term to split\n{MessageData.ofGoal mvarId}"
return none
def splitLocalDecl? (mvarId : MVarId) (fvarId : FVarId) : MetaM (Option (List MVarId)) := commitWhenSome? do
@ -137,4 +150,6 @@ def splitLocalDecl? (mvarId : MVarId) (fvarId : FVarId) : MetaM (Option (List MV
else
return none
builtin_initialize registerTraceClass `Meta.Tactic.split
end Lean.Meta

View file

@ -63,7 +63,7 @@ def discharge? (useDecide := false) : Simp.Discharge := fun prop => do
/-- Return the condition of an `if` expression to case split. -/
partial def findIfToSplit? (e : Expr) : Option Expr :=
if let some iteApp := e.find? fun e => !e.hasLooseBVars && (e.isIte || e.isDIte) then
if let some iteApp := e.find? fun e => (e.isIte || e.isDIte) && !(e.getArg! 1 5).hasLooseBVars then
let cond := iteApp.getArg! 1 5
-- Try to find a nested `if` in `cond`
findIfToSplit? cond |>.getD cond