fix: assertion violation in mkEqProofImpl (#12473)

This PR fixes an assertion violation in `grind` reported at #12246 This
assertion fails when in examples containing heterogenous equalities with
elements of different types (e.g., `Fin n` and `Fin m`) attached to the
same theory solver.

Closes #12246
This commit is contained in:
Leonardo de Moura 2026-02-13 16:43:15 -08:00 committed by GitHub
parent c1ad6aa0db
commit e579dfdb14
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 53 additions and 3 deletions

View file

@ -334,7 +334,8 @@ It assumes `a` and `b` are in the same equivalence class.
-/
@[export lean_grind_mk_eq_proof]
def mkEqProofImpl (a b : Expr) : GoalM Expr := do
assert! (← hasSameType a b)
unless (← hasSameType a b) do
throwError "internal `grind` error, `mkEqProof` invoked with terms of different types{indentExpr a}\nhas type{indentExpr (← inferType a)}\nbut{indentExpr b}\nhas type{indentExpr (← inferType b)}"
mkEqProofCore a b (heq := false)
@[export lean_grind_mk_heq_proof]

View file

@ -1967,7 +1967,10 @@ def SolverExtension.markTerm (ext : SolverExtension σ) (e : Expr) : GoalM Unit
| .nil => return .next id e .nil
| .next id' e' sTerms' =>
if id == id' then
(← solverExtensionsRef.get)[id]!.newEq e e'
-- Skip if `e` and `e'` have different types (e.g., they were merged via `HEq` from `cast`).
-- This can happen when we have heterogenous equalities in an equivalence class containing types such as `Fin n` and `Fin m`
if (← pure !root.heqProofs <||> hasSameType e e') then
(← solverExtensionsRef.get)[id]!.newEq e e'
return sTerms
else if id < id' then
return .next id e sTerms
@ -2047,7 +2050,11 @@ where
match p with
| .nil => return ()
| .eq solverId lhs rhs rest =>
(← solverExtensionsRef.get)[solverId]!.newEq lhs rhs
-- Skip if `lhs` and `rhs` have different types (e.g., they were merged via `HEq` from `cast`).
-- This can happen when we have heterogenous equalities in an equivalence class containing types such as `Fin n` and `Fin m`
let root ← getRootENode lhs
if (← pure !root.heqProofs <||> hasSameType lhs rhs) then
(← solverExtensionsRef.get)[solverId]!.newEq lhs rhs
go rest
| .diseqs solverId parentSet rest =>
forEachDiseq parentSet (propagateDiseqOf solverId)

View file

@ -0,0 +1,42 @@
import Std.Do
import Std.Tactic.Do
def Matrix' (α β γ : Type) : Type := α → β → γ
namespace Matrix'
variable {α : Type} {m n : Nat} {M : Matrix' (Fin m) (Fin n) α}
variable {i i' : Fin m} {j j' : Fin n}
def shuffleRows (M : Matrix' (Fin m) (Fin n) α) (j : Fin n) :
Matrix' (Fin m) (Fin n) α := sorry
def altColSort (M : Matrix' (Fin m) (Fin n) α) :
Matrix' (Fin m) (Fin n) α := Id.run do
let mut M' : Matrix' (Fin m) (Fin n) α := M
for hj : j in [:n] do M' := M'.shuffleRows ⟨j, by sorry⟩
return M'
open Std.Do
variable [LE α] [Std.IsLinearOrder α]
set_option mvcgen.warning false
def Monotone' {α : Type} [LE α] (f : Fin n → α) : Prop := ∀ i j, i ≤ j → f i ≤ f j
attribute [grind =] Fin.le_def Monotone'
theorem altColSort_rowSorted' (hM : ∀ i, Monotone' (M i)) (i : Fin m) :
Monotone' (M.altColSort i) := by
generalize h : M.altColSort = x
apply Id.of_wp_run_eq h
mvcgen invariants
| inv1 => ⇓⟨cur, M'⟩ => ⌜(∀ j : Fin n, j < cur.pos → Monotone' (M' · j))⌝
case vc2 => grind
case vc3 => sorry
case vc1 =>
fail_if_success grind -verbose
sorry
end Matrix'