lean4-htt/tests/elab/test_simp_reducible_class.lean
Wojciech Różowski 3fc99eef10
feat: add instance validation checks in addInstance (#13389)
This PR adds two validation checks to `addInstance` that provide early
feedback for common mistakes in instance declarations:

1. **Non-class instance check**: errors when an instance target type is
not a type class. This catches the common mistake of writing `instance`
for a plain structure. Previously handled by the `nonClassInstance`
linter in Batteries (`Batteries.Tactic.Lint.TypeClass`), this is now
checked directly at declaration time.

2. **Impossible argument check**: errors when an instance has arguments
that cannot be inferred by instance synthesis. Specifically, it flags
arguments that are not instance-implicit and do not appear in any
subsequent instance-implicit argument or in the return type. Previously
such instances would be silently accepted but could never be
synthesised.

Supersedes #13237 and #13333.
2026-04-16 17:48:16 +00:00

57 lines
2 KiB
Text

module
/-!
# Test: `simp` with `@[reducible]` class field projections
When a class field like `X.x` is marked `@[reducible]`, `isDefEqDelta` unfolds it to `.proj` form.
`isDefEqProj` must then bump transparency to `.instances` when comparing the struct arguments,
since the projection's parameter is instance-implicit. Without this bump, `eq_self` fails because
instances like `instX a` vs `instX b` are stuck at `.reducible`.
-/
namespace SimpReducibleClassField
@[implicit_reducible] def a := 0
@[implicit_reducible] def b := 0
class X where
x : Nat
@[implicit_reducible]
def instX (n : Nat) : X where
x := n
-- Test 1: plain simp, semireducible X.x (works on master)
-- isDefEqArgs bumps to .instances for instance-implicit param of X.x
example : (instX a).x = (instX b).x := by simp
-- Test 2: plain simp, @[reducible] X.x
-- With backward.whnf.reducibleClassField = false: isDefEqDelta unfolds X.x to .proj form,
-- isDefEqProj bumps to .instances via withInstanceConfig.
-- With backward.whnf.reducibleClassField = true: tryHeuristic in isDefEqDelta applies the
-- argument-comparison heuristic, and isDefEqArgs bumps to .instances for instance-implicit params.
set_option allowUnsafeReducibility true
attribute [reducible] X.x
example : (instX a).x = (instX b).x := by simp
-- Test 2b: same as Test 2 with backward.whnf.reducibleClassField explicitly enabled
set_option allowUnsafeReducibility true
attribute [reducible] X.x
set_option backward.whnf.reducibleClassField true in
example : (instX a).x = (instX b).x := by simp
-- Test 3: simp [X.x] with semireducible args exposes stuck .proj node
-- reduceProjFn? unfolds X.x at .instances, but the .proj can't reduce further
-- because instX a' is not a constructor app at .reducible. This is expected:
-- the user explicitly requested the unfolding.
def a' := 0
def b' := 0
/--
error: unsolved goals
⊢ (instX a').1 = (instX b').1
-/
#guard_msgs in
example : (instX a').x = (instX b').x := by simp [X.x]
end SimpReducibleClassField