lean4-htt/tests/elab/grind_canon_bug_2.lean
Leonardo de Moura e55f69acd0
refactor: simplify grind canonicalizer and fix preprocessing issues (#13149)
This PR simplifies the `grind` canonicalizer by removing dead state and
unnecessary
complexity, and fixes two bugs discovered during the cleanup.

## Changes

**Canonicalizer cleanup:**
- Remove dead `Canon.State.canon` field — values were inserted but never
read.
The canonicalizer uses a transient `HashMap` local to each `canonImpl`
invocation.
- Remove `proofCanon` — it deduplicated `Grind.nestedProof` terms by
mapping
canonicalized propositions to a single representative, but different
proofs may
reference different hypotheses, making the result context-dependent and
preventing
  cache sharing across goals.
- Remove `isDefEqBounded` — a fallback that retried `isDefEq` at default
transparency
with a heartbeat budget. The one test that depended on it was actually
masking a
  transparency bug in `propagateCtorHomo`.

**Bug fixes:**
- Use `withDefault` for `mkAppOptM` in `propagateCtorHomo` (`Ctor.lean`)
— the
injectivity proof construction needs default transparency to unify
implicit
  arguments of indexed inductive types like `Vector`.
- Add `Grind.abstractFn` gadget to protect lambda abstractions created
by
`abstractGroundMismatches?` from beta reduction during preprocessing.
Without
this, `Core.betaReduce` in `preprocessLight` collapses `(fun x => body)
arg`
back to `body[arg/x]`, undoing the abstraction that congruence closure
needs.

**Eta reduction infrastructure:**
- Lower `etaReduceAll` from `MetaM` to `CoreM` — it only performs
structural
  operations, no `MetaM` needed.
- Add `etaReduceWithCache` that takes and returns an explicit `HashMap`
cache,
  enabling callers to thread a single cache across multiple expressions.

The net effect on `Canon.State` is removing 3 fields (`canon`,
`proofCanon`)
and the `isDefEqBounded` function, along with the `useIsDefEqBounded`
and
`parent` parameters from `canonElemCore`.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 05:00:01 +00:00

22 lines
755 B
Text

import Std.Data.ExtHashMap
open Std
set_option warn.sorry false
-- Without `proofCanon`, two `m[k]` appear because they carry different proofs.
/--
trace: [grind.lia.model] k := 101
[grind.lia.model] (ExtHashMap.filter (fun k x => decide (101 ≤ k)) (m.insert 1 3))[k] := 4
[grind.lia.model] (m.insert 1 2)[k] := 4
[grind.lia.model] (m.insert 1 3)[k] := 4
[grind.lia.model] m[k] := 4
[grind.lia.model] m[k] := 4
[grind.lia.model] (m.insert 1 2).getKey k ⋯ := 101
[grind.lia.model] m.getKey k ⋯ := 101
-/
#guard_msgs in
example (m : ExtHashMap Nat Nat) :
(m.insert 1 2).filter (fun k _ => k > 1000) = (m.insert 1 3).filter fun k _ => k > 100 := by
ext1 k
set_option trace.grind.lia.model true in
fail_if_success grind (splits := 4)
sorry