lean4-htt/tests/elab/1380.lean
Kim Morrison e01cbf2b8f
feat: add structured TraceResult to TraceData (#12698)
This PR adds a `result? : Option TraceResult` field to `TraceData` and
populates it in `withTraceNode` and `withTraceNodeBefore`, so that
metaprograms walking trace trees can determine success/failure
structurally instead of string-matching on emoji.

`TraceResult` has three cases: `.success` (checkEmoji), `.failure`
(crossEmoji), and `.error` (bombEmoji, exception thrown). An
`ExceptToTraceResult` typeclass converts `Except` results to
`TraceResult` directly, with instances for `Bool` and `Option`.
`TraceResult.toEmoji` converts back to emoji for display. This replaces
the previous `ExceptToEmoji` typeclass — `TraceResult` is now the
primary representation rather than being derived from emoji strings.

`withTraceNodeBefore` (used by `isDefEq`) uses
`ExceptToTraceResult.toTraceResult` directly, correctly handling `Bool`
(`.ok false` = failure) and `Option` (`.ok none` = failure), with
`Except.error` mapping to `.error`.

For `withTraceNode`, `result?` defaults to `none`. Callers can pass
`mkResult?` to provide structured results; when set, the corresponding
emoji is auto-prepended to the message.

Motivated by mathlib's `#defeq_abuse` diagnostic tactic
(https://github.com/leanprover-community/mathlib4/pull/35750) which
currently string-matches on emoji to determine trace node outcomes. See
https://leanprover.zulipchat.com/#narrow/channel/113488-general/topic/backward.2EisDefEq.2ErespectTransparency

🤖 Prepared with Claude Code

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 02:42:57 +00:00

37 lines
1,007 B
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

set_option linter.unusedSimpArgs false
variable (n v₁ v₂) (hv₁: v₁ < n + 1) (hv₂: v₂ < n + 1)
theorem foo (_: ¬ Fin.mk v₂ hv₂ = Fin.mk v₁ hv₁ ): True := trivial
/--
trace: [Meta.Tactic.simp.unify] eq_self:1000, failed to unify
?a = ?a
with
⟨v₂, hv₂⟩ = ⟨v₁, hv₁⟩
[Meta.Tactic.simp.rewrite] Fin.mk.injEq:1000:
⟨v₂, hv₂⟩ = ⟨v₁, hv₁⟩
==>
v₂ = v₁
[Meta.Tactic.simp.unify] eq_self:1000, failed to unify
?a = ?a
with
v₂ = v₁
[Meta.Tactic.simp.discharge] ✅️ Nat.ne_of_gt discharge ✅️
v₁ < v₂
[Meta.Tactic.simp.rewrite] hv:1000:
v₁ < v₂
==>
True
[Meta.Tactic.simp.rewrite] Nat.ne_of_gt:1000:
v₂ = v₁
==>
False
-/
#guard_msgs in
set_option trace.Meta.Tactic.simp true in
example (hv: v₁ < v₂) : True :=
foo n v₁ v₂ _ _
(by simp +decide only [hv, Fin.mk.injEq, Nat.ne_of_gt, Nat.lt_succ_iff])
#check Fin.mk.injEq