Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a1155de
Stash
nomeata Nov 17, 2025
6b29b12
stash
nomeata Nov 17, 2025
e8d867b
Add file
nomeata Nov 17, 2025
1cb7527
progress
nomeata Nov 17, 2025
05521de
Seems to work
nomeata Nov 17, 2025
04c56b3
Remove dead code
nomeata Nov 17, 2025
9efa483
fix: let `realizeConst` run `withDeclNameForAuxNaming`
nomeata Nov 17, 2025
577fb91
Add test case
nomeata Nov 17, 2025
6d7b71e
Merge branch 'joachim/realizeConst_withDeclNameForAuxNaming' into joa…
nomeata Nov 17, 2025
c8d1b46
Not needed
nomeata Nov 17, 2025
ab44217
More dead code
nomeata Nov 17, 2025
0b9db11
Spurious newline
nomeata Nov 17, 2025
e69c1da
Merge branch 'nightly-with-mathlib' of https://github.com/leanprover/…
nomeata Nov 18, 2025
6ebb738
refactor: extract functionality from Match.MatchEqs
nomeata Nov 18, 2025
73be069
Merge branch 'joachim/splitter-refactor' into joachim/splitter-via-match
nomeata Nov 18, 2025
c6a449e
Merge commit 'be6457284a200ad8936f97a57c88dcd8f8c1164e' into joachim/…
nomeata Nov 18, 2025
c685c19
Merge commit 'f6e580ccf8997d6ba65424377dc2f5e65d676153^' into joachim…
nomeata Nov 18, 2025
95d7bbe
Merge branch 'master' of https://github.com/leanprover/lean4 into joa…
nomeata Nov 18, 2025
039339a
Heed overlaps in new code
nomeata Nov 19, 2025
423db87
Update test
nomeata Nov 19, 2025
84fcfab
Merge branch 'master' of https://github.com/leanprover/lean4 into joa…
nomeata Nov 20, 2025
a1854d1
Avoid needsSplitter field
nomeata Nov 20, 2025
230fb8b
Reduce diff
nomeata Nov 21, 2025
5aebd96
Don’t add splitter to matcherExt
nomeata Nov 21, 2025
f828fd5
feat: allow setting reducibilityCoreExt in async contexts
nomeata Nov 21, 2025
2247c98
Merge branch 'joachim/reducibility-replay' into joachim/splitter-via-…
nomeata Nov 21, 2025
9bb4009
Remove unused code, move common code to helper modules
nomeata Nov 21, 2025
d1d23b8
test: add big match on nat lit benchmarks
nomeata Dec 4, 2025
caf137c
Merge branch 'master' of https://github.com/leanprover/lean4 into joa…
nomeata Dec 4, 2025
4988c6e
Merge branch 'joachim/bench-nat-match' into joachim/splitter-via-match
nomeata Dec 4, 2025
035b886
Merge branch 'master' of https://github.com/leanprover/lean4 into joa…
nomeata Dec 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/Lean/Elab/PreDefinition/Structural/Eqns.lean
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ module
prelude
public import Lean.Elab.PreDefinition.FixedParams
import Lean.Elab.PreDefinition.EqnsUtils
import Lean.Meta.Tactic.Split
import Lean.Meta.Tactic.CasesOnStuckLHS
import Lean.Meta.Tactic.Delta
import Lean.Meta.Tactic.Simp.Main
import Lean.Meta.Tactic.Delta
import Lean.Meta.Tactic.CasesOnStuckLHS
import Lean.Meta.Tactic.Split

namespace Lean.Elab
open Meta
Expand Down
4 changes: 3 additions & 1 deletion src/Lean/Meta/Constructions/CasesOnSameCtor.lean
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,9 @@ public def mkCasesOnSameCtor (declName : Name) (indName : Name) : MetaM Unit :=
numDiscrs := info.numIndices + 3
altInfos
uElimPos? := some 0
discrInfos := #[{}, {}, {}]}
discrInfos := #[{}, {}, {}]
overlaps := {}
}

