This PR fixes the interaction between `backward.whnf.reducibleClassField` and `isDefEqDelta`'s argument-comparison heuristic. When `backward.whnf.reducibleClassField` is enabled, `unfoldDefault` reduces class field projections past the `.proj` form at `.instances` transparency. This causes `isDefEqDelta` to lose the instance structure that `isDefEqProj` needs to bump transparency for instance-implicit parameters. The fix adds an `.abbrev` branch in `isNonTrivialRegular` that classifies class field projections as nontrivial when the option is enabled, so `tryHeuristic` applies the argument-comparison heuristic (with the correct transparency bump) instead of unfolding. Key insight: all projection functions receive `.abbrev` kernel hints (not `.regular`), regardless of their reducibility status. Structure projections default to `.reducible` status, while class projections default to `.semireducible` status. The old code only handled the `.regular` case and treated everything else (including `.abbrev`) as trivial. Also fixes two minor comment issues in `tryHeuristic`: "non-trivial regular definition" → "non-trivial definition" (since `.abbrev` definitions can now be nontrivial too), and "when `f` is not simple" → "when `f` is simple" (logic inversion in the original comment). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
56 lines
2 KiB
Text
56 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
|
|
|
|
instance 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 in
|
|
attribute [reducible] X.x in
|
|
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 in
|
|
attribute [reducible] X.x in
|
|
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
|