Skip to content

Commit 57ec1a5

Browse files
kim-emclaude
andcommitted
feat: deprecate hint tactic in favor of try?
This commit deprecates the `hint` tactic and associated infrastructure in favor of the built-in `try?` tactic (available in Lean 4.26.0+). - Replace all `register_hint` calls with `register_try?_tactic` - Deprecate the `hint` tactic (now wraps `try?` with a warning) - Keep `register_hint` command as deprecated for backward compatibility - Update test files to use `try?` and verify correct behavior The `hint` tactic now logs a deprecation warning and delegates to `try?`. All deprecated infrastructure is marked with @[deprecated] attributes. 🤖 Prepared with Claude Code Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent f83e6b6 commit 57ec1a5

17 files changed

Lines changed: 158 additions & 218 deletions

Mathlib/Tactic/Abel.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ macro (name := abelConv) "abel" : conv =>
545545
end Mathlib.Tactic.Abel
546546

547547
/-!
548-
We register `abel` with the `hint` tactic.
548+
We register `abel` with the `try?` tactic.
549549
-/
550550

551-
register_hint 950 abel
551+
register_try?_tactic (priority := 950) abel

Mathlib/Tactic/Bound.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ macro_rules
254254
`(tactic| ($haves;*; bound%$tk))
255255

256256
/-!
257-
We register `bound` with the `hint` tactic.
257+
We register `bound` with the `try?` tactic.
258258
-/
259259

260-
register_hint 70 bound
260+
register_try?_tactic (priority := 70) bound

Mathlib/Tactic/Common.lean

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -133,21 +133,21 @@ import hierarchy.
133133
public meta section
134134

135135
/-!
136-
# Register tactics with `hint`. Tactics with larger priority run first.
136+
# Register tactics with `try?`. Tactics with larger priority run first.
137137
-/
138138

139-
section Hint
139+
section Try
140140

141-
register_hint 200 grind
142-
register_hint 1000 trivial
143-
register_hint 500 tauto
144-
register_hint 1000 split
145-
register_hint 1000 intro
146-
register_hint 80 aesop
147-
register_hint 800 simp_all?
148-
register_hint 600 exact?
149-
register_hint 1000 decide
150-
register_hint 200 omega
151-
register_hint 200 fun_prop
141+
register_try?_tactic (priority := 200) grind
142+
register_try?_tactic (priority := 1000) trivial
143+
register_try?_tactic (priority := 500) tauto
144+
register_try?_tactic (priority := 1000) split
145+
register_try?_tactic (priority := 1000) intro
146+
register_try?_tactic (priority := 80) aesop
147+
register_try?_tactic (priority := 800) simp_all?
148+
register_try?_tactic (priority := 600) exact?
149+
register_try?_tactic (priority := 1000) decide
150+
register_try?_tactic (priority := 200) omega
151+
register_try?_tactic (priority := 200) fun_prop
152152

153-
end Hint
153+
end Try

Mathlib/Tactic/ComputeDegree.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,6 @@ end Tactic
526526
end Mathlib.Tactic.ComputeDegree
527527

528528
/-!
529-
We register `compute_degree` with the `hint` tactic.
529+
We register `compute_degree` with the `try?` tactic.
530530
-/
531-
register_hint 1000 compute_degree
531+
register_try?_tactic (priority := 1000) compute_degree

Mathlib/Tactic/Field.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,5 @@ elab (name := field) "field" d:(ppSpace discharger)? args:(ppSpace simpArgs)? :
8080

8181
end Mathlib.Tactic.FieldSimp
8282

83-
/-! We register `field` with the `hint` tactic. -/
84-
register_hint 850 field
83+
/-! We register `field` with the `try?` tactic. -/
84+
register_try?_tactic (priority := 850) field

Mathlib/Tactic/FieldSimp.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,6 @@ simproc_decl fieldLt (LT.lt _ _) := FieldSimp.proc
789789
attribute [field, inherit_doc FieldSimp.proc] fieldEq fieldLe fieldLt
790790

791791
/-!
792-
We register `field_simp` with the `hint` tactic.
792+
We register `field_simp` with the `try?` tactic.
793793
-/
794-
register_hint 1000 field_simp
794+
register_try?_tactic (priority := 1000) field_simp

Mathlib/Tactic/Finiteness.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,6 @@ macro (name := finiteness_nonterminal) "finiteness_nonterminal" c:Aesop.tactic_c
7373
(rule_sets := [$(Lean.mkIdent `finiteness):ident, -default, -builtin]))
7474

