Files
lean4/tests/elab/sym_pattern_level.lean
Leonardo de Moura cfa8c5a036 fix: handle universe level commutativity in sym pattern matching (#12923)
This PR fixes a bug where `max u v` and `max v u` fail to match in
SymM's pattern matching. Both `processLevel` (Phase 1) and
`isLevelDefEqS` (Phase 2) treated `max` positionally, so `max u v ≠ max
v u` structurally even though they are semantically equal.

The fix has three parts:
- Eagerly normalize universe levels in patterns at creation time
(`preprocessDeclPattern`, `preprocessExprPattern`,
`mkSimprocPatternFromExpr`)
- Normalize the target level in `processLevel` before matching, using a
`where go` refactor
- Add `tryApproxMaxMax` to `processLevel` and `isLevelDefEqS`: when
positional `max/max` matching would fail, check if one argument from
each side matches structurally and match the remaining pair

Also moves `normalizeLevels` from `Grind.Util` to `Sym.Util` to avoid
code duplication, since both Sym and Grind need it.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 01:06:16 +00:00

46 lines
1.5 KiB
Lean4
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Lean.Meta.Sym
open Lean Meta Sym
/-! ## Level commutativity: `max u v` vs `max v u` with concrete params -/
/--
info: rule.apply succeeds: max u v matches max v u
-/
#guard_msgs in
#eval show MetaM Unit from do
let u := Level.param `u
let v := Level.param `v
let maxUV := Level.max u v
let maxVU := Level.max v u
let proof := mkApp2 (mkConst ``Eq.refl [maxUV.succ]) (mkSort maxUV) (mkSort maxUV)
let rule mkBackwardRuleFromExpr proof (levelParams := [`u, `v])
let goalType := mkApp3 (mkConst ``Eq [maxVU.succ]) (mkSort maxVU) (mkSort maxVU) (mkSort maxVU)
let r SymM.run do
let mvar mkFreshExprMVar goalType
let mvarId preprocessMVar mvar.mvarId!
rule.apply mvarId
match r with
| .goals _ => logInfo "rule.apply succeeds: max u v matches max v u"
| .failed => logInfo "rule.apply FAILED: max u v did not match max v u"
/-! ## `tryApproxMaxMax`: pattern `max _uvar 1` matching target `max 1 u` -/
axiom lvlAxiom : (α : Sort (max u 1)), α α
/--
info: pattern match succeeded
-/
#guard_msgs in
#eval show MetaM Unit from do
let pat mkPatternFromDecl ``lvlAxiom
-- Target has `max 1 u` (swapped from pattern's `max u 1`)
let u := Level.param `u
let lvl := Level.max (.succ .zero) u -- max 1 u
let targetType := Expr.forallE `α (.sort lvl) (Expr.forallE `a (.bvar 0) (.bvar 1) .default) .implicit
let r SymM.run do
pat.match? targetType
match r with
| some _ => logInfo "pattern match succeeded"
| none => logInfo "pattern match FAILED"