Skip to content

Commit 36a2b22

Browse files
kim-emclaude
andauthored
feat: extract_goal preserves explicit foralls (#31342)
* feat: extract_goal preserves explicit foralls * fix: update goalSignature call for new return type The goalSignature function now returns a 4-tuple including a boolean for hasOriginalForalls. Update the destructuring pattern in TacticAnalysis/Declarations.lean to account for this new field. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 337d737 commit 36a2b22

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

Mathlib/Tactic/ExtractGoal.lean

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,19 @@ The return values are:
143143
* A formatted piece of `MessageData`, like `m!"myTheorem (a b : Nat) : a + b = b + a"`.
144144
* The full type of the declaration, like `∀ a b, a + b = b + a`.
145145
* The imports needed to state this declaration, as an array of module names.
146+
* A boolean indicating whether the original goal type had top-level foralls.
146147
-/
147-
def goalSignature (name : Name) (g : MVarId) : TermElabM (MessageData × Expr × Array Name) :=
148+
def goalSignature (name : Name) (g : MVarId) : TermElabM (MessageData × Expr × Array Name × Bool) :=
148149
withoutModifyingEnv <| withoutModifyingState do
149150
let (g, _) ← g.renameInaccessibleFVars
151+
-- Check if the original goal has foralls before reverting
152+
-- We only consider it to have "original foralls" if it has a named forall,
153+
-- not just implications (which have anonymous or internal hygienic names)
154+
let originalTy ← instantiateMVars (← g.getType)
155+
let hasOriginalForalls :=
156+
originalTy.isForall &&
157+
!originalTy.bindingName!.isAnonymous &&
158+
!originalTy.bindingName!.isInternal
150159
let (_, g) ← g.revert (clearAuxDeclsInsteadOfRevert := true) (← g.getDecl).lctx.getFVarIds
151160
let ty ← instantiateMVars (← g.getType)
152161
if ty.hasExprMVar then
@@ -179,7 +188,7 @@ def goalSignature (name : Name) (g : MVarId) : TermElabM (MessageData × Expr ×
179188
if !fins.contains new then fins := fins.insert new
180189
let tot := Mathlib.Command.MinImports.getIrredundantImports (← getEnv) (fins.erase .anonymous)
181190
let fileNames := tot.toArray.qsort Name.lt
182-
return (sig, ty, fileNames)
191+
return (sig, ty, fileNames, hasOriginalForalls)
183192

184193
elab_rules : tactic
185194
| `(tactic| extract_goal $cfg:config $[using $name?]?) => do
@@ -200,9 +209,15 @@ elab_rules : tactic
200209
-- Note: `getFVarIds` does `withMainContext`
201210
g.cleanup (toPreserve := (← getFVarIds fvars)) (indirectProps := false)
202211
| _ => throwUnsupportedSyntax
203-
let (sig, ty, _) ← goalSignature name g
212+
let (sig, ty, _, hasOriginalForalls) ← goalSignature name g
204213
let cmd := if ← Meta.isProp ty then "theorem" else "def"
205-
pure m!"{cmd} {sig} := sorry"
214+
let msg ← if hasOriginalForalls then
215+
-- Preserve foralls: format as "theorem name : ty := sorry"
216+
pure m!"{cmd} {name} : {ty} := sorry"
217+
else
218+
-- Convert foralls to parameters: format using signature
219+
pure m!"{cmd} {sig} := sorry"
220+
pure msg
206221
logInfo msg
207222

208223
end Mathlib.Tactic.ExtractGoal

Mathlib/Tactic/TacticAnalysis/Declarations.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def terminalReplacement (oldTacticName newTacticName : String) (oldTacticKind :
6464
catch _e =>
6565
let name ← mkAuxDeclName `extracted
6666
-- Rerun in the original tactic context, since `omega` changes the state.
67-
let ((sig, _, modules), _) ← ctxI.runTactic i goal (fun goal =>
67+
let ((sig, _, modules, _), _) ← ctxI.runTactic i goal (fun goal =>
6868
(Mathlib.Tactic.ExtractGoal.goalSignature name goal).run)
6969
let imports := modules.toList.map (s!"import {·}")
7070
return .error tac m!"{"\n".intercalate imports}\n\ntheorem {sig} := by\n fail_if_success {tac}\n {stx}"

MathlibTest/ExtractGoal.lean

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,19 @@ example : ∀ n, n < n + 1 := by
175175
have : m < _ := Nat.lt_succ_of_lt (Nat.lt_add_one m)
176176
extract_goal
177177
sorry
178+
179+
/--
180+
info: theorem foralls_variants.extracted_1_1 : ∀ (n : ℕ), n + 0 = n → n + 1 + 0 = n + 1 := sorry
181+
---
182+
info: theorem foralls_variants.extracted_1_3 (n : ℕ) : n + 0 = n → n + 1 + 0 = n + 1 := sorry
183+
-/
184+
#guard_msgs in
185+
theorem foralls_variants : ∀ (n : Nat), n + 0 = n := by
186+
intro n
187+
have step1 : ∀ n, n + 0 = n → (n + 1) + 0 = n + 1 := by
188+
extract_goal
189+
simp
190+
have step2 : n + 0 = n → (n + 1) + 0 = n + 1 := by
191+
extract_goal
192+
simp
193+
simp

0 commit comments

Comments
 (0)