lean4-htt/tests/lean/run/matchSparse.lean
Joachim Breitner af6d2077a0
refactor: use match compilation to generate splitter (#11220)
This PR changes how match splitters are generated: Rather than rewriting
the match statement, the match compilation pipeline is used again.


The benefits are:

* Re-doing the match compilation means we can do more intelligent book
keeping, e.g. prove overlap assumptions only once and re-use the proof,
or prune the context of the MVar to speed up `contradiction`. This may
have allowed a different solution than #11200.
 
* It would unblock #11105, as the existing splitter implementation would
have trouble dealing with the matchers produced that way.
 
* It provides the necessary machinery also for source-exposed “none of
the above” bindings, a feature that we probably want at some point (and
we mostly need to find good syntax for, see #3136, although maybe I
should open a dedicated RFC).

* It allows us to skip costly things during matcher creation that would
only be useful for the splitter, and thus allows performance
improvements like #11508.
 
 * We can drop the existing implementation.
 
It’s not entirely free:

* We have to run `simpH` twice, once for the match equations and once
for the splitter.
2025-12-04 15:03:13 +00:00

104 lines
4 KiB
Text

import Lean
open Lean Expr Level -- just for shorter outpt
-- set_option trace.Meta.Match.match true
-- set_option trace.Meta.Match.debug true
-- set_option trace.Meta.Tactic.induction true
def simple : Lean.Expr → Bool
| .sort _ => true
| _ => false
/--
info: def simple.match_1.{u_1} : (motive : Expr → Sort u_1) →
(x : Expr) → ((u : Level) → motive (sort u)) → ((x : Expr) → motive x) → motive x :=
fun motive x h_1 h_2 => simple._sparseCasesOn_1 x (fun u => h_1 u) fun h => h_2 x
-/
#guard_msgs in
#print simple.match_1
-- Check that the splitter re-uses the sparseCasesOn generated for the matcher:
/--
info: private def simple.match_1.splitter.{u_1} : (motive : Expr → Sort u_1) →
(x : Expr) →
((u : Level) → motive (sort u)) → ((x : Expr) → (∀ (u : Level), x = sort u → False) → motive x) → motive x :=
fun motive x h_1 h_2 => simple._sparseCasesOn_1 x (fun u => h_1 u) fun h => h_2 x ⋯
-/
#guard_msgs in
#print simple.match_1.splitter
def expensive : Lean.Expr → Lean.Expr → Bool
| .app (.app (.sort 1) (.sort 1)) (.sort 1), .app (.app (.sort 1) (.sort 1)) (.sort 1) => false
| _, _ => true
/-- info: false -/
#guard_msgs in
#eval expensive (.app (.app (.sort 1) (.sort 1)) (.sort 1)) (.app (.app (.sort 1) (.sort 1)) (.sort 1))
/-- info: true -/
#guard_msgs in
#eval expensive (.app (.app (.sort 2) (.sort 1)) (.sort 1)) (.app (.app (.sort 1) (.sort 1)) (.sort 1))
example : expensive (.app (.app (.sort 1) (.sort 1)) (.sort 1)) (.app (.app (.sort 1) (.sort 1)) (.sort 1)) = false := rfl
example : expensive (.app (.app (.sort 2) (.sort 1)) (.sort 1)) (.app (.app (.sort 1) (.sort 1)) (.sort 1)) = true := rfl
/--
info: expensive.match_1.{u_1} (motive : Expr → Expr → Sort u_1) (x✝ x✝¹ : Expr)
(h_1 :
Unit →
motive (((sort zero.succ).app (sort zero.succ)).app (sort zero.succ))
(((sort zero.succ).app (sort zero.succ)).app (sort zero.succ)))
(h_2 : (x x_1 : Expr) → motive x x_1) : motive x✝ x✝¹
-/
#guard_msgs in
#check expensive.match_1
/--
info: expensive.match_1.splitter.{u_1} (motive : Expr → Expr → Sort u_1) (x✝ x✝¹ : Expr)
(h_1 :
Unit →
motive (((sort zero.succ).app (sort zero.succ)).app (sort zero.succ))
(((sort zero.succ).app (sort zero.succ)).app (sort zero.succ)))
(h_2 :
(x x_1 : Expr) →
(x = ((sort zero.succ).app (sort zero.succ)).app (sort zero.succ) →
x_1 = ((sort zero.succ).app (sort zero.succ)).app (sort zero.succ) → False) →
motive x x_1) :
motive x✝ x✝¹
-/
#guard_msgs in
#check expensive.match_1.splitter
/--
info: expensive.match_1.eq_1.{u_1} (motive : Expr → Expr → Sort u_1)
(h_1 :
Unit →
motive (((sort zero.succ).app (sort zero.succ)).app (sort zero.succ))
(((sort zero.succ).app (sort zero.succ)).app (sort zero.succ)))
(h_2 : (x x_1 : Expr) → motive x x_1) :
(match ((sort zero.succ).app (sort zero.succ)).app (sort zero.succ),
((sort zero.succ).app (sort zero.succ)).app (sort zero.succ) with
| ((sort zero.succ).app (sort zero.succ)).app (sort zero.succ),
((sort zero.succ).app (sort zero.succ)).app (sort zero.succ) => h_1 ()
| x, x_1 => h_2 x x_1) =
h_1 ()
-/
#guard_msgs in
#check expensive.match_1.eq_1
/--
info: expensive.match_1.eq_2.{u_1} (motive : Expr → Expr → Sort u_1) (x✝ x✝¹ : Expr)
(h_1 :
Unit →
motive (((sort zero.succ).app (sort zero.succ)).app (sort zero.succ))
(((sort zero.succ).app (sort zero.succ)).app (sort zero.succ)))
(h_2 : (x x_1 : Expr) → motive x x_1) :
(x✝ = ((sort zero.succ).app (sort zero.succ)).app (sort zero.succ) →
x✝¹ = ((sort zero.succ).app (sort zero.succ)).app (sort zero.succ) → False) →
(match x✝, x✝¹ with
| ((sort zero.succ).app (sort zero.succ)).app (sort zero.succ),
((sort zero.succ).app (sort zero.succ)).app (sort zero.succ) => h_1 ()
| x, x_1 => h_2 x x_1) =
h_2 x✝ x✝¹
-/
#guard_msgs in
#check expensive.match_1.eq_2