Skip to content

Commit

Permalink
feat: failing macros to show error from first registered rule
Browse files Browse the repository at this point in the history
fixes #3770

Also start `rfl` with a `fail` message that is hopefully more helpful
than what we get now (see updated test output). This would be a cheaper
way to address #3302 without changing the implementation of rfl (as
tried in #3714).
  • Loading branch information
nomeata committed Mar 26, 2024
1 parent 80d2455 commit eade05a
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 42 deletions.
12 changes: 8 additions & 4 deletions src/Init/Tactics.lean
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ macro:1 x:tactic tk:" <;> " y:tactic:2 : tactic => `(tactic|
with_annotate_state $tk skip
all_goals $y:tactic)

/-- `fail msg` is a tactic that always fails, and produces an error using the given message. -/
syntax (name := fail) "fail" (ppSpace str)? : tactic

/-- `eq_refl` is equivalent to `exact rfl`, but has a few optimizations. -/
syntax (name := eqRefl) "eq_refl" : tactic

Expand All @@ -365,8 +368,12 @@ for new reflexive relations.
Remark: `rfl` is an extensible tactic. We later add `macro_rules` to try different
reflexivity theorems (e.g., `Iff.rfl`).
-/
macro "rfl" : tactic => `(tactic| eq_refl)
macro "rfl" : tactic => `(tactic| fail "The rfl tactic failed. Possible reasions:
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma)
- The arguments of the relation are not equal.
Try using the reflexivitiy lemma for your relation explicitly, e.g. `exact Eq.rfl`.")

macro_rules | `(tactic| rfl) => `(tactic| eq_refl)
macro_rules | `(tactic| rfl) => `(tactic| exact HEq.rfl)

/--
Expand Down Expand Up @@ -907,9 +914,6 @@ example : ∀ x : Nat, x = x := by unhygienic
-/
macro "unhygienic " t:tacticSeq : tactic => `(tactic| set_option tactic.hygienic false in $t)

/-- `fail msg` is a tactic that always fails, and produces an error using the given message. -/
syntax (name := fail) "fail" (ppSpace str)? : tactic

/--
`checkpoint tac` acts the same as `tac`, but it caches the input and output of `tac`,
and if the file is re-elaborated and the input matches, the tactic is not re-run and
Expand Down
5 changes: 3 additions & 2 deletions src/Lean/Elab/Tactic/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,9 @@ partial def evalTactic (stx : Syntax) : TacticM Unit := do
| _ => throwError m!"unexpected tactic{indentD stx}"
where
throwExs (failures : Array EvalTacticFailure) : TacticM Unit := do
if let some fail := failures[0]? then
-- Recall that `failures[0]` is the highest priority evalFn/macro
if h : 0 < failures.size then
-- For macros we want to report the error from the first registered / last tried rule (#3770)
let fail := failures[failures.size-1]
fail.state.restore (restoreInfo := true)
throw fail.exception -- (*)
else
Expand Down
23 changes: 23 additions & 0 deletions tests/lean/run/issue3770.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
macro "foo" : tactic => `(tactic|fail "first")
macro_rules | `(tactic|foo) => `(tactic|exact 1)
macro_rules | `(tactic|foo) => `(tactic|fail "middle")
macro_rules | `(tactic|foo) => `(tactic|exact 2)
macro_rules | `(tactic|foo) => `(tactic|fail "last")

def what_is_foo : Nat := by foo

/-- info: 2 -/
#guard_msgs in
#eval what_is_foo


macro "bar" : tactic => `(tactic|fail "first")
macro_rules | `(tactic|bar) => `(tactic|fail "middle")
macro_rules | `(tactic|bar) => `(tactic|fail "last")

/--
error: first
⊢ Nat
-/
#guard_msgs in
def what_is_bar : Nat := by bar
75 changes: 39 additions & 36 deletions tests/lean/runTacticMustCatchExceptions.lean.expected.out
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
runTacticMustCatchExceptions.lean:2:25-2:28: error: type mismatch
Iff.rfl
has type
?m ↔ ?m : Prop
but is expected to have type
1 ≤ a + b : Prop
runTacticMustCatchExceptions.lean:3:25-3:28: error: type mismatch
Iff.rfl
has type
?m ↔ ?m : Prop
but is expected to have type
a + b ≤ b : Prop
runTacticMustCatchExceptions.lean:4:25-4:28: error: type mismatch
Iff.rfl
has type
?m ↔ ?m : Prop
but is expected to have type
b ≤ 2 : Prop
runTacticMustCatchExceptions.lean:9:18-9:21: error: type mismatch
Iff.rfl
has type
?m ↔ ?m : Prop
but is expected to have type
1 ≤ a + b : Prop
runTacticMustCatchExceptions.lean:10:14-10:17: error: type mismatch
Iff.rfl
has type
?m ↔ ?m : Prop
but is expected to have type
a + b ≤ b : Prop
runTacticMustCatchExceptions.lean:11:14-11:17: error: type mismatch
Iff.rfl
has type
?m ↔ ?m : Prop
but is expected to have type
b ≤ 2 : Prop
runTacticMustCatchExceptions.lean:2:25-2:28: error: The rfl tactic failed. Possible reasions:
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma)
- The arguments of the relation are not equal.
Try using the reflexivitiy lemma for your relation explicitly, e.g. `exact Eq.rfl`.
a b : Nat
⊢ 1 ≤ a + b
runTacticMustCatchExceptions.lean:3:25-3:28: error: The rfl tactic failed. Possible reasions:
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma)
- The arguments of the relation are not equal.
Try using the reflexivitiy lemma for your relation explicitly, e.g. `exact Eq.rfl`.
a b : Nat
this : 1 ≤ a + b
⊢ a + b ≤ b
runTacticMustCatchExceptions.lean:4:25-4:28: error: The rfl tactic failed. Possible reasions:
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma)
- The arguments of the relation are not equal.
Try using the reflexivitiy lemma for your relation explicitly, e.g. `exact Eq.rfl`.
a b : Nat
this✝ : 1 ≤ a + b
this : a + b ≤ b
⊢ b ≤ 2
runTacticMustCatchExceptions.lean:9:18-9:21: error: The rfl tactic failed. Possible reasions:
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma)
- The arguments of the relation are not equal.
Try using the reflexivitiy lemma for your relation explicitly, e.g. `exact Eq.rfl`.
a b : Nat
⊢ 1 ≤ a + b
runTacticMustCatchExceptions.lean:10:14-10:17: error: The rfl tactic failed. Possible reasions:
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma)
- The arguments of the relation are not equal.
Try using the reflexivitiy lemma for your relation explicitly, e.g. `exact Eq.rfl`.
a b : Nat
⊢ a + b ≤ b
runTacticMustCatchExceptions.lean:11:14-11:17: error: The rfl tactic failed. Possible reasions:
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma)
- The arguments of the relation are not equal.
Try using the reflexivitiy lemma for your relation explicitly, e.g. `exact Eq.rfl`.
a b : Nat
⊢ b ≤ 2

0 comments on commit eade05a

Please sign in to comment.