7575
/-!
76-
We register `finiteness` with the `hint` tactic.
76+
We register `finiteness` with the `try?` tactic.
7777
-/
78-
register_hint 1000 finiteness
78+
register_try?_tactic (priority := 1000) finiteness

Mathlib/Tactic/GCongr.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The core implementation of the `gcongr` ("generalized congruence") tactic is in
1616
public meta section
1717

1818
/-!
19-
We register `gcongr` with the `hint` tactic.
19+
We register `gcongr` with the `try?` tactic.
2020
-/
2121

22-
register_hint 1000 gcongr
22+
register_try?_tactic (priority := 1000) gcongr

Mathlib/Tactic/Group.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ macro_rules
9393
end Mathlib.Tactic.Group
9494

9595
/-!
96-
We register `group` with the `hint` tactic.
96+
We register `group` with the `try?` tactic.
9797
-/
9898

99-
register_hint 900 group
99+
register_try?_tactic (priority := 900) group

Mathlib/Tactic/Hint.lean

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ public meta import Mathlib.Lean.Elab.InfoTree
1313
public meta import Mathlib.Tactic.Basic
1414

1515
/-!
16-
# The `hint` tactic.
16+
# The `hint` tactic (deprecated).
1717
18-
The `hint` tactic tries the kitchen sink:
19-
it runs every tactic registered via the `register_hint <prio> tac` command
20-
on the current goal, and reports which ones succeed.
18+
The `hint` tactic is deprecated in favor of `try?`, which is built into Lean 4.26.0+.
2119
22-
## Future work
23-
It would be nice to run the tactics in parallel.
20+
Use `register_try?_tactic (priority := N) <tactic>` to register tactics with `try?`.
21+
22+
The `hint` tactic and `register_hint` command are kept for backward compatibility
23+
but will be removed in a future release.
2424
-/
2525

2626
public meta section
@@ -31,28 +31,34 @@ open Lean.Meta.Tactic.TryThis
3131

3232
namespace Mathlib.Tactic.Hint
3333

34-
/-- An environment extension for registering hint tactics with priorities. -/
34+
/-- An environment extension for registering hint tactics with priorities. (Deprecated) -/
35+
@[deprecated "Use `register_try?_tactic` instead" (since := "2025-12-08")]
3536
initialize hintExtension :
3637
SimplePersistentEnvExtension (Nat × TSyntax `tactic) (List (Nat × TSyntax `tactic)) ←
3738
registerSimplePersistentEnvExtension {
3839
addEntryFn := (·.cons)
3940
addImportedFn := mkStateFromImportedEntries (·.cons) {}
4041
}
4142

42-
/-- Register a new hint tactic. -/
43+
/-- Register a new hint tactic. (Deprecated) -/
44+
@[deprecated "Use `register_try?_tactic` instead" (since := "2025-12-08")]
4345
def addHint (prio : Nat) (stx : TSyntax `tactic) : CoreM Unit := do
4446
modifyEnv fun env => hintExtension.addEntry env (prio, stx)
4547

46-
/-- Return the list of registered hint tactics. -/
48+
/-- Return the list of registered hint tactics. (Deprecated) -/
49+
@[deprecated "Use `register_try?_tactic` instead" (since := "2025-12-08")]
4750
def getHints : CoreM (List (Nat × TSyntax `tactic)) :=
4851
return hintExtension.getState (← getEnv)
4952

5053
open Lean.Elab.Command in
5154
/--
5255
Register a tactic for use with the `hint` tactic, e.g. `register_hint 1000 simp_all`.
56+
(Deprecated: use `register_try?_tactic (priority := N) <tactic>` instead)
57+
5358
The numeric argument specifies the priority: tactics with larger priorities run before
5459
those with smaller priorities. The priority must be provided explicitly.
5560
-/
61+
@[deprecated "Use `register_try?_tactic` instead" (since := "2025-12-08")]
5662
elab (name := registerHintStx)
5763
"register_hint" prio:num tac:tactic : command =>
5864
liftTermElabM do
@@ -70,7 +76,9 @@ Construct a suggestion for a tactic.
7076
* If found, use that as the suggestion.
7177
* Otherwise use the provided syntax.
7278
* Also, look for remaining goals and pretty print them after the suggestion.
79+
(Deprecated)
7380
-/
81+
@[deprecated "Use `try?` instead" (since := "2025-12-08")]
7482
def suggestion (tac : TSyntax `tactic) (trees : PersistentArray InfoTree) : TacticM Suggestion := do
7583
-- TODO `addExactSuggestion` has an option to construct `postInfo?`
7684
-- Factor that out so we can use it here instead of copying and pasting?
@@ -95,42 +103,20 @@ def suggestion (tac : TSyntax `tactic) (trees : PersistentArray InfoTree) : Tact
95103
return { preInfo?, suggestion, postInfo? }
96104

97105
/--
98-
Run all tactics registered using `register_hint`.
99-
Print a "Try these:" suggestion for each of the successful tactics.
106+
The `hint` tactic is deprecated in favor of `try?`.
100107
101-
If one tactic succeeds and closes the goal, we don't look at subsequent tactics.
102-
-/
103-
-- TODO We could run the tactics in parallel.
104-
-- TODO With widget support, could we run the tactics in parallel
105-
-- and do live updates of the widget as results come in?
106-
def hint (stx : Syntax) : TacticM Unit := withMainContext do
107-
let tacs := (← getHints).toArray.qsort (·.1 > ·.1) |>.toList.map (·.2)
108-
let tacs := Nondet.ofList tacs
109-
let results := tacs.filterMapM fun t : TSyntax `tactic => do
110-
if let some { msgs, trees, .. } ← observing? (withResetServerInfo (evalTactic t)) then
111-
if msgs.hasErrors then
112-
return none
113-
else
114-
return some (← getGoals, ← suggestion t trees)
115-
else
116-
return none
117-
let results ← (results.toMLList.takeUpToFirst fun r => r.1.1.isEmpty).asArray
118-
let results := results.qsort (·.1.1.length < ·.1.1.length)
119-
addSuggestions stx (results.map (·.1.2))
120-
match results.find? (·.1.1.isEmpty) with
121-
| some r =>
122-
-- We don't restore the entire state, as that would delete the suggestion messages.
123-
setMCtx r.2.term.meta.meta.mctx
124-
| none => admitGoal (← getMainGoal)
108+
The `try?` tactic provides similar functionality by trying multiple tactics
109+
and reporting successes. Register tactics using:
110+
`register_try?_tactic (priority := N) <tactic>`
125111
126-
/--
127-
The `hint` tactic tries every tactic registered using `register_hint <prio> tac`,
128-
and reports any that succeed.
112+
Note: User-registered tactics run after built-in `try?` strategies.
129113
-/
114+
@[deprecated "Use `try?` instead" (since := "2025-12-08")]
130115
syntax (name := hintStx) "hint" : tactic
131116

132-
@[inherit_doc hintStx]
133117
elab_rules : tactic
134-
| `(tactic| hint%$tk) => hint tk
118+
| `(tactic| hint) => do
119+
logWarning "The `hint` tactic is deprecated. Use `try?` instead."
120+
evalTactic (← `(tactic| try?))
135121

136122
end Mathlib.Tactic.Hint

0 commit comments

Comments
 (0)