Skip to content

Commit f3e168c

Browse files
committed
feat: Add codeaction and widget to success_if_fail_with_msg tactic (#20378)
make the `success_if_fail_with_msg` tactic give a codeaction when the tactics given fail with a different error, to update the expected error message. example: ```lean4 example : Nat → Nat → True := by success_if_fail_with_msg "no goals" -- Update with tactic error message: "no goals to be solved" intro intro trivial trivial intros; trivial ```
1 parent 30db47d commit f3e168c

File tree

2 files changed

+35
-6
lines changed

2 files changed

+35
-6
lines changed

Mathlib/Tactic/SuccessIfFailWithMsg.lean

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Authors: Mario Carneiro, Simon Hudon, Sébastien Gouëzel, Kim Morrison, Thomas
66
import Lean.Elab.Eval
77
import Lean.Elab.Tactic.BuiltinTactic
88
import Mathlib.Init
9+
import Lean.Meta.Tactic.TryThis
910

1011
/-!
1112
# Success If Fail With Message
@@ -16,7 +17,7 @@ It's mostly useful in tests, where we want to make sure that tactics fail in cer
1617
circumstances.
1718
-/
1819

19-
open Lean Elab Tactic
20+
open Lean Meta Elab Tactic
2021

2122
namespace Mathlib.Tactic
2223

@@ -28,16 +29,22 @@ syntax (name := successIfFailWithMsg) "success_if_fail_with_msg " term:max tacti
2829

2930
/-- Evaluates `tacs` and succeeds only if `tacs` both fails and throws an error equal (as a string)
3031
to `msg`. -/
31-
def successIfFailWithMessage {s α : Type} {m : TypeType}
32-
[Monad m] [MonadLiftT BaseIO m] [MonadBacktrack s m] [MonadError m]
33-
(msg : String) (tacs : m α) (ref : Option Syntax := none) : m Unit := do
32+
def successIfFailWithMessage {s α : Type} {m : TypeType} [Monad m] [MonadLiftT BaseIO m]
33+
[MonadLiftT MetaM m] [MonadBacktrack s m] [MonadError m] (msg : String) (tacs : m α)
34+
(msgref : Option Syntax := none) (ref : Option Syntax := none) : m Unit := do
3435
let s ← saveState
3536
let err ←
3637
try _ ← tacs; pure none
3738
catch err => pure (some (← err.toMessageData.toString))
3839
restoreState s
3940
if let some err := err then
4041
unless msg.trim == err.trim do
42+
if let .some msgref := msgref then
43+
let suggestion : TryThis.Suggestion :=
44+
{ suggestion := s!"\"{err.trim}\""
45+
toCodeActionTitle? := .some (fun _ => "Update with tactic error message")}
46+
TryThis.addSuggestion msgref suggestion (header := "Update with tactic error message: ")
47+
4148
if let some ref := ref then
4249
throwErrorAt ref "tactic '{ref}' failed, but got different error message:\n\n{err}"
4350
else
@@ -51,7 +58,7 @@ def successIfFailWithMessage {s α : Type} {m : Type → Type}
5158
elab_rules : tactic
5259
| `(tactic| success_if_fail_with_msg $msg:term $tacs:tacticSeq) =>
5360
Term.withoutErrToSorry <| withoutRecover do
54-
let msg ← unsafe Term.evalTerm String (.const ``String []) msg
55-
successIfFailWithMessage msg (evalTacticSeq tacs) tacs
61+
let msg'unsafe Term.evalTerm String (.const ``String []) msg
62+
successIfFailWithMessage msg' (evalTacticSeq tacs) msg tacs
5663

5764
end Mathlib.Tactic

MathlibTest/success_if_fail_with_msg.lean

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,28 @@ example : Nat → Nat → True := by
1111
trivial
1212
intros; trivial
1313

14+
/--
15+
info: Update with tactic error message: "no goals to be solved"
16+
---
17+
error: tactic '
18+
intro
19+
intro
20+
trivial
21+
trivial' failed, but got different error message:
22+
23+
no goals to be solved
24+
-/
25+
#guard_msgs in
26+
example : Nat → Nat → True := by
27+
success_if_fail_with_msg "no goals"
28+
intro
29+
intro
30+
trivial
31+
trivial
32+
intros; trivial
33+
34+
35+
1436
def err (t : Bool) := if t then
1537
"tactic 'rewrite' failed, equality or iff proof expected
1638
n ≤ n.succ

0 commit comments

Comments
 (0)