@@ -246,47 +246,34 @@ private def casesWithTrace (mvarId : MVarId) (major : Expr) : GoalM (List MVarId
246246
247247namespace Action
248248
249- private def isTargetFalse (mvarId : MVarId) : MetaM Bool := do
250- return (← mvarId.getType).isFalse
251-
252- private def getFalseProof? (mvarId : MVarId) : MetaM (Option Expr) := mvarId.withContext do
253- let proof ← instantiateMVars (mkMVar mvarId)
254- if (← isTargetFalse mvarId) then
255- return some proof
256- else if proof.isAppOfArity ``False.elim 2 || proof.isAppOfArity ``False.casesOn 2 then
257- return some proof.appArg!
258- else
259- return none
260-
261249/--
262- Returns the maximum free variable id occurring in `e`
250+ Given a `mvarId` associated with a subgoal created by `splitCore`, inspects the
251+ proof term assigned to `mvarId` and tries to extract the proof of `False` that does not
252+ depend on hypotheses introduced in the subgoal.
253+ For example: suppose the subgoal is of the form `p → q → False` where `p` and `q` are new
254+ hypotheses introduced during case analysis. If the proof is of the form `fun _ _ => h`, returns
255+ `some h`.
263256-/
264- private def findMaxFVarIdx? (e : Expr) : MetaM (Option Nat) := do
265- let go (e : Expr) : StateT (Option Nat) MetaM Bool := do
266- unless e.hasFVar do return false
267- let .fvar fvarId := e | return true
268- let localDecl ← fvarId.getDecl
269- modify fun
270- | none => some localDecl.index
271- | some index => some (max index localDecl.index)
272- return false
273- let (_, s?) ← e.forEach' go |>.run none
274- return s?
275-
276- /--
277- Returns `some falseProof` if we can use non-chronological backtracking with `subgoal`.
278- That is, `subgoal` was closed using `falseProof`, but its proof does not use any of the
279- new hypotheses. A hypothesis is new if its `index >= oldNumIndices`.
280- -/
281- private def useNCB? (oldNumIndices : Nat) (subgoal : Goal) : MetaM (Option Expr) := do
282- let some falseProof ← getFalseProof? subgoal.mvarId
283- | return none
284- let some max ← subgoal.withContext <| findMaxFVarIdx? falseProof
285- | return some falseProof -- Proof actually closes any pending split
286- if max < oldNumIndices then
287- return some falseProof
288- else
289- return none
257+ private def getFalseProof? (mvarId : MVarId) : MetaM (Option Expr) := mvarId.withContext do
258+ let proof ← instantiateMVars (mkMVar mvarId)
259+ go proof
260+ where
261+ go (proof : Expr) : MetaM (Option Expr) := do
262+ match_expr proof with
263+ | False.elim _ p => return some p
264+ | False.casesOn _ p => return some p
265+ | id α p => if α.isFalse then return some p else return none
266+ | _ =>
267+ /-
268+ **Note** : `intros` tactics may hide the `False` proof behind a `casesOn`
269+ For example: suppose the subgoal has a type of the form `p₁ → q₁ ∧ q₂ → p₂ → False`
270+ The proof will be of the form `fun _ h => h.casesOn (fun _ _ => hf)` where `hf` is the proof
271+ of `False` we are looking for.
272+ Non-chronological backtracking currently fails in this kind of example.
273+ -/
274+ let .lam _ _ b _ := proof | return none
275+ if b.hasLooseBVars then return none
276+ go b
290277
291278/--
292279Performs a case-split using `c`.
@@ -325,12 +312,16 @@ private def splitCore (c : SplitInfo) (numCases : Nat) (isRec : Bool) (stopAtFir
325312 else
326313 stuckNew := stuckNew ++ gs
327314 | .closed seq =>
328- if let some falseProof ← useNCB? numIndices subgoal then
315+ if let some falseProof ← getFalseProof? subgoal.mvarId then
329316 goal.mvarId.assignFalseProof falseProof
330317 return .closed seq
331318 else
332319 seqNew := seqNew.push seq
333- goal.mvarId.assign (← instantiateMVars (mkMVar mvarId))
320+ if (← goal.mvarId.getType).isFalse then
321+ /- **Note** : We add the marker to assist `getFalseExpr?` -/
322+ goal.mvarId.assign (mkExpectedPropHint (← instantiateMVars (mkMVar mvarId)) (mkConst ``False))
323+ else
324+ goal.mvarId.assign (← instantiateMVars (mkMVar mvarId))
334325 if stuckNew.isEmpty then
335326 if traceEnabled then
336327 let seqListNew ← if h : seqNew.size = 1 then
0 commit comments