lean4-htt/tests/elab/grind_congr_hash_issue.lean
Leonardo de Moura 9fa1a252f2
fix: nondeterministic crash in grind congruence closure (#13027)
This PR fixes a nondeterministic crash in `grind` caused by a
`BEq`/`Hashable` invariant
violation in the congruence table. `congrHash` uses each expression's
own `funCC` flag to
compute its hash (one-level decomposition for `funCC = true`, full
recursive decomposition
for `funCC = false`), but `isCongruent` only checked the stored
expression's flag. When two
expressions with mismatched `funCC` flags accidentally hash-collided
(via pointer-based
`ptrAddrUnsafe` hashing), `isCongruent` could declare them congruent
despite different
argument counts, leading to an assertion failure in `mkCongrProof`.

The fix requires matching `funCC` flags in `isCongruent`. The PR also
fixes the debug
invariant checker (`checkParents`) to skip `funCC` parents and adds a
regression test for
funCC congruence.

Observed as a nondeterministic crash in Mathlib at
`Analysis/ODE/PicardLindelof.lean`.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 22:54:58 +00:00

32 lines
913 B
Text

module
set_option grind.debug true
opaque f : Nat → Nat
opaque g : (Nat → Nat) → Prop
example
: f a = x →
-- At this point `f` has not been internalized
g f →
-- Since `f` has now occurred as the argument of `f`, it is internalized
f b = y →
-- The congruence hash for `f a` must not depend on whether `f` has been internalized or not
b = a →
x = y := by
grind
-- Same example with `a = b` to ensure the previous issue does not depend on how we break
-- ties when merging equivalence classes of the same size
example
: f a = x →
g f →
f b = y →
a = b →
x = y := by
grind
-- funCC congruence: `h a` and `k` are in the same equivalence class as functions,
-- so `h a b c = k b c` should follow.
example (h : Nat → Nat → Nat → Nat) (k : Nat → Nat → Nat)
: h a = k → h a b c = k b c := by
grind