Skip to content

Commit af6d207

Browse files
authored
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.
1 parent 31d629c commit af6d207

File tree

14 files changed

+177
-313
lines changed

14 files changed

+177
-313
lines changed

src/Lean/Elab/PreDefinition/Structural/Eqns.lean

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ module
88
prelude
99
public import Lean.Elab.PreDefinition.FixedParams
1010
import Lean.Elab.PreDefinition.EqnsUtils
11-
import Lean.Meta.Tactic.Split
11+
import Lean.Meta.Tactic.CasesOnStuckLHS
12+
import Lean.Meta.Tactic.Delta
1213
import Lean.Meta.Tactic.Simp.Main
1314
import Lean.Meta.Tactic.Delta
1415
import Lean.Meta.Tactic.CasesOnStuckLHS
16+
import Lean.Meta.Tactic.Split
1517

1618
namespace Lean.Elab
1719
open Meta

src/Lean/Meta/Constructions/CasesOnSameCtor.lean

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,9 @@ public def mkCasesOnSameCtor (declName : Name) (indName : Name) : MetaM Unit :=
213213
numDiscrs := info.numIndices + 3
214214
altInfos
215215
uElimPos? := some 0
216-
discrInfos := #[{}, {}, {}]}
216+
discrInfos := #[{}, {}, {}]
217+
overlaps := {}
218+
}
217219

218220
-- Compare attributes with `mkMatcherAuxDefinition`
219221
withExporting (isExporting := !isPrivateName declName) do

src/Lean/Meta/IndPredBelow.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ public partial def mkBelowMatcher (matcherApp : MatcherApp) (belowParams : Array
319319
(ctx : RecursionContext) (transformAlt : RecursionContext → Expr → MetaM Expr) :
320320
MetaM (Option (Expr × MetaM Unit)) :=
321321
withTraceNode `Meta.IndPredBelow.match (return m!"{exceptEmoji ·} {matcherApp.toExpr} and {belowParams}") do
322-
let mut input ← getMkMatcherInputInContext matcherApp
322+
let mut input ← getMkMatcherInputInContext matcherApp (unfoldNamed := false)
323323
let mut discrs := matcherApp.discrs
324324
let mut matchTypeAdd := #[] -- #[(discrIdx, ), ...]
325325
let mut i := discrs.size

src/Lean/Meta/Match/Basic.lean

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ structure Alt where
150150
After we perform additional case analysis, their types become definitionally equal.
151151
-/
152152
cnstrs : List (Expr × Expr)
153+
/--
154+
Indices of previous alternatives that this alternative expects a not-that-proofs.
155+
(When producing a splitter, and in the future also for source-level overlap hypotheses.)
156+
-/
157+
notAltIdxs : Array Nat
153158
deriving Inhabited
154159

155160
namespace Alt

src/Lean/Meta/Match/Match.lean

Lines changed: 87 additions & 45 deletions
Large diffs are not rendered by default.

src/Lean/Meta/Match/MatchEqs.lean

Lines changed: 28 additions & 249 deletions
Large diffs are not rendered by default.

src/Lean/Meta/Match/MatcherApp/Basic.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def matchMatcherApp? [Monad m] [MonadEnv m] [MonadError m] (e : Expr) (alsoCases
6767
matcherName := declName
6868
matcherLevels := declLevels.toArray
6969
uElimPos?, discrInfos, params, motive, discrs, alts, remaining, altInfos
70+
overlaps := {} -- CasesOn constructor have no overlaps
7071
}
7172

7273
return none

src/Lean/Meta/Match/MatcherInfo.lean

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ structure Overlaps where
2323
map : Std.HashMap Nat (Std.TreeSet Nat) := {}
2424
deriving Inhabited, Repr
2525

26+
def Overlaps.isEmpty (o : Overlaps) : Bool :=
27+
o.map.isEmpty
28+
2629
def Overlaps.insert (o : Overlaps) (overlapping overlapped : Nat) : Overlaps where
2730
map := o.map.alter overlapped fun s? => some ((s?.getD {}).insert overlapping)
2831

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

4649
/--
47-
A "matcher" auxiliary declaration has the following structure:
48-
- `numParams` parameters
49-
- motive
50-
- `numDiscrs` discriminators (aka major premises)
51-
- `altInfos.size` alternatives (aka minor premises) with parameter structure information
52-
- `uElimPos?` is `some pos` when the matcher can eliminate in different universe levels, and
53-
`pos` is the position of the universe level parameter that specifies the elimination universe.
54-
It is `none` if the matcher only eliminates into `Prop`.
55-
- `overlaps` indicates which alternatives may overlap another
50+
Information about the structure of a matcher declaration
5651
-/
5752
structure MatcherInfo where
53+
/-- Number of parameters -/
5854
numParams : Nat
55+
/-- Number of discriminants -/
5956
numDiscrs : Nat
57+
/-- Parameter structure information for each alternative -/
6058
altInfos : Array AltParamInfo
59+
/--
60+
`uElimPos?` is `some pos` when the matcher can eliminate in different universe levels, and
61+
`pos` is the position of the universe level parameter that specifies the elimination universe.
62+
It is `none` if the matcher only eliminates into `Prop`.
63+
-/
6164
uElimPos? : Option Nat
6265
/--
63-
`discrInfos[i] = { hName? := some h }` if the i-th discriminant was annotated with `h :`.
66+
`discrInfos[i] = { hName? := some h }` if the i-th discriminant was annotated with `h :`.
6467
-/
6568
discrInfos : Array DiscrInfo
66-
overlaps : Overlaps := {}
69+
/--
70+
(Conservative approximation of) which alternatives may overlap another.
71+
-/
72+
overlaps : Overlaps
6773
deriving Inhabited, Repr
6874

6975
@[expose] def MatcherInfo.numAlts (info : MatcherInfo) : Nat :=

stage0/src/stdlib_flags.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "util/options.h"
22

3+
// please update stage0
4+
35
namespace lean {
46
options get_default_options() {
57
options opts;

tests/lean/run/casesOnSameCtor.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ info: Vec.match_on_same_ctor.{u_1, u} {α : Type u}
3838
/--
3939
info: Vec.match_on_same_ctor.splitter.{u_1, u} {α : Type u}
4040
{motive : {a : Nat} → (t t_1 : Vec α a) → t.ctorIdx = t_1.ctorIdx → Sort u_1} {a✝ : Nat} (t t✝ : Vec α a✝)
41-
(h : t.ctorIdx = t✝.ctorIdx) (h_1 : Unit → motive nil nil ⋯)
42-
(h_2 : (a : α) → (n : Nat) → (a_1 : Vec α n) → (a' : α) → (a'_1 : Vec α n) → motive (cons a a_1) (cons a' a'_1) ⋯) :
41+
(h : t.ctorIdx = t✝.ctorIdx) (nil : Unit → motive nil nil ⋯)
42+
(cons : (a : α) → {n : Nat} → (a_1 : Vec α n) → (a' : α) → (a'_1 : Vec α n) → motive (cons a a_1) (cons a' a'_1) ⋯) :
4343
motive t t✝ h
4444
-/
4545
#guard_msgs in

0 commit comments

Comments
 (0)