lean4-htt/tests/elab/typeCheckNote.lean
Sebastian Ullrich 508a113242
feat: add .instances-transparency type-check diagnostics (#13368)
This PR adds infrastructure to help diagnose cases where tactics like
`unfold`
leave the goal in a state that is type-correct only at `.default`
transparency,
causing `rw`/`simp` to fail at `.instances` transparency.

Changes:
- Add a `transparency` parameter to `Meta.check` (defaults to `.all`)
- Add `withInstancesTypeCheckNote` which appends a
lazy note to tactic errors when the target is not type-correct at
`.instances`
- Wrap `rw`, `simp`, `dsimp`, and `simp_all` at the Elab level
- Add opt-in `linter.tacticCheckInstances` that proactively checks every
  tactic goal and reports semireducible defs that should be marked
`@[implicit_reducible]`, using diagnostic counter diffing between
`.default`
  and `.instances` checks
2026-05-02 12:17:51 +00:00

104 lines
3.4 KiB
Text

module
set_option backward.isDefEq.respectTransparency.types true
/-!
After `unfold`, the goal may become not type-correct at `instances` transparency
because hypotheses still refer to the pre-unfolded definition. When `rw`/`simp`
fails in such a goal, the error message should include a note about the
type-correctness issue.
-/
structure S where
decls : Array Nat
structure E where
s : S
structure Inp (s : S) where
x : Nat
class C (β : S → Type) (f : (s : S) → β s → E) where
decl_eq : ∀ (s : S) (input : β s)
(idx : Nat) (h1 : idx < s.decls.size) (h2 : idx < (f s input).s.decls.size),
(f s input).s.decls[idx]'h2 = s.decls[idx]'h1
def myF (s : S) (_ : Inp s) : E := ⟨s⟩
set_option warn.sorry false in
instance : C Inp myF where
decl_eq := by intros; sorry
def composed (s : S) (a b : Nat) : E :=
let res := myF s ⟨a⟩
myF res.s ⟨b⟩
section rw
-- Without `unfold`, the note should NOT fire (goal is type-correct at `instances`)
/--
error: Tactic `rewrite` failed: Did not find an occurrence of the pattern
(myF ?s ?input).s.decls[?idx]
in the target expression
(composed s a b).s.decls[idx] = s.decls[idx]
s : S
a b idx : Nat
h1 : idx < s.decls.size
h2 : idx < (composed s a b).s.decls.size
⊢ (composed s a b).s.decls[idx] = s.decls[idx]
-/
#guard_msgs in
example (s : S) (a b idx : Nat) (h1 : idx < s.decls.size)
(h2 : idx < (composed s a b).s.decls.size) :
(composed s a b).s.decls[idx]'h2 = s.decls[idx]'h1 := by
rw [C.decl_eq (f := myF)]
-- With `unfold`, the note SHOULD fire (`h2`'s type no longer matches after unfolding)
/--
Note: The target expression is not type-correct under the `instances` transparency level, which may have triggered the failure. This is usually caused by unfolding of semireducible definitions in prior tactic steps.
-/
#guard_msgs (substring := true) in
example (s : S) (a b idx : Nat) (h1 : idx < s.decls.size)
(h2 : idx < (composed s a b).s.decls.size) :
(composed s a b).s.decls[idx]'h2 = s.decls[idx]'h1 := by
unfold composed
rw [C.decl_eq (f := myF)]
-- The defeq abuse may already be part of the initial goal.
/--
Note: The target expression is not type-correct under the `instances` transparency level, which may have triggered the failure. This is usually caused by unfolding of semireducible definitions in prior tactic steps.
-/
#guard_msgs (substring := true) in
example (s : S) (a b idx : Nat) (h1 : idx < s.decls.size) :
(composed s a b).s.decls[idx] = s.decls[idx] := by
rw [C.decl_eq (f := myF)]
end rw
section simp
-- Without `unfold`, the note should NOT fire
/--
error: `simp` made no progress
-/
#guard_msgs in
example (s : S) (a b idx : Nat) (h1 : idx < s.decls.size)
(h2 : idx < (composed s a b).s.decls.size) :
(composed s a b).s.decls[idx]'h2 = s.decls[idx]'h1 := by
simp (config := { zeta := false })
-- With `unfold`, the note SHOULD fire
/--
error: `simp` made no progress
Note: The target expression is not type-correct under the `instances` transparency level, which may have triggered the failure. This is usually caused by unfolding of semireducible definitions in prior tactic steps. Use `set_option linter.tacticCheckInstances true` to investigate the source of the issue.
-/
#guard_msgs in
example (s : S) (a b idx : Nat) (h1 : idx < s.decls.size)
(h2 : idx < (composed s a b).s.decls.size) :
(composed s a b).s.decls[idx]'h2 = s.decls[idx]'h1 := by
unfold composed
simp (config := { zeta := false })
end simp