Commit graph

40010 commits

Author SHA1 Message Date
Sebastian Graf
f2d36227cf
chore: rename mvcgen_invariant_type attribute to spec_invariant_type, part 1 (#13153)
This PR registers the new `spec_invariant_type` attribute alongside the
old
`mvcgen_invariant_type`, renames internal identifiers, and replaces the
hardcoded `Invariant` check in `Spec.lean` with `isSpecInvariantType`.

A follow-up PR will switch all usages to `spec_invariant_type` and
remove
the old attribute after stage0 is updated.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 11:29:26 +00:00
Sebastian Ullrich
0b401cd17c
refactor: compile @[extern] via standard pipeline (#13102) 2026-03-27 10:31:22 +00:00
Sebastian Ullrich
fda4793215
test: copy ver_clash test data to temp dir before modifying (#13134)
Avoids git/(especially) jj thinking the files have vanished from the
root repo
2026-03-27 10:25:58 +00:00
Lean stage0 autoupdater
215aa4010b chore: update stage0 2026-03-27 11:03:27 +00:00
Joachim Breitner
142ca24192
feat: support #print axioms under the module system (#13117)
This PR re-enables `#print axioms` under the module system by computing
axiom dependencies at olean serialization time. It reverts #8174 and
replaces it with a proper fix.

Depends on #13142, which refactors `exportEntriesFnEx` to return all
three olean levels at once via a new `OLeanEntries` structure, allowing
extensions to share expensive computation.

The axiom extension uses `exportEntriesFnEx` to walk bodies of all
public declarations in the current module, collecting axiom dependencies
in a single batch with a shared cache across declarations. The results
are stored sorted for binary search and exported uniformly to all olean
levels. Downstream modules look up pre-computed axiom data from imported
oleans, so axiom collection never crosses module boundaries. During
elaboration of the current module, `collectAxioms` walks bodies directly
since they are always available locally.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 10:15:49 +00:00
Henrik Böving
c71a0ea9a5
perf: coalescing of RC ops within one basic block (#13136)
This PR introduces coalescing of RC operations to the RC optimizer.
Whenever we perform multiple `inc`s for a single value within one basic
block it is legal to instead perform all of these `inc`s at once at the
first `inc` side. This is the case because the value will stay alive
until at least the last `inc` and was thus never observable with `RC=1`.
Hence, this change of `inc` location never destroys reuse opportunities.
2026-03-27 10:13:04 +00:00
Joachim Breitner
439c3c5544
refactor: make exportEntriesFnEx return all olean levels at once (#13142)
This PR replaces the per-level `OLeanLevel → Array α` return type of
`exportEntriesFnEx` with a new `OLeanEntries (Array α)` structure that
bundles exported, server, and private entries together. This allows
extensions to share expensive computation across all three olean levels
instead of being called three separate times.

A new `computeExtEntries` function in `Environment.lean` calls each
extension's export function once and distributes results across levels.
`mkModuleData` accepts optional pre-computed entries, and `writeModule`
uses `computeExtEntries` to compute once for all three olean parts.

Extensions that previously relied on `env.setExporting` being
pre-applied by `mkModuleData` now call `env.setExporting true`
internally for their exported/server-level filtering, since the export
function is called once rather than per-level.

Extracted from #13117 to be reviewed independently.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 08:57:45 +00:00
Mac Malone
2bc7a77806
fix: lake: lake cache help put-staged (#13150)
This PR fixes a typo in #13144 where `lake cache help put-staged` was
incorrectly `lake cache help putStaged`.
2026-03-27 05:11:43 +00:00
Leonardo de Moura
e55f69acd0
refactor: simplify grind canonicalizer and fix preprocessing issues (#13149)
This PR simplifies the `grind` canonicalizer by removing dead state and
unnecessary
complexity, and fixes two bugs discovered during the cleanup.

## Changes

**Canonicalizer cleanup:**
- Remove dead `Canon.State.canon` field — values were inserted but never
read.
The canonicalizer uses a transient `HashMap` local to each `canonImpl`
invocation.
- Remove `proofCanon` — it deduplicated `Grind.nestedProof` terms by
mapping
canonicalized propositions to a single representative, but different
proofs may
reference different hypotheses, making the result context-dependent and
preventing
  cache sharing across goals.
- Remove `isDefEqBounded` — a fallback that retried `isDefEq` at default
transparency
with a heartbeat budget. The one test that depended on it was actually
masking a
  transparency bug in `propagateCtorHomo`.

**Bug fixes:**
- Use `withDefault` for `mkAppOptM` in `propagateCtorHomo` (`Ctor.lean`)
— the
injectivity proof construction needs default transparency to unify
implicit
  arguments of indexed inductive types like `Vector`.
- Add `Grind.abstractFn` gadget to protect lambda abstractions created
by
`abstractGroundMismatches?` from beta reduction during preprocessing.
Without
this, `Core.betaReduce` in `preprocessLight` collapses `(fun x => body)
arg`
back to `body[arg/x]`, undoing the abstraction that congruence closure
needs.

**Eta reduction infrastructure:**
- Lower `etaReduceAll` from `MetaM` to `CoreM` — it only performs
structural
  operations, no `MetaM` needed.
- Add `etaReduceWithCache` that takes and returns an explicit `HashMap`
cache,
  enabling callers to thread a single cache across multiple expressions.

The net effect on `Canon.State` is removing 3 fields (`canon`,
`proofCanon`)
and the `isDefEqBounded` function, along with the `useIsDefEqBounded`
and
`parent` parameters from `canonElemCore`.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 05:00:01 +00:00
Mac Malone
50785098d8
feat: lake: cache staging (#13144)
This PR adds three new `lake cache` subcommands for staged cache
uploads: `stage`, `unstage`, and `put-staged`. These are designed to
function as parallels for the commands of the same name in Mathlib's
`lake exe cache`.

- `lake cache stage`: Copies the build outputs of a mappings file from
the Lake cache to a staging directory.
- `lake cache unstage`: Copies the build outputs from a staging
directory back into the Lake cache.
- `lake cache put-staged`: Uploads build outputs from a staging
directory to a remote cache service. Unlike `lake cache put`, this
command does not load the workspace configuration. As a result, platform
and toolchain settings must be supplied manually via `--platform` and
`--toolchain` if needed.

This PR also removes deprecation warnings when using environment
variables to configure the cache service for `lake cache put` (and `lake
cache put-staged`).

🤖 Prepared with Claude Code

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 03:16:09 +00:00
Henrik Böving
fee2d7a6e8
fix: potential Array.get!Internal leaks part 2 (#13148)
Part 2 for #13147, adding the necessary constant semantics to the
interpreter.
2026-03-27 02:51:39 +00:00
Lean stage0 autoupdater
bc5210d52a chore: update stage0 2026-03-27 01:15:51 +00:00
Lean stage0 autoupdater
12c547122f chore: update stage0 2026-03-27 01:04:33 +00:00
Henrik Böving
f9c8b5e93d
fix: potential Array.get!Internal leaks part 1 (#13147)
This PR fixes theoretical leaks in the handling of `Array.get!Internal`
in the code generator.
Currently, the code generator assumes that the value returned by
`get!Internal` is derived from the
`Array` argument. However, this does not generally hold up as we might
also return the `Inhabited`
value in case of an out of bounds access (recall that we continue
execution after panics by
default). This means that we sometimes convert an `Array.get!Internal`
to
`Array.get!InternalBorrowed` when we are not allowed to do so because in
the panic case the
`Inhabited` instance can be returned and if it is an owned value it is
going to leak.

The fix consists of adapting several components to this change:
1. `PropagateBorrow` will only mark the derived value as forcibly
borrowed if both the `Inhabited`
   and `Array` argument are forcibly borrowed.
2. `InferBorrow` will do the same for its data flow analysis
3. The derived value analysis of `ExplicitRC` is extended from a derived
value tree to a derived
value graph where a value may have more than one parent. We only
consider a value borrowed if all
of its parents are still accessible. Then `get!Internal` is equipped
with both its `Inhabited`
   and its `Array` parent.

These changes are sufficient for correctness on their own. However, they
are going to break
`get!Internal` to `get!InternalBorrowed` conversion in most places. This
happens because almost all
`Inhabited` instances are going to be constants. Currently reads from
constants yield semantically
owned values and thus block the `get!InternalBorrowed` conversion. We
would thus prefer for these
constants to be treated as borrows instead.

The owned return is implemented in two ways at the moment:
1. In the C code emitter we do not need to do anything as constants are
marked persistent to begin
   with
2. In the interpreter whenever a constant is pulled from the constant
cache it is `inc`-ed and then
later `dec`-ed somewhere (potentially using a `dec[persistent]` which is
a no-op in C)

This PR changes the semantics of constant reads to instead be borrows
from the constant (they can be
cutely interpreted as "being borrowed from the world"). This enables
many `get!Internal` to have
both their arguments be marked as borrowed and thus still converted to
`get!InternalBorrowed`. Note
that this PR does not yet change the semantics of the interpreter to
account for this
(it will be done in a part 2) and thus introduces (very minor) leaks
temporarily.

Furthermore, we observed code with signatures such as the following:
```lean
@[specialize]
def foo {a : Type} [inst : Inhabited a] (xs : Array a) (f : a -> a -> Bool) ... :=
  ...
  let x := Array.get!Internal inst xs i
  ...
```
being instantiated with `a := UInt32`. This poses a challenge because
`Inhabited` is currently
marked as `nospecialize`, meaning that we are sometimes going to end up
with code such as:
```
def foo._spec (inst : UInt32) (xs : @&Array UInt32) ... :=
  ...
  let inst := box inst
  let x := Array.get!Internal inst xs i
  dec inst
  ...
```
Here `xs` itself was inferred as borrowed, however, the `UInt32`
`Inhabited` instance was not
specialized for (as `Inhabited` is marked `nospecialize`) and thus needs
to be boxed. This causes
the `inst` parameter to `get!Internal` to be owned and thus
`get!InternalBorrowed` conversion fails.
This PR marks `Inhabited` as `weak_specialize` which will make it get
specialized for in this case,
yielding code such as:

```
def foo._spec (xs : @&Array UInt32) ... :=
  ...
  let inst := instInhabitedUInt32
  let inst := box inst
  let x := Array.get!Internal inst xs i
  dec inst
  ...
```
Fortunately the closed term extractor has support for precisely this
feature and thus produces:

```
def inst.boxed_const :=
  let inst := instInhabitedUInt32
  let inst := box inst
  return inst

def foo._spec (xs : @&Array UInt32) ... :=
  ...
  let inst := inst.boxed_const
  let x := Array.get!Internal inst xs i
  ...
```
As described above reads from constants are now interpreted as borrows
and thus the conversion to
`get!InternalBorrowed` becomes legal again.
2026-03-27 00:13:17 +00:00
Mac Malone
f8f12fdbc8
fix: lake: run git clean -xf when updating packages (#13141)
This PR changes Lake's materialization process to run remove untracked
files in tracked directories (via `git clean -xf`) when updating
dependency repositories. This ensures stale leftovers in the source tree
are removed.

In particular, if a `.hash` ends up in the source tree and the package
is updated, that `.hash` file will be stale but nonetheless trusted by a
Lake build. This will cause incorrect trace computation and break
builds. This happened with ProofWidgets in Mathlib (see [this Zulip
discussion](https://leanprover.zulipchat.com/#narrow/channel/113488-general/topic/ProofWidgets.20not.20up-to-date)).

This PR serves as alternative to #13130 (by @kim-em) and instead
provides a more generic solution to the problem. Nonetheless, thank them
for diagnosing this issue in the first place!
2026-03-26 22:12:54 +00:00
Lean stage0 autoupdater
7f424b371e chore: update stage0 2026-03-26 22:47:08 +00:00
Henrik Böving
d56424b587
feat: weak_specialize annotations (#13138)
This PR introduces the `weak_specialize` attribute. Unlike the
`nospecialize` attribute it does not
block specialization for parameters marked with this type completely.
Instead, `weak_specialize`
parameters are only specialized for if another parameter provokes
specialization. If no such
parameter exists, they are treated like `nospecialize`.
2026-03-26 21:58:52 +00:00
Henrik Böving
144db355ea
fix: rebootstrap cache in github CI (#13143)
The old approach isn't smart enough to trick the lake cache anymore.
Making an explicit
update-stage0 commit will make it work again.
2026-03-26 20:50:03 +00:00
Lean stage0 autoupdater
0975b7136a chore: update stage0 2026-03-26 16:38:25 +00:00
Wojciech Różowski
ccef9588ae
feat: add further cbv annotations (#13135)
This PR adds several `cbv_opaque` and `cbv_eval` annotations to the
standard library.
2026-03-26 14:55:40 +00:00
Garmelon
a8bbc95d9f
chore: remove lean4checker from release repos (#13121)
Lean4checker has been merged into this repository and is no longer a
standalone repo.
2026-03-26 12:15:37 +00:00
Sebastian Graf
a54eafb84f
refactor: decouple solve from grind in sym-based mvcgen (#13133)
This PR refactors the sym-based VCGen (`tests/bench/mvcgen/sym`) to
separate concerns between
goal decomposition and VC discharge, following the architecture of
loom2's `mvcgen'`.

- `solve` now operates on plain `MVarId` with no knowledge of grind,
returning `List MVarId`
  in `SolveResult.goals`.
- `work` handles grind E-graph internalization: after `solve` returns
multiple subgoals, it
calls `processHypotheses` on the parent goal to share context before
forking.
- `emitVC` dispatches on a new `PreTac` enum (`.none`, `.grind`,
`.tactic`) to try solving
each VC, replacing the previous inline grind logic and post-hoc tactic
loop in the elaborator.
- The redundant `WorkItem` wrapper (which duplicated `Grind.Goal`'s
`mvarId`) is removed; the
  worklist operates directly on `Grind.Goal`.
- `GrindContext` is replaced by `PreTac` + `hypSimpMethods` fields in
`VCGen.Context`, cleanly
  separating hypothesis simplification from the discharge strategy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 11:19:08 +00:00
Markus Himmel
6f2745d88b
feat: verification of backwards string patterns (#13129)
This PR implements verification infrastructure for backwards patterns
that is analogous to the existing infrastructure for forward patterns.
Based on this it adds verification for the `skipSuffix?`, `endsWith` and
`dropSuffix?` functions on strings.

To enable this, we add some supporting theory about `String.slice`
(that's a lowercase `s`) and `String.Pos.prev`.
2026-03-26 08:44:47 +00:00
Eric Wieser
25c71d91aa
feat: add rfl lemmas about ExceptCpsT.runK (#12912)
This PR adds trivial lemmas about `ExceptCpsT.runK` to match the
existing lemmas about `.run`.
2026-03-26 08:13:20 +00:00
Leonardo de Moura
db491ddd35
refactor: move issue tracker from grind to SymM (#13125)
This PR moves the issue tracking infrastructure from `GrindM` to `SymM`.
Issues can occur in different places within a `sym =>` block (e.g.,
during
arithmetic normalization, simplification), not just during `grind`
invocations. Moving them to `SymM` makes them available to all modules
operating within the symbolic computation framework.

- `Sym.reportIssue`: adds an issue to the `SymM` state
- `Sym.getIssues`: retrieves accumulated issues
- `Sym.withNewIssueContext`: saves/restores the issue list around a
  computation, used at grind entry points to isolate per-invocation
  issues while preserving them in the outer context
- `GrindM.State.issues` removed; `Grind.reportIssue` delegates to
`Sym.reportIssue`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 02:27:27 +00:00
Wojciech Różowski
e8c3485e08
fix: cbv getting stuck after a rewrite of cbv_opaque function (#13122)
This PR fixes `cbv` tactic getting stuck after rewriting functions
marked with `cbv_opaque` that have a `cbv_eval` lemma registered.
2026-03-25 18:13:13 +00:00
Sebastian Graf
dee571e13b
chore: revert mvcgen witnesses syntax (#12882) (#13120)
This PR reverts the `mvcgen witnesses` syntax addition and undoes the
back compat hack in `elabMVCGen`.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 17:56:04 +00:00
Sebastian Graf
51f67be2bd
chore: remove unnecessary level normalization from Sym-based mvcgen (#13119)
This PR removes level normalization from Sym-based mvcgen that is
unnecessary after #12923.
2026-03-25 16:06:57 +00:00
Sebastian Ullrich
c77f2124fb
fix: include modPkgExt in .ir file exports (#13118)
This PR fixes an incompatibility of `--load-dynlib` with the module
system.

When a transitive non-public import's data came from the `.ir` file
instead of `.olean`, `getModulePackageByIdx?` returned `none`, producing
wrong symbol names (e.g., `initialize_Batteries_Data_UInt` instead of
`initialize_batteries_Batteries_Data_UInt`), leading to `dlsym` failures
and double-registration errors.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:49:42 +00:00
Lean stage0 autoupdater
d634f80149 chore: update stage0 2026-03-25 15:45:01 +00:00
Sebastian Graf
40cdec76c5
chore: revert @[mvcgen_witness_type] attribute (#12882) (#13111)
This PR reverts #12882 which added the `@[mvcgen_witness_type]` tag
attribute and `witnesses` section to `mvcgen`. Théophile Wallez
confirmed he doesn't need this feature and can get by with `invariants`,
so there is no use in having it.

The actual `mvcgen` syntax needs to be adjusted after a stage0 update in
order for `elabMVCGen` to cope with both old and new syntax.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 14:38:59 +00:00
Lean stage0 autoupdater
4227765e2b chore: update stage0 2026-03-25 14:58:54 +00:00
Henrik Böving
438d1f1fe1
perf: reading from persistent values should count as borrowing (#13116)
This PR ensures that reads from constants count as borrows in the eyes
of the borrow inference analysis. This reduces RC pressure in the
presence of constant reads.
2026-03-25 12:22:00 +00:00
Kim Morrison
4786e082dc
doc: update inferInstanceAs docstring and rename normalizeInstance to wrapInstance (#13115)
This PR updates the `inferInstanceAs` docstring to reflect current
behavior: it requires an
expected type from context and should not be used as a simple
`inferInstance` synonym. The
old example (`#check inferInstanceAs (Inhabited Nat)`) no longer works,
so it's replaced
with one demonstrating the intended transport use case.

Additionally, renames `InstanceNormalForm.lean` to `WrapInstance.lean`,
`normalizeInstance`
to `wrapInstance`, and the trace class `Meta.instanceNormalForm` to
`Meta.wrapInstance`,
removing the "instance normal form" terminology from both documentation
and code.

Context:
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/inferInstanceAs.20is.20broken/near/581449313

🤖 Prepared with Claude Code

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 02:20:49 +00:00
Kim Morrison
bd5fb4e90c
fix: handle duplicate nightly tag in scheduled CI runs (#13114)
This PR fixes the scheduled nightly CI run failing with `fatal: tag
'nightly-YYYY-MM-DD' already exists` when a manual `workflow_dispatch`
has already created today's nightly tag.

The scheduled path now uses the same `-revK` revision logic that the
manual re-release path already has: if `nightly-2026-03-24` exists, it
creates `nightly-2026-03-24-rev1` (and so on). The existing guard
against creating nightlies when HEAD has a non-nightly tag (e.g. a
release tag) is preserved.

🤖 Prepared with Claude Code

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:10:54 +00:00
Sebastian Graf
e60078db3b
test: harden sym mvcgen bench script and tune benchmark sizes (#13107)
This PR fixes the sym mvcgen benchmark script and tunes input sizes.

**run_bench.sh**: Replace `| tee` with the `capture` helper from
`util.sh`.
Without `pipefail`, piping through `tee` masks non-zero exit codes from
`lake build`, so build failures (OOM, stack overflow) go unnoticed.

**Benchmark sizes**: Scale down inputs for benchmarks that exceeded the
2s
budget so each benchmark completes in 1-2s across its 3 linearly
increasing
inputs.

**Metric collision**: Copy `GetThrowSet.Goal` into a `GetThrowSetGrind`
namespace so the grind variant reports as `GetThrowSetGrind(n)` instead
of
colliding with `GetThrowSet(n)` in `measurements.jsonl`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 21:14:36 +00:00
Mac Malone
f7102363de
fix: lake: race condition in Cache.saveArtifact (#13110)
This PR fixes a race condition in `Cache.saveArtifact` that caused
intermittent "permission denied" errors when two library facets (e.g.,
`static` and `static.export`) produce artifacts with the same content
hash and attempt to cache them concurrently.

The race occurs because `saveArtifact` checks `cacheFile.pathExists`,
then writes the file and makes it read-only. When two tasks race past
the existence check, the second task's write fails because the first
task already created the file and set it to read-only. On Linux, this is
common for `static` vs `static.export` since both resolve to the same
`coExport` object files, producing byte-identical archives.

The fix introduces `writeFileIfNew` and `writeBinFileIfNew` helpers that
use `O_CREAT | O_EXCL` (via `IO.FS.Mode.writeNew`) to atomically
create-or-skip, eliminating the race window. For the binary path, hard
link `alreadyExists` errors are also handled explicitly to avoid an
unnecessary copy fallback.

Additionally, `IO.setAccessRights` for the cache file is moved outside
the `unless pathExists` block so that permissions are always enforced,
and the `getMTime` call no longer silently swallows errors.

🤖 Prepared with Claude Code
2026-03-24 19:05:56 +00:00
Markus Himmel
ce073771b1
feat: String.drop lemmas (#13109)
This PR adds lemmas about the `String` operations `drop`, `dropEnd`,
`take`, `takeEnd`.
2026-03-24 17:51:06 +00:00
Markus Himmel
dec394d3a4
feat: lemmas about String.Pos.nextn (#13106)
This PR verifies `String.Pos.nextn` by providing the low-level API
`nextn_zero`/`nextn_add_one` as well as a `Splits` lemma.

The `Splits` lemma trivially implies, for a string `s`, the statement
`(s.drop n).copy.toList = s.toList.drop n`, to be included in a later
PR.
2026-03-24 16:12:57 +00:00
Markus Himmel
6457e3686f
feat: lemmas for String.front? (#13105)
This PR proves `theorem front?_eq {s : String} : s.front? =
s.toList.head?` and related results.
2026-03-24 14:38:27 +00:00
Lean stage0 autoupdater
c14fa66068 chore: update stage0 2026-03-24 14:42:18 +00:00
Henrik Böving
d0aa7d2faa
perf: mark inhabited arguments to extern as borrowed (#13094)
This PR marks the `Inhabited` arguments of all functions in core marked
as `extern` as borrowed
(panicking array accessors and `panic!` itself). This in turn causes a
transitive effect throughout
the codebase and promotes most, if not all, `Inhabited` arguments to
functions to borrowed.
2026-03-24 13:54:06 +00:00
JadAbouHawili
4117ceaf84
doc: typo fix for strict implicit binder (#13099)
This PR fixes a typo of implicit binders in doc-strings which was `{{
}}` instead of `⦃ ⦄`
2026-03-24 13:15:23 +00:00
Sebastian Graf
a824e5b85e
test: add iota reduction via reduceRecMatcher? to sym-based mvcgen' (#13100)
This PR adds iota reduction to the sym-based `mvcgen'` tactic by calling
`reduceRecMatcher?` before falling back to the match split backward
rule.
When a matcher/recursor has a concrete discriminant, it is reduced
directly
instead of constructing and applying a splitting backward rule, which is
significantly faster for benchmarks like `MatchIota` (previously
`MatchSplit`)
where `loop n` unrolls into `n` nested matches with known `Nat`
discriminants.

The old `MatchSplit` test case (concrete discriminants) is renamed to
`MatchIota`
and a new `MatchSplit` test case with symbolic discriminants (matching
on state)
is added to keep exercising the split backward rule code path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 12:52:01 +00:00
Sebastian Graf
83c6f6e5ac
test: add mvcgen' with <tac> and mvcgen' with grind to sym-based VCGen (#12893)
This PR extends the sym-based `mvcgen'` tactic with two new modes:

1. `mvcgen' with <tac>`: run VCGen, then apply `<tac>` to each remaining
VC.
2. `mvcgen' with grind`: integrate grind into the VCGen loop for
incremental context internalization. Each VC inherits the parent's
E-graph state, so hypothesis processing is shared across sibling VCs,
avoiding O(n) re-internalization per VC.

The grind mode accepts the full grind configuration syntax (`mvcgen'
with grind (config := { ... }) [params]`).

A persistent `Sym.Simp` cache with a `reassocNatAdd` simproc normalizes
hypothesis types (e.g., `s + 1 + 1 + 1` → `s + 3`) before grind
internalization, achieving O(1) amortized simplification per VC.

Benchmark results for GetThrowSet (`mvcgen' with grind`):
- n=100: 400ms total, 180ms kernel
- n=250: 855ms total, 1.8s kernel
- n=500: 1.9s total, 11.8s kernel

Kernel checking time grows superlinearly and is the dominant cost at
larger sizes. This is a separate issue from VCGen performance.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 11:27:13 +00:00
Markus Himmel
9ffd748104
chore: generalize theorems about Nat.ofDigitChars (#13098)
This PR generalizes some theorems about `Nat.ofDigitChars` which were
needlessly restricted to base 10.
2026-03-24 11:01:20 +00:00
Henrik Böving
fd8d89853b
feat: print more information for LCNF RC ops (#13097)
This PR makes the compiler traces contain more information about the
kind of `inc`/`dec` that are
being conducted (`persistent`, `checked` etc.)
2026-03-24 10:54:08 +00:00
Markus Himmel
0260c91d03
feat: lemmas comparing List.Cursor.pos to List.length (#13096)
This PR show the trivial result that given `c : l.Cursor`, we have that
`c.pos ≤ l.length`.
2026-03-24 10:40:03 +00:00
Henrik Böving
7ef25b8fe3
chore: remove dead code (#13093) 2026-03-24 09:07:47 +00:00
Lean stage0 autoupdater
50544489a9 chore: update stage0 2026-03-24 08:45:44 +00:00