chore: improve grind.clear_aux_decls error message (#7931)

cc @kim-em
This commit is contained in:
Leonardo de Moura 2025-04-11 19:39:51 -07:00 committed by GitHub
parent 2657f4e62c
commit 38ed4346c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 35 additions and 24 deletions

View file

@ -97,7 +97,8 @@ def _root_.Lean.MVarId.clearAuxDecls (mvarId : MVarId) : MetaM MVarId := mvarId.
try
mvarId ← mvarId.clear fvarId
catch _ =>
throwTacticEx `grind.clear_aux_decls mvarId "failed to clear local auxiliary declaration"
let userName := (← fvarId.getDecl).userName
throwTacticEx `grind mvarId m!"the goal mentions the declaration `{userName}`, which is being defined. To avoid circular reasoning, try rewriting the goal to eliminate `{userName}` before using `grind`."
return mvarId
/--

View file

@ -0,0 +1,17 @@
reset_grind_attrs%
set_option grind.warning false
attribute [grind] List.not_mem_nil
/--
error: tactic 'grind' failed, the goal mentions the declaration `incList`, which is being defined. To avoid circular reasoning, try rewriting the goal to eliminate `incList` before using `grind`.
as✝ : List Nat
a : Nat
as : List Nat
⊢ ∀ (a : Nat), a ∈ (incList as).val → a > 0
-/
#guard_msgs (error) in
def incList (as : List Nat) : { as : List Nat // ∀ a, a ∈ as → a > 0 } :=
match as with
| [] => ⟨[], by grind⟩
| a::as => ⟨(incList as).1, by grind⟩

View file

@ -187,9 +187,6 @@ def IfNormalization : Type := { Z : IfExpr → IfExpr // ∀ e, (Z e).normalized
See `Statement.lean` for background.
-/
macro "◾" : tactic => `(tactic| grind)
macro "◾" : term => `(term| by grind)
set_option grind.warning false
namespace IfExpr
@ -228,6 +225,9 @@ We don't want a `simp` lemma for `(ite i t e).eval` in general, only once we kno
| var _ => 1
| .ite i t e => 2 * normSize i + max (normSize t) (normSize e) + 1
notation "g⟨" a "⟩" => ⟨a, by grind⟩
macro "c⟨" a:term "⟩" : term => `(have aux := $a; ⟨aux.1, by grind⟩)
/-- Normalizes the expression at the same time as assigning all variables in
`e` to the literal booleans given by `l` -/
def normalize (l : AList (fun _ : Nat => Bool)) :
@ -235,40 +235,33 @@ def normalize (l : AList (fun _ : Nat => Bool)) :
(∀ f, e'.eval f = e.eval (fun w => (l.lookup w).elim (f w) id))
∧ e'.normalized
∧ ∀ (v : Nat), v ∈ vars e' → l.lookup v = none }
| lit b => ⟨lit b, ◾
| lit b => g⟨lit b⟩
| var v =>
match h : l.lookup v with
| none => ⟨var v, ◾⟩
| some b => ⟨lit b, ◾⟩
| .ite (lit true) t e =>
-- Fails with `tactic 'grind.clear_aux_decls' failed`:
⟨(normalize l t).1, ◾⟩
-- Workaround:
-- have t' := normalize l t; ⟨t'.1, ◾⟩
| .ite (lit false) t e => have e' := normalize l e; ⟨e'.1, ◾⟩
| .ite (.ite a b c) t e => have i' := normalize l (.ite a (.ite b t e) (.ite c t e)); ⟨i'.1, ◾⟩
| none => g⟨var v⟩
| some b => g⟨lit b⟩
| .ite (lit true) t e => c⟨normalize l t⟩
| .ite (lit false) t e => c⟨normalize l e⟩
| .ite (.ite a b c) t e => c⟨normalize l (.ite a (.ite b t e) (.ite c t e))⟩
| .ite (var v) t e =>
match h : l.lookup v with
| none =>
have ⟨t', _⟩ := normalize (l.insert v true) t
have ⟨e', _⟩ := normalize (l.insert v false) e
⟨if t' = e' then t' else .ite (var v) t' e', by
-- TODO: automate this proof
refine ⟨fun f => ?_, ?_, fun w b => ?_⟩
· -- eval = eval
simp only [apply_ite, eval_ite_var]
cases hfv : f v
· simp_all
· ◾
· simp_all; grind
· grind
· -- normalized
split
· ◾
· simp only [normalized, disjoint]
· -- lookup = none
◾⟩
| some b =>
have i' := normalize l (.ite (lit b) t e); ⟨i'.1, ◾⟩
· grind
· simp only [normalized, disjoint]; grind
· grind⟩
| some b => c⟨normalize l (.ite (lit b) t e)⟩
termination_by e => e.normSize
/-