-- Compare attributes with `mkMatcherAuxDefinition`
withExporting (isExporting := !isPrivateName declName) do
Expand Down
2 changes: 1 addition & 1 deletion src/Lean/Meta/IndPredBelow.lean
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ public partial def mkBelowMatcher (matcherApp : MatcherApp) (belowParams : Array
(ctx : RecursionContext) (transformAlt : RecursionContext → Expr → MetaM Expr) :
MetaM (Option (Expr × MetaM Unit)) :=
withTraceNode `Meta.IndPredBelow.match (return m!"{exceptEmoji ·} {matcherApp.toExpr} and {belowParams}") do
let mut input ← getMkMatcherInputInContext matcherApp
let mut input ← getMkMatcherInputInContext matcherApp (unfoldNamed := false)
let mut discrs := matcherApp.discrs
let mut matchTypeAdd := #[] -- #[(discrIdx, ), ...]
let mut i := discrs.size
Expand Down
5 changes: 5 additions & 0 deletions src/Lean/Meta/Match/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ structure Alt where
After we perform additional case analysis, their types become definitionally equal.
-/
cnstrs : List (Expr × Expr)
/--
Indices of previous alternatives that this alternative expects a not-that-proofs.
(When producing a splitter, and in the future also for source-level overlap hypotheses.)
-/
notAltIdxs : Array Nat
deriving Inhabited

namespace Alt
Expand Down
132 changes: 87 additions & 45 deletions src/Lean/Meta/Match/Match.lean

Large diffs are not rendered by default.

277 changes: 28 additions & 249 deletions src/Lean/Meta/Match/MatchEqs.lean

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/Lean/Meta/Match/MatcherApp/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def matchMatcherApp? [Monad m] [MonadEnv m] [MonadError m] (e : Expr) (alsoCases
matcherName := declName
matcherLevels := declLevels.toArray
uElimPos?, discrInfos, params, motive, discrs, alts, remaining, altInfos
overlaps := {} -- CasesOn constructor have no overlaps
}

return none
Expand Down
30 changes: 18 additions & 12 deletions src/Lean/Meta/Match/MatcherInfo.lean
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ structure Overlaps where
map : Std.HashMap Nat (Std.TreeSet Nat) := {}
deriving Inhabited, Repr

def Overlaps.isEmpty (o : Overlaps) : Bool :=
o.map.isEmpty

def Overlaps.insert (o : Overlaps) (overlapping overlapped : Nat) : Overlaps where
map := o.map.alter overlapped fun s? => some ((s?.getD {}).insert overlapping)

Expand All @@ -41,29 +44,32 @@ structure AltParamInfo where
numOverlaps : Nat
/-- Whether this alternatie has an artifcial `Unit` parameter -/
hasUnitThunk : Bool
deriving Inhabited, Repr
deriving Inhabited, Repr, BEq

/--
A "matcher" auxiliary declaration has the following structure:
- `numParams` parameters
- motive
- `numDiscrs` discriminators (aka major premises)
- `altInfos.size` alternatives (aka minor premises) with parameter structure information
- `uElimPos?` is `some pos` when the matcher can eliminate in different universe levels, and
`pos` is the position of the universe level parameter that specifies the elimination universe.
It is `none` if the matcher only eliminates into `Prop`.
- `overlaps` indicates which alternatives may overlap another
Information about the structure of a matcher declaration
-/
structure MatcherInfo where
/-- Number of parameters -/
numParams : Nat
/-- Number of discriminants -/
numDiscrs : Nat
/-- Parameter structure information for each alternative -/
altInfos : Array AltParamInfo
/--
`uElimPos?` is `some pos` when the matcher can eliminate in different universe levels, and
`pos` is the position of the universe level parameter that specifies the elimination universe.
It is `none` if the matcher only eliminates into `Prop`.
-/
uElimPos? : Option Nat
/--
`discrInfos[i] = { hName? := some h }` if the i-th discriminant was annotated with `h :`.
`discrInfos[i] = { hName? := some h }` if the i-th discriminant was annotated with `h :`.
-/
discrInfos : Array DiscrInfo
overlaps : Overlaps := {}
/--
(Conservative approximation of) which alternatives may overlap another.
-/
overlaps : Overlaps
deriving Inhabited, Repr

@[expose] def MatcherInfo.numAlts (info : MatcherInfo) : Nat :=
Expand Down
2 changes: 2 additions & 0 deletions stage0/src/stdlib_flags.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "util/options.h"

// please update stage0

namespace lean {
options get_default_options() {
options opts;
Expand Down
4 changes: 2 additions & 2 deletions tests/lean/run/casesOnSameCtor.lean
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ info: Vec.match_on_same_ctor.{u_1, u} {α : Type u}
/--
info: Vec.match_on_same_ctor.splitter.{u_1, u} {α : Type u}
{motive : {a : Nat} → (t t_1 : Vec α a) → t.ctorIdx = t_1.ctorIdx → Sort u_1} {a✝ : Nat} (t t✝ : Vec α a✝)
(h : t.ctorIdx = t✝.ctorIdx) (h_1 : Unit → motive nil nil ⋯)
(h_2 : (a : α) → (n : Nat) → (a_1 : Vec α n) → (a' : α) → (a'_1 : Vec α n) → motive (cons a a_1) (cons a' a'_1) ⋯) :
(h : t.ctorIdx = t✝.ctorIdx) (nil : Unit → motive nil nil ⋯)
(cons : (a : α) → {n : Nat} → (a_1 : Vec α n) → (a' : α) → (a'_1 : Vec α n) → motive (cons a a_1) (cons a' a'_1) ⋯) :
motive t t✝ h
-/
#guard_msgs in
Expand Down
2 changes: 1 addition & 1 deletion tests/lean/run/issue8274.lean
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ info: private def myTest.match_1.splitter.{u_1} : (motive : List Bool → Sort u
(x : List Bool) →
((x_1 : Bool) → (xs : List Bool) → x = x_1 :: xs → motive (x_1 :: xs)) → (x = [] → motive []) → motive x :=
fun motive x h_1 h_2 =>
List.casesOn (motive := fun x_1 => x = x_1 → motive x_1) x h_2 (fun head tail => h_1 head tail) ⋯
(fun x_1 => List.casesOn (motive := fun x_2 => x = x_2 → motive x_2) x_1 h_2 fun head tail => h_1 head tail) x
-/
#guard_msgs in
#print myTest.match_1.splitter
Expand Down
4 changes: 3 additions & 1 deletion tests/lean/run/match2.lean
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Lean

set_option linter.unusedVariables false

def checkWithMkMatcherInput (matcher : Lean.Name) : Lean.MetaM Unit :=
Lean.Meta.Match.withMkMatcherInput matcher fun input => do
Lean.Meta.Match.withMkMatcherInput matcher (unfoldNamed := false) fun input => do
let res ← Lean.Meta.Match.mkMatcher input
let origMatcher ← Lean.getConstInfo matcher
if not <| input.matcherName == matcher then
Expand Down
20 changes: 20 additions & 0 deletions tests/lean/run/matchSparse.lean
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,25 @@ 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
Expand Down Expand Up @@ -49,6 +68,7 @@ info: expensive.match_1.splitter.{u_1} (motive : Expr → Expr → Sort u_1) (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 :
Expand Down
3 changes: 3 additions & 0 deletions tests/lean/run/split1.lean
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
-- set_option trace.Meta.Match.match true
-- set_option trace.Meta.Match.matchEqs true

def f (xs : List Nat) : Nat :=
match xs with
| [] => 1
Expand Down
Loading