This PR extends Lake's use of response files (`@file`) from Windows-only
to all platforms, avoiding `ARG_MAX` limits when invoking `clang`/`ar`
with many object files.
Lake already uses response files on Windows to avoid exceeding CLI
length limits. On macOS and Linux, linking Mathlib's ~15,000 object
files into a shared library can exceed macOS's `ARG_MAX` (262,144
bytes). Both `clang` and `gcc` support `@file` response files on all
platforms, so this is safe to enable unconditionally.
Reported as a macOS issue at
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/The.20clang.20command.20line.20with.20all.20~15.2C000.20Mathlib.20.2Ec.2Eo.2Eexport/near/574369912:
the Mathlib cache ships Linux `.so` shared libs but not macOS `.dylib`
files, so `precompileModules` on macOS triggers a full re-link that
exceeds `ARG_MAX`.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds the `fixedToolchain` Lake package configuration option.
Setting this to `true` informs Lake that the package is only expected to
function on a single toolchain (like Mathlib). This causes Lake's
toolchain update procedure to prioritize its toolchain and avoids the
need to separate input-to-output mappings for the package by toolchain
version in the Lake cache.
The tests need to run with certain environment variables set that only
cmake really knows and that differ between stages. Cmake could just set
the variables directly when running the tests and benchmarks, but that
would leave no good way to manually run a single benchmark. So cmake
generates some stage-specific scripts instead that set the required
environment variables.
Previously, those scripts were sourced directly by the individual
`run_*` scripts, so the env scripts of different stages would overwrite
each other. This PR changes the setup so they can instead be generated
next to each other. This also simplifies the `run_*` scripts themselves
a bit, and makes `tests/bench/build` less of a hack.
This PR fixes the `HSub PlainTime Duration` instance, which had its
operands reversed: it computed `duration - time` instead of `time -
duration`. For example, subtracting 2 minutes from `time("13:02:01")`
would give `time("10:57:59")` rather than the expected
`time("13:00:01")`. We also noticed that `HSub PlainDateTime
Millisecond.Offset` is similarly affected.
Closes#12918
This PR places `set_option compiler.ignoreBorrowAnnotation true in` on
to all `export`/`extern`
pairs. This is necessary because `export` forces all arguments to be
passed as owned while `extern`
respects borrow annotations. The current approach to the
`export`/`extern` trick was always broken
but never surfaced. However, with upcoming changes many
`export`/`extern` pairs are going to be
affected by borrow annotations and would've broken without this.
This PR replaces `find -print0 | xargs -0 -I{} sh -c '...'` with
`find -print0 | while IFS= read -r -d '' f; do ... done` for the
subverso sub-manifest sync in release_steps.py. The original xargs
invocation had fragile nested shell quoting; the while-read loop is
both null-delimiter safe and more readable.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR changes `lake cache get` to download artifacts by default.
Artifacts can be downloaded on demand with the new `--mappings-only`
option (`--download-arts` is now obsolete).
In the future, the plan is to have Lake download mappings when cloning
dependencies. Then, `lake cache get` will primarily be used to download
artifacts eagerly. Thus, it makes sense to have that as the default.
This PR removes unused functions (`mkPatternCoreFromLambda`,
`mkPatternFromLambda`, `mkSimprocPatternFromExpr`) and the `import
Lean.Meta.AbstractMVars` that were added to `Lean.Meta.Sym.Pattern`
after merging #12597.
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>
This PR adds eta reduction to the sym discrimination tree lookup
functions (`getMatch`, `getMatchWithExtra`, `getMatchLoop`). Without
this, expressions like `StateM Nat` that unfold to eta-expanded forms
`(fun α => StateT Nat Id α)` fail to match discrimination tree entries
for the eta-reduced form `(StateT Nat Id)`.
Also optimizes `etaReduce` with an early exit for non-lambda expressions
and removes a redundant `n == 0` check.
Includes a test verifying that `P (StateM Nat)` matches a disc tree
entry for `P (StateT Nat Id)`.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR optimizes the `String.reduceEq`, `String.reduceNe`, and
`Sym.Simp` string equality simprocs to produce kernel-efficient proofs.
Previously, these used `String.decEq` which forced the kernel to run
UTF-8 encoding/decoding and byte array comparison, causing 86+ kernel
unfoldings on short strings.
The new approach reduces string inequality to `List Char` via
`String.ofList_injective`, then uses two strategies depending on the
difference:
- **Different characters at position `i`**: Projects to `Nat` via
`congrArg (fun l => (List.get!Internal l i).toNat)`, then uses
`Nat.ne_of_beq_eq_false rfl`. This avoids `Decidable` instances entirely
— the kernel only evaluates `Nat.beq` on two concrete natural numbers.
- **One string is a prefix of the other**: Uses `congrArg (List.drop n
·)` with `List.cons_ne_nil`, which is a definitional proof requiring no
`decide` step at all.
For equal strings, `eq_true rfl` avoids kernel evaluation entirely.
The shared proof construction is in `Lean.Meta.mkStringLitNeProof`
(`Lean/Meta/StringLitProof.lean`), used by both the standard simprocs
and the `Sym.Simp` ground evaluator.
Kernel max unfolds for `"hello" ≠ "foo"`: 86+ → 6.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adjusts the JSON encoding of RPC references from `{"p": "n"}` to
`{"__rpcref": "n"}`. Existing clients will continue to work unchanged,
but should eventually move to the new format by advertising the
`rpcWireFormat` client capability.
- This came up in leanprover/vscode-lean4#712.
- The new encoding is far less likely to clash with real-world names,
and is now documented as a "reserved internal name".
- At 8 bytes vs. 1 byte, it incurs a ~5% size increase on the JSON size
of interactive terms, e.g. from 868KiB to 903KiB on the
leanprover/vscode-lean4#500 test.
- Make `deriving RpcEncodable` throw an error when it encounters the
reserved name. We cannot easily guard against clashes in user-provided
JSON, however, so we just assume it does not clash.
- Add a notion of *RPC wire format* with corresponding `rpcWireFormat`
client and server capabilities. The format before this PR is now called
`v0`, whereas here we implement `v1`. Existing clients should eventually
implement compatibility with `v1` (because doing so fixes the above
bug), but will continue to work in the meantime. The format may be
revised again in the future (but we don't expect to revise it so often
that semver would be useful).
- Document everything.
## Alternative designs (abandoned for now)
- Option 1. Add a method `$/lean/rpc/metadata` which, given the name of
an RPC method `foo`, returns metadata containing a description of where
the RPC refs in any return value of `foo` would be (essentially a
description of the structure of the return type).
- Option 2. Wrap every response to `$/lean/rpc/call` in such metadata.
This would be a different change to the wire format.
- To implement this in an extensible way, we extend `RpcEncodable` by a
`refPaths` field. But how does `refPaths` describe where the refs are?
- Option A. Emit the code of a JS method that extracts the refs. This is
maybe simplest, but it would leave non-JS clients (e.g. `lean.nvim`)
behind.
- Option B. Give the description in some query language. The query
language must be able to describe paths into arbitrary inductive types.
- The most popular option,
[JSONPath](https://www.rfc-editor.org/rfc/rfc9535), seemingly cannot
describe non-uniform paths (e.g. both the `a`s in `{a: 1, {b: {a:
2}}}`).
- [JMESPath](https://jmespath.org/) can describe non-uniform paths, and
has 'fully compliant' implementations in many languages, but doesn't
seem to handle recursive paths.
- The most expressive option is [jq](https://github.com/jqlang/jq), but
the most popular way to run it is via an Emscripten WASM blob in
[jq-web](https://github.com/fiatjaf/jq-web) which seems heavy. There is
[jqjs](https://github.com/mwh/jqjs) as well; I'm not sure how
production-ready that is.
This PR makes `@[cbv_opaque]` unconditionally block all evaluation of a
constant
by `cbv`, including `@[cbv_eval]` rewrite rules. Previously,
`@[cbv_eval]` could
bypass `@[cbv_opaque]`, and for bare constants (not applications),
`isOpaqueConst`
could fall through to `handleConst` which would unfold the definition
body.
The intended usage pattern is now: mark subterm-producing functions
(like
`DHashMap.insert`) as `@[cbv_opaque]` to prevent unfolding, and provide
`@[cbv_eval]` theorems on the *consuming* function (like
`DHashMap.contains`)
which pattern-matches against the opaque subterms.
This PR generalizes the sym MVCGen's match splitting from `ite`-only to
`ite`, `dite`, and arbitrary matchers. Previously, only `ite` was
supported; `dite` and match expressions were rejected with an error.
`mkBackwardRuleForSplit` uses `SplitInfo.splitWith` to build the
splitting proof. Hypothesis types are discovered via `rwIfOrMatcher`
inside the splitter telescope, and `TransformAltFVars.all` provides the
proper fvars for `mkForallFVars`. Subgoal type metavariables use
`mkFreshExprSyntheticOpaqueMVar` so that `rwIfOrMatcher`'s internal
`assumption` tactic cannot assign them.
Adds `DiteSplit`, `MatchSplit`, and `MatchSplitState` test cases and a
`vcgen_match_split` benchmark.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR introduces a `TransformAltFVars` structure to replace the flat
`Array Expr`
parameter in the `onAlt` callback of `MatcherApp.transform`. The new
structure gives
callers structured access to the different kinds of fvars introduced in
matcher
alternative telescopes: constructor fields, overlap parameters,
discriminant equations,
and extra equations from `addEqualities`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds support for ignoring user defined borrow annotations. This
can be useful when defining
`extern`/`export` pairs as the `extern` might be infected by borrow
annotations while in `export`
they are already ignored.
This PR adds a benchmark that measures `simp` performance on string
literal equality and inequality for various string lengths and
difference positions.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR ports the C emission pass from IR to LCNF, marking the last step
of the IR/LCNF conversion and thus enabling end-to-end code generation
through the new compilation infrastructure.
This PR adds an `@[mvcgen_witness_type]` tag attribute, analogous to
`@[mvcgen_invariant_type]`, that allows users to mark types as witness
types. Goals whose type is an application of a tagged type are
classified as witnesses rather than verification conditions, and appear
in a new `witnesses` section in the `mvcgen` tactic syntax (before
`invariants`).
Witnesses are concrete values the prover supplies (inspired by
zero-knowledge proofs), as opposed to invariants (predicates maintained
across iterations) or verification conditions (propositions to prove).
The test uses a ZK-inspired example where a `SquareRootWitness` value
must be provided by the prover, with the resulting constraint
auto-discharged.
Changes:
- `src/Lean/Elab/Tactic/Do/Attr.lean`: register `@[mvcgen_witness_type]`
tag attribute and `isMVCGenWitnessType` helper
- `src/Lean/Elab/Tactic/Do/VCGen/Basic.lean`: add `witnesses` field to
`State`, three-way classification in `addSubGoalAsVC`
- `src/Std/Tactic/Do/Syntax.lean`: add `witnesses` section syntax
(before `invariants`), extract shared `goalDotAlt`/`goalCaseAlt` syntax
kinds
- `src/Lean/Elab/Tactic/Do/VCGen.lean`: extract shared
`elabGoalSection`, add `elabWitnesses`, wire up witness labeling and
elaboration
- `tests/elab/mvcgenWitnessType.lean`: end-to-end tests for
witness-only, witness with `-leave`, and combined witness+invariant
scenarios
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds `Invariant.withEarlyReturnNewDo`,
`StringInvariant.withEarlyReturnNewDo`, and
`StringSliceInvariant.withEarlyReturnNewDo` which use `Prod` instead of
`MProd` for the state tuple, matching the new do elaborator's output.
The existing `withEarlyReturn` definitions are reverted to `MProd` for
backwards compatibility with the legacy do elaborator. Tests and
invariant suggestions are updated to use the `NewDo` variants.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR applies `@[mvcgen_invariant_type]` to `Std.Do.Invariant` and
removes the hard-coded fallback in `isMVCGenInvariantType` that was
needed for bootstrapping (cf. #12874). It also extracts
`StringInvariant` and `StringSliceInvariant` as named abbreviations
tagged with `@[mvcgen_invariant_type]`, so that `mvcgen` classifies
string and string slice loop invariants correctly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds an `@[mvcgen_invariant_type]` tag attribute so that users
can mark
custom types as invariant types for the `mvcgen` tactic. Goals whose
type is an
application of a tagged type are classified as invariants rather than
verification
conditions. The hard-coded check for `Std.Do.Invariant` is kept as a
fallback
until a stage0 update allows applying the attribute directly.
A follow-up PR (after a stage0 update) will apply
`@[mvcgen_invariant_type]` to
`Std.Do.Invariant` and remove the hard-coded fallback.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a CMake error when the `lake-ci` label is used. The
previous
implementation appended the full `tests/lake/tests/` glob to a base list
that
already included `tests/lake/tests/shake/test.sh`, causing a duplicate
`add_test` name. This uses an if/else to select the appropriate glob
instead.
Discovered via https://github.com/leanprover/lean4/pull/12540 which has
the
`lake-ci` label.
🤖 Prepared with Claude Code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR makes sure that identifiers with `Meta` or `Simproc` in their
name do not show up in library search results.
For example, `Nat.Simproc.eq_add_gt` can currently be suggested by
library search, even though it is an implementation detail.
Additionally, there are various declarations in mathlib in the
`Mathlib.Meta` namespace that we do not want to suggest.
This PR adds support for simp/equational spec theorems in the SymM-based
`mvcgen'` tactic,
catching up with a feature that the original `mvcgen` has supported for
a long time.
Users can write `@[spec] theorem : get (m := StateT σ m) = fun s => pure
(s, s) := rfl`
instead of manually specifying equivalent Hoare triples. The equational
form is more
concise and natural for specs that simply unfold definitions.
The universe level normalization (`normalizeLevelsExpr`) applied in
`work` and the backward
rule constructors is a workaround; ideally this should be integrated
into
`preprocessMVar`/`preprocessExpr` in the SymM framework so all users
benefit.
Changes:
- Add `SpecTheoremKind` to distinguish triple vs simp specs in
`SpecTheoremNew`
- Add `mkSpecTheoremNewFromSimpDecl?` to create spec entries from
equational lemmas, filtering no-op equations
- Add `mkBackwardRuleFromSimpSpec` to build backward rules via
`Eq.mpr`/`congrArg`, with instance synthesis, projection reduction, and
`unfoldReducible` on the RHS
- Migrate simp theorems from `SimpTheorems` database during
`migrateSpecTheoremsDatabase`
- Normalize universe levels so structural matching in
`BackwardRule.apply` succeeds when `max u v` vs `max v u` arise from
different code paths
- Simplify `mkSpecContext` by removing the mock `simp` context
construction
- Use `mkBackwardRuleFromExpr` instead of `mkAuxLemma` for triple specs,
since the proof may contain free variables from the goal context
- Add `AddSubCancelSimp` benchmark case and test exercising the simp
spec code path
- Change `AddSubCancel` spec proofs from `mvcgen` to `mvcgen'`
(dogfooding)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR extracts the example programs from the sym mvcgen benchmarks
into
shared `Cases.*` modules so that both benchmarks and a new fast test
suite
can reuse them. It also renames `vcgen_deep_add_sub_cancel` to
`vcgen_add_sub_cancel_deep` for consistency.
The test suite (`test_vcgen.lean`) runs all cases at n=10, completing in
~2s vs minutes for the full benchmarks. It is wired up as a `lake test`
driver and integrated with the lean4 test/bench infrastructure via
`run_test`/`run_bench` scripts registered in `CMakeLists.txt`.
Benchmark output now uses aligned `CaseName(n):` labels. The `run_bench`
script extracts per-case vcgen and kernel timings into
`measurements.jsonl`.
Benchmarks run single-threaded (`LEAN_NUM_THREADS=1`) for
reproducibility.
`vcgen_get_throw_set` is excluded from benchmarks due to pathological
`instantiateMVars` behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds `optType` support to the `doPatDecl` parser, allowing
`let ⟨width, height⟩ : Nat × Nat ← action` in do-notation. Previously,
only
the less ergonomic `let ⟨width, height⟩ : Nat × Nat := ← action`
workaround
was available. The type annotation is propagated to the monadic action
as an
expected type, matching `doIdDecl`'s existing behavior.
Both the legacy and new (BuiltinDo) elaborators are updated.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a `cbv_simproc` system for the `cbv` tactic, mirroring
simp's `simproc` infrastructure but tailored to cbv's three-phase
pipeline (`↓` pre, `cbv_eval` eval, `↑` post). User-defined
simplification procedures are indexed by discrimination tree patterns
and dispatched during cbv normalization.
New syntax:
- `cbv_simproc [↓|↑|cbv_eval] name (pattern) := body` — define and
register a cbv simproc
- `cbv_simproc_decl name (pattern) := body` — define without registering
- `attribute [cbv_simproc [↓|↑|cbv_eval]] name` — register an existing
declaration
- `builtin_cbv_simproc` variants for the internal use
New files:
- `src/Init/CbvSimproc.lean` — syntax and macros
- `src/Lean/Meta/Tactic/Cbv/CbvSimproc.lean` — types, env extensions,
registration, dispatch
- `src/Lean/Elab/Tactic/CbvSimproc.lean` — pattern elaboration and
command elaborators
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR add support for erasing `@[cbv_eval]` annotations using
`attribute [-cbv_eval]`, mirroring the existing `@[-simp]` mechanism for
simp lemmas.
The `CbvEvalEntry` now tracks the original declaration name (`origin`)
so that inverted theorems (`@[cbv_eval ←]`) can be erased by their
original name. The `CbvEvalState` stores individual entries alongside
the composed `Theorems` discrimination tree, allowing the tree to be
rebuilt from remaining entries after erasure. Erasure is properly scoped
via `modifyState`, so `attribute [-cbv_eval]` inside a `section` is
reverted when the section ends.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
This PR adds a `lake-ci` label that enables the full Lake test suite in
CI,
avoiding the need to temporarily commit and revert changes to
`tests/CMakeLists.txt`. The `lake-ci` label implies `release-ci` (check
level
3), so all release platforms are also tested.
Motivated by
https://github.com/leanprover/lean4/pull/12540#issuecomment-4000081071
where @tydeu requested running `release-ci` with Lake tests enabled,
which
previously required temporarily uncommenting a line in
`tests/CMakeLists.txt`.
Users can add it via a PR comment containing `lake-ci` on its own line,
or by
adding the label manually. CI automatically restarts when the label is
added.
Implementation:
- `ci.yml`: detect `lake-ci` label, set check level 3, pass
`-DLAKE_CI=ON` to cmake
- `tests/CMakeLists.txt`: `option(LAKE_CI ...)` conditionally enables
full `tests/lake/tests/` glob
- `restart-on-label.yml`: restart CI on `lake-ci` label
- `labels-from-comments.yml`: support `lake-ci` comment
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a `set_option grind.unusedLemmaThreshold` that, when set to
N > 0
and `grind` succeeds, reports E-matching lemmas that were activated at
least N
times but do not appear in the final proof term. This helps identify
`@[grind]`
annotations that fire frequently without contributing to proofs.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a `result? : Option TraceResult` field to `TraceData` and
populates it in `withTraceNode` and `withTraceNodeBefore`, so that
metaprograms walking trace trees can determine success/failure
structurally instead of string-matching on emoji.
`TraceResult` has three cases: `.success` (checkEmoji), `.failure`
(crossEmoji), and `.error` (bombEmoji, exception thrown). An
`ExceptToTraceResult` typeclass converts `Except` results to
`TraceResult` directly, with instances for `Bool` and `Option`.
`TraceResult.toEmoji` converts back to emoji for display. This replaces
the previous `ExceptToEmoji` typeclass — `TraceResult` is now the
primary representation rather than being derived from emoji strings.
`withTraceNodeBefore` (used by `isDefEq`) uses
`ExceptToTraceResult.toTraceResult` directly, correctly handling `Bool`
(`.ok false` = failure) and `Option` (`.ok none` = failure), with
`Except.error` mapping to `.error`.
For `withTraceNode`, `result?` defaults to `none`. Callers can pass
`mkResult?` to provide structured results; when set, the corresponding
emoji is auto-prepended to the message.
Motivated by mathlib's `#defeq_abuse` diagnostic tactic
(https://github.com/leanprover-community/mathlib4/pull/35750) which
currently string-matches on emoji to determine trace node outcomes. See
https://leanprover.zulipchat.com/#narrow/channel/113488-general/topic/backward.2EisDefEq.2ErespectTransparency🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR makes notations such as `∨`, `∧`, `≤`, and `≥` pretty print
using ASCII versions when `pp.unicode` is false.
Continuation of #10373. Closes#1056.
This will require followup with a stage0 update and removal of the
ASCII-only `<=` and `>=` syntaxes from `Init.Notation`, for cleanup.
This PR optimizes the handling of `match_same_ctor.het` to make it emit
nice match trees as opposed to unoptimized CPS style code.
`match_same_ctor.het` is essentially a specialized kind of matcher where
we know that two objects are built from the same constructor and we wish
to call a continuation on their data. This means for every constructor
that contains data `het` takes one closure as an argument. Then after
matching on one of the objects every closure but the one relevant for
the match is released in every match arm, causing quadratic code
generation. This PR ensures that the `het` declarations get inlined and
then further processed by ordinary matcher and casesOn compilation,
thereby removing all of the continuations from the compiled code.
This PR replaces the default `instantiateMVars` implementation with a
two-pass variant that fuses fvar substitution into the traversal,
avoiding separate `replace_fvars` calls for delayed-assigned MVars and
preserving sharing. The old single-pass implementation is removed
entirely.
The previous implementation had quadratic complexity when instantiating
expressions with long chains of nested delayed-assigned MVars. Such
chains arise naturally from repeated `intro`/`apply` tactic sequences,
where each step creates a new delayed assignment wrapping the previous
one. The new two-pass approach resolves the entire chain in a single
traversal with a fused fvar substitution, reducing this to linear
complexity.
### Terminology (used in this PR and in the source)
* **Direct MVar**: an MVar that is not delayed-assigned.
* **Pending MVar**: the direct MVar stored in a
`DelayedMetavarAssignment`.
* **Assigned MVar**: a direct MVar with an assignment, or a
delayed-assigned MVar with an assigned pending MVar.
* **MVar DAG**: the directed acyclic graph of MVars reachable from the
expression.
* **Resolvable MVar**: an MVar where all MVars reachable from it
(including itself) are assigned.
* **Updateable MVar**: an assigned direct MVar, or a delayed-assigned
MVar that is resolvable but not reachable from any other resolvable
delayed-assigned MVar.
In the MVar DAG, the updateable delayed-assigned MVars form a cut (the
**updateable-MVar cut**) with only assigned MVars behind it and no
resolvable delayed-assigned MVars before it.
### Two-pass architecture
**Pass 1** (`instantiate_direct_fn`): Traverses all MVars and
expressions reachable from the initial expression and instantiates all
updateable direct MVars (updating their assignment with the result),
instantiates all level MVars, and determines if there are any updateable
delayed-assigned MVars.
**Pass 2** (`instantiate_delayed_fn`): Only run if pass 1 found
updateable delayed-assigned MVars. Has an **outer** and an **inner**
mode, depending on whether it has crossed the updateable-MVar cut.
In outer mode (empty fvar substitution), all MVars are either unassigned
direct MVars (left alone), non-updateable delayed-assigned MVars
(pending MVar traversed in outer mode and updated with the result), or
updateable delayed-assigned MVars. When a delayed-assigned MVar is
encountered, its MVar DAG is explored (via `is_resolvable_pending`) to
determine if it is resolvable (and thus updateable). Results are cached
across invocations.
If it is updateable, the substitution is initialized from its arguments
and traversal continues with the value of its pending MVar in inner
mode. In inner mode (non-empty substitution), all encountered
delayed-assigned MVars are, by construction, resolvable but not
updateable. The substitution is carried along and extended as we cross
such MVars. Pending MVars of these delayed-assigned MVars are NOT
updated with the result (as the result is valid only for this
substitution, not in general).
Applying the substitution in one go, rather than instantiating each
delayed-assigned MVar on its own from inside out, avoids the quadratic
overhead of that approach when there are long chains of delayed-assigned
MVars.
**Write-back behavior**: Pass 2 writes back the normalized pending MVar
values of delayed-assigned MVars above the updateable-MVar cut (the
non-resolvable ones whose children may have been resolved). This is
exactly the right set: these MVars are visited in outer mode, so their
normalized values are suitable for storing in the mctx. MVars below the
cut are visited in inner mode, so their intermediate values cannot be
written back.
### Pass 2 scope-tracked caching
A `scope_cache` data structure ensures that sharing is preserved even
across different delayed-assigned MVars (and hence with different
substitutions), when possible. Each `visit_delayed` call pushes a new
scope with fresh fvar bindings. The cache correctly handles cross-scope
reuse, fvar shadowing, and late-binding via generation counters and
scope-level tracking.
The `scope_cache` has been formally verified:
`tests/elab/scopeCacheProofs.lean` contains a complete Lean proof that
the lazy generation-based implementation refines the eager
specification, covering all operations (push, pop, lookup, insert)
including the rewind lazy cleanup with scope re-entry and degradation.
The key correctness invariant is inter-entry gen list consistency
(GensConsistent), which, unlike per-entry alignment with `currentGens`,
survives pop+push cycles.
### Behavioral differences from original `instantiateMVars`
The implementation matches the original single-pass `instantiateMVars`
behavior with one cosmetic difference: the new implementation
substitutes fvars inline during traversal rather than constructing
intermediate beta-redexes, producing more beta-reduced terms in some
edge cases. This changes the pretty-printed output for two elab tests
(`1179b`, `depElim1`) but all terms remain definitionally equal.
### Tests
Correctness and performance tests for the new implementation were added
in #12808.
### Files
- `src/library/instantiate_mvars.cpp` — C++ implementation of both
passes (replaces `src/kernel/instantiate_mvars.cpp`)
- `src/library/scope_cache.h` — scope-aware cache data structure
- `src/Lean/MetavarContext.lean` — exported accessors for
`DelayedMetavarAssignment` fields
- `tests/elab/scopeCacheProofs.lean` — formal verification of
`scope_cache` correctness
- `tests/elab/1179b.lean.out.expected`,
`tests/elab/depElim1.lean.out.expected` — updated expected output
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR changes the way the linting for `linter.unusedSimpArgs` gets the
value from the environment. This is achieved by using the appropriate
helper functions defined in `Lean.Linter.Basic`.
The following now compiles without warning
```lean4
set_option linter.all false in
example : True := by simp [False]
```
Fixes#12559
This PR constructs SizeOf instances directly in SizeOf spec theorem
generation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR makes the `omit`, `unusedSectionVars` and `loopingSimpArgs`
linters respect the `linter.all` option:
when `linter.all` is set to false (and the respective linter option is
unset), the linter should not report errors.
Similarly to #12559, these linters should honour the linter.all flag
being set to false. These are all remaining occurrences of this pattern.
This fixes an issue analogous to #12559.
This PR and #12560 fix all occurrences of this pattern. (The only
question is around `RCases.linter.unusedRCasesPattern`: should this also
respect this? I have left this alone for now.)
Co-authored-by: fiforeach <249703130+fiforeach@users.noreply.github.com>
This PR modifies `#eval e` to elaborate `e` with section variables in
scope. While evaluating expressions with free variables is not possible,
this lets `#eval` give a better error message than "unknown identifier."
Example:
```lean
section
variable (n : Nat)
/-- error: Cannot evaluate, contains free variable `n` -/
#guard_msgs in #eval n
end
```
The error is localized to `#eval`. It would be more friendly if the
error were to be placed on uses of free variables.
[Zulip
discussion](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Unknown.20identifier.20error.20messages.20for.20.60.23eval.60/near/560864544)
This PR changes the elaboration of the `structure`/`class` commands so
that default values have later fields in context as well. This allows
field defaults to depend on fields that come both before and after them.
While this was already the case for inherited fields to some degree, it
now applies uniformly to all fields. Additionally, when elaborating the
default value for a field, all fields that depend on it are cleared from
the context to avoid situations where the default value depends on
itself.
This addresses an issue reported by Aaron Liu [on
Zulip](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/default.20structure.20values.20can.20depend.20on.20themselves/near/578014370).
This PR changes "structure-like" terminology to "non-recursive
structure" across internal documentation, error messages, the
metaprogramming API, and the kernel, to clarify Lean's type theory. A
*structure* is a one-constructor inductive type with no indices — these
can be created by either the `structure` or `inductive` commands — and
are supported by the primitive `Expr.proj` projections. Only
*non-recursive* structures have an eta conversion rule. The PR
description contains the APIs that were renamed.
Addresses RFC #5891, which proposed this rename. The change is motivated
by the need to distinguish between `structure`-defined structures,
structures, and non-recursive structures. Especially since #5783, which
enabled the `structure` command to define recursive structures,
"structure-like" has been easy to misunderstand.
Changes:
- Kernel: `is_structure_like()` -> `is_non_rec_structure()`
- `Lean.isStructureLike` -> `Lean.isNonRecStructure`
- `Lean.matchConstStructLike` -> `Lean.matchConstNonRecStructure`
- `Lean.getStructureLikeCtor?` -> `Lean.getNonRecStructureCtor?`
- `Lean.getStructureLikeNumFields` -> `Lean.getNonRecStructureNumFields`
- `Lean.Expr.proj`: extended and corrected documentation (note: despite
the fact that not every projection can be written as a recursor
application, I left in this claim since it seems good to document a
more-restrictive specification, and some users have requested the kernel
be more restrictive in this way)
Closes#5891
This PR changes the default behavior of the `restoreAllArtifacts`
package configuration to mirror that of the workspace. If the workspace
also has it unset, the default remains the same (`false`).
This PR changes Lake to only emit `.nobuild` traces (introduced in
#12076) if the normal trace file already exists. This fixes an issue
where a `lake build --no-build` would create the build directory and
thereby prevent a cloud release fetch in a future build.
This PR migrates most remaining tests to the new test suite. It also
completes the migration of directories like `tests/lean/run`, meaning
that PRs trying to add tests to those old directories will now fail.
This PR solves three distinct issues with the handling of
`ite`/`dite`,`decide`.
1) We prevent the simprocs from picking up `noncomputable`, `Classical`
instances, such as `Classical.propDecidable`, when simplifying the
proposition in `ite`/`dite`/`decide`.
2) We fix a type mismatch occurring when the condition/proposition is
unchanged but the `Decidable` instance is simplified.
3) If we rewrite the proposition from `c` to `c'` and the evaluation of
the original instance `Decidable c` gets stuck we try fallback path of
of obtaining `Decidable c'` instance and evaluating it. This matters
when the instance is evaluated via `cbv_eval` lemmas.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR implements a merge sort algorithm on arrays. It has been
measured to be about twice as fast as `List.mergeSort` for large arrays
with random elements, but for small or almost sorted ones, the list
implementation is faster. Compared to `Array.qsort`, it is stable and
has O(n log n) worst-case cost. Note: There is still a lot of potential
for optimization. The current implementation allocates O(n log n)
arrays, one per recursive call.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adjusts the module parser to set the leading whitespace of the
first token to the whitespace up to that token. If there are no actual
tokens in the file, the leading whitespace is set on the final (empty)
EOI token. This ensures that we do not lose the initial whitespace (e.g.
comments) of a file in `Syntax`.
(Tests generated/adjusted by Claude)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This PR replaces three independent name demangling implementations
(Lean, C++, Python) with a single source of truth in
`Lean.Compiler.NameDemangling`. The new module handles the full
pipeline: prefix parsing (`l_`, `lp_`, `_init_`, `initialize_`,
`lean_apply_N`, `_lean_main`), postprocessing (suffix flags, private
name stripping, hygienic suffix stripping, specialization contexts),
backtrace line parsing, and C exports via `@[export]`.
The C++ runtime backtrace handler now calls the Lean-exported functions
instead of its own 792-line reimplementation. This is safe because
`print_backtrace` is only called from `lean_panic_impl` (soft panics),
not `lean_internal_panic`.
The Python profiler demangler (`script/profiler/lean_demangle.py`) is
replaced with a thin subprocess wrapper around a Lean CLI tool,
preserving the `demangle_lean_name` API so downstream scripts work
unchanged.
**New files:**
- `src/Lean/Compiler/NameDemangling.lean` — single source of truth (483
lines)
- `tests/lean/run/demangling.lean` — comprehensive tests (281 lines)
- `script/profiler/lean_demangle_cli.lean` — `c++filt`-style CLI tool
**Deleted files:**
- `src/runtime/demangle.cpp` (792 lines)
- `src/runtime/demangle.h` (26 lines)
- `script/profiler/test_demangle.py` (670 lines)
Net: −1,381 lines of duplicated C++/Python code.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds tests and a benchmark exercising `instantiateMVars` on
metavariable assignment graphs with nested delayed assignments, in
preparation for optimizing the delayed mvar resolution path.
- `tests/elab/instantiateMVarsShadow.lean`: Two test cases for
correctness when the same fvar is bound to different values at different
scope levels (fvar shadowing and late-bind patterns). A buggy cache
could return a stale result from one scope level in another.
- `tests/elab/instantiateMVarsSharing.lean`: Verifies correct resolution
and object sharing on a graph with nested delayed mvars producing `∀ s,
(s = s → (s = s) ∧ (s = s)) ∧ (s = s)`.
- `tests/elab_bench/delayed_assign.lean`: Constructs an O(n²) delayed
mvar graph (n=700) and measures `instantiateMVars` resolution time,
calibrated to ~1s total elaboration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a warning to any `def` of class type that does not also
declare an appropriate reducibility.
The warning check runs after elaboration (checking the actual
reducibility status via `getReducibilityStatus`) rather than
syntactically checking modifiers before elaboration. This is necessary
to accommodate patterns like `@[to_additive (attr :=
implicit_reducible)]` in Mathlib, where the reducibility attribute is
applied during `.afterCompilation` by another attribute, and would be
missed by a purely syntactic check.
---------
Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR moves the universe-level-count check from
`unfold_definition_core` into `is_delta`, establishing the invariant
that if `is_delta` succeeds then `unfold_definition` also succeeds. This
prevents a crash (SIGSEGV or garbled error) that occurred when call
sites in `lazy_delta_reduction_step` unconditionally dereferenced the
result of `unfold_definition` even on a level-parameter-count mismatch.
Additionally, moves the `is_prop` check for theorem types in
`add_theorem` to occur after `check_constant_val`, so the type is
verified to be well-formed before `is_prop` evaluates it. This prevents
`is_prop` from being called on an ill-typed term when a malformed
theorem declaration is supplied.
Fixes#10577.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nomeata <148037+nomeata@users.noreply.github.com>
This PR reverts https://github.com/leanprover/lean4/pull/12757.
We suspect this caused the v4.29.0-rc5 tag CI to fail. All 6 test jobs
on the tag CI (run
https://github.com/leanprover/lean4/actions/runs/22699133179) are
failing with:
```
PANIC at _private.Lean.Environment.0.Lean.EnvExtension.getStateUnsafe Lean.Environment:1425:6:
called on `async` extension, must set `asyncDecl` or pass `(asyncMode := .local)` to explicitly access local state
```
29 tests fail, affecting deriving, grind, linter, interactive, and pkg
tests. The v4.29.0-rc4 tag CI passed, and the only code changes between
rc4 and rc5 are this PR and
https://github.com/leanprover/lean4/pull/12782. The failure only
manifests in release builds (with `LEAN_VERSION_IS_RELEASE=1` and
`CHECK_OLEAN_VERSION=ON`).
🤖 Prepared with Claude Code
This PR changes Lake to use the modification times of traces (where
available) for artifact modification times.
When artifacts are hard-linked from the cache, they retain the
modification time of the artifact in the cache. Thus, the artifact
modification time is an unreliable metric for determining whether an
artifact is up-to-date relative to other artifacts in the presence of
the cache. The trace file, however, is modified consistently when the
artifacts are updated, making it the most reliable indicator of
modification time.
This PR fixes a false positive in `release_checklist.py` where the check
for the dev cycle being started would fail even when it was correctly
set up.
The script was looking for `set(LEAN_VERSION_IS_RELEASE 0)` as an exact
prefix match, but CMakeLists.txt uses the CMake cache variable form:
`set(LEAN_VERSION_IS_RELEASE 0 CACHE STRING "")`. The fix uses a regex
that handles both syntaxes.
This was discovered during the v4.29.0-rc4 release when the checklist
incorrectly reported that a "begin dev cycle" PR was needed, even though
PR #12526 had already set `LEAN_VERSION_IS_RELEASE 0` and
`LEAN_VERSION_MINOR 30` on master.
🤖 Prepared with Claude Code
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This PR marks `Id.run` as `[implicit_reducible]` to ensure that
`Id.instMonadLiftTOfPure` and `instMonadLiftT Id` are definitionally
equal when using `.implicitReducible` transparency setting.
This PR takes a more principled approach in deriving `String` pattern
lemmas by reducing to simpler cases similar to how the instances are
defined.
This reduces duplication of complex arguments (at the expense of having
to state more simple lemmas; however these lemmas are useful to users as
well).
This PR adds a `set_option cbv.maxSteps N` option that controls the
maximum
number of simplification steps the `cbv` tactic performs. Previously the
limit
was hardcoded to the `Sym.Simp.Config` default of 100,000 with no way
for
users to override it. The option is threaded through `cbvCore`,
`cbvEntry`,
`cbvGoal`, and `cbvDecideGoal`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR moves cbv tests to the correct test directories. `cbv4.lean` is
a
straightforward elaboration test and is moved to `tests/elab/`. The AES
and ARM
load/store tests are performance-oriented stress tests and are moved to
`tests/elab_bench/`.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR makes the compiler removes arguments to join points that are
void, avoiding a bunch of dead
stores in the bytecode and the initial C (though LLVM was surely able to
optimize these away further
down the line already).
This PR introduces the core HTTP data types: `Request`, `Response`,
`Status`, `Version`, and `Method`. Currently, URIs are represented as
`String` and headers as `HashMap String (Array String)`. These are
placeholders, future PRs will replace them with strict implementations.
This contains the same code as #10478, divided into separate pieces to
facilitate easier review.
The pieces of this feature are:
- Core data structures: #12126
- Headers: #12127
- URI: #12128
- Body: #12144
- H1: #12146
- Server: #12151
- Client:
---------
Co-authored-by: Rob23oba <152706811+Rob23oba@users.noreply.github.com>
This PR skips the noncomputable pre-check in `processDefDeriving` when
the instance type is `Prop`. Since proofs are erased by the compiler,
computability is irrelevant for `Prop`-valued instances.
Previously (since https://github.com/leanprover/lean4/pull/12756),
`deriving instance` would reject instances that transitively depend on
noncomputable definitions, even when the class extends `Prop`. This came
up in mathlib where `Precoverage.IsStableUnderBaseChange` (a `Prop`
class) needs `deriving noncomputable instance` unnecessarily.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes `release_steps.py` for `verso`. After running `lake
update` in the root, the `test-projects/*/lake-manifest.json` files
retain stale subverso pins, causing verso's "SubVerso version
consistency" CI check to fail. The fix syncs the root manifest's
subverso rev into all test-project sub-manifests.
Root cause: verso has nested Lake projects in `test-projects/` each with
their own `lake-manifest.json`. Running `lake update` in the root
updates the root manifest but doesn't touch the nested ones.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This PR adds high priority to instances for `OfSemiring.Q` in the grind
ring envelope. When Mathlib is imported, instance synthesis for types
like `OfSemiring.Q Nat` becomes very expensive because the solver
explores many irrelevant paths before finding the correct instances. By
marking these instances as high priority and adding shortcut instances
for basic operations (`Add`, `Sub`, `Mul`, `Neg`, `OfNat`, `NatCast`,
`IntCast`, `HPow`), instance synthesis resolves quickly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR fixes `release_checklist.py` to report failing CI checks
immediately, even when other checks are still in progress. Previously,
having any in-progress checks would return `"pending"` status, masking
failures that had already occurred. Now it returns `"failure"` with a
message like `"1 check(s) failing, 2 still in progress"`.
Also adds a section to `.claude/commands/release.md` instructing the AI
assistant to investigate any CI failure immediately rather than
reporting it as "in progress" and moving on.
🤖 Prepared with Claude Code
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This PR fixes a parsing bug in \`release_checklist.py\` introduced by
https://github.com/leanprover/lean4/pull/12700, which reformatted
\`src/CMakeLists.txt\` to use \`CACHE STRING \"\"\`:
\`\`\`cmake
set(LEAN_VERSION_MINOR 30 CACHE STRING "")
\`\`\`
The old code used \`split()[-1].rstrip(")")\` to extract the version
number, which now yields \`""\` (the empty string argument) instead of
the minor version. Use a regex to extract the digit directly.
🤖 Prepared with Claude Code
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This PR adds user-facing API lemmas for `s.contains t`, where `s` and
`t` are both a string or a slice.
Under the hood these lemmas are backed by the correctness proof for KMP
that was added a few weeks ago.
This PR fixes a CMake scoping bug that made `-DLEAN_VERSION_*` overrides
ineffective.
The version variables (`LEAN_VERSION_MAJOR`, `MINOR`, `PATCH`,
`IS_RELEASE`) were declared with plain `set()`, which creates normal
variables that shadow cache variables set by `-D` on the command line.
The fix changes them to `CACHE STRING ""` to match the existing
`LEAN_SPECIAL_VERSION_DESC` pattern.
However, `CACHE STRING ""` alone isn't sufficient because `project(LEAN
CXX C)` implicitly creates empty `LEAN_VERSION_{MAJOR,MINOR,PATCH}`
normal variables (CMake sets `<PROJECT>_VERSION_*` for the project
name). These shadow the cache values, so we `unset()` them after the
cache declarations to let `${VAR}` fall through to the cache.
Closes https://github.com/leanprover/lean4/issues/12681🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR replaces `lean.code-workspace` with standard `.vscode/`
configuration
files (`settings.json`, `tasks.json`, `extensions.json`). The workspace
file
required users to explicitly "Open Workspace from File" (and moreover
gives a
noisy prompt whether or not they want to open it), while `.vscode/`
settings
are picked up automatically when opening the folder. This became
possible after
#12652 reduced the workspace to a single folder.
Also drops the `rewrap.wrappingColumn` markdown setting, as the Rewrap
extension
is no longer signed on the VS Code marketplace.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR deprecates `levelZero` in favor of `Level.zero` and `levelOne`
in favor of the new `Level.one`, and updates all usages throughout the
codebase. The `levelZero` alias was previously required for computed
field `data` to work, but this is no longer needed.
🤖 Prepared with Claude Code
This PR adds general projection lemmas for `ExceptConds` conjunction:
- `ExceptConds.and_elim_left`: `(x ∧ₑ y) ⊢ₑ x`
- `ExceptConds.and_elim_right`: `(x ∧ₑ y) ⊢ₑ y`
The existing `and_true`, `true_and`, `and_false`, `false_and` are
refactored as one-line corollaries.
Suggested by @sgraf812 in
https://github.com/leanprover-community/cslib/pull/376#discussion_r2066993469.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
MacOS uses a very old version of bash where `"${FOO[@]}"` fails if `set
-u` is enabled and `FOO` is undefined. Newer versions of bash expand
this to zero arguments instead.
Also, `lint.py` used the shebang `#!/usr/bin/env python` instead of
`python3`, which fails on some systems.
In CI, all macos tests run on nscloud runners. Presumably, they have
installed newer versions of various software, hence this didn't break in
CI.
This PR fixes `@[implicit_reducible]` on well-founded recursive
definitions.
`addPreDefAttributes` sets WF-recursive definitions as `@[irreducible]`
by default, skipping this only when the user explicitly wrote
`@[reducible]` or `@[semireducible]`. It was missing
`@[instance_reducible]` and `@[implicit_reducible]`, causing those
attributes to be silently overridden.
Add `instance_reducible` and `implicit_reducible` to the check in
`src/Lean/Elab/PreDefinition/Mutual.lean` that guards against overriding
user-specified reducibility attributes, and add regression tests in
`tests/elab/wfirred.lean`.
## Example
```lean
-- Before fix: printed @[irreducible] def f : List Nat → Nat
-- After fix: printed @[implicit_reducible] def f : List Nat → Nat
@[instance_reducible] def f : ∀ _l : List Nat, Nat
| [] => 0
| [_x] => 1
| x :: y :: l => if h : x = y then f (x :: l) else f l + 2
termination_by l => sizeOf l
#print sig f
```
Fixes#12775
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nomeata <148037+nomeata@users.noreply.github.com>
This PR provides a `ForwardPatternModel` for string patterns and deduces
theorems and lawfulness instances from the corresponding results for
slice patterns.
This PR fixes an inconsistency in `getStuckMVar?` where the instance
argument to class projection functions and auxiliary parent projections
was not whnf-normalized before checking for stuck metavariables. Every
other case in `getStuckMVar?` (recursors, quotient recursors, `.proj`
nodes) normalizes the major argument via `whnf` before recursing — class
projection functions and aux parent projections were the exception.
This bug was identified by Matthew Jasper. When the instance parameter
to a class projection is not normalized, `getStuckMVar?` may fail to
detect stuck metavariables that would be revealed by whnf, or conversely
may report stuckness for expressions that would reduce to constructors.
This caused issues with `OfNat` and `Zero` at
`with_reducible_and_instances` transparency.
Note: PR #12701 (already merged) is also required to fix the original
Mathlib examples.
This PR adds `at` location syntax to the `cbv` tactic, matching the
interface of `simp at`. Previously `cbv` could only reduce the goal
target; now it supports `cbv at h`, `cbv at h |-`, and `cbv at *`.
`cbvGoal` is rewritten to use `Sym.preprocessMVar` followed by `cbvCore`
within a single `SymM` context, sharing the term table across all
hypotheses and the target. The old `cbvGoalCore` (which reduced one side
of an equation goal at a time) is replaced by a general approach that
reduces arbitrary goal types and hypothesis types, with special handling
for `True` targets and `False` hypotheses. `cbvDecideGoal` is updated to
use the extracted `cbvCore` as well.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a dedicated cbv simproc for `Decidable.decide` that
directly matches on `isTrue`/`isFalse` instances, producing simpler
proof terms and avoiding unnecessary unfolding through `Decidable.rec`.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR generalizes `String.Slice.Pos.cast`, which turns an `s.Pos` into
a `t.Pos`, to no longer require `s = t`, but merely `s.copy = t.copy`.
This is a breaking change, but one that is easy to adapt to, by
replacing `proof` with `congrArg Slice.copy proof` where required.
This PR adds `deriving noncomputable instance Foo for Bar` syntax so
that delta-derived instances can be marked noncomputable. Previously,
when the underlying instance was noncomputable, `deriving instance`
would fail with an opaque async compilation error.
Now:
- `deriving noncomputable instance Foo for Bar` marks the generated
instance as noncomputable (using `addDecl` + `addNoncomputable` instead
of `addAndCompile`)
- `deriving instance Foo for Bar` pre-checks for noncomputable
dependencies and gives an actionable error with a "Try this:" suggestion
pointing to the noncomputable variant
- For handler-based deriving (inductives/structures), `noncomputable`
sets `isNoncomputable` on the scope
The `optDefDeriving` and `optDeriving` trailing parsers are updated with
`notSymbol "noncomputable"` to prevent them from stealing the parse of
`deriving noncomputable instance ...`.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR enables Lake to download artifacts from a remote cache service
on demand as part of a `lake build`. It also refactors much of the cache
API to be more type safe.
The newly documented `lake cache add` command loads input-to-output
mappings from a file and stores them in the cache with optional
information about which cache service and what scope they come from.
With this information, Lake can now download artifacts on demand during
a `lake build`.
The `lake cache get` command has also changed its default behavior to
download just the input-to-outputs mapping and then lazily fetch
artifacts from Reservoir as part of a `lake build`. The original eager
behavior can be forced via the new `--download-arts` option.
This PR using `StateT.run` rather than the "defeq abuse" of function
application. There remain many places where we still use function
application for `ReaderT`, but I've updated this in the touched files.
(To really solve this, we would make `StateT` irreducible, but that is
not happening here.)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR ensures `linter.all` disables `constructorNameAsVariable`.
The issue was discovered by @eric-wieser while investigating a quote4
issue.
This seems like an easy mistake to make when setting up a new linter,
and perhaps we need a better structure to make it easy to do the right
thing.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR replaces the `isImplicitReducible` check with `Meta.isInstance`
in the `shouldInline` function within `inlineCandidate?`.
At the base phase, we skip inlining instances tagged with
`[inline]`/`[always_inline]`/`[inline_if_reduce]` because their local
functions will be lambda lifted during the base phase. The goal is to
keep instance code compact so the lambda lifter can extract
cheap-to-inline declarations. Inlining instances prematurely expands the
code and creates extra work for the lambda lifter — producing many
additional lambda-lifted closures.
The previous check used `isImplicitReducible`, which does not capture
the original intent: some `instanceReducible` declarations are not
instances. `Meta.isInstance` correctly targets only actual type class
instances. Although `Meta.isInstance` depends on the scoped extension
state, this is safe because `shouldInline` runs during LCNF compilation
at `addDecl` time — any instance referenced in the code was resolved
during elaboration when the scope was active, and LCNF compilation
occurs before the scope changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR changes the approach in `simpIteCbv` and `simpDIteCbv`, by
replacing call to `Decidable.decide`
with reducing and direct pattern matching on the `Decidable` instance
for `isTrue`/`isFalse`. This produces simpler proof terms.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds pre-pass simprocs `simpOr` and `simpAnd` to the `cbv`
tactic that evaluate only the left argument of `Or`/`And` first,
short-circuiting when the result is determined without evaluating the
right side. Previously, `cbv` processed `Or`/`And` via congruence, which
always evaluated both arguments. For expressions like `decide (m < n ∨
expensive)`, when `m < n` is true, the expensive right side is now
skipped entirely.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR provides injectivity lemmas for `List.getElem`, `List.getElem?`,
`List.getElem!` and `List.getD` as well as for `Option`. Note: This
introduces a breaking change, changing the signature of
`Option.getElem?_inj`.
This PR adds a section to the /release command explaining how to use `gh
pr checks --watch` to wait for CI or merges without polling.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes `pp.fvars.anonymous` to display loose free variables as
`_fvar._` instead of `_` when the option is set to `false`. This was the
intended behavior in https://github.com/leanprover/lean4/pull/12688 but
the fix was committed locally and not pushed before that PR was merged.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR switches four lightweight workflows from `pull_request` to
`pull_request_target` to stop GitHub from requiring manual approval when
the
`mathlib-lean-pr-testing[bot]` app triggers label events (e.g. adding
`builds-mathlib`). Since the bot never lands commits on master, it is
perpetually treated as a "first-time contributor" and every
`pull_request`
event it triggers requires approval. `pull_request_target` events always
run
without approval because they execute trusted code from the base branch.
This is safe for all four workflows because none check out or execute
code
from the PR branch — they only read labels, PR body, and file lists from
the
event payload and API:
- `awaiting-mathlib.yml` — checks label combinations
- `awaiting-manual.yml` — checks label combinations
- `pr-body.yml` — checks PR body formatting
- `check-stdlib-flags.yml` — checks if stdlib_flags.h was modified via
API
Also adds explicit `permissions: pull-requests: read` to each workflow
as a
least-privilege hardening measure, since `pull_request_target` has
access to
secrets.
Addresses the issue reported by Sebastian:
https://lean-fro.zulipchat.com/#narrow/channel/398861-general/topic/mathlib.20pr-testing.20breakage.3F/near/575084348🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR changes the shebang in `lean_profile.sh` from `#!/bin/bash` to
`#!/usr/bin/env bash` so the script works on NixOS and other systems
where bash is not at `/bin/bash`, and adds a Claude Code skill pointing
to the profiler documentation.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR gives the `generate` function's "apply @Foo to Goal" trace nodes
their own trace sub-class `Meta.synthInstance.apply` instead of sharing
the parent `Meta.synthInstance` class.
This allows metaprograms that walk synthesis traces to distinguish
instance application attempts from other synthesis nodes by checking
`td.cls` rather than string-matching on the header text.
The new class is registered with `inherited := true`, so `set_option
trace.Meta.synthInstance true` continues to show these nodes.
Motivated by mathlib's `#defeq_abuse` diagnostic tactic
(https://github.com/leanprover-community/mathlib4/pull/35750) which
currently checks `headerStr.contains "apply"` to identify these nodes.
See
https://leanprover.zulipchat.com/#narrow/channel/113488-general/topic/backward.2EisDefEq.2ErespectTransparency🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a `pp.fvars.anonymous` option (default `true`) that
controls the display of loose free variables (fvars not in the local
context).
- When `true` (default), loose fvars display their internal name like
`_fvar.42`
- When `false`, they display as `_fvar._`
This is analogous to `pp.mvars.anonymous` for metavariables. It's useful
for stabilizing output in `#guard_msgs` when messages contain fvar IDs
that vary between runs — for example, in diagnostic tools that report
`isDefEq` failures from trace output where the local context is not
available.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a gap in how `@[implicit_reducible]` is assigned to parent
projections during structure elaboration.
When `class C extends P₁, P₂` has diamond inheritance, some ancestor
structures become constructor subobject fields even though they aren't
direct parents. For example, in `Monoid extends Semigroup, MulOneClass`,
`One` becomes a constructor subobject of `Monoid` — its field `one`
doesn't overlap with `Semigroup`'s fields, and `inSubobject?` is `none`
during `MulOneClass` flattening.
`mkProjections` creates the projection `Monoid.toOne` but defers
reducibility to `addParentInstances` (guarded by `if !instImplicit`).
However, `addParentInstances` only processes direct parents from the
`extends` clause. Grandparent subobject projections fall through the gap
and stay `semireducible`.
This causes defeq failures when `backward.isDefEq.respectTransparency`
is enabled (#12179): at `.instances` transparency, the semireducible
grandparent projection can't unfold, so two paths to the same ancestor
structure aren't recognized as definitionally equal.
Fix: before `addParentInstances`, iterate over all `.subobject` fields
and set `implicitReducible` on those whose parent is a class.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The linter was running in parallel with other tests, which were creating
and deleting files. Since the linter was iterating over some files and
directories at the time, it crashed.
This PR relates `String.split` to `List.splitOn` and `List.splitOnP`,
provided that we are splitting by a character or character predicate.
Also included: some more lemmas about `List.splitOn`, and a refactor of
the generic `split` verification to get rid of the awkward `SlicesFrom`
constuct.
This PR ensures the compiler extracts `Array`/`ByteArray`/`FloatArray`
literals as one big closed term to avoid quadratic overhead at closed
term initialization time.
This PR changes the spec lookup procedure in Sym-based mvcgen so that
1. Spec candidates are sorted first before being filtered
2. Instead of filtering the whole set of candidates using
`spec.pattern.match?`, we take the first match with the highest
priority.
The second point means we will do a lot fewer matches when the highest
priority spec matches immediately. In this case, the one match is still
partially redundant with the final application of the backward rule
application. It would be great if could somehow specialize the backward
rule after it has been created. Still, this yields some welcome
speedups. Before and after for each.
```
vcgen_add_sub_cancel:
goal_1000: 865 ms, 1 VCs by grind: 228 ms, kernel: 435 ms
goal_1000: 540 ms, 1 VCs by grind: 229 ms, kernel: 426 ms
vcgen_ping_pong:
goal_1000: 458 ms, 0 VCs, kernel: 431 ms
goal_1000: 454 ms, 0 VCs, kernel: 443 ms (unchanged, because there is only ever one candidate spec)
vcgen_deep_add_sub_cancel:
goal_1000: 986 ms, 1 VCs by grind: 234 ms, kernel: 735 ms
goal_1000: 728 ms, 1 VCs by grind: 231 ms, kernel: 708 ms
vcgen_reader_state:
goal_1000: 746 ms, 1 VCs by sorry: 1 ms, kernel: 803 ms
goal_1000: 525 ms, 1 VCs by sorry: 1 ms, kernel: 840 ms
```
This PR fixes a bug in `Meta.zetaReduce` where `have` expressions were
not being zeta reduced. It also adds a feature where applications of
local functions are beta reduced, and another where zeta-delta reduction
can be disabled. These are all controllable by flags:
- `zetaDelta` (default: true) enables unfolding local definitions
- `zetaHave` (default: true) enables zeta reducing `have` expressions
- `beta` (default: true) enables beta reducing applications of local
definitions
Closes#10850
This PR adds support for generating and discharging postcondition VCs in
Sym-based `mvcgen`. It also adds a new benchmark case
`vcgen_ping_pong.lean` that tests this functionality. This benchmark
required a more diligent approach to maintain maximal sharing in goal
preprocessing. Goal preprocessing was subsequently merged into the main
VC generation function.
This PR changes the order of implicit parameters `α` and `ps` such that
`α` consistently comes before `ps` in `PostCond.noThrow`,
`PostCond.mayThrow`, `PostCond.entails`, `PostCond.and`, `PostCond.imp`
and theorems.
This PR ports the simple ground expression extraction pass from IR to
LCNF.
I locally confirmed that this produces no diff between stage1/stage2 at
the C level (apart from the
changed compiler files) so this should essentially be binary equivalent.
This PR upstreams `List.splitOn` and `List.splitOnP` from
Batteries/mathlib.
The function `splitOnP.go` is factored out to `splitOnPPrepend`, because
it is useful to state induction hypotheses in terms of
`splitOnPPrepend`.
This PR ports the expand reset/reuse pass from IR to LCNF. In addition
it prevents exponential code generation unlike the old one. This results
in a ~15% decrease in binary size and slight speedups across the board.
The change also removes the "is this reset actually used" syntactic
approximation as the previous passes guarantee (at the moment) that all
uses are in the continuation and will thus be caught by this.
This PR enables the module system, in cooperation with the linker, to
separate meta and non-meta code in native binaries. In particular, this
ensures tactics merely used in proofs do not make it into the final
binary. A simple example using `meta import Lean` has its binary size
reduced from 130MB to 1.7MB.
# Breaking change
`importModules (loadExts := true)` must now be preceded by
`enableInitializersExecution`. This was always the case for correct
importing but is now enforced and checked eagerly.
This PR adds two `decide_cbv` stress tests extracted from LNSym (ARMv8
symbolic
simulator, Apache 2.0). `cbv_aes.lean` tests a full AES-128 encryption
on large
bitvector computations. `cbv_arm_ldst.lean` tests ARMv8 load/store
instruction
decoding and execution with nested pattern matching over bitvectors.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a `cbv` tactic test based on a minimized example extracted
from verifying the Collatz conjecture for small numbers, suggested by
Bhavik Mehta (@b-mehta).
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Bhavik Mehta <bhavikmehta8@gmail.com>
This PR reverts commit 9b7a8eb7c8. After
some more contemplation on
the implications of these changes I think this is not the direction we
want to move into.
This PR sets up the new integrated test/bench suite. It then migrates
all benchmarks and some related tests to the new suite. There's also
some documentation and some linting.
For now, a lot of the old tests are left alone so this PR doesn't become
even larger than it already is. Eventually, all tests should be migrated
to the new suite though so there isn't a confusing mix of two systems.
This PR fixes an issue where `mutual public structure` would have a
private constructor. The fix copies the fix from #11940.
Closes#10067. Also recloses duplicate issue #11116 (its test case is
added to the test suite).
This PR adds several useful lemmas for `List`, `Array` and `Vector`
whenever they were missing, improving API coverage and consistency among
these types.
- `size_singleton`/`sum_singleton`/`sum_push`
-
`foldlM_toArray`/`foldlM_toList`/`foldl_toArray`/`foldl_toList`/`foldrM_toArray`/`foldrM_toList`/`foldr_toList`
- `toArray_toList`
- `foldl_eq_apply_foldr`/`foldr_eq_apply_foldl`, `foldr_eq_foldl`:
relates `foldl` and `foldr` for associative operations with identity
- `sum_eq_foldl`: relates sum to `foldl` for associative operations with
identity
- `Perm.pairwise_iff`/`Perm.pairwise`: pairwise properties are preserved
under permutations of arrays
This PR provides `WellFounded.partialExtrinsicFix`, which makes it
possible to implement and verify partially terminating functions, safely
building on top of the seemingly less general `extrinsicFix` (which is
now called `totalExtrinsicFix`). A proof of termination is only
necessary in order to formally verify the behavior of
`partialExtrinsicFix`.
This PR changes all `lean-toolchain` to use relative toolchain paths
instead of `lean4` and `lean4-stage0` identifiers, which removes the
need for manually linking toolchains via Elan.
After this PR, at least Elan 4.2.0 and 0.0.224 of the Lean VS Code
extension will be needed to edit core.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This PR marks `List.flatten`, `List.flatMap`, `List.intercalate` as
noncomputable to ensure that their `csimp` variants are used everywhere.
We also mark `List.flatMapM` as noncomputable and provide a
tail-recursive implementation, and mark `List.utf8Encode` as
noncomputable, which only exists for specification purposes anyway (at
this point).
Closes#12676.
This PR adds a feature where `inductive` constructors can override the
binder kinds of the type's parameters, like in #9480 for `structure`.
For example, it's possible to make `x` explicit in the constructor
`Eq.refl`, rather than implicit:
```lean
inductive Eq {α : Type u} (x : α) : α → Prop where
| refl (x) : Eq x x
```
In the Prelude, this is currently accomplished by taking advantage of
auto-promotion of indices to parameters.
**Breaking change.** Inductive types with a constructor that starts with
typeless binders may need to be rewritten, e.g. changing `(x)` to `(x :
_)` if there is a `variable` with that name or if it is meant to shadow
one of the inductive type's parameters.
This PR fixes an issue where `withLocation` wasn't saving the info
context, which meant that tactics that use `at *` location syntax and do
term elaboration would save infotrees but revert the metacontext,
leading to Infoview messages like "Error updating: Error fetching goals:
Rpc error: InternalError: unknown metavariable" if the tactic failed at
some locations but succeeded at others.
Closes#10898
This PR fixes two aspects of pretty printing of private names.
1. Name unresolution. Now private names are not special cased: the
private prefix is stripped off and the `_root_` prefix is added, then it
tries resolving all suffixes of the result. This is sufficient to handle
imported private names in the new module system. (Additionally,
unresolution takes macro scopes into account now.)
2. Delaboration. Inaccessible private names use a deterministic
algorithm to convert private prefixes into macro scopes. The effect is
that the same private name appearing in multiple times in the same
delaborated expression will now have the same `✝` suffix each time. It
used to use fresh macro scopes per occurrence.
Note: There is currently a small hack to support pretty printing in the
compiler's trace messages, which print constants that do not exist (e.g.
`obj`, `tobj`, and auxiliary definitions being compiled). Even though
these names are inaccessible (for the stronger reason that they don't
exist), we make sure that the pretty printer won't add macro scopes. It
also does some analysis of private names to see if the private names are
for the current module.
Closes#10771, closes#10772, and closes#10773
This PR adds the missing `popScopes` call to `withNamespace`, which
previously
only dropped scopes from the elaborator's `Command.State` but did not
pop the
environment's `ScopedEnvExtension` state stacks. This caused scoped
syntax
declarations to leak keywords outside their namespace when
`withNamespace` had
been called.
Closes#12630
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR allows for a leightweight version of dependent `match` in the
new `do` elaborator: discriminant types get abstracted over previous
discriminants. The match result type and the local context still are not
considered for abstraction. For example, if both `i : Nat` and `h : i <
len` are discrminants, then if an alternative matches `i` with `0`, we
also have `h : 0 < len`:
```lean
example {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
let rec loop (i : Nat) (h : i ≤ as.size) (b : β) : m β := do
match i, h with
| 0, _ => pure b
| i+1, h =>
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
match (← f as[as.size - 1 - i] (Array.getElem_mem this) b) with
| ForInStep.done b => pure b
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
loop as.size (Nat.le_refl _) b
```
This feature turns out to be enough to save quite a few adaptations
(6/16) during bootstrep.
This PR adds the benchmark vcgen_reader_state that is a variant of
vcgen_add_sub_cancel that takes the value to subtract from a `ReaderT`
layer. Measurements:
```
goal_100: 201 ms, 1 VCs by sorry: 0 ms, kernel: 52 ms
goal_500: 382 ms, 1 VCs by sorry: 0 ms, kernel: 327 ms
goal_1000: 674 ms, 1 VCs by sorry: 1 ms, kernel: 741 ms
```
Which suggests it scales linearly. The generated VC triggers superlinear
behavior in `grind`, though, hence it is discharged by `sorry`.
This PR adds the pretty printer option `pp.mdata`, which causes the
pretty printer to annotate terms with any metadata that is present. For
example,
```lean
set_option pp.mdata true
/-- info: [mdata noindex:true] 2 : Nat -/
#guard_msgs in #check no_index 2
```
The `[mdata ...] e` syntax is only for pretty printing.
Thanks to @Rob23oba for an initial version.
Closes#10929
This PR fixes spurious unused variable warnings for variables used in
non-atomic match discriminants in `do` notation. For example, in `match
Json.parse s >>= fromJson? with`, the variable `s` would be reported as
unused.
The root cause is that `expandNonAtomicDiscrs?` eagerly elaborates the
discriminant via `Term.elabTerm`, which creates TermInfo for variable
references. The result is then passed to `elabDoElem` for further
elaboration. When the match elaboration is postponed (e.g. because the
discriminant type contains an mvar from `fromJson?`), the result is a
postponed synthetic mvar. The `withTermInfoContext'` wrapper in
`elabDoElemFns` checks `isTacticOrPostponedHole?` on this result,
detects a postponed mvar, and replaces the info subtree with a `hole`
node — discarding all the TermInfo that was accumulated during
discriminant elaboration.
The fix applies `mkSaveInfoAnnotation` to the result, which prevents
`isTacticOrPostponedHole?` from recognizing it as a hole. This is the
same mechanism that `elabLetMVar` uses to preserve info trees when the
body is a metavariable.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR avoids false-positive error messages on specialization
restrictions under the module system when the declaration is explicitly
marked as not specializable. It could also provide some minor public
size and rebuild savings.
This PR fixes false-positive "unused variable" warnings for mutable
variables reassigned inside `try`/`catch` blocks with the new do
elaborator.
The root cause was that `ControlStack.stateT.runInBase` packed mutable
variables into a state tuple without calling `Term.addTermInfo'`, so the
unused variable linter could not see that the variables were used. The
fix mirrors how the `for` loop elaborator handles the same pattern in
`useLoopMutVars`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds the experimental `idbg e`, a new do-element (and term)
syntax for live debugging between the language server and a running
compiled Lean program.
When placed in a `do` block, `idbg` captures all local variables in
scope and expression `e`, then:
- **In the language server**: starts a TCP server on localhost waiting
for the running program to
connect; the editor will mark this part of the program as "in progress"
during this wait but that
will not block `lake build` of the project.
- **In the compiled program**: on first execution of the `idbg` call
site, connects to the server,
receives the expression, compiles and evaluates it using the program's
actual runtime values, and
sends the `repr` result back.
The result is displayed as an info diagnostic on the `idbg` keyword. The
expression `e` can be
edited while the program is running - each edit triggers re-elaboration
of `e`, a new TCP exchange,
and an updated result. This makes `idbg` a live REPL for inspecting and
experimenting with
program state at a specific point in execution. Only when `idbg` is
inserted, moved, or removed does
the program need to be recompiled and restarted.
# Known Limitations
* The program will poll for the server for up to 10 minutes and needs to
be killed manually
otherwise.
* Use of multiple `idbg` at once untested, likely too much overhead from
overlapping imports without
further changes.
* `LEAN_PATH` must be properly set up so compiled program can import its
origin module.
* Untested on Windows and macOS.
This PR fixes a performance regression introduced by enabling
`backward.whnf.reducibleClassField`
(https://github.com/leanprover/lean4/pull/12538). The
`isNonTrivialRegular` function in `ExprDefEq` was classifying class
projections as nontrivial at all transparency levels, but the extra
`.instances` reduction in `unfoldDefault` that motivates this
classification only applies at `.reducible` transparency. At higher
transparency levels, the nontrivial classification caused unnecessary
heuristic comparison attempts in `isDefEqDelta` that cascaded through
BitVec reductions, causing elaboration of `Lean.Data.Json.Parser` to
double from ~3.6G to ~7.2G instructions.
The fix restricts the nontrivial classification to `.reducible`
transparency only, matching the scope of `unfoldDefault`'s extra
reduction behavior.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR enables the `cbv` tactic to unfold nullary (non-function)
constant
definitions such as `def myNat : Nat := 42`, allowing ground term
evaluation
(e.g. `evalEq`, `evalLT`) to recognize their values as literals.
Previously, `handleConst` skipped all nullary constants. Now it performs
direct
delta reduction using `instantiateValueLevelParams` instead of going
through
the equation theorem machinery (`getUnfoldTheorem`), which would trigger
`realizeConst` and fail for constants (such as derived typeclass
instances)
where `enableRealizationsForConst` has not been called.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a performance regression from #12538 caused by
`PlausibleIterStep.yield/skip/done` becoming abbreviation, which changes
the inlining behavior.
This PR ports the toposorting pass from IR to LCNF.
We can already do this now as the remaining IR pipeline does not insert
any new auxiliary
declarations into the SCC so now is as good a time as ever to do it.
This PR adds documentation to the Cbv evaluator files under
`Meta/Tactic/Cbv/`. Module docstrings describe the evaluation strategy,
limitations, attributes, and unfolding order. Function docstrings cover
the public API and key internal simprocs.
## Summary
- `Main.lean`: module docstring covering evaluation strategy,
limitations, attributes, unfolding order, and entry points; function
docstrings on `handleConstApp`, `handleApp`, `handleProj`,
`simplifyAppFn`, `cbvPreStep`, `cbvPre`, `cbvPost`, `cbvEntry`,
`cbvGoalCore`, `cbvGoal`
- `ControlFlow.lean`: module docstring on how Cbv control flow differs
from standard `Sym.Simp`; function docstrings on `simpIteCbv`,
`simpDIteCbv`, `simpControlCbv`
- `CbvEvalExt.lean`: module docstring on the `@[cbv_eval]` extension;
function docstring on `mkCbvTheoremFromConst`
- `Opaque.lean`: module docstring on the `@[cbv_opaque]` extension
- `TheoremsLookup.lean`: module docstring on the theorem cache
- `Util.lean`: module docstring; function docstrings on
`isBuiltinValue`, `isProofTerm`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR ensures that failure in initial compilation marks the relevant
definitions as `noncomputable`, inside and outside `noncomputable
section`, so that follow-up errors/noncomputable markings are detected
in initial compilation as well instead of somewhere down the pipeline.
This may require additional `noncomputable` markers on definitions that
depend on definitions inside `noncomputable section` but accidentally
passed the new computability check.
Reported at
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Cryptic.20error.20message.20in.20new.20lean.20toolchain.3F.
This PR derives the linear order on string positions (`String.Pos.Raw`,
`String.Pos`, `String.Slice.Pos`) via `Std.LinearOrderPackage`, which
ensures that all data-carrying and propositional instances are present.
Previously, we were misssing some, like `Ord`.
This PR fixes `getStuckMVar?` to detect stuck metavariables through
auxiliary parent projections created for diamond inheritance. These
coercions (e.g., `AddMonoid'.toAddZero'`) are not registered as regular
projections because they construct the parent value from individual
fields rather than extracting a single field. Previously,
`getStuckMVar?` would give up when encountering them, preventing TC
synthesis from being triggered.
- Add `AuxParentProjectionInfo` environment extension to `ProjFns.lean`
recording `numParams` and `fromClass` for these coercions
- Register the info during structure elaboration in
`mkCoercionToCopiedParent`
- Consult the new extension in `getStuckMVar?` as a fallback when
`getProjectionFnInfo?` returns `none`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR enables `backward.whnf.reducibleClassField` for v4.29.
The support is particularly important when the user marks a class field
as `[reducible]` and
the transparency mode is `.reducible`. For example, suppose `e` is `a ≤
b` where `a b : Nat`,
and `LE.le` is marked as `[reducible]`. Simply unfolding `LE.le` would
give `instLENat.1 a b`,
which would be stuck because `instLENat` has transparency
`[instance_reducible]`. To avoid this, when we unfold
a `[reducible]` class field, we also unfold the associated projection
`instLENat.1` using
`.instances` reducibility, ultimately returning `Nat.le a b`.
---------
Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR fixes the interaction between
`backward.whnf.reducibleClassField` and `isDefEqDelta`'s
argument-comparison heuristic.
When `backward.whnf.reducibleClassField` is enabled, `unfoldDefault`
reduces class field projections past the `.proj` form at `.instances`
transparency. This causes `isDefEqDelta` to lose the instance structure
that `isDefEqProj` needs to bump transparency for instance-implicit
parameters. The fix adds an `.abbrev` branch in `isNonTrivialRegular`
that classifies class field projections as nontrivial when the option is
enabled, so `tryHeuristic` applies the argument-comparison heuristic
(with the correct transparency bump) instead of unfolding.
Key insight: all projection functions receive `.abbrev` kernel hints
(not `.regular`), regardless of their reducibility status. Structure
projections default to `.reducible` status, while class projections
default to `.semireducible` status. The old code only handled the
`.regular` case and treated everything else (including `.abbrev`) as
trivial.
Also fixes two minor comment issues in `tryHeuristic`: "non-trivial
regular definition" → "non-trivial definition" (since `.abbrev`
definitions can now be nontrivial too), and "when `f` is not simple" →
"when `f` is simple" (logic inversion in the original comment).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a new, extensible `do` elaborator. Users can opt into the
new elaborator by unsetting the option `backward.do.legacy`.
New elaborators for the builtin `doElem` syntax category can be
registered with attribute `doElem_elab`. For new syntax, additionally a
control info handler must be registered with attribute
`doElem_control_info` that specifies whether the new syntax `return`s
early, `break`s, `continue`s and which `mut` vars it reassigns.
Do elaborators have type ``TSyntax `doElem → DoElemCont → DoElabM
Expr``, where `DoElabM` is essentially `TermElabM` and the `DoElemCont`
represents how the rest of the `do` block is to be elaborated. Consult
the docstrings for more details.
Breaking Changes:
* The syntax for `let pat := rhs | otherwise` and similar now scope over
the `doSeq` that follows. Furthermore, `otherwise` and the sequence that
follows are now `doSeqIndented` in order not to steal syntax from record
syntax.
Breaking Changes when opting into the new `do` elaborator by unsetting
`backward.do.legacy`:
* `do` notation now always requires `Pure`.
* `do match` is now always non-dependent. There is `do match (dependent
:= true)` that expands to a
term match as a workaround for some dependent uses.
This PR makes `isDefEqProj` bump transparency to `.instances` (via
`withInstanceConfig`) when comparing the struct arguments of class
projections. This makes the behavior consistent with `isDefEqArgs`,
which already applies the same bump for instance-implicit parameters
when comparing function applications.
When a class field like `X.x` is marked `@[reducible]`, `isDefEqDelta`
unfolds it to `.proj` form. Previously, `isDefEqProj` compared the
struct arguments at the ambient transparency (`.reducible` in simp),
which meant instance definitions (which are `[implicit_reducible]`)
could not be unfolded, causing `eq_self` to fail. In the function
application form (`X.x inst` vs `X.x inst'`), `isDefEqArgs` correctly
bumps to `.instances` for the instance-implicit parameter. The `.proj`
path should behave the same way.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR updates the CLAUDE.md instructions to better conform with our PR
conventions. Specifically, it clarifies that PR bodies must start with
"This PR" (which gets incorporated into release notes), and that
markdown headings like `## Summary` or `## Test plan` should not be used
in PR descriptions.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a System F formalization as a `cbv` tactic benchmark. It is
a translation of the Rocq case study from:
*Definitional Proof Irrelevance Made Accessible* by Thiago Felicissimo,
Yann Leray, Loïc Pujet, Nicolas Tabareau, Éric Tanter, Théo Winterhalter
The authors have given permission to use their development.
The benchmark includes:
- A full System F formalization (substitution lemmas, confluence of
λ-calculus, strong normalization)
- A `pow2DoubleEq` benchmark that verifies 2^(n+1) = 2^n + 2^n via
normalization in System F, measuring both `cbv` tactic time and kernel
checking time for n = 0..6
Co-Authored-By: @david-christiansen
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
This PR fixes a bug where `simp` made no progress on class projection
reductions when `backward.whnf.reducibleClassField` is `true`.
- In `reduceProjFn?`, for class projections applied to constructor
instances (`Class.projFn (Class.mk ...)`), the code called
`reduceProjCont? (← unfoldDefinitionAny? e)`. The helper
`reduceProjCont?` expects the unfolded result to have a `.proj` head so
it can apply `reduceProj?`. However, when `reducibleClassField` is
enabled, `unfoldDefault` in WHNF.lean already reduces the `.proj` node
during unfolding, so `reduceProjCont?` discards the fully-reduced
result.
- The fix uses `unfoldDefinitionAny?` directly, bypassing
`reduceProjCont?`. The dsimp traversal revisits the result (via
`.visit`) and handles any remaining `.proj` nodes naturally.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a bug where `reduceRecMatcher?` and `reduceProj?` bypassed
the `@[cbv_opaque]` attribute. These kernel-level reduction functions
use `whnf` internally, which does not know about `@[cbv_opaque]`. This
meant `@[cbv_opaque]` values were unfolded when they appeared as match
discriminants, recursor major premises, or projection targets. The fix
introduces `withCbvOpaqueGuard`, which wraps these calls with
`withCanUnfoldPred` to prevent `whnf` from unfolding `@[cbv_opaque]`
definitions.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a flipped condition in `handleConst` that prevented `cbv`
from unfolding nullary (non-function) constant definitions like
`def myVal : Nat := 42`. The check `unless eType matches .forallE` was
intended to skip bare function constants (whose unfold theorems expect
arguments) but instead skipped value constants. The fix changes the
guard to `if eType matches .forallE`, matching the logic used in the
standard `simp` ground evaluator.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR removes the type correction heuristic from the RC pass as it is
already present in the
boxing pass. Previously the boxing pass did not try to correct types so
the RC pass did. We
discovered issues with not doing this in the boxing pass and
accidentally maintained two corrections
for a while. This PR merges both and removes the one from RC.
This PR fixes a crash in the `cbv` tactic's `handleProj` simproc when
processing a dependent projection (e.g. `Sigma.snd`) whose struct is
rewritten via `@[cbv_eval]` to a non-definitionally-equal term that
cannot be further reduced.
- Previously, `handleProj` returned `.rfl (done := false)`, causing the
`.proj` expression to flow into `simpStep` which throws "unexpected
kernel projection term"
- The fix marks the result as `done := true` so that `cbv` gracefully
gets stuck instead of crashing
- Adds regression tests for dependent projections on `Sigma`, custom
structures, and `Subtype`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR registers the
[leanprover/skills](https://github.com/leanprover/skills) plugin
marketplace in `.claude/settings.json` so that Claude Code users working
on lean4 are automatically prompted to install it.
Also un-ignores `.claude/settings.json` in `.gitignore` — the blanket
`settings.json` rule was blocking it from being tracked.
🤖 Prepared with Claude Code
This PR makes the derived value analysis in RC insertion recognize
`Array.uget` as another kind of
"projection-like" operation. This allows it to reduce reference count
pressure on elements accessed
through uget.
This PR implements lazy initialization of closed terms. Previous work
has already made sure that ~70% of the closed terms occurring in core
can be statically initialized from the binary. With this the remaining
ones are initialized lazily instead of at startup.
For this we implement a small statically initializable lock that goes
with each term. When trying to access the term we quickly check a flag
to say whether it has already been initialized. If not we take the lock
and initialize it, otherwise we dereference the pointer and fetch the
value.
This PR removes `Subarray.foldl(M)`, `Subarray.toArray` and
`Subarray.size` in favor of the `Std.Slice`-namespaced operations. Dot
notation will continue to work. If, say, `Subarray.size` is explicitly
referred to, an error suggesting to use `Std.Slice.size` will show up.
This PR adds a system-wide Lake configuration file and uses it to
configure the remote cache services used by `lake cache`.
The system configuration is written in TOML. The exact location of the
file is system dependent and can be controlled via the `LAKE_CONFIG`
environment variable, but is usually located at `~/.lake/config.toml`.
As an example, one can configure a custom S3 cache service like so:
**~/.lake/config.toml**
```toml
cache.defaultService = "my-s3"
cache.defaultUploadService = "my-s3"
[[cache.service]]
name = "my-s3"
kind = "s3"
artifactEndpoint = "https://my-s3.com/a0"
revisionEndpoint = "https://my-s3.com/r0"
```
If no `cache.defaultService` is configured, Lake will use Reservoir for
downloads by default. A Reservoir mirror (or Reservoir-like service) can
be configured using `kind = "reservoir"` and setting an `apiEndpoint`. A
list of configured cache service (one name per line) can be obtained via
`lake cache services`.
This PR is part 2 of the `implicit_reducible` refactoring (part 1:
#12567).
**Background.** When Lean checks definitional equality of function
applications
`f a₁ ... aₙ =?= f b₁ ... bₙ`, it compares arguments `aᵢ =?= bᵢ` at a
transparency level determined by the binder type. Previously, only
instance-implicit (`[C]`) arguments received a transparency bump to
`.instances`. With `backward.isDefEq.implicitBump` enabled, ALL implicit
arguments (`{x}`, `⦃x⦄`, and `[x]`) are bumped to `.instances`, so that
definitions marked `[implicit_reducible]` unfold when comparing implicit
arguments. This is important because implicit arguments often carry type
information (e.g., `P (i + 0)` vs `P i`) where the mismatch is in
non-proof positions (Sort arguments to `cast`) — proof irrelevance does
not
help here, so the relevant definitions must actually unfold.
**`[implicit_reducible]`** (renamed from `[instance_reducible]` in part
1) marks
definitions that should unfold at `TransparencyMode.instances` — between
`[reducible]` (unfolds at `.reducible` and above) and the default
`[semireducible]` (unfolds only at `.default` and above). This is the
right
level for core arithmetic operations that appear in type indices.
## Changes
- **Enable `backward.isDefEq.implicitBump` by default** and set it in
`stage0/src/stdlib_flags.h` so stage0 also compiles with it
- **Mark `Nat.add`, `Nat.mul`, `Nat.sub`, `Array.size` as
`[implicit_reducible]`**
so they unfold when comparing implicit arguments at `.instances`
transparency
- **Remove redundant unification hints** (`n + 0 =?= n`, `n - 0 =?= n`,
`n * 0 =?= 0`) that are now handled by `[implicit_reducible]`
- **Rename all remaining `[instance_reducible]` attribute usages** to
`[implicit_reducible]` across the codebase (the old name remains as an
alias)
- **Remove 28 `set_option backward.isDefEq.respectTransparency false
in`**
workarounds that are no longer needed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a warning when using `cbv` or `decide_cbv` in tactic mode,
matching the existing warning in conv mode
(`src/Lean/Elab/Tactic/Conv/Cbv.lean`). The warning informs users that
these tactics are experimental and still under development. It can be
disabled with `set_option cbv.warning false`.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR ports the RC insertion from IR to LCNF.
In doing so it makes the entire code monadic as opposed to simulating a
ReaderT StateRefT stack manually.
Cmake only builds cadical if it isn't already installed on the user's
system. However, it then force-updates the cache variable with the new
path to the built cadical binary, leading subsequent cmake calls to
believe cadical is already installed on the user's system.
This only becomes a problem when cmake is called more than once before
the first call to make, which apparently happens roughly never.
This PR adds an `Std.Do` spec lemma for `ForIn` over strings.
This spec lemma does not use the list cursor machinery used by other
spec lemmas, but instead is stated in terms of `String.Pos`, to be used
together with `String.Pos.Splits` (which is basically the same as the
list cursors, but specialized to strings).
This PR removes unnecessary `simp` call in `simpAppFn` in `cbv` tactic
and updates the usage of `cbv_eval` attribute in
`tests/lean.run/cbv1.lean` to follow the new syntax that does not
require an explicit name of the function for which we are registering
the unfold lemma.
This PR fixes a bug with rendering of hygiene info nodes in embedded
Verso code examples. The embedded anonymous identifier was being
rendered as [anonymous] instead of being omitted.
This PR improves the Sym VCGen such that we can use Sym.simp to unfold
definitions in the benchmark driver. To do so, it adds support for
zeta-reduction in the VCGen and ensures that proof terms are maximally
shared before being sent to the kernel.
This PR removes unnecessary `trySynthInstance ` in `ite` and `dite`
simprocs used by `cbv` that previously contributed to too much of
unnecessary unrolling by the tactic.
This PR fixes#12554 where the `cbv` tactic throws "unexpected kernel
projection term during structural definitional equality" when a rewrite
theorem's pattern contains a lambda and the expression being matched has
a `.proj` (kernel projection) at the corresponding position.
The `Sym` pattern matching infrastructure (`isDefEqMain` in
`Pattern.lean`) does not handle `.proj` expressions and can throw an
exception. Rather than presenting it as an error in `cbv`, we fail
quietly and let the `cbv` tactic try other fallback paths.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR inlines the accessor for the computed hash field of `Name`. This
ensures that accessing the
value is basically always just a single load instead of doing a full
function call.
This PR uses a `ptrEq` fast path for `Name.quickCmp`. It is particularly
effective at speeding up
`quickCmp` calls in `TreeMap`'s indexed by `FVarId` as usually there is
only one pointer per `FVarId`
so equality is always instantly detected without traversing the linked
list of `Name` components.
I had to use an `implemented_by` instead of just changing the definition
as lake proves things about
`quickCmp` for use in a `DTreeMap`.
This PR makes `computed_field` respect the inline attributes on the
function for computing the
field. This means we can inline the accessor for the field, allowing
quicker access.
This PR provides the necessary hooks for the new do elaborator to call
into the let and match elaborator.
The `do match` elaborator needs access to a couple of functions from the
term `match` elaborator to implement its own `elabMatchAlt`. In
particular, `withEqs`, `withPatternVars` and `checkNumPatterns` need to
be exposed. Furthermore, I think it makes sense to share
`instantiateAltLHSs`.
This PR adds `Sym.mkPatternFromDeclWithKey` to the Sym API to generalize
and implement `Sym.mkEqPatternFromDecl`. This is useful to implement
custom rewrite-like tactics that want to use `Pattern`s for
discrimination tree lookup.
This PR improves universe level inference for the `inductive` and
`structure` commands to be more reliable and to produce better error
messages. Recall that the main constraint for inductive types is that if
`u` is the universe level for the type and `u > 0`, then each
constructor field's universe level `v` satisfies `v ≤ u`, where a
*constructor field* is an argument that is not one of the type's
*parameters* (recall: the type's parameters are a prefix of the
parameters shared by the type former and all the constructors). Given
this constraint, the `inductive` elaborator attempts to find reasonable
assignments to metavariables that may be present:
- For the universe level `u`, choosing an assignment that makes this
level least is reasonable, provided it is unique.
- For constructor fields, choosing the unique assignment is usually
reasonable.
- For the type's parameters, promoting level metavariables to new
universe level parameters is reasonable.
The order of these steps led to somewhat convoluted error messages; for
example, metavariable->parameter promotion was done early, leading to
errors mentioning `u_1`, `u_2`, etc. instead of metavariables, as well
as extraneous level constraint errors. Furthermore, early parameter
promotion meant it was too late to perform certain kinds of inferences.
Now there is a straightforward order of inference:
1. If the type's universe level could be zero, it checks that the type
is an "obvious `Prop` candidate", which means it's non-recursive, has
one constructor with at least one field, and all the fields are proofs.
If it's a `Prop` candidate, the level is set to zero and we skip to step
4.
2. If the type's simplified universe level is of the form `?u + k`, it
will accumulate level constraints to find a least upper bound solution
for `?u`. To avoid sort polymorphism, it adds `1 ≤ ?u + k`, ensuring the
result stays in `Type _`, or at least `Sort (max 1 _)`. It allows other
metavariables to appear in the assignment for `?u`, provided they appear
in the type former, or for `structure` in the `extends` clause.
3. If the type's simplified universe level is then of the form `r + k`,
where `r` is a parameter, metavariable, or zero, then for every
constructor field it will take the `v ≤ r + k` constraint and extract
`?v ≤ r + k'` constraints. It will also *weakly* extract `1 ≤ ?v`
constraints, using the observation that it's surprising if fields are
automatically inferred to be proofs. Once the constraints are collected,
each metavariable is solved for independently. Heuristically, if there
is a unique non-constant solution we take that, or else a unique
constant solution.
4. Any remaining level metavariables in the type former (or `extends`
clause) become level parameters.
5. Remaining level metavariables in the constructor fields are reported
as errors.
6. Then, the elaborator checks that the level constraints actually hold
and reports an error if they don't.
In 2 and 3, there are procedures to simplify universe levels. You can
write `Sort (max 1 _)` for the resulting type now and it will solve for
`_`.
The "accidentally higher universe" error is now a warning. The
constraint solving is also done in a more careful way, which keeps it
from being reported erroneously. There are still some erroneous reports,
but these ones are hard for the checker to reject. As before, the
warning can be turned off by giving an explicit universe.
Note about `extends` clauses: in testing, there were examples where it
was surprising if the universe polymorphism of parent structures didn't
carry over to the type being defined, even though parent structures are
actually constructor fields.
**Breaking change.** Universe level metavariables present only in
constructor fields are no longer promoted to be universe level
parameters: use explicit universe level parameters. This promotion was
inconsistently done depending on whether the inductive type's universe
level had a metavariable, and also it caused confusion for users, since
these universe levels are not constrained by the type former's
parameters.
**Breaking change.** Now recursive types do not count as "obvious `Prop`
candidates". Use an explicit `Prop` type former annotation on recursive
inductive predicates.
Additional changes:
- level metavariable errors are now localized to constructors, and
`structure` fields have such errors localized to fields
- adds module docs for the index promotion algorithm and the universe
level inference algorithm for inductives
- factors out `Lean.Elab.Term.forEachExprWithExposedLevelMVars` for
printing out the context of an expression with universe level
metavariables
- makes universe level metavariable exposure more effective at exposing
level metavariables (with an exception of `sorry` terms, which are too
noisy to expose)
Supersedes #11513 and #11524.
This PR removes `tryMatchEquations` and `tryMatcher` from
`Lean.Meta.Tactic.Cbv.Main`, as both are already defined and used in
`Lean.Meta.Tactic.Cbv.ControlFlow`. The copies in `Main.lean` were
unreachable dead code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR renames `instance_reducible` to `implicit_reducible` and adds a
new
`backward.isDefEq.implicitBump` option to prepare for treating all
implicit
arguments uniformly during definitional equality checking.
## Changes
**Rename `instance_reducible` → `implicit_reducible`:**
- Rename `ReducibilityStatus.instanceReducible` constructor to
`implicitReducible`
- Register new `[implicit_reducible]` attribute, keep
`[instance_reducible]` as alias
- Rename `isInstanceReducible` → `isImplicitReducible` (with deprecated
aliases)
- Update all references across src/ and tests/
The rename reflects that this reducibility level is used not just for
instances
but for any definition that needs unfolding during implicit argument
resolution
(e.g., `Nat.add`, `Array.size`).
**Add `backward.isDefEq.implicitBump` option:**
- When `true` (+ `respectTransparency`), bumps transparency to
`.instances` for
ALL implicit arguments in `isDefEqArgs`, not just instance-implicit ones
- Defaults to `false` for staging compatibility — will be flipped to
`true` after
stage0 update
- Adds `// update me!` to `stage0/src/stdlib_flags.h` to trigger CI
stage0 update
## Follow-up (after stage0 update)
- Flip `backward.isDefEq.implicitBump` default to `true`
- Fix resulting test/module failures
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary
This PR adds documentation comments to the key transparency-related
definitions explaining the design rationale behind the transparency
hierarchy and the v4.29 changes:
- `TransparencyMode`: explains "try-hard" vs "speculative" `isDefEq`,
the transparency hierarchy (`none < reducible < instances < default <
all`), instance diamonds, and why implicit arguments received special
treatment
- `ReducibilityStatus`: documents each status with its corresponding
`TransparencyMode` level and typical use case
- `@[instance_reducible]`: explains decoupling of instance registration
from transparency
- `backward.isDefEq.respectTransparency`: explains the original
motivation for bumping transparency on implicit arguments, and why it
became a performance bottleneck
- `backward.whnf.reducibleClassField`: explains why `[reducible]` class
fields need special handling when the instance is only
`[instance_reducible]`
- `canUnfoldDefault` and `isDefEqArgs`: brief inline comments linking to
the design rationale
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a `(kernel) declaration has metavariables` error that
occurred when a `by` tactic was used in a dependent inductive type index
that refers to a previous index:
```lean
axiom P : Prop
axiom Q : P → Prop
-- Previously gave: (kernel) declaration has metavariables 'Foo'
inductive Foo : (h : P) → (Q (by exact h)) → Prop
```
The root cause: `elabDepArrow` calls `mkForallFVars [h_fvar] body`
before the `by` tactic's metavariable `?m` is resolved. Since `h_fvar`
is in `?m`'s local context, `elimMVarDeps` creates a delayed assignment
`?newMVar #[h_fvar] := ?m`. After `synthesizeSyntheticMVarsNoPostponing`
assigns `?m := h_fvar`, `instantiateMVars` can resolve the delayed
assignment (substituting `h_fvar` with the actual argument, `bvar 0`, in
the pending value), yielding the correct type `∀ (h : P), Q (bvar 0) →
Prop`. The fix is to call `instantiateMVars` on the header type right
after `synthesizeSyntheticMVarsNoPostponing` in `elabHeadersAux`.
Fixes#12543.
🤖 This PR was created with [Claude Code](https://claude.ai/claude-code).
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This PR fixes an issue where commands that do not support incrementality
did not have their elaboration interrupted when a relevant edit is made
by the user. As all built-in variants of def/theorem share a common
incremental elaborator, this likely had negligible impact on standard
Lean files but could affect other use cases heavily relying on custom
commands such as Verso.
This PR fixes a bug where Lake recached artifacts already present within
the cache. As a result, Lake would attempt to overwrite the read-only
artifacts, causing a permission denied error.
This PR adds guidance to `.claude/CLAUDE.md` about the `module` +
`prelude` convention required for files in `src/Lean/`, `src/Std/`, and
`src/lake/Lake/`. CI enforces that these files contain `prelude`, but
with `prelude` nothing is auto-imported, so explicit `Init.*` imports
are needed for standard library features like `while`,
`String.startsWith`, etc.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a "Copyright Headers" section to `.claude/CLAUDE.md`
instructing Claude to:
- Always use `date +%Y` for the copyright year instead of relying on
memory
- Match the copyright holder to what the author uses in other recent
files in the repo
- Skip copyright headers for test files in `tests/`
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds guidance to the release slash command to check actual PR
merge state (using `gh pr view`) when reporting status, rather than
relying on cached CI results. This prevents incorrectly reporting
already-merged PRs as still needing review.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR removes the batteries dependency from ProofWidgets4 in
`release_repos.yml`. ProofWidgets4 no longer has any `require`
statements in its lakefile, so it doesn't depend on batteries.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The `releases_drafts/` folder contained two entries that were already
covered in earlier releases:
- `module-system.md` — the module system was stabilized in v4.27.0
(https://github.com/leanprover/lean4/pull/11637)
- `environment.md` — the `importModules`/`finalizeImport` `loadExts`
change landed in v4.20.0 (https://github.com/leanprover/lean4/pull/6325)
Discovered while preparing the v4.29.0-rc1 release notes.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR begins the development cycle for v4.30.0 by updating
`LEAN_VERSION_MINOR` to 30 in `src/CMakeLists.txt`.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a bug with `cache clean` where it would fail if the cache
directory does not exist.
This introduces a `removeDirAllIfExists` utility which is also now used
in `lake clean`. While `lake clean` did previously check for a
nonexistent build directory, this version should be more robust to
racing runs of `lake clean` as well.
This PR bundles some lemmas about hash maps into equivalences for easier
rewriting.
It still makes sense to have the individual directions since they
sometimes have weaker typeclass assumptions.
This PR improves the error messages produced by the `decide_cbv` tactic
by only reducing the left-hand side of the equality introduced by
`of_decide_eq_true`, rather than attempting to reduce both sides via
`cbvGoal`.
Previously, `evalDecideCbv` called `cbvGoalCore` which would try to
reduce both sides of `decide P = true` and leave a remaining goal on
failure, resulting in a generic error showing the mvar ID. Now, a
dedicated `cbvDecideGoal` function in `Cbv/Main.lean`:
- closes the goal immediately when the LHS reduces to `Bool.true`
- reports a clear error when the LHS reduces to `Bool.false`, telling
the user the proposition is false
- reports a clear error with the stuck expression when reduction cannot
complete
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This PR improves the error message when `mvcgen` cannot resolve the name
of a spec theorem.
Example:
```lean
/-- error: Could not resolve spec theorem `abc` -/
#guard_msgs (error) in
example : True := by mvcgen [abc]
```
This used to print the syntax object representing the ident "abc".
This PR adds declaration names to leanchecker error messages to make
debugging easier when the kernel rejects a declaration.
Previously, leanchecker would only show the kernel error without
identifying which declaration failed:
```
uncaught exception: (kernel) type checker does not support loose bound variables
```
Now it includes the declaration name:
```
uncaught exception: while replaying declaration 'myDecl':
(kernel) type checker does not support loose bound variables
```
Fixes: #11937
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nomeata <148037+nomeata@users.noreply.github.com>
This PR adds `Std.Iter.toHashSet` and variants.
Included: variants starting from both monadic and non-monadic iterators,
producing extensional and non-extensional hash sets and tree sets.
Lemmas are included, showing that `it.toHashSet ~m HashSet.ofList
it.toList` (equivalence of hash sets) and `it.toExtHashSet =
ExtHashSet.ofList it.toList` (equality of extensional hash sets).
This PR adds the ability to register theorems with the `cbv_eval`
attribute in the reverse direction using the `←` modifier, mirroring the
existing `simp` attribute behavior. When `@[cbv_eval ←]` is used, the
equation `lhs = rhs` is inverted to `rhs = lhs`, allowing `cbv` to
rewrite occurrences of `rhs` to `lhs`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR shows `HashSet.ofList l ~m l.foldl (init := ∅) fun acc a =>
acc.insert a` (which is "just" the definition).
We also include the analogous statement about `insertMany`, and prove
this lemmas for dependent hash maps, normal hash maps, hash sets, as
well as the raw and extensional versions, and of course we also give the
corresponding tree map statements.
This PR adds tooling for profiling Lean programs with human-readable
function names in Firefox Profiler:
- **`script/lean_profile.sh`** — One-command pipeline: record with
samply, symbolicate, demangle, and open in Firefox Profiler
- **`script/profiler/lean_demangle.py`** — Faithful port of
`Name.demangleAux` from `NameMangling.lean`, with a postprocessor that
folds compiler suffixes into compact annotations (`[λ, arity↓]`, `spec
at context[flags]`)
- **`script/profiler/symbolicate_profile.py`** — Resolves raw addresses
via samply's symbolication API
- **`script/profiler/serve_profile.py`** — Serves demangled profiles to
Firefox Profiler without re-symbolication
- **`PROFILER_README.md`** — Documentation including a guide to reading
demangled names
### Example output in Firefox Profiler
| Raw C symbol | Demangled |
|---|---|
| `l_Lean_Meta_Sym_main` | `Lean.Meta.Sym.main` |
| `l_Lean_Meta_foo___redArg___lam__0` | `Lean.Meta.foo [λ, arity↓]` |
| `l_Lean_MVarId_withContext___at__...___spec__2___boxed` |
`Lean.MVarId.withContext [boxed] spec at Lean.Meta.bar[λ, arity↓]` |
Example:
<img width="1145" height="570" alt="image"
src="https://github.com/user-attachments/assets/8d23cc6a-1b89-4c60-9f4a-9f9f0f6e7697"
/>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a bug where `grind [foo]` fails when the theorem `foo` has
a different universe variable name than the goal, even though universe
polymorphism should allow the universes to unify.
The issue was in `instantiateGroundTheorem` (used for theorems with no
quantified parameters), which was passing `thm.proof` directly instead
of calling `getProofWithFreshMVarLevels`. This meant ground theorems
retained their original universe level params instead of getting fresh
level metavariables that could unify with the goal's universe levels.
Fixes
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/grind.20fails.20because.20of.20universe.20variable.20name🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes a release workflow bug where the reference-manual
repository would get tagged with a stale release notes title (e.g.,
still showing "-rc1" for a stable release).
The root cause was a sequencing issue: `release_steps.py` didn't update
the release notes title when bumping the reference-manual toolchain, and
`release_checklist.py` only checked the title while the bump PR was
open. Once merged, it went straight to tagging without rechecking.
Two fixes:
- `release_checklist.py`: add a title correctness check before tagging
reference-manual (blocks tagging if the title is wrong)
- `release_steps.py`: automatically update the `#doc` title line in the
release notes file when bumping reference-manual (handles both
RC-to-stable and RC-to-RC transitions)
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR proves that membership is preserved by eraseDups: an element
exists in the deduplicated list iff it was in the original.
Includes a helper lemma for the loop invariant of eraseDupsBy.loop to
establish the relationship between membership in the result, remaining
list, and accumulator.
The proof changed compared to the proposal discussed on Zulip:
https://leanprover.zulipchat.com/#narrow/channel/348111-batteries/topic/Where.20should.20List.2Emem_eraseDup.20and.20List.2Emem_eraseDups.20l.2E.2E.2E
Specifically, I could not apply @Rob23oba 's short proof suggestion
because it is located in `src/Init/Data`, a context where the `grind`
strategy is not yet available.
In the Zulip thread, there is a discussion about the
similarities/differences between Lean's `List.eraseDups` and Batteries'
`List.eraseDup`; whether it makes sense to keep both (perhaps with a
suitable renaming of Batterie's definition) or deprecate one (if any, it
would be Batteries' since it is currently unused whereas Lean's is used
across the board in Lean, Batteries, and Mathlib). See the Batteries PR:
https://github.com/leanprover-community/batteries/pull/1580
changelog-library
Closes https://github.com/leanprover/lean4/issues/11786
---------
Co-authored-by: Kim Morrison <477956+kim-em@users.noreply.github.com>
This PR introduces the theorem
`BitVec.sshiftRight_eq_setWidth_extractLsb_signExtend` theorem, proving
`x.sshiftRight n` is equivalent to first sign-extending `x`, extracting
the appropriate least significant bits, and then setting the width back
to `w`.
---------
Co-authored-by: Tobias Grosser <github@grosser.es>
This PR strips unneeded symbol names from libleanshared.so on Linux. It
appears that on other platforms the symbols names we are interested in
here are already removed by the linker.
This PR deprecates `extract_eq_drop_take` in favor of the more correct
name `extract_eq_take_drop`, so that we'll be able to use the old name
for a lemma `xs.extract start stop = (xs.take stop).drop start`. Until
the deprecation deadline has passed, this new lemma will be called
`extract_eq_drop_take'`.
This PR adds automatic ProofWidgets4 version pin updates to
`release_steps.py` when processing mathlib4. ProofWidgets4 uses
sequential version tags (`v0.0.X`) rather than toolchain-based tags
(`v4.X.Y`), so the existing regex that updates dependency versions in
lakefiles doesn't match it. This has caused CI failures in two
consecutive releases where the mathlib4 PR was created with a stale
ProofWidgets4 pin.
Changes:
- `script/release_steps.py`: Add `find_proofwidgets_tag()` to look up
the latest ProofWidgets4 tag compatible with the target toolchain, and
use it to update mathlib4's lakefile automatically
- `doc/dev/release_checklist.md`: Document the ProofWidgets4 pin update
step for mathlib4
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes#12495 where equational theorem generation fails for
structurally recursive definitions using a Box-like wrapper around
nested inductives.
## Root Cause
`withInferTypeConfig` (in `InferType.lean`) ensures various MetaM config
settings (`beta`, `iota`, `zeta`, `zetaHave`, `zetaDelta`, `proj`) are
enabled during type inference, but was missing `etaStruct`. When
`inferType` is called from a context where `etaStruct` is disabled —
such as inside `simpMatch` (which sets `etaStruct := .none` via
`SimpM.run` → `withSimpContext`) — `whnf` cannot eta-expand structure
values needed for recursor iota reduction.
Concretely, projecting from a type like `Rec.rec_2 ... base` (where
`base : Box Rec`) requires eta-expanding `base` to `Box.mk base.data` so
the `Box` recursor can reduce. With `etaStruct := .none`,
`toCtorWhenStructure` skips the eta-expansion, leaving `whnf` stuck and
`inferProjType` unable to recognize the resulting type as a structure.
## Fix
Add `etaStruct := .all` to the config settings ensured by
`withInferTypeConfig`, alongside the existing `beta`, `iota`, `zeta`,
`zetaHave`, `zetaDelta`, and `proj` settings. This also allows reverting
the workaround (`try/catch` around `simpMatch?`) that was added in the
first commit.
## Test plan
- [x] Existing test `tests/lean/run/issue12495.lean` passes
- [x] Full test suite (3561 tests) passes with 0 failures
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Avoids wasted work in `setImportedEntries`. This is still not ideal as
exts that are set but never/rarely read still have a cost proportional
to the number of imported modules but it's an easy step forward.
This PR removes the unnecessary and potentially broken handling of
`let`s by zeta-reduction in Sym-based `mvcgen`.
It turns out to be unnecessary for the benchmarks so far, so there is a
lack of motivation to publicize `betaRevS` which would be needed to fix
it.
This PR ensures `isDefEq` does not increase the transparency mode to
`.default` when checking whether implicit arguments are definitionally
equal. The previous behavior was creating scalability problems in
Mathlib. That said, this is a very disruptive change. The previous
behavior can be restored using the command
```
set_option backward.isDefEq.respectTransparency false
```
This PR makes the `Rat.abs_*` lemmas (`abs_zero`, `abs_nonneg`,
`abs_of_nonneg`, `abs_of_nonpos`, `abs_neg`, `abs_sub_comm`,
`abs_eq_zero_iff`, `abs_pos_iff`) protected, so they don't shadow the
general `abs_*` lemmas when the `Rat` namespace is opened in downstream
projects.
All internal references already use the fully qualified `Rat.abs_*`
form, so this is a no-op within lean4 itself.
Suggested by @Rob23oba in
https://github.com/leanprover-community/mathlib4-nightly-testing/pull/177#discussion_r2812925068.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR shares the driver code from the Sym-based mvcgen benchmarks. It
also moves the `simp only [loop, step]` call out of the measured
section, so that we measure purely the overhead of VC generation.
The new benchmark results are as follows. All measurements for n=1000:
```
baseline_add_sub_cancel: 719.318425 ms, kernel: 382.708178 ms
vcgen_add_sub_cancel: 306.883079 ms, kernel: 455.050825 ms
vcgen_deep_add_sub_cancel: 543.350543 ms, kernel: 896.926298 ms
vcgen_get_throw_set: 669.566541 ms, kernel: 60754.202714 ms
```
Note that `vcgen_add_sub_cancel` sped up by 100% because we no longer
measure unfolding `loop` and `step`. The baseline didn't speed up as
much because it unfolded in the same `Sym.simp` call that also does
other rewrites, so there was no `simp` pass that could be eliminated.
This PR fixes a diamond problem in delta deriving where
instance-implicit class parameters in the derived instance type were
using instances synthesized for the underlying type, not the alias type.
When deriving an instance for a type alias (e.g., `def ENat := WithTop
ℕ`), this caused a diamond when the alias has its own instance for a
dependency class (e.g., `AddMonoidWithOne` from `CommSemiring`) that
differs from the underlying type's instance (e.g.,
`WithTop.addMonoidWithOne`). Instance search would fail because it
expected the alias's instance but the derived instance used the
underlying's.
The fix: after synthesis succeeds, for each instance-implicit class
parameter, re-synthesize for the target type and use that instance if
it's defeq to what we synthesized for the underlying type.
### Example
```lean
class MyBase (α : Type) where value : Nat := 42
class MyHigher (α : Type) [MyBase α] : Prop where prop : True
instance instBaseNat : MyBase Nat := {}
def MyAlias := Nat
instance instBaseMyAlias : MyBase MyAlias := {} -- Different expression, but defeq
instance instHigherNat : MyHigher Nat where prop := trivial
deriving instance MyHigher for MyAlias
```
**Before**: `instMyHigherMyAlias : @MyHigher MyAlias instBaseNat` →
instance search fails
**After**: `instMyHigherMyAlias : @MyHigher MyAlias instBaseMyAlias` →
instance search succeeds
### Motivation
This fixes the `CharZero ℕ∞` diamond in Mathlib under #12179 where the
derived instance was using `WithTop.addMonoidWithOne` instead of the
`AddMonoidWithOne` from `CommSemiring ℕ∞`.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR expands the docstring for `@[univ_out_params]` to explain:
- How universe output parameters affect the typeclass resolution cache
(they are erased from cache keys, so queries differing only in output
universes share entries)
- When a universe parameter should be considered an output (determined
by inputs) vs. not (part of the question being asked)
This came up while adapting Mathlib for lean4#12286 and lean4#12423. We
needed `@[univ_out_params]` on ~19 classes (`Category`,
`HasLimitsOfSize`, `PreservesLimitsOfSize`, `Functor.IsContinuous`,
`UCompactlyGeneratedSpace`, etc.)
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR ensures the type resolution cache properly caches results for
type classe containing output parameters.
It ensures the cache key for a query like
```
HAppend.{0, 0, ?u} (BitVec 8) (BitVec 8) ?m
```
should be independent of the specific metavariable IDs in output
parameter positions. To achieve this, output parameter arguments are
erased from the cache key. Universe levels that only appear in output
parameter types (e.g., ?u corresponding to the result type's universe)
must also be erased to avoid cache misses when the same query is issued
with different universe metavariable IDs.
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR adds support for higher-order Miller patterns in `grind`'s
e-matching engine.
Previously, lambda arguments in e-matching patterns were always treated
as `dontCare`, meaning
they could not contribute to matching or bind pattern variables. This
was a significant limitation
for theorems where lambda arguments carry essential structure, such as
`List.foldl`, `List.foldrM`,
or any combinator that takes a function argument.
With this change, when a pattern argument is a lambda whose body
satisfies the **Miller pattern
condition** — i.e., pattern variables are applied only to distinct
lambda-bound variables — the
lambda is preserved as an `ho[...]` pattern. At instantiation time,
these higher-order patterns
are matched via `isDefEq` after all first-order pattern variables have
been assigned by the E-graph.
### Example
```lean
@[grind =] theorem applyFlip_spec (f : Nat → Nat → Nat) (a b : Nat)
: applyFlip (fun x y => f y x) a b = f b a := sorry
```
The pattern `applyFlip ho[fun x => fun y => #2 y x] #1 #0` captures the
lambda argument
structurally: `#2` (the pattern variable for `f`) is applied to distinct
lambda-bound
variables `y` and `x`. When `grind` encounters `applyFlip (fun x y =>
Nat.add y x) 3 4`,
it binds `f := Nat.add` via `isDefEq` and fires the rewrite.
### Key design decisions
- **Miller condition check**: Only lambdas where at least one pattern
variable appears
in applied Miller position (applied to distinct lambda-bound vars) are
promoted to
`ho[...]`. Other lambdas remain `dontCare`.
- **Redundancy elimination**: A post-processing pass demotes `ho[...]`
patterns to `dontCare`
if all their pattern variables already appear in non-HO positions of the
same pattern. This
avoids unnecessary `isDefEq` calls when the lambda doesn't contribute
new variable bindings.
- **E-graph bypass**: HO patterns are not internalized into the E-graph.
They are accumulated
during matching and checked via `isDefEq` after the first-order
assignment is complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes an internal `grind` error where `mkEqProof` is invoked
with terms of different types. When equivalence classes contain
heterogeneous equalities (e.g., `0 : Fin 3` and `0 : Fin 2` merged via
`HEq`), `closeGoalWithValuesEq` would call `mkEqProof` on terms with
incompatible types, triggering an internal error.
Closes#12140🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes#12245 where `grind` works on `Fin n` but fails on `Fin (n
+ 1)`.
The `outParam` argument (e.g., the `range` parameter of `ToInt`) was
included as a relevant position in the e-matching pattern. The `grind`
normalizer rewrites `↑(n + 1)` to `↑n + 1` inside the range expression,
causing the pattern to no longer match. Since `outParam` arguments are
uniquely determined by type class resolution, they can be safely
wildcarded in patterns — the same reasoning that already applies to
instance-implicit arguments.
Reproducer from the issue:
```lean
example {n : Nat} {a : Fin (n + 1)} {b : Nat} (hb : b < n + 1)
(h : (a : Nat) < b) : a < ⟨b, hb⟩ := by grind -- fails without fix
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes `grind` failing when hypotheses contain metavariables
(e.g., after `refine`). The root cause was that `abstractMVars` in
`withProtectedMCtx` only abstracted metavariables in the target, not in
hypotheses, creating a disconnect in grind's e-graph.
The fix removes `abstractMVars` and instead resolves delayed
metavariable assignments before exiting `withNewMCtxDepth`.
`instantiateMVars` refuses to resolve a delayed assignment when the
pending assignment is non-ground (contains unassigned expression
metavariables). This function converts such delayed assignments to
regular ones using `LocalContext.mkLambda`, allowing `instantiateMVars`
to resolve them via beta reduction. The mvar internalization warning is
also removed since grind now handles mvars.
Closes#12242
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a panic in `grind` where `sreifyCore?` could encounter
power subterms not yet internalized in the E-graph during nested
propagation. The ring reifier (`reifyCore?`) already had a defensive
`alreadyInternalized` check before creating variables, but the semiring
reifier (`sreifyCore?`) was missing this guard. When `propagatePower`
decomposed `a ^ (b₁ + b₂)` into `a^b₁ * a^b₂` and the resulting terms
triggered further propagation, the semiring reifier could be called on
subterms not yet in the E-graph, causing `markTerm` to fail.
Closes#12428🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes an assertion violation in `grind` reported at #12246 This
assertion fails when in examples containing heterogenous equalities with
elements of different types (e.g., `Fin n` and `Fin m`) attached to the
same theory solver.
Closes#12246
This PR fixes an `AppBuilder` exception in the `cbv` tactic when
simplifying projections whose projection function is dependent (closes
#12457).
Previously, `handleProj` unconditionally used `mkCongrArg` to prove `e.i
= e'.i` from `e = e'`, but `mkCongrArg` requires a non-dependent
function. For dependent projections (e.g., `fun x => x.2 : (x :
String.Slice) → x.1.Pos`), this would fail.
Now, `handleProj` first checks whether the projection function type is
non-dependent (a simple arrow). If so, it proceeds with `mkCongrArg` as
before. Otherwise, it falls back to:
1. Attempting to reduce the projection directly.
2. If reduction fails, using a heterogeneous congruence lemma
(`mkHCongr`) converted to an equality via `mkEqOfHEq`, provided the
original and rewritten struct are definitionally equal.
This PR implements two changes to LRAT checking in `bv_decide`:
1. The LRAT trimmer previously used to drop delete instructions as we
did not act upon them in a meaningful way (as explained in 2). Now it
figures out the earliest point after which a clause may be deleted in
the trimmed LRAT proof and inserts a deletion there.
2. The LRAT checker takes in an `Array IntAction` and explodes it into
an `Array DefaultClauseAction` before passing it into the checking loop.
`DefaultClauseAction` has a much larger memory footprint compared to
`IntAction`. Thus materializing the entire proof as
`DefaultClauseAction` upfront consumes a lot of memory. In the adapted
LRAT checker we take in an `Array IntAction` and only ever convert the
step we are currently working on to a `DefaultClauseAction`. In
combination with the fact that we now insert deletion instructions this
can drastically reduce memory consumption.
In SMT-LIB's 20210312-Bouvier/vlsat3_a11.smt2 memory consumption went
from 8GB+ to 3.7GB through this combination of changes.
This PR fixes two issues discovered during the first test of the revised
nightly release workflow
(https://github.com/leanprover/lean4/pull/12461):
**1. Date logic:** The `workflow_dispatch` path used `date -u +%F`
(current UTC date) to find the base nightly to revise. If the most
recent nightly was from yesterday (e.g. `nightly-2026-02-12`) but UTC
has rolled over to Feb 13, the code would look for `nightly-2026-02-13`,
not find it, and create a fresh nightly instead of a revision. Now finds
the latest `nightly-*` tag via `sort -rV` and creates a revision of
that.
**2. Mathlib trigger:** The "Update toolchain on mathlib4's
nightly-testing branch" step was broken in two ways:
- Workflow renamed: `nightly_bump_toolchain.yml` →
`nightly_bump_and_merge.yml` (leanprover-community/mathlib4#34827)
- `MATHLIB4_BOT` PAT expired after mathlib migrated to GitHub Apps
(leanprover-community/mathlib4#34751)
- Replace with `actions/create-github-app-token` using the
`mathlib-nightly-testing` app, matching the pattern used in mathlib4's
own workflows.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This adds the ancillary materials for the IJCAR 2026 grind paper to
`doc/examples/IJCAR2026/`.
- `examples.lean`: interactive examples from the paper
- `analyze_grind_loc.py`: script used for the evaluation section
(analyzing grind adoption LoC changes in mathlib)
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds support for manually re-releasing nightlies when a build
issue or critical fix requires it. When a `workflow_dispatch` triggers
the nightly release job and a `nightly-YYYY-MM-DD` tag already exists,
the CI now creates `nightly-YYYY-MM-DD-rev1` (then `-rev2`, etc.)
instead of silently skipping.
### Lake `ToolchainVer`
- Extend `ToolchainVer.nightly` with an optional `rev : Option Nat`
field
- Parse `-revK` suffixes from nightly tags in `ofString`
- Ordering: `nightly-YYYY-MM-DD` < `nightly-YYYY-MM-DD-rev1` < `-rev2` <
`nightly-YYYY-MM-DD+1`
- Round-trip: `toString (ofString s) == s` for both variants
### CI workflow
- "Set Nightly" step probes existing tags on `workflow_dispatch` to find
next available `-revK`
- Scheduled nightlies retain existing behavior (skip if commit already
tagged)
- Changelog grep updated from `nightly-[-0-9]*` to `nightly-[^ ,)]*` to
match `-revK` suffixes
### `lean-bisect`
- Updated `NIGHTLY_PATTERN` regex, sort key, error messages, and help
text
### Companion PRs
- https://github.com/leanprover-community/mathlib4/pull/35220: update
`nightly_bump_and_merge.yml` tag grep and `nightly_detect_failure.yml`
warning message
-
https://github.com/leanprover-community/leanprover-community.github.io/pull/787:
update `tags_and_branches.md` documentation
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR bounds-checks `constants.size` directly instead of
`constNames.size` in `LazyDiscrTree.loadImportedModule`, eliminating the
unsafe `constants[i]!` access and the intermediate `constNames[i]`
lookup. The constant name is obtained from `constInfo.name` instead.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR verifies all of the `String` iterators except for the bytes
iterator by relating them to `String.toList`.
Along the way we define `String.posLE` and `String.posLT` analogously to
`String.posGE` and `String.posGT` and redefine `String.prev` to go
through `String.posLT`.
We also define and verify `String.positionsFrom` and
`String.revPositionsFrom`, which are the obvious generaliziations of
`String.positions` and `String.revPositions` starting at a positions
other than the start/end.
Finally, we get various lemmas about strings and positions, including
some nice induction principles `String.Pos.next_induction` and
`String.Pos.prev_induction`.
Of course, we also have all of the analogous results for `String.Slice`.
This is a mitigation for the fact that the upfront noncomputable checker
currently doesn't error out early enough in certain situations so we
violate invariants later on.
This PR adds a simplification rule for `Task.get (Task.pure x) = x` into
the LCNF simplifier. This
ensures that we avoid touching the runtime for a `Task` that instantly
gets destructed anyways.
This PR changes the way artifacts are transferred from the local Lake
cache to a local build path. Now, Lake will first attempt to hard link
the local build path to artifact in the cache. If this fails (e.g.,
because the cache is on a different file system or drive), it will
fallback to pre-existing approach of copying the artifact. Lake also now
marks cache artifacts as read-only to avoid corrupting the cache by
writing to a hard linked artifact.
Lake will also hard link binary artifacts into the cache. If this fails,
it will similarly fall back to copying them. Text artifacts are always
copied, not linked, as the line endings in the cache copy are
normalized.
This PR adds two more benchmarks for the Sym-based mvcgen prototype in
the style of `add_sub_cancel`.
The first is `deep_add_sub_cancel`, which is like `add_sub_cancel` but
with a much deeper monad stack:
```lean
abbrev M := ExceptT String <| ReaderT String <| ExceptT Nat <| StateT Nat <| ExceptT Unit <| StateM Unit
```
By specializing the specs for `get` and `set`, we get competitive
performance:
```
goal_100: 180.365086 ms, kernel: 79.634989 ms
goal_200: 313.465611 ms, kernel: 187.808631 ms
goal_300: 478.278585 ms, kernel: 270.210634 ms
goal_400: 638.884320 ms, kernel: 380.381127 ms
goal_500: 759.802772 ms, kernel: 472.662882 ms
goal_600: 933.575180 ms, kernel: 649.040746 ms
goal_700: 1174.367200 ms, kernel: 759.470010 ms
goal_800: 1298.866482 ms, kernel: 864.420171 ms
goal_900: 1475.315552 ms, kernel: 1008.662783 ms
goal_1000: 1627.957444 ms, kernel: 1078.627830 ms
```
Recall that `add_sub_cancel` had `goal_1000: 824.476962 ms, kernel:
477.069045 ms`, but that doesn't need to repeatedly unwrap 3 layers of
the monad.
The second benchmark is `get_throw_set`. Its kernel is
```lean
def step (lim : Nat) : ExceptT String (StateM Nat) Unit := do
let s ← get
if s > lim then
throw "s is too large"
set (s + 1)
def loop (n : Nat) : ExceptT String (StateM Nat) Unit := do
match n with
| 0 => pure ()
| n+1 => loop n; step n
def Goal (n : Nat) : Prop := ⦃fun s => ⌜s = 0⌝⦄ loop n ⦃⇓_ s => ⌜s = n⌝⦄
```
It will generate `n+1` VCs. We get `n` VCs of the form
```
s✝ : Nat
_ : ¬0 < s✝
...
_ : n < s✝ + 1 ...<n times>... + 1
⊢ ⌜s✝ = 0⌝ ⊢ₛ ⌜False⌝ (s✝ + ...<n times>...)
```
and one VC of the form
```
⌜s✝ = 0⌝ ⊢ₛ ⌜s✝ + 1 + <n times> ... + 1 = n⌝
```
which can be discharged by `grind`, but presently are discharged with
`sorry`.
Statistics:
```
goal_100: 209.435869 ms, kernel: 128.768919 ms
goal_200: 386.639441 ms, kernel: 482.244717 ms
goal_300: 559.795137 ms, kernel: 1251.777405 ms
goal_400: 753.243978 ms, kernel: 3020.878177 ms
goal_500: 1014.939522 ms, kernel: 5182.120327 ms
goal_600: 1229.173622 ms, kernel: 9296.551442 ms
goal_700: 1410.024180 ms, kernel: 16655.954682 ms
goal_800: 1684.059305 ms, kernel: 32065.951705 ms
goal_900: 1905.602401 ms, kernel: 55299.942894 ms
goal_1000: 2172.823244 ms, kernel: 84082.492485 ms
```
Need to look at kernel times here, but tactic time looks about alright.
Using `grind` to discharge just `n=100` goals took 8s.
This PR uses `getImpureSignature?` instead of the `findEnvDecl` from IR
in the LCNF compiler. We
were previously still relying on the IR function because only IR
contained proper borrow
annotations. Now we infer the borrow annotations on the LCNF level and
can thus use the LCNF
signatures.
This PR adds the attribute `@[univ_out_params]` for specifying which
universe levels should be treated as output parameters. By default, any
universe level that does not occur in any input parameter is considered
an output parameter.
This PR verifies the `String.Slice.splitToSubslice` function by relating
it to a model implementation `Model.split` based on a
`ForwardPatternModel`.
The proof is generic, so it works for splitting by characters, strings
etc.
From this, we will be able to give user-facing API lemmas for
`String.split` and friends in future PRs.
We also move the verification of string patterns from
`String.Slice.Pattern` to `String.Slice.Pattern.Model` to achieve better
separation between code that users run in their programs and code that
only supports the theory.
This PR changes the proof for `Char.toUpper` to make it easier to
typecheck for external checkers (nanoda in particular).
---------
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
This PR removes the uses of `shared_timed_mutex` that were introduced
because we were stuck on C++14
with the `shared_mutex` available from C++17 and above.
This PR adds the lemma `Acc.inv_of_transGen`, a generalization of
`Acc.inv`. While `Acc.inv` shows that `Acc r x` implies `Acc r y` given
that `r y x`, the new lemma shows that this also holds if `y` is only
*transitively* related to `x`.
This PR sets the `irreducible` attribute before generating the equations
for recursive definitions. This prevents these equations to be marked as
`defeq`, which could lead to `simp` generation proofs that do not type
check at default transparency.
This issue is surfacing more easily since well-founded recursion on
`Nat` is implemented with a dedicated fix point operator (#7965). Before
that, `WellFounded.fix` was used, which is inherently not reducing, so
we did get the desired result even without the explicit reducibility
setting.
Fixes#12398.
This PR refactors the main loop of the `cbv` tactic. Rather than using
multiple simprocs, a central pre simproc is introduced. Moreover, let
expressions are no longer immediately zeta-reduced due to performance on
one of the benchmarks (`leroy.lean`).
Stacked on top of #12416
This PR introduces `Rat.abs` and adds missing lemmas about `Int` and
`Rat`.
For `Int`:
- Lemmas about the interaction of negation and order: `neg_le_iff`,
`le_neg_iff`, `neg_lt_iff`, `lt_neg_iff`
For `Rat`:
- Declaration of `Rat.abs`
- Lemmas for `Rat.abs`, `Rat.floor` and `Rat.ceil`
- More basic lemmas that would all be provable with `grind` but might
still be good to have in the library
- Type class instances: `Std.Associative`, `Std.Commutative`,
`Std.LawfulIdentity` for addition
This PR adds a finishing `decide_cbv` tactic, which applies
`of_decide_eq_true` and then tries to discharge the remaining goal using
`cbv`.
Stacked on top of #12408.
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This PR adds caching to `replaceRecApps`, the procedure responsible for
replacing recursive applications for wellfounded recursion, improving
performance when many references to the same recursive call exist, e.g.
when recursive calls exist in proof terms.
Closes#12404
---------
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
This PR adds a user facing `cbv` tactic that can be used outside of the
`conv` mode.
Example usage:
```lean4
example : "hello" ++ " " ++ "world" = "hello world" := by cbv
```
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This PR gives a proof of `LawfulToForwardSearcherModel` for `Slice`
patterns, which amounts to proving that our implementation of KMP is
correct.
Note that this PR also changes the KMP implementation to make it
slightly more efficient and easier to verify. I also have a correctness
proof for the old implementation, so there were no bugs in the old
implementation.
This PR fixes a bug in `mvcgen` caused by incomplete `match` splitting.
In particular, if a program `match s with ...` matches on a state
variable `s` (presumably the result of a call to `get`), then `s` will
also occur in the stateful goal `H ⊢ₛ wp⟦match s with ...⟧ Q s`
*outside* the program expression; this was not anticipated before.
This PR adds `LawfulOrderOrd` instances for `Nat`, `Int`, and all
fixed-width integer types (`Int8`, `Int16`, `Int32`, `Int64`, `ISize`,
`UInt8`, `UInt16`, `UInt32`, `UInt64`, `USize`). These instances
establish that the `Ord` instances for these types are compatible with
their `LE` instances. Additionally, this PR adds a few missing lemmas
and `grind` patterns.
This PR changes the alters the file format of outputs stored in the
local Lake cache to include an identifier indicating the service (if
any) the output came from. This will be used to enable lazily
downloading artifacts on-demand during builds.
This PR adds comprehensive test running instructions to
`.claude/CLAUDE.md`,
replacing the single `test_single.sh` example with the full range of
test
commands documented in `doc/dev/testing.md`: full suite, filtered by
name,
rerun failures, and direct ctest usage.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR is similar to #12403.
We previously conjectured that "all type class fields that are types
should be marked as reducible." The problem is that propositions are
types, but they are also used as data (with `Decidable`). For example,
we often see the proposition `x <= y` as a Boolean. So, we refined the
conjecture to:
"All type class fields that are types (and not propositions) should be
marked as reducible."
This PR adds `mvcgen` support for specifications in the local context.
Example:
```lean
import Std.Tactic.Do
open Std.Do
set_option mvcgen.warning false
def foo (x : Id Nat → Id Nat) : Id Nat := do
let r₁ ← x (pure 42)
let r₂ ← x (pure 26)
pure (r₁ + r₂)
theorem foo_spec
(x : Id Nat → Id Nat)
(x_spec : ∀ (k : Id Nat) (_ : ⦃⌜True⌝⦄ k ⦃⇓r => ⌜r % 2 = 0⌝⦄), ⦃⌜True⌝⦄ x k ⦃⇓r => ⌜r % 2 = 0⌝⦄) :
⦃⌜True⌝⦄ foo x ⦃⇓r => ⌜r % 2 = 0⌝⦄ := by
mvcgen [foo, x_spec] <;> grind
def bar (k : Id Nat) : Id Nat := do
let r ← k
if r > 30 then return 12 else return r
example : ⦃⌜True⌝⦄ foo bar ⦃⇓r => ⌜r % 2 = 0⌝⦄ := by
mvcgen [foo_spec, bar] -- unfold `bar` and automatically apply the spec for the higher-order argument `k`
```
This PR improves the slice API with lemmas for `drop`/`take` operations
on `Subarray` and more lemmas about `Std.Slice.fold`, `Std.Slice.foldM`
and `Std.Slice.forIn`. It also changes the `simp` and `grind`
annotations for `Slice`-related lemmas. Lemmas converting between slices
of different shapes are no longer `simp`/`grind`-annotated because they
often complicated lemmas and hindered automation.
This PR adds a custom simproc to handle `Decidable.rec`, where we force
the rewrite in the argument of the `Decidable` type, that normally is
not rewritten due to being a subsingleton.
Closes#12386
This PR develops custom simprocs for dealing with `ite`/`dite`
expressions in `cbv` tactics, based on equivalent simprocs from
`Sym.simp`, with the difference that if the condition is not reduced to
`True`/`False`, we make use of the decidable instance and calculate to
what the condition reduces to.
Stacked on top of #12391.
This PR adds `IO.FS.Metadata.numLinks`, which contains the number of
hard links to a file.
This changes the implementation of `System.FilePath.metadata` and
`System.FilePath.symlinkMetadata` to use libuv. Otherwise, `st_nlink`
was not properly set on Windows. This also has the side benefit of
provided sub-second precision for file times on Windows (fulfilling an
old TODO). Also, while libuv supports `lstat` for Windows, enabling that
is left to a future PR.
This PR fixes a platform inconsistency in `IO.FS.removeFile` where it
could not delete read-only files on Windows.
The implementation now uses `uv_fs_unlink` instead of `std::remove`, as
libuv can delete read-only files. The PR also fixes a inconsistency in
`IO_test.lean` where it would generate files in the wrong directory when
run interactively.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
This PR fixes an issue in LCNF simp where it would attempt to act on
type incorrect `cases`
statements and look for a branch, otherwise panic. This issue did not
yet manifest in production as
various other invariants upheld by LCNF simp help mask it but will start
to become an issue with the
upcoming changes.
This is the proper fix for #6957.
This PR provides a `LawfulForwardPatternModel` instance for string
patterns, i.e., it proves correctness of the `dropPrefix?` and
`startsWith` functions for string patterns.
Note that this is "just" the correctness proof; there isn't a way to
actually use it yet. API lemmas will follow.
This PR adds identifying information about a module available to `lean`
(e.g., its name and package identifier) to the module's dependency
trace. This ensures modules with different identification have different
input hashes even if their source files and imports are identical.
This PR adds a few unification hints that we will need after
`backward.isDefEq.respectTransparency` is `true` by default.
See #12338
It was part of #12179.
This PR makes disabling the artifact cache (e.g., via
`LAKE_ARTIFACT_CACHE=false` or `enableArtifactCache = false`) now stop
Lake from fetching from the cache (whereas it previously only stopped
writing to it).
There are now 3 possible configuration of the local artifact cache for a
package:
* `true`: Artifacts will be fetched from the cache before building (if
available) and built artifacts will be cached.
* `false:`: Lake will neither fetch artifacts from the cache or store
them into it.
* **default** (no configuration set): Lake will fetch artifacts from the
cache but not store them into it. A key motivation for this is to, by
default, reuse artifacts downloaded into the cache from a remote
service.
This PR tags `List.reduceOption` with `@[expose]`. #12348 accidentally
moved the definition out of an `@[expose] section` which caused problems
in mathlib because `List.reduceOption` was expected to be exposed.
This PR extends shake with tracking of attribute names passed to
`simp`/`grind`.
On the way there, it also fixes `register_simp/grind_attr` uses outside
`public meta section` as well as go-to-definition on declaration-level
uses of the created attributes (tactic-level goto would be a separate
todo).
This PR moves the elaboration of structure/class Verso docstrings until
after the fact that it's a class is registered, so code samples in the
docstring can use it as a class. Redundant addition of structure and
constructor docstrings are also removed, because they're already handled
in MutualInductive.lean.
Closes#11651
This PR uses an `Array` instead of a `List` to store the clauses in
`Std.CNF`. This reduces the memory footprint and pressure on the
allocator, leading to noticeable performance changes with gigantic CNFs.
This PR treats the first character of the first line of a docstring as
being in the leftmost column, even if it physically is not. This allows
left-column items like headers to be used even after spaces. It also
detects the indentation of the entire docstring, using it as the
zero-point for indentation sensitive syntax such as headers.
Closes#12067.
This PR fixes poor error reporting from Verso docstrings. Before, if the
Verso parser didn't consume the whole docstring, then Lean would try to
parse the closing -/ and fail; this would lead to backtracking and an
assumption that the docstring must be non-Verso, with only the non-Verso
commands like #guard_msgs as possibilities. Now, the input is always
consumed.
Closes#12118.
This PR implements better support for unfolding class fields marked as
`reducible`. For example, we want to mark fields that are types such as
```lean
MonadControlT.stM : Type u -> Type u
```
The motivation is similar to our heuristic that type definitions should
be abbreviations.
Now, suppose we want to unfold `stM m (ExceptT ε m) α` using the
`.reducible` transparency setting, we want the result to be `stM m m
(MonadControl.stM m (ExceptT ε m) α)` instead of
`(instMonadControlTOfMonadControl m m (ExceptT ε m)).1 α`. The latter
would defeat the intent of marking the field as reducible, since the
instance `instMonadControlTOfMonadControl` is `[instance_reducible]` and
the resulting term would be stuck when using `.reducible` transparency
mode.
**Remark**: This feature introduces a few breakages in core and Mathlib.
So, it is disabled for now in this PR. To enable, we must use
`set_option backward.whnf.reducibleClassField true`
This PR adds two benchmarks (sieve of Eratosthenes, removing duplicates
from the list) and one test (a function with sublinear complexity
defined via well-founded recursion evaluated on large naturals with up
to `60` digits).
The tests have been suggested by @b-mehta.
This PR changes the semantics of `inline` annotations in the compiler.
The behavior of the original `@[inline]` attribute remains the same but
the function `inline` now comes with a restriction that it can only use
declarations that are local to the current module. This comes as a
preparation to pulling the compiler out into a separate process.
Closes: #12334
This PR changes the handling of over-applied cases expressions in
`ToLCNF` to avoid generating function declarations that are called
immediately. For example, `ToLCNF` previously produced this:
```lean-4
set_option trace.Compiler.init true
/--
trace: [Compiler.init] size: 4
def test x y : Bool :=
fun _y.1 _y.2 : Bool :=
cases x : Bool
| PUnit.unit =>
fun _f.3 a : Bool :=
return a;
let _x.4 := _f.3 _y.2;
return _x.4;
let _x.5 := _y.1 y;
return _x.5
-/
#guard_msgs in
def test (x : Unit) (y : Bool) : Bool :=
x.casesOn (fun a => a) y
```
which is now simplified to
```lean-4
set_option trace.Compiler.init true
/--
trace: [Compiler.init] size: 3
def test x y : Bool :=
cases x : Bool
| PUnit.unit =>
let a := y;
return a
-/
#guard_msgs in
def test (x : Unit) (y : Bool) : Bool :=
x.casesOn (fun a => a) y
```
This is especially relevant for #8309 because there `dite` is defined as
an over-applied `Bool.casesOn`.
This PR adds the option `doc.verso.module`. If set, it controls whether
module docstrings use Verso syntax. If not set, it defaults to the value
of the `doc.verso` option.
Closes#12070.
This PR fixes an issue on new NeoVim versions that would cause the
language server to display an error when using certain code actions.
(For some reason, NeoVim recently decided to diverge from VS Code in
terms of when it emits code action resolution requests, which means that
not setting the `data?` field won't preclude NeoVim from emitting a
request anymore, which in turn means that the server can't resolve the
code action.)
This PR implements preparatory work for #12179. It implements a new
feature in `isDefEq` to ensure it does not increase the transparency
level to `.default` when checking definitionally equality of implicit
arguments. This transparency level bump was introduced in Lean 3, but it
is not a performance issue and is affecting Mathlib. This PR adds the
new feature, but it is disabled by default.
This PR adds a default `Inhabited` instance to `Theorem` type.
The need to do so came up in #12296 , as `Theorem` is one of the entries
of the structure which is the key entry of `SimpleScopedEnvExtension`.
This PR fixes the PR release workflow which was failing due to the
deprecated `MATHLIB4_COMMENT_BOT` PAT being invalid.
**Error:** `jq: error (at <stdin>:4): Cannot index string with string
"name"` when fetching labels - the API returned an error response
instead of labels array because the PAT credentials were bad.
**Changes:**
- Generate a token from the `mathlib-lean-pr-testing` GitHub App (ID:
2785182) for posting comments to Lean PRs about mathlib compatibility
- Use `GITHUB_TOKEN` for read-only label fetching (no special identity
needed)
- Update the bot username check from `leanprover-community-bot` to
`mathlib-lean-pr-testing[bot]`
**Secrets added:** `MATHLIB_LEAN_PR_TESTING_APP_ID` and
`MATHLIB_LEAN_PR_TESTING_PRIVATE_KEY` have been added to the repository.
Fixes the CI failure at
https://github.com/leanprover/lean4/actions/runs/21705647318/job/62595966115🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds `String.Slice.Subslice`, which is an unbundled version of
`String.Slice`.
This type is of interest because it is the correct type for string
searching and splitting operations to land in.
This PR just adds the type with minimal API. Additional API and
subsequent refactoring of the searching and splitting API is left for
future PRs.
This PR reverses the relationship between the `ForwardPattern` and
`ToForwardSearcher` classes.
Previously, it was possible to derive `ForwardPattern` (i.e.,
`dropPrefix?`) from `ToForwardSearcher` (i.e., get an iterator of
`SearchStep (s)`). Now, we give the default instance in the other
direction: it is now possible to derive `ToForwardSearcher` from
`ForwardPattern`. Since it is usually much easier to provide
`ForwardPattern` than `ToForwardSearcher`, this means more shared code,
which pays off double since we will give a correctness proof for the
default implementation in an upcoming PR.
This PR also adds some string lemmas.
This PR adds theorems that directly state that div and mod form an
injective pair: if `a / n = b / n` and `a % n = b % n` then `a = b`.
These complement existing div/mod lemmas and are useful for extension
arguments.
Upstreaming from
https://github.com/leanprover-community/mathlib4/pull/34201🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR fixes the PR release workflow which is failing to create
`lean-pr-testing` branches due to the deprecated `MATHLIB4_BOT` PAT (see
https://github.com/leanprover/lean4/actions/runs/21698772126/job/62574742680).
The fix uses `actions/create-github-app-token@v2` to generate a token
from the `mathlib-nightly-testing` GitHub App (ID: 2784211) instead,
which has write access to both `leanprover-community/batteries` and
`leanprover-community/mathlib4-nightly-testing`.
Requires adding `MATHLIB_NIGHTLY_TESTING_APP_ID` and
`MATHLIB_NIGHTLY_TESTING_PRIVATE_KEY` secrets to leanprover/lean4
(done).
🤖 Prepared with Claude Code
This PR ensures `simp` does not "simplify" instances by default. The old
behavior can be retrieved by using `simp +instances`. This PR is similar
to #12195, but for `dsimp`.
The backward compatibility flag for `dsimp` also deactivates this new
feature.
```
set_option backward.dsimp.instances true
```
Applying `simp` (and `dsimp`) to instances creates non-standard
instances, and this creates all sorts of problems in Mathlib.
---------
Co-authored-by: Henrik Böving <hargonix@gmail.com>
Co-authored-by: Sebastian Graf <sgraf1337@gmail.com>
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR leverages the fact that expressions are type correct in `grind`
and the conclusion of extensionality theorems is of the form `?a = ?b`.
This PR is relevant for #12179 because it enables us to use a weaker
`isDefEq` that does not bump the transparency level when processing
implicit arguments.
This adds a `maxSuggestions : Option Nat := none` field to both
`Simp.Config` and `Grind.Config`. When `suggestions` is enabled, this
field controls the maximum number of library suggestions to use. If
`none`, the default limit is used.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This adds `set_option debug.byAsSorry true` and `decreasing_by sorry` to
various files to allow bootstrapping with Config structure changes. These
changes will be restored after the bootstrap dance is complete.
This PR adds and updates docstrings for syntax (and one for ranges).
The reference manual's section on syntax operators is gaining more
content, so the resulting docstrings were reviewed and the missing ones
added.
This PR adds an experimental `cbv` tactic that can be invoked from
`conv` mode. The tactic is not suitable for production use and an
appropriate warning is displayed.
This PR introduces the functions `(String|Slice).posGE` and
`(String|Slice).posGT` will full verification and deprecates
`Slice.findNextPos` in favor of `Slice.posGT`.
The KMP implementation is adapted to use these two new functions.
Various useful string and order lemmas are added along the way.
Also add a `simp` attribute to `Std.le_refl` and fix the resulting
fallout (yes, this would have been better as a separate PR).
This PR improves and simplifies the SymM-based mvcgen prototype by
creating `BackwardRule.apply`-ready auxiliary theorems for spec
theorems. These auxiliary theorems have types that have reducible
definitions unfolded and shared, just like the rest of the SymM world
assumes. Furthermore, in order to aid kernel checking times,
definitional reductions leave behind expected type hints. With #12290,
we get the following numbers:
```
goal_100: 100.671964 ms, kernel: 34.104676 ms
goal_200: 152.650808 ms, kernel: 70.653251 ms
goal_300: 222.973242 ms, kernel: 105.874266 ms
goal_400: 294.032333 ms, kernel: 150.025106 ms
goal_500: 366.748098 ms, kernel: 193.483843 ms
goal_600: 442.509542 ms, kernel: 236.845115 ms
goal_700: 517.527685 ms, kernel: 268.804230 ms
goal_800: 601.657910 ms, kernel: 310.765606 ms
goal_900: 681.020759 ms, kernel: 357.428032 ms
goal_1000: 762.212989 ms, kernel: 403.789517 ms
```
The baseline is `shallow_add_sub_cancel`:
```
goal_100: 62.721757 ms, kernel: 22.109237 ms
goal_200: 140.118652 ms, kernel: 45.219512 ms
goal_300: 241.077690 ms, kernel: 78.779379 ms
goal_400: 363.274462 ms, kernel: 128.951250 ms
goal_500: 517.350791 ms, kernel: 155.498217 ms
goal_600: 678.291416 ms, kernel: 212.325487 ms
goal_700: 881.479043 ms, kernel: 258.690695 ms
goal_800: 1092.357375 ms, kernel: 351.996079 ms
goal_900: 1247.759480 ms, kernel: 319.197608 ms
goal_1000: 1497.203628 ms, kernel: 364.532560 ms
```
The latter is with the main solving loop in interpreter mode, but the
kernel checking times are still representative.
Earlier experiments suggest that the precompiled baseline performs at
roughly 650ms for `goal_1000`, so the new mvcgen is getting close.
This PR moves the `PredTrans.apply` structure field into a separate
`def`. Doing so improves kernel reduction speed because the kernel is
less likely to unfold definitions compared to structure field
projections. This causes minor shifts in `simp` normal forms.
In preparation for adding the bench suite to the cmake-based test suite,
this PR moves test-related cmake code into the `tests` directory.
It also fixes a warning by removing an obsolete bit of the cmake code.
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/releases">actions/cache's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<blockquote>
<p>[!IMPORTANT]
<strong><code>actions/cache@v5</code> runs on the Node.js 24 runtime and
requires a minimum Actions Runner version of
<code>2.327.1</code>.</strong></p>
<p>If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<hr />
<h2>What's Changed</h2>
<ul>
<li>Upgrade to use node24 by <a
href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1630">actions/cache#1630</a></li>
<li>Prepare v5.0.0 release by <a
href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1684">actions/cache#1684</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v4.3.0...v5.0.0">https://github.com/actions/cache/compare/v4.3.0...v5.0.0</a></p>
<h2>v4.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add note on runner versions by <a
href="https://github.com/GhadimiR"><code>@GhadimiR</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1642">actions/cache#1642</a></li>
<li>Prepare <code>v4.3.0</code> release by <a
href="https://github.com/Link"><code>@Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1655">actions/cache#1655</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/GhadimiR"><code>@GhadimiR</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1642">actions/cache#1642</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v4...v4.3.0">https://github.com/actions/cache/compare/v4...v4.3.0</a></p>
<h2>v4.2.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@nebuk89</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1620">actions/cache#1620</a></li>
<li>Upgrade <code>@actions/cache</code> to <code>4.0.5</code> and move
<code>@protobuf-ts/plugin</code> to dev depdencies by <a
href="https://github.com/Link"><code>@Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1634">actions/cache#1634</a></li>
<li>Prepare release <code>4.2.4</code> by <a
href="https://github.com/Link"><code>@Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1636">actions/cache#1636</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/nebuk89"><code>@nebuk89</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1620">actions/cache#1620</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v4...v4.2.4">https://github.com/actions/cache/compare/v4...v4.2.4</a></p>
<h2>v4.2.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update to use <code>@actions/cache</code> 4.0.3 package &
prepare for new release by <a
href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1577">actions/cache#1577</a>
(SAS tokens for cache entries are now masked in debug logs)</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/salmanmkc"><code>@salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1577">actions/cache#1577</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v4.2.2...v4.2.3">https://github.com/actions/cache/compare/v4.2.2...v4.2.3</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/blob/main/RELEASES.md">actions/cache's
changelog</a>.</em></p>
<blockquote>
<h1>Releases</h1>
<h2>Changelog</h2>
<h3>5.0.1</h3>
<ul>
<li>Update <code>@azure/storage-blob</code> to <code>^12.29.1</code> via
<code>@actions/cache@5.0.1</code> <a
href="https://redirect.github.com/actions/cache/pull/1685">#1685</a></li>
</ul>
<h3>5.0.0</h3>
<blockquote>
<p>[!IMPORTANT]
<code>actions/cache@v5</code> runs on the Node.js 24 runtime and
requires a minimum Actions Runner version of <code>2.327.1</code>.
If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<h3>4.3.0</h3>
<ul>
<li>Bump <code>@actions/cache</code> to <a
href="https://redirect.github.com/actions/toolkit/pull/2132">v4.1.0</a></li>
</ul>
<h3>4.2.4</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v4.0.5</li>
</ul>
<h3>4.2.3</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v4.0.3 (obfuscates SAS token in
debug logs for cache entries)</li>
</ul>
<h3>4.2.2</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v4.0.2</li>
</ul>
<h3>4.2.1</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v4.0.1</li>
</ul>
<h3>4.2.0</h3>
<p>TLDR; The cache backend service has been rewritten from the ground up
for improved performance and reliability. <a
href="https://github.com/actions/cache">actions/cache</a> now integrates
with the new cache service (v2) APIs.</p>
<p>The new service will gradually roll out as of <strong>February 1st,
2025</strong>. The legacy service will also be sunset on the same date.
Changes in these release are <strong>fully backward
compatible</strong>.</p>
<p><strong>We are deprecating some versions of this action</strong>. We
recommend upgrading to version <code>v4</code> or <code>v3</code> as
soon as possible before <strong>February 1st, 2025.</strong> (Upgrade
instructions below).</p>
<p>If you are using pinned SHAs, please use the SHAs of versions
<code>v4.2.0</code> or <code>v3.4.0</code></p>
<p>If you do not upgrade, all workflow runs using any of the deprecated
<a href="https://github.com/actions/cache">actions/cache</a> will
fail.</p>
<p>Upgrading to the recommended versions will not break your
workflows.</p>
<h3>4.1.2</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9255dc7a25"><code>9255dc7</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1686">#1686</a>
from actions/cache-v5.0.1-release</li>
<li><a
href="8ff5423e8b"><code>8ff5423</code></a>
chore: release v5.0.1</li>
<li><a
href="9233019a15"><code>9233019</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1685">#1685</a>
from salmanmkc/node24-storage-blob-fix</li>
<li><a
href="b975f2bb84"><code>b975f2b</code></a>
fix: add peer property to package-lock.json for dependencies</li>
<li><a
href="d0a0e18134"><code>d0a0e18</code></a>
fix: update license files for <code>@actions/cache</code>,
fast-xml-parser, and strnum</li>
<li><a
href="74de208dcf"><code>74de208</code></a>
fix: update <code>@actions/cache</code> to ^5.0.1 for Node.js 24
punycode fix</li>
<li><a
href="ac7f1152ea"><code>ac7f115</code></a>
peer</li>
<li><a
href="b0f846b50b"><code>b0f846b</code></a>
fix: update <code>@actions/cache</code> with storage-blob fix for
Node.js 24 punycode depr...</li>
<li><a
href="a783357455"><code>a783357</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1684">#1684</a>
from actions/prepare-cache-v5-release</li>
<li><a
href="3bb0d78750"><code>3bb0d78</code></a>
docs: highlight v5 runner requirement in releases</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/cache/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 6 to 7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>v7 - What's new</h2>
<blockquote>
<p>[!IMPORTANT]
actions/download-artifact@v7 now runs on Node.js 24 (<code>runs.using:
node24</code>) and requires a minimum Actions Runner version of 2.327.1.
If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<h3>Node.js 24</h3>
<p>This release updates the runtime to Node.js 24. v6 had preliminary
support for Node 24, however this action was by default still running on
Node.js 20. Now this action by default will run on Node.js 24.</p>
<h2>What's Changed</h2>
<ul>
<li>Update GHES guidance to include reference to Node 20 version by <a
href="https://github.com/patrikpolyak"><code>@patrikpolyak</code></a>
in <a
href="https://redirect.github.com/actions/download-artifact/pull/440">actions/download-artifact#440</a></li>
<li>Download Artifact Node24 support by <a
href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/415">actions/download-artifact#415</a></li>
<li>fix: update <code>@actions/artifact</code> to fix Node.js 24
punycode deprecation by <a
href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/451">actions/download-artifact#451</a></li>
<li>prepare release v7.0.0 for Node.js 24 support by <a
href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/452">actions/download-artifact#452</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/patrikpolyak"><code>@patrikpolyak</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/download-artifact/pull/440">actions/download-artifact#440</a></li>
<li><a href="https://github.com/salmanmkc"><code>@salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/download-artifact/pull/415">actions/download-artifact#415</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/download-artifact/compare/v6.0.0...v7.0.0">https://github.com/actions/download-artifact/compare/v6.0.0...v7.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="37930b1c2a"><code>37930b1</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/452">#452</a>
from actions/download-artifact-v7-release</li>
<li><a
href="72582b9e0a"><code>72582b9</code></a>
doc: update readme</li>
<li><a
href="0d2ec9d4cb"><code>0d2ec9d</code></a>
chore: release v7.0.0 for Node.js 24 support</li>
<li><a
href="fd7ae8fda6"><code>fd7ae8f</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/451">#451</a>
from actions/fix-storage-blob</li>
<li><a
href="d484700543"><code>d484700</code></a>
chore: restore minimatch.dep.yml license file</li>
<li><a
href="03a808050e"><code>03a8080</code></a>
chore: remove obsolete dependency license files</li>
<li><a
href="56fe6d904b"><code>56fe6d9</code></a>
chore: update <code>@actions/artifact</code> license file to 5.0.1</li>
<li><a
href="8e3ebc4ab4"><code>8e3ebc4</code></a>
chore: update package-lock.json with <code>@actions/artifact</code><a
href="https://github.com/5"><code>@5</code></a>.0.1</li>
<li><a
href="1e3c4b4d49"><code>1e3c4b4</code></a>
fix: update <code>@actions/artifact</code> to ^5.0.0 for Node.js 24
punycode fix</li>
<li><a
href="458627d354"><code>458627d</code></a>
chore: use local <code>@actions/artifact</code> package for Node.js 24
testing</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/download-artifact/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This PR shifts the conversion from LCNF mono to lambda pure into the
LCNF impure phase. This is preparatory work for the upcoming refactor of
IR into LCNF impure.
The LCNF impure phase differs from the other LCNF phases in two crucial
ways:
1. I decided to have `Decl.type` be the result type as opposed to an
arrows from the parameter types to the result type. This is done because
impure does not have a notion of arrows anymore so keeping them around
for this one particular purpose would be slightly odd.
2. In order to avoid cluttering up the olean size LCNF impure saves only
the signature persistently to the disk. This is possible because we no
longer have inlining/specialization at this point of compilation so all
we need is typing information (and potentially other environment
extensions) to guide our analyses.
This PR implements RFC #12216: native computation (`native_decide`,
`bv_decide`) is represented in the logic as one axiom per computation,
asserting the equality that was obtained from the native computation.
`#print axiom` will no longer show `Lean.trustCompiler`, but rather the
auto-generated names of these axioms (with, for example,
`._native.bv_decide.` in the name). See the RFC for more information.
This PR introduces a common MetaM helper (`nativeEqTrue`) used by
`native_decide` and `bv_decide` alike that runs the computation and then
asserts the result using an axiom.
It also deprecated the `ofReduceBool` axioms etc.
Not included in this PR is infrastructure for enumerating these axioms,
prettier `#print axioms` (should we want his) and tactic concurrency.
Fixes#12216.
This PR implements a cache for the positions of class universe level
parameters that only appear in output parameter types.
During type class resolution, the cache key for a query like
`HAppend.{0, 0, ?u} (BitVec 8) (BitVec 8) ?m` should be independent of
the specific metavariable IDs in output parameter positions. To achieve
this, output parameter arguments are erased from the cache key. However,
universe levels that only appear in output parameter types (e.g., `?u`
corresponding to the result type's universe) must also be erased to
avoid cache misses when the same query is issued with different universe
metavariable IDs.
This function identifies which universe level parameter positions are
"output-only" by collecting all level param names that appear in
non-output parameter domains, then returning the positions of any level
params not in that set.
**Remark**: This PR requires a manual update stage0 because it changes
the structure of our .olean files.
This PR refines upon #12106, by setting the `isRecursive` env extension
after adding the declaration, but before processing attributes like
`macro_inline` that want to look at the flag. Fixes#12268.
This PR avoids a potential deadlock on shutdown of a Lean program when
the number of pooled threads has temporarily been pushed above the
limit.
There's a potential race between the finalizer "waking up everyone"
after setting `m_shutting_down = true` and a worker that is about to be
throttled because of concurrency limits.
- `m_max_std_workers = 1`, `m_std_workers.size() = 2`, and the queue
still has tasks.
- Finalizer sets `m_shutting_down = true` and calls `notify_all()` while
a worker is running a task (outside of the mutex).
- Worker finishes a task, re-enters the loop, sees work, and "should
wait" because `active >= max`.
- Worker then calls `wait()` after the notify and never wakes, so
`join()` in the finalizer hangs.
This PR avoids the worker being blocked by not `wait()`ing if we are
already shutting down. The code is restructured a bit for readability,
where the first section is "there's no work in the queue" and the next
section is "there is some work in the queue"
This PR fixes a unification issue that appeared in
`Lean.Meta.MkIffOfInductiveProp` machinery that was upstreamed from
Mathlib. Inside of `toInductive`, wrong free variables were passed,
which made it impossible to perform a unification in certain cases.
Closes#12215
This PR provides more lemmas about sums of lists/arrays/vectors,
especially sums of `Nat` or `Int` lists/arrays/vectors.
This change has been motivated by my experience solving
`human-eval-lean` problems. Sums, minima and maxima are frequently
required and the improvements provided in this PR make it easier to
verify such programming tasks.
Changes:
* Added lemmas that `sum` equals `foldl`/`foldr`.
* Generalized `sum_append_nat` and `sum_reverse_nat` lemmas so that they
are polymorphic, requiring only some type class instances about the list
elements' type. The polymorphic lemmas aren't simp- or grind-annotated
because I fear the instance synthesis overhead. However, the `Nat` and
`Int` specializations are annotated (see below). Note that as
`{Array,Vector}.min` do not exist, some lemmas can't be stated and were
omitted.
* Added `List.min_singleton` and `List.max_singleton` lemmas as they
were needed for some proofs.
* `Nat`-related:
* Moved all `{List,Array,Vector}.sum` lemmas that are specific for `Nat`
into their own module: `Init.Data.List.Nat.Sum`, `Init.Data.Array.Nat`
and `Int.Data.Vector.Nat`.
* Notably, moved `Nat.sum_pos_iff_exists_pos` and renamed it to
`List.sum_pos_iff_exists_pos_nat`. This is more consistent and made it
possible to add `Array` and `Vector` variants of this lemma.
* Added lemmas proving that `l.sum / l.length` lies between the minimum
and the maximum of a list.
* Added analogous lemmas for `Int` lists/arrays/vectors to parallel
modules: `Init.Data.List.Int.Sum`, `Init.Data.Array.Int` and
`Int.Data.Vector.Int`.
* Renamed `sum_eq_sum_toList` to `sum_toList`, which better represents
the theorem's content.
This PR makes several small improvements to the list/array/vector API:
* It fixes typos in `Init.Core`.
* It adds `List.isSome_min_iff` and `List.isSome_max_iff`.
* It adds `grind` and `simp` annotations to various previously
unannotated lemmas.
* It adds lemmas for characterizing `∃ x ∈ xs, P x` using indices as `∃
(i : Nat), ∃ hi, P (xs[i])`, and similar universally quantified lemmas:
`exists_mem_iff_exists_getElem` and `forall_mem_iff_forall_getElem`.
* It adds `Vector.toList_zip`.
* It adds `map_ofFn` and `ofFn_getElem` for lists/arrays/vectors.
This PR adds the new transparency setting `@[instance_reducible]`. We
used to check whether a declaration had `instance` reducibility by using
the `isInstance` predicate. However, this was not a robust solution
because:
- We have scoped instances, and `isInstance` returns `true` only if the
scope is active.
- We have auxiliary declarations used to construct instances manually,
such as:
```lean
def lt_wfRel : WellFoundedRelation Nat
```
`isInstance` also returns `false` for this kind of declaration.
In both cases, the declaration may be (or may have been) used to
construct an instance, but `isInstance`
returns `false`. Thus, we claim it is a mistake to check the
reducibility status using `isInstance`.
`isInstance` indicates whether a declaration is available for the type
class resolution mechanism,
not its transparency status.
**We are decoupling whether a declaration is available for type class
resolution from its transparency status.**
**Remak**: We need a update stage0 to complete this feature.
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR fixes a bug on Windows with `IO.Process.spawn` where setting an
environment variable to the empty string would not set the environment
variable on the subprocess.
This PR adds the function `Std.Iter.isEmpty` and proves the
specification lemmas `Std.Iter.isEmpty_eq_match_step` and
`Std.Iter.isEmpty_toList` if the iterator is productive.
The monadic variant on `Std.IterM` is also provided.
This PR introduces projected minima and maxima, also known as
"argmin/argmax", for lists under the names `List.minOn` and
`List.maxOn`. It also introduces `List.minIdxOn` and `List.maxIdxOn`,
which return the index of the minimal or maximal element. Moreover,
there are variants with `?` suffix that return an `Option`. The change
further introduces new instances for opposite orders, such as
`LE.opposite`, `IsLinearOrder.opposite` etc. The change also adds the
missing `Std.lt_irrefl` lemma.
This PR ensures we cache the result of `unfold_definition` definition in
the kernel type checker. We used to cache this information in a thread
local storage, but it was deleted during the Lean 3 to Lean 4
transition.
This PR fixes a bug where `grind?` suggestions would not include
parameters using local variable dot notation (e.g.,
`cs.getD_rightInvSeq` where `cs` is a local variable). These parameters
were incorrectly filtered out because the code assumed all ident params
resolve to global declarations. In fact, local variable dot notation
produces anchors that need the original term to be loaded during replay,
so they must be preserved in the suggestion.
Closes#12185🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR recognizes certain kinds of composite proof terms of the form
`hpre.trans hspec |> (wp prog).mono _ _ hpost` and abstracts them into
bespoke theorems. This should yield smaller proof terms. Sadly, kernel
checking time is unaffected, even regressing a bit. The number of shared
terms stays almost the same (+- a constant). Hence I deactivate the code
path in this patch. We keep the code, though, because it might be useful
in the future, also there are a few other improvements.
This PR gives a simpler semantics to `noncomputable`, improving
predictability as well as preparing codegen to be moved into a separate
build step without breaking immediate generation of error messages.
Specifically, `noncomputable` is now needed whenever an axiom or another
`noncomputable` def is used by a def except for the following special
cases:
* uses inside proofs, types, type formers, and constructor arguments
corresponding to (fixed) inductive parameters are ignored
* uses of functions marked `@[extern]/@[implemented_by]/@[csimp]` are
ignored
* for applications of a function marked `@[macro_inline]`,
noncomputability of the inlining is instead inspected
# Breaking change
After this change, more `noncomputable` annotations than before may be
required in exchange for improved future stability.
This PR adds a clone of the `mvcgen` tactic based on `SymM` and
evaluates it based on a ported `add_sub_cancel` benchmark. Notably, it
can reuse all the existing `@[spec]`-annotated theorems to generate VCs.
(It doesn't do control-flow splitting, simp rules on the program
expression or handling of lets; we'll get there.)
It is quite fast already, with the kernel being the bottle-neck:
```
goal_50: 69.524305 ms, kernel: 155.327778 ms
goal_100: 93.834221 ms, kernel: 407.370786 ms
goal_150: 131.364098 ms, kernel: 762.936720 ms
goal_200: 169.577172 ms, kernel: 1181.199093 ms
goal_250: 206.421738 ms, kernel: 1707.539380 ms
```
```
goal_200: 169.458637 ms, kernel: 1186.221085 ms
goal_400: 322.819718 ms, kernel: 3791.613854 ms
goal_600: 474.929013 ms, kernel: 7763.373757 ms
goal_800: 634.379422 ms, kernel: 13107.810430 ms
```
It is best compared to the `solveUsingSym <n> false true` measurements
of the SymM `add_sub_cancel` benchmark (`false`: without intermediate
eager simplification). For `n=200`, it reports
```
goal_200: 779.482300 ms, kernel: 742.097404 ms
```
suggesting that the generated proof term could be improved for kernel
reduction. (TODO.)
I'm unsure whether `solveUsingSym` is run in interpreted mode, so take
the >400% speedup with a grain of salt.
We can definitely conclude that VC generation time is currently not a
bottleneck compared to kernel checking time.
Plot for discharging goals of sizes 100..800:
<img width="1000" height="600" alt="Code_Generated_Image(1)"
src="https://github.com/user-attachments/assets/90e76a45-fa46-4d02-912a-c3355e2aa094"
/>
Plot comparing Kernel and Goal time:
<img width="1000" height="600" alt="Code_Generated_Image(2)"
src="https://github.com/user-attachments/assets/5849ba0f-1d83-4f2d-98dd-fa65b840bb4e"
/>
This PR introduces the defining equality `Triple.iff` and uses that in
proofs instead of relying on definitional equality. It also introduces
`Triple.iff_conseq` that is useful for backward reasoning and introduces
verification conditions. Similarly, `Triple.entails_wp_*` theorems are
introduced for backward reasoning where the target is an stateful
entailment rather than a triple.
This PR introduces a phase separation to the LCNF IR. This is a
preparation for the merge of
the old `Lean.Compiler.IR` and the new `Lean.Compiler.LCNF` framework.
The change parametrizes all relevant `LCNF` data structures over a
`Purity` parameter and
additionally carries around proofs that the `Purity` has certain values,
depending on what's
required. This is done as opposed to indexing the types over `Purity`
because we do (almost) never
have to store the `Purity` value for phase generic structures this way.
This PR reverts a lot of the changes done in #8308. We practically
encountered situations such as:
```
fun y (z) :=
let x := inst
mkInst x z
f y
```
Where the instance puller turns it into:
```
let x := inst
fun y (z) :=
mkInst x z
f y
```
The current heuristic now discovers `x` being in scope at the call site
of `f` and being used under a binder in `y` and thus blocks pulling in
`x` to the specialization, abstracting over an instance.
According to @zwarich this was done at the time either due to observed
stack overflows or pulling in computation into loops. With the current
configuration for abstraction in specialization it seems rather unlikely
that we pull in a non trivial computation into a loop with this. We also
practically didn't observe stack overflows in our tests or benchmarks.
Cameron speculates that the issues he observed might've been fixed
otherwise by now.
Crucial note: Deciding not to abstract over ground terms *might* cause
us to pull in computationally intensive ground terms into a loop. We
could decide to weaken this to just instance terms though of course even
computing instances might end up being non-trivial.
This PR provides `Array` operations analogous to `List.min(?)` and
`List.max(?)`.
I had to prove a few auxiliary lemmas. Downstream in Batteries, which
already had `List.min` and `List.max`, I renamed their variants to
`List.rangeMin` and `List.rangeMax` in the PR testing branch. Their
version is more general in the sense that it has `start` and `stop`
autoParams, like `Array.foldl` has, but I think the futore belongs to
`Subarray.min` instead (which I haven't implemented yet).
This PR updates docstrings and function signatures in order to complete
the transition from `Iter.Partial` to `Iter.Total` (extrinsically
terminating by default). It also deprecates `allowNontermination` and
adds `Iter.Total.atIdxSlow?`.
This PR ensures `dsimp` does not "simplify" instances by default. The
old behavior can be retrieved by using
```
set_option backward.dsimp.instances true
```
Applying `dsimp` to instances creates non-standard instances, and this
creates all sorts of problems in Mathlib.
This modification is similar to
```
set_option backward.dsimp.proofs true
```
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: Claude <noreply@anthropic.com>
This PR documents the available `changelog-*` labels and when to use
them in the project-specific CLAUDE.md instructions.
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes `Init.Data.Dyadic.Instances` and `Init.Data.Dyadic.Inv`.
Previously, all declarations defined in boths file were private and not
exposed.
This PR fixes how we determine whether a function parameter is an
instance.
Previously, we relied on binder annotations (e.g., `[Ring A]` vs `{_ :
Ring A}`)
to make this determination. This is unreliable because users
legitimately use
`{..}` binders for class types when the instance is already available
from
context. For example:
```lean
structure OrdSet (α : Type) [Hashable α] [BEq α] where
...
def OrdSet.insert {_ : Hashable α} {_ : BEq α} (s : OrdSet α) (a : α) : OrdSet α :=
...
```
Here, `Hashable` and `BEq` are classes, but the `{..}` binder is
intentional, the
instances come from `OrdSet`'s parameters, so type class resolution is
unnecessary.
The fix checks the parameter's *type* using `isClass?` rather than its
syntax, and
caches this information in `FunInfo`. This affects several subsystems:
- **Discrimination trees**: instance parameters should not be indexed
even if marked with `{..}`
- **Congruence lemma generation**: instances require special treatment
- **`grind` canonicalizer**: must ensure canonical instances
**Potential regressions**: automation may now behave differently in
cases where it
previously misidentified instance parameters. For example, a rewrite
rule in `simp` that was
not firing due to incorrect indexing may now fire.
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: Claude <noreply@anthropic.com>
Due to the way variable expansion and if interact in cmake, unquoted
variable expansions should essentially never be used inside if and may
lead to unexpected behavior. Also, quoted variable expansions can
usually be replaced by the unquoted variable name.
For more details, see this section in the cmake docs:
https://cmake.org/cmake/help/latest/command/if.html#variable-expansion
As one example of the kinds of issues that can occur with unquoted
variable expansions, consider this check from
`src/shell/CMakeLists.txt`, which tries to ensure that a test is only
run in non-WASM builds.
```cmake
if(NOT ${EMSCRIPTEN})
```
If the variable `EMSCRIPTEN` is empty or not defined (as is the case in
a non-WASM build), `${EMSCRIPTEN}` expands to 0 arguments, meaning the
check becomes
```cmake
if(NOT)
```
Since the `NOT` is unquoted, the if now tries to resolve it as a
variable. Since the variable `NOT` does not exist, the condition is
false and the test is never executed, even in non-WASM builds.
This PR provides the `Nat`/`Int` lemmas `x ≤ y * z ↔ (x + z - 1) / z ≤
y`, `x ≤ y * z ↔ (x + y - 1) / y ≤ z` and `x / z + y / z ≤ (x + y) / z`.
The PR is inspired by a `human-eval-lean` problem, the solution of which
required these lemmas.
This PR adds the `introSubstEq` MetaM tactic, as an optimization over
`intro h; subst h` that avoids introducing `h : a = b` if it can be
avoided,
which is the case when `b` can be reverted without reverting anything
else. Speeds up the generation of `injEq` theorem.
This PR removes the LCNF testing framework. Unfortunately it never got
used much and porting it to
the extended LCNF structure now would be a bit of effort that would
ultimately be in vain.
This PR fixes a bug in `System.Uri.fileUriToPath?` where it wouldn't use
the default Windows path separator in the path it produces.
It also adjusts the URI patching in the interactive test runner to be
more robust.
This PR adds `mkBackwardRuleFromExpr` to create backward rules from
expressions, complementing the existing `mkBackwardRuleFromDecl` which
only works with declaration names.
The new function enables creating backward rules from partially applied
terms. For example, `mkBackwardRuleFromExpr (mkApp (mkConst
``Exists.intro [1]) Nat.mkType)` creates a rule for `Exists.intro` with
the type parameter fixed to `Nat`, leaving only the witness and proof as
subgoals.
The `levelParams` parameter supports universe polymorphism: when
creating a rule like `Prod.mk Nat` that should work at multiple universe
levels, the caller specifies which level parameters remain polymorphic.
The pattern's universe variables are then instantiated appropriately at
each application site.
Also refactors `Pattern.lean` to share code between declaration-based
and expression-based pattern creation, extracting `mkPatternFromType`
and `mkEqPatternFromType` as common helpers.
This PR adds theorems showing the consistency between `find?` and the
various index-finding functions. The theorems establish bidirectional
relationships between finding elements and finding their indices.
**Forward direction** (find? in terms of index):
- `find?_eq_map_findFinIdx?_getElem`: `xs.find? p = (xs.findFinIdx?
p).map (xs[·])`
- `find?_eq_bind_findIdx?_getElem?`: `xs.find? p = (xs.findIdx? p).bind
(xs[·]?)`
- `find?_eq_getElem?_findIdx`: `xs.find? p = xs[xs.findIdx p]?`
**Reverse direction** (index in terms of find?):
- `findIdx?_eq_bind_find?_idxOf?`: `xs.findIdx? p = (xs.find? p).bind
(xs.idxOf?)`
- `findFinIdx?_eq_bind_find?_finIdxOf?`: `xs.findFinIdx? p = (xs.find?
p).bind (xs.finIdxOf?)`
- `findIdx_eq_getD_bind_find?_idxOf?`: `xs.findIdx p = ((xs.find?
p).bind (xs.idxOf?)).getD xs.length`
All theorems are provided for `List`, `Array`, and `Vector` (where
applicable).
Requested at
https://leanprover.zulipchat.com/#narrow/channel/113488-general/topic/show.20that.20Array.2Efind.3F.20and.20Array.2EfindFinIdx.3F.20consistent/near/567340199🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR activates `getElem?_pos` more aggressively, triggered by `c[i]`.
- [x] depends on: #12176🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes an issue where PR releases were not created when the test
suite failed, even though the build artifacts were available. The
workflow now runs whenever a PR's CI completes, regardless of
success/failure, and relies on the artifact verification step to ensure
the necessary build artifacts exist before proceeding.
This allows developers to get PR toolchains and test against Mathlib
even when the Lean test suite has failures, as long as the build jobs
succeeded.
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes a bug where delayed E-match theorem instances could cause
uniqueId collisions in the instance tracking map.
The `uniqueId` for theorem instances is generated using `numInstances`,
but this counter was only bumped for immediately activated instances
(`.ready` case), not for delayed instances (`.next` case). This caused
ID collisions:
1. Theorem A matches, becomes delayed, gets `uniqueId = N`
2. Counter isn't bumped (stays at N)
3. Theorem B matches next, gets `uniqueId = N` (same!)
4. B's entry overwrites A's entry in `instanceMap`
5. A's tracking is lost
This manifested as `grind?` and `finish?` producing `instantiate approx`
(meaning "we couldn't determine which theorems to use") instead of
proper `instantiate only [...]` with specific theorem lists.
The fix bumps `numInstances` for delayed instances too, ensuring each
theorem instance gets a truly unique ID.
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds `prefix_map_iff_of_injective` and
`suffix_map_iff_of_injective` lemmas to Init.Data.List.Nat.Sublist.
These lemmas establish that if a function `f` is injective, then the
prefix and suffix relations are preserved under mapping (e.g., `l₁.map f
<+: l₂.map f ↔ l₁ <+: l₂`). These additions complement the existing
index-based lemmas in this file and allow for simpler structural proofs
without resorting to `take`, `drop`, or manual index manipulation.
This PR adds the function `Std.Iter.first?` and proves the specification
lemma `Std.Iter.first?_eq_match_step` if the iterator is productive.
The monadic variant on `Std.IterM` is also provided.
We use this new function to fix the default implementation for
`startsWith` and `dropPrefix` on `String` patterns, which used to fail
if the searcher returned a `skip` at the beginning. None of the patterns
we ship out of the box were affected by this, but user-defined patterns
were vulnerable.
---------
Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
This PR adds regression tests that catch issues where structures/classes
with class-typed fields produce HEq goals in `congr` instead of handling
Prop fields automatically.
Both tests pass on v4.28.0-rc1 (before isInstance detection changes).
## Test 1: Structure extending classes (mirrors Mathlib's GroupTopology)
```lean
structure MyGroupTopology (α : Type) extends MyTopology α, IsContinuousMul α
theorem MyGroupTopology.toMyTopology_injective {α : Type} :
Function.Injective (MyGroupTopology.toMyTopology : MyGroupTopology α → MyTopology α) := by
intro f g h
cases f
cases g
congr
```
**Failure mode:** `⊢ toIsContinuousMul✝¹ ≍ toIsContinuousMul✝`
## Test 2: Class with explicit class-typed field (mirrors Mathlib's
PseudoEMetricSpace)
```lean
class MyMetricSpace (α : Type) extends MyDist α where
dist_self : ∀ x : α, dist x x = 0
toMyUniformity : MyUniformity α -- explicit class-typed field (NOT from extends)
uniformity_dist : toMyUniformity.uniformity (fun x y => dist x y = 0)
protected theorem MyMetricSpace.ext {α : Type} {m m' : MyMetricSpace α}
(h : m.toMyDist = m'.toMyDist) (hU : m.toMyUniformity = m'.toMyUniformity) : m = m' := by
cases m
cases m'
congr 1 <;> assumption
```
**Failure mode:** `⊢ dist_self✝¹ ≍ dist_self✝` and `⊢ uniformity_dist✝¹
≍ uniformity_dist✝`
## Context
These tests are related to #12172, which changes instance parameter
detection from binder-based to `isClass?`-based. That change can affect
how structure fields are classified in congruence lemma generation.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR clarifies the release notes title format in the release
checklist documentation.
**Changes:**
- Add explicit section explaining title format for -rc1, subsequent RCs,
and stable releases
- Make it clear that titles should include both the RC suffix AND the
date (e.g., "Lean 4.7.0-rc1 (2024-03-15)")
- Update example to use realistic date format instead of YYYY-MM-DD
- Clarify that only content is written for -rc1, subsequent releases
just update the title
This addresses confusion about whether RC release notes should include
the date in the title.
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR documents an issue encountered during the v4.28.0-rc1 release:
if release notes are merged to the reference-manual repository AFTER the
version tag is created, the deployed documentation won't include them.
The fix is to either:
1. Include release notes in the same PR as the toolchain bump (or merge
before tagging)
2. Regenerate the tag after merging release notes
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR switches the PR release workflow from
`softprops/action-gh-release` to `gh release create`.
The `softprops/action-gh-release` action enumerates all releases to
check for existing ones, which fails when the repository has more than
10000 releases due to GitHub API pagination limits. The
`lean4-pr-releases` repository has accumulated over 10000 releases,
causing the PR release workflow to fail with:
```
Only the first 10000 results are available.
```
This is currently blocking all PR toolchain releases, including
https://github.com/leanprover/lean4/pull/12175.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes a comment that said "implicit arguments" when the code
actually checks `isInstImplicit`, which is specifically for instance
implicit arguments (`[...]` binders), not all implicit arguments.
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR bumps the version to 4.29.0 to begin the next development cycle
after v4.28.0-rc1.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds two benchmarks for mvcgen in the style of Leo's SymM
benchmarks.
While performance on add_sub_cancel_StateM.lean is in the same order of
magnitude as the corresponding MetaM benchmark, add_if_sub_StateM.lean
is far slower.
Measurements for add_sub_cancel:
```
goal_10: 245.576221 ms, kernel: 134.134182 ms
goal_20: 613.945320 ms, kernel: 115.453811 ms
goal_30: 1074.053596 ms, kernel: 179.076070 ms
goal_40: 1680.678302 ms, kernel: 252.066677 ms
goal_50: 2457.209584 ms, kernel: 293.974096 ms
goal_60: 3271.773330 ms, kernel: 368.394386 ms
goal_70: 3981.247921 ms, kernel: 434.297822 ms
goal_80: 5077.300540 ms, kernel: 507.047772 ms
goal_90: 6486.990060 ms, kernel: 556.952095 ms
goal_100: 7791.399986 ms, kernel: 623.605163 ms
```
Measurements for add_if_sub:
```
goal_2: 89.762349 ms, kernel: 43.320205 ms
goal_3: 190.655546 ms, kernel: 38.888499 ms
goal_4: 434.461936 ms, kernel: 75.234581 ms
goal_5: 1110.295284 ms, kernel: 161.698707 ms
goal_6: 3241.383031 ms, kernel: 326.137173 ms
goal_7: 11675.609970 ms, kernel: 684.907188 ms
```
Much room for improvement.
This PR adds `Option.of_wp_eq` and `Except.of_wp_eq`, similar to the
existing `Except.of_wp`. `Except.of_wp` is deprecated because applying
it requires prior generalization, at which point it is more convenient
to use `Except.of_wp_eq`.
This PR makes the compiler produce C code that statically initializes
close terms when possible. This change reduces startup time as the terms
are directly stored in the binary instead of getting computed at
startup.
The set of terms currently supported by this mechanism are:
- string literals
- ctors called with other statically initializeable arguments
- `Name.mkStrX` and other `Name` ctors as they require special support
due to their computed field and occur frequently due to name literals.
In core there are currently 152,524 closed terms and of these 103,929
(68%) get initialized statically with this PR. The remaining 48585 ones
are not extracted because they use (potentially transitively) various
non trivial pieces of code like `stringToMessageData` etc. We might
decide to add special support for these in the future but for the moment
this feels like it's overfitting too much for core.
This extracts a `postCallback` helper so that only the actual callback
is inlined.
Part of the motivation here is to exclude these tracing frames from
flame graph profiles.
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR documents the release notes writing process in detail and adds a
guard check to `release_checklist.py` to ensure release notes are
created for `-rc1` releases before proceeding with downstream repository
updates.
- **doc/dev/release_checklist.md**: Expanded "Writing the release notes"
section with detailed steps for generating, reviewing, and formatting
release notes in Verso format
- **script/release_checklist.py**: Added
`check_release_notes_file_exists()` to verify the release notes file
exists in reference-manual repository
- **.claude/commands/release.md**: Added "Release Notes" section
explaining the process for creating release notes during `-rc1` releases
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
verso depends on plausible, but this wasn't recorded in
release_repos.yml. This caused the release checklist to not properly
track the dependency ordering.
This PR adds `simpTelescope`, a simproc that simplifies telescope
binders (`have`-expression values and arrow hypotheses) but not the
final body. This is useful for simplifying targets before introducing
hypotheses.
This PR adds `simpArrowTelescope`, a simproc that simplifies telescopes
of non-dependent arrows (p₁ → p₂ → ... → q) while avoiding quadratic
proof growth.
When using `Expr.forallE` to represent nested implications, each nesting
level bumps de Bruijn indices in subterms, destroying sharing even with
hash-consing. For example, a free variable `x` gets different de Bruijn
representations at each depth, causing proof terms to grow.
`simpArrowTelescope` works by:
- Converting arrows to `Arrow p q` (a definitional wrapper)
- Simplifying each component
- Converting back to `→` form
Since `Arrow` arguments are not under binders, subterms remain identical
across nesting levels and can be shared.
The `simp_4` benchmark demonstrates the improvement:
With `forallE`: ~160ms, proof_size ≈ 173k
With `Arrow`: ~43ms, proof_size ≈ 16k
Tradeoff: `simpArrowTelescope` misses simplifications that depend on the
arrow structure (e.g., `p → p` to `True`), since post-methods aren't
applied to intermediate arrows. Thus, it is not used by default. to use
it, one has to set `simpArrowTelescope` as a `pre`-method.
This PR reverts #12000, which introduced a regression where `simp`
incorrectly rejects valid rewrites for perm lemmas.
The issue is that `NameGenerator.mkChild` creates names that don't
maintain the ordering assumption used by `acLt` for perm lemma
decisions. For example, after the change:
- Child generator creates names like `_uniq.102.2`
- Parent continues with `_uniq.7`
- But `Name.lt (.num (.num `_uniq 102) 2) (.num `_uniq 7)` is true
This causes fvars created later (in async tasks) to compare as smaller
than fvars created earlier, breaking the assumption that later fvars
compare greater according to `Name.lt`.
Fixes#12136.
🤖 Prepared with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds an API for building symbolic simulation engines and
verification
condition generators that leverage `grind`. The API wraps `Sym`
operations to
work with `grind`'s `Goal` type, enabling lightweight symbolic execution
while
carrying `grind` state for discharge steps.
New operations on `Goal`:
- `mkGoal`: create a `Goal` from an `MVarId`
- `introN`, `intros`: introduce binders
- `apply`: apply backward rules
- `simp`, `simpIgnoringNoProgress`: simplify using `Sym.Simp`
- `internalize`, `internalizeAll`: add hypotheses to the E-graph
- `grind`: attempt to close the goal using `grind`
- `assumption`: close by matching a hypothesis
A new test demonstrates the API on a stateful program with conditionals,
using `grind` to discharge arithmetic side conditions.
This PR fixes a bug introduced in #12086 where a `lake build :release
--no-build` would exit with code 1 rather than the `--no-build ` code 3.
Now both the bug from #12086 and this bug are fixed.
This PR adds a new benchmark `shallow_add_sub_cancel.lean` that
demonstrates symbolic simulation using a shallow embedding into monadic
`do` notation, as opposed to the deep embedding approach in
`add_sub_cancel.lean`.
The shallow embedding approach:
- Uses Lean's `StateM` monad directly instead of a custom command
language
- Defines `Exec s k post` as a simple predicate: `post (k s).1 (k s).2`
- Proves helper theorems for reasoning about monadic operations (`pure`,
`bind`, `get`, `set`, `modify`, `ite`)
- Programs are written in actual `do`-notation rather than a custom AST
The benchmark solves goals using both the `MetaM` and `SymM` frameworks,
showing that the shallow embedding integrates well with the symbolic
simulation infrastructure. `SymM` is again way faster than `MetaM`
### Symbolic simulation benchmark — tactic time only
Problem size `n` corresponds to a program with `4·n` monadic actions.
| n | MetaM tactic (ms) | SymM tactic (ms) | Speedup |
|-----|-------------------|------------------|---------|
| 10 | 82.10 | 11.37 | ~7.2× |
| 20 | 176.21 | 17.71 | ~9.9× |
| 30 | 306.47 | 25.39 | ~12.1× |
| 40 | 509.52 | 34.53 | ~14.7× |
| 50 | 689.19 | 43.51 | ~15.8× |
| 60 | 905.86 | 52.47 | ~17.3× |
| 70 | 1172.31 | 62.50 | ~18.8× |
| 80 | 1448.48 | 70.65 | ~20.5× |
| 90 | 1787.15 | 80.89 | ~22.1× |
| 100 | 2128.12 | 90.77 | ~23.5× |
<img width="580" height="455" alt="image"
src="https://github.com/user-attachments/assets/3511aaab-4d53-4520-8302-65d2d100df4a"
/>
This PR fixes a bug in the CI version validation where `grep -oE
'[0-9]+'` matches
multiple numbers from the comment on the same line:
```
set(LEAN_VERSION_IS_RELEASE 1) # This number is 1 in the release revision, and 0 otherwise.
```
The grep extracts `1`, `1`, and `0`, causing the comparison to fail.
🤖 Prepared with Claude Code
This PR adds a check to the release checklist script that verifies the
reference-manual release notes title matches the release type:
- For RC releases (e.g., v4.27.0-rc1): verifies the title contains the
exact
RC suffix (e.g., "Lean 4.27.0-rc1")
- For final releases (e.g., v4.27.0): verifies the title does NOT
contain
any "-rc" suffix (e.g., "Lean 4.27.0")
The check looks at the PR branch (bump_to_vX.Y.Z) for the release notes
file
at `Manual/Releases/v4_X_Y.lean` and parses the `#doc (Manual) "Lean
..."` line.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds documentation about the nightly build infrastructure to the
`/release` command to help future release managers understand the
relationship between branches and tags:
- `nightly` and `nightly-with-mathlib` are **branches** in
`leanprover/lean4`
- Dated tags like `nightly-YYYY-MM-DD` are **tags** in
`leanprover/lean4-nightly`
- When a nightly succeeds with mathlib, all three should point to the
same commit
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR fixes an issue that may sporadically trigger ASAN to got into a
deadlock when running a subprocess through the `IO.Process.spawn`
framework.
The general issue here is that we run `fork()` and then perform an
allocation in the child before going to `execvp` (for allocating the
arguments to `execvp`). As it turns out, doing this can cause a race
condition in ASAN that ultimately causes a deadlock in the child. This
was fixed upstream but then rolled back (see
https://github.com/google/sanitizers/issues/774). Thus, we must avoid
allocating any memory in between `fork` and `execvp`.
This PR fixes the verso hint that appears when using `sorry` in an
example block. It previously said: `` The `+error` flag indicates that
warnings are expected: +warning `` This PR replaces `error` with
`warning`. Fixes#12064
This PR revives the ability to specify modules in dependencies via the
basic `+mod` target key.
Implementation-wise, this removes deprecation of `BuildKey.module` and
once again uses it for `+mod` target keys. It also adds a test for
depending on a module of a dependency via `needs`.
This PR fixes the `lake query` output for targets which produce an
`Array` or `List` of a value with a custom `QueryText` or `QueryJson`
instance (e.g., `deps` and `transDeps`).
The most important change is that all bench scripts now must always
output to `measurements.jsonl` instead of being allowed to output
results on stdout/err.
This PR implements iteration over ranges for `Fin` and `Char`.
To this end, we introduce machinery for pulling back lawfulness of
`UpwardEnumerable` along an injective map and study the function
`Char.ordinal : Char -> Fin Char.numCodePoints`.
This PR fixes two Lake cache issues: a bug where a failed upload would
not produce an error and a mistake in the `--wfail` checks of the cache
commands.
This PR adds a comparison between `MetaM` and `SymM` for a benchmark was
proposed during the Lean@Google Hackathon.
### Benchmark description
In this benchmark, we define the semantics of a very simple imperative
language using an inductive predicate
```
Exec prog events mem lctx post
```
The predicate holds if, when executing the program `prog` with an
initial list of events `events`, memory `mem`, and local context `lctx`,
the postcondition `post` holds.
We then consider the following program:
```
input b
a := b
a := a + a
a := a - b
...
a := a + a
a := a - b
```
That is, after reading an input value `b`, the program repeatedly
updates the variable `a` by doubling it and then subtracting `b`.
We prove that, for any initial memory `m` and local context `l`, and
starting from the empty list of events, the following postcondition
holds:
```
fun t' m' l' =>
m' = m ∧ -- memory did not change
∃ v : Word,
t' = [IOEvent.IN v] ∧ -- exactly one input event
l'.get "a" = some v -- `a` contains the input value
```
In other words, executing the program produces exactly one input event,
leaves the memory unchanged, and ensures that the final value of `a` is
equal to the input value.
### Symbolic simulation benchmark (problem size `n`, with `2·n + 2`
instructions)
| Problem size (n) | MetaM time (ms) | MetaM kernel (ms) | SymM time
(ms) | SymM kernel (ms) | Total speedup |
|------------------|------------------|-------------------|----------------|------------------|---------------|
| 10 | 94.83 | 6.60 | 7.04 | 6.18 | ~13.5× |
| 20 | 218.92 | 13.33 | 14.15 | 13.02 | ~15.5× |
| 30 | 375.10 | 22.95 | 26.51 | 19.81 | ~14.2× |
| 40 | 563.82 | 34.99 | 40.42 | 29.55 | ~14.0× |
| 50 | 815.89 | 53.78 | 60.84 | 42.25 | ~13.4× |
| 60 | 1081.09 | 73.46 | 80.99 | 53.52 | ~13.3× |
| 70 | 1400.80 | 102.70 | 106.02 | 68.61 | ~13.2× |
| 80 | 1772.19 | 126.65 | 134.23 | 87.64 | ~13.2× |
| 90 | 2203.41 | 161.68 | 168.26 | 115.52 | ~13.1× |
| 100 | 2474.09 | 191.23 | 209.13 | 143.86 | ~11.8× |
<img width="580" height="455" alt="image"
src="https://github.com/user-attachments/assets/bc7058fa-e71a-4c2c-be28-860f39166965"
/>
### Symbolic simulation with extra simplification (SymM)
Problem size `n` corresponds to a program with `2·n + 2` instructions.
| n | Total time (ms) | Kernel time (ms) | Non-kernel time (ms) |
|-----|------------------|------------------|----------------------|
| 10 | 6.33 | 3.97 | 2.36 |
| 20 | 10.30 | 5.59 | 4.71 |
| 30 | 13.72 | 7.38 | 6.34 |
| 40 | 17.85 | 8.84 | 9.01 |
| 50 | 21.90 | 10.63 | 11.27 |
| 60 | 27.00 | 12.56 | 14.44 |
| 70 | 32.02 | 14.04 | 17.98 |
| 80 | 37.25 | 15.76 | 21.49 |
| 90 | 42.55 | 17.95 | 24.60 |
| 100 | 49.30 | 20.03 | 29.27 |
| 200 | 125.56 | 38.21 | 87.36 |
| 300 | 293.58 | 66.79 | 226.79 |
| 400 | 361.87 | 78.96 | 282.91 |
| 500 | 518.51 | 102.51 | 416.00 |
| 600 | 716.63 | 122.81 | 593.82 |
This PR fixes a bug where a `lake build --no-build` would exit with code
`3` if the optional job to fetch a GitHub or Reservoir release for a
package failed (even if nothing else needed rebuilding).
This PR fixes the procedure for finding the mangled symbol name of boxed
variants of native functions. Previously, the wrong symbol name has been
used for names ending in `_`: For example `test_` mangles to `l_test__`
but `test_._boxed` mangles to `l_test___00__boxed`, not
`l_test_____boxed` which the compiler would previously wrongly use.
This probably didn't affect anybody though since the failure condition
is pretty rare: the name of a native function that the interpreter tries
to execute would've had to end in `_`.
This PR adds the debugging helper functions `Expr.checkMaxShared` and
`MVarId.checkMaxShared` to `Sym`, and fixes a bug when visiting
telescopes in `Sym.simp`.
This PR adds additional debugging information to a run of `lake build
--no-build` via a `.nobuild` trace file. When a build fails due to
needing a rebuild, Lake emits the new expected trace next as `.nobuild`
file next to the build's old `.trace`. The inputs recorded in these
files can then be compared to debug what caused the mismatch.
To help keep the build directory clean, the `.nobuild` trace file is
removed on the next successful build.
This PR makes the automatic first token detection in tactic docs much
more robust, in addition to making it work in modules and other contexts
where builtin tactics are not in the environment. It also adds the
ability to override the tactic's first token as the user-visible name.
Previously, first token detection would look up the parser descriptor in
the environment and process its syntax. This would be incorrect for
builtin parsers, as well as for modules in which the definition is not
loaded. Now, it instead consults the Pratt parsing table for the
`tactic` syntax category. Tests are added that ensure this keeps working
in modules, and also that the first token of all tactics that ship with
Lean are either detected unambiguously or annotated to remove ambiguity.
Closes#12038.
This PR fixes a bug where the unknown identifier code actions were
broken in NeoVim due to the language server not properly setting the
`data?` field for all code action items that it yields.
This PR adds support for offset terms in `SymM`. This is essential for
handling equational theorems for functions that pattern match on natural
numbers in `Sym.simp`. Without this, it cannot handle simple examples
such as
```lean
def pw (n : Nat) : Nat :=
match n with
| 0 => 1
| n+1 => 2 * pw n
example : pw 4 = 16 := by
sym_simp [pw.eq_1, pw.eq_2]
example : pw (a + 2) = 2 * (2 * pw a) := by
sym_simp [pw.eq_2]
```
This PR adds `lake shake` as a built-in Lake command, moving the shake
functionality from `script/Shake.lean` into the Lake CLI.
## Motivation
Per discussion with @Kha and @tydeu, having shake as a top-level Lake
command is preferable to `lake exe shake` because:
- Avoids the awkwardness of accessing core tools via `lake exe`
- Compiles shake into the Lake binary, avoiding lakefile issues
- No benefit to lazy compilation on user machines for this tool
## Changes
- Move shake logic from `script/Shake.lean` to
`src/lake/Lake/CLI/Shake.lean`
- Add `lake shake` command dispatch in `Lake/CLI/Main.lean`
- Add help text in `Lake/CLI/Help.lean`
- Remove the standalone shake executable from `script/lakefile.toml`
## Usage
```
lake shake [OPTIONS] [<MODULE>...]
```
See `lake shake --help` for full documentation.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Mac Malone <mac@lean-fro.org>
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR moves `String.ofList` to `Init.Prelude`. It is a function that
the Lean kernel expects to be present and has special support for (when
reducing string literals). By moving this to `Init.Prelude`, all
declarations that are special to the kernel are in that single module.
After #12001, it was no longer true that `lean_trace(name(...), ...)`
would only perform the name allocation if no trace option was set. This
PR instead avoids the allocation in any case by avoiding this pattern.
This PR changes the default of `enableArtifactCache` to use the
workspace's `enableArtifactCache` setting if the package is a dependency
and `LAKE_ARTIFACT_CACHE` is not set. This means that dependencies of a
project with `enableArtifactCache` set will also, by default, use Lake's
local artifact cache.
This PR adds `simpControl`, a simproc that handles control-flow
expressions such as `if-then-else`. It simplifies conditions while
avoiding unnecessary work on branches that won't be taken.
The key behavior of `simpControl`:
- Simplifies the condition of `if-then-else` expressions
- If the condition reduces to `True` or `False`, returns the appropriate
branch, and continue simplifying.
- If the condition simplifies to a new expression, rebuilds the
`if-then-else` with the simplified condition (synthesizing a new
`Decidable` instance), and mark it as "done". That is, simplifier main
loop will not visit branches.
- Does **not** visit branches unless the condition becomes `True` or
`False`
This is useful for symbolic simplification where we want to avoid
wasting effort
simplifying branches that may be eliminated after the condition is
resolved.
This PR also fixes a bug in `Sym/Simp/EvalGround.lean`, and adds some
helper functions.
This PR adds `Sym.Simp.evalGround`, a simplification procedure for
evaluating ground terms of builtin numeric types. It is designed for
`Sym.simp`.
Key design differences from `Meta.Simp` simprocs:
- Pure value extraction: `getValue?` functions are `OptionT Id` rather
than
`MetaM`, avoiding `whnf` overhead since `Sym` maintains canonical forms
- Specialized predicate lemmas: comparisons use pre-proved lemmas like
`Int.lt_eq_true` applied with `rfl`, avoiding `Decidable` instance
reconstruction at each call site
- Type dispatch via `match_expr`: assumes standard instances, no
synthesis
Supported types: `Nat`, `Int`, `Rat`, `Fin n`, `BitVec n`,
`UInt8/16/32/64`,
`Int8/16/32/64`.
Supported operations: arithmetic (`+`, `-`, `*`, `/`, `%`, `^`), bitwise
(`&&&`, `|||`, `^^^`, `~~~`), shifts (`<<<`, `>>>`), comparisons (`<`,
`≤`,
`>`, `≥`, `=`, `≠`, `∣`), and boolean predicates (`==`, `!=`).
This PR fixes an issue where attributes like `@[irreducible]` would not
be allowed under the module system unless combined with `@[exposed]`,
but the former may be helpful without the latter to ensure downstream
non-`module`s are also affected.
Fixes#12025
Drastically speeds up `isTracingEnabledFor` in the common case, which
has evolved from "no options set" to "`Elab.async` and probably some
linter options set but no `trace`".
## Breaking changes
`Lean.Options` is now an opaque type. The basic but not all of the
`KVMap` API has been redefined on top of it.
Ensure that individual definitions known statically to be unreachable
are stripped out by the linker instead of only whole modules. Achieves
sizeable savings today and will do more so with upcoming module system
compilation refinements.
This PR allows 'Go to Definition' to look through reducible definition
when looking for typeclass instance projections.
Specifically, this means that using 'Go to Definition' on uses of
`GT.gt` will now yield the corresponding `LT` instance as well.
This PR fixe a superliniear behavior in the closed subterm extractor.
Consider an LCNF of the shape:
```
let x1 := f arg
let x2 := f x1
let x3 := f x2
let x4 := f x3
...
```
In this case the previous closed term extraction algorithm would visit
`x1`, then `x2` and `x1`,
then `x3`,`x2`,`x1` and so on, failing each time. We now introduce a
cache to avoid this behavior.
This PR splits up the SCC that the compiler manages into (potentially)
multiple ones after
performing lambda lifting. This aids both the closed term extractor and
the elimDeadBranches pass as
they are both negatively influenced when more declarations than required
are within one SCC.
This PR fixes the pretty-printing of the `extract_lets` tactic.
Previously, the pretty-printer would expect a space after the
`extract_lets` tactic, when it was followed by another tactic on the
same line: for example,
`extract_lets; exact foo`
would be changed to
`extract_lets ; exact foo`.
This PR fixes this oversight. Found by using the pretty-printer for
formatting linting in leanprover-community/mathlib4#30658.
This PR fixes an issue where go-to-definition would jump to the wrong
location in presence of async theorems.
While the elaborator does not explicitly depend on `FVar`s not being
reused between declarations, the language server turned out to do so. As
we would have to split the name generator in any case as soon as we add
any parallelism within proofs, we now do so for any async code in order
to uphold this invariant again.
---------
Co-authored-by: mhuisi <mhuisi@protonmail.com>
This PR adds support for simplifying the arguments of over-applied and
under-applied function application terms in `Sym.simp`, completing the
implementation for all three congruence strategies (fixed prefix,
interlaced, and congruence theorems).
This PR adds missing dependencies in `src/CMakeLists.txt` to ensure that
leanrt_initial-exec, leanrt, and leancpp_1 targets wait for copy-leancpp
to complete before building. Fixes potential build race conditions in
stage 2+ builds on systems with large `nproc`.
Closes https://github.com/leanprover/lean4/issues/11808
This PR removes the need to write `.ofNat` for numeric options in
`lakefile.lean`. Note that `lake translate-config` incorrectly assumed
this was already legal in earlier revisions.
This replaces #11771.
This PR implements support for auto-generated congruence theorems in
`Sym.simp`, enabling simplification of functions with complex argument
dependencies such as proof arguments and `Decidable` instances.
Previously, `Sym.simp` used basic congruence lemmas (`congrArg`,
`congrFun`, `congrFun'`, `congr`) to construct proofs when simplifying
function arguments. This approach is efficient for simple cases but
cannot handle functions with dependent proof arguments or `Decidable`
instances that depend on earlier arguments.
The new `congrThm` function applies pre-generated congruence theorems
(similar to the main simplifier) to handle these complex cases.
This PR fixes the `floatLetIn` pass to not move variables in case it
could break linearity (owned variables being passed with RC 1). This
mostly improves the situation in the parser which previously had many
functions that were supposed to be linear in terms of `ParserState` but
the compiler made them non-linear. For an example of how this affected
parsers:
```lean-4
def optionalFn (p : ParserFn) : ParserFn := fun c s =>
let iniSz := s.stackSize
let iniPos := s.pos
let s := p c s
let s := if s.hasError && s.pos == iniPos then s.restore iniSz iniPos else s
s.mkNode nullKind iniSz
```
previously moved the `let iniSz := ...` declaration into the `hasError`
branch. However, this means that at the point of calling the inner
parser (`p c s`), the original state `s` needs to have RC>1 because it
is used later in the `hasError` branch, breaking linearity. This fix
prevents such moves, keeping `iniSz` before the `p c s` call.
This PR introduces two induction principles for bitvectors, based on the
concat and cons operations. We show how this principle can be useful to
reason about bitvectors by refactoring two population count lemmas
(`cpopNatRec_zero_le` and `toNat_cpop_append`) and introducing a new
lemma (`toNat_cpop_not`).
To use the induction principle we also move `cpopNatRec_cons_of_le` and
`cpopNatRec_cons_of_lt` earlier in the popcount section (they are the
building blocks enabling us to take advantage of the new induction
principle).
---------
Co-authored-by: luisacicolini <luisacicolini@gmail.com>
Co-authored-by: Luisa Cicolini <48860705+luisacicolini@users.noreply.github.com>
This PR adds missing type checking for pattern variables during pattern
matching/unification to prevent incorrect matches.
Previously, the pattern matcher could incorrectly match expressions even
when pattern variable types were incompatible with the matched subterm
types. For example, a pattern like `x` where `x : BitVec 0` could match
any term, ignoring the specific type constraint on `x`.
This PR introduces a two-phase type checking approach:
1. **Static analysis** (`mkCheckTypeMask`): Identifies which pattern
variables require type checking based on their syntactic position.
Variables that appear only as arguments to function applications skip
checking (the application structure already constrains their types),
while variables in function position, binder contexts, or standalone
positions must be checked.
2. **Runtime validation**: During matching, when a pattern variable is
assigned, its type is checked against the matched subterm's type if
flagged by the mask. Checking uses `withReducible` to balance soundness
and performance.
The PR also adds helper functions for debugging (`Sym.mkMethods`,
`Sym.simpWith`, `Sym.simpGoal`) and fixes a minor issue where
`Theorem.rewrite` could return `.step` with identical expressions
instead of `.rfl`.Body:
This PR optimizes congruence proof construction in `Sym.simp` by
avoiding
`inferType` calls on expressions that are less likely to be cached.
Instead of
inferring types of expressions like `@HAdd.hAdd Nat Nat Nat instAdd 5`,
we infer
the type of the function prefix `@HAdd.hAdd Nat Nat Nat instAdd` and
traverse
the forall telescope.
The key insight is that function prefixes are more likely shared across
many call sites
(e.g., all `Nat` additions use the same `@HAdd.hAdd Nat Nat Nat
instAdd`), so they
benefit from `inferType` caching.
Benchmark results show improvements on workloads with shared function
prefixes:
- `many_rewrites_5000`: 48.8ms → 43.1ms (-12%)
- `term_tree_5000`: 53.4ms → 30.5ms (-43%)
This PR implements a new strategy for simplifying `have`-telescopes in
`Sym.simp` that achieves linear kernel type-checking time instead of
quadratic.
## Problem
When simplifying deep `have`-telescopes, the previous approach using
`have_congr'` produced proofs that type-checked in quadratic time. The
simplifier itself was fast, but the kernel became the bottleneck for
large telescopes.
For example, at n=100:
- **Before**: simp = 2.4ms, kernel = **225ms**
- **After**: simp = 3.5ms, kernel = **10ms**
The quadratic behavior occurred because the kernel creates fresh free
variables for each binder when type-checking, destroying sharing and
producing O(n²) intermediate terms.
## Solution
We transform sequential `have`-telescopes into a parallel
beta-application form:
```
have x₁ := v₁; have x₂ := v₂[x₁]; b[x₁, x₂]
↓ (definitionally equal)
(fun x₁ x₂' => b[x₁, x₂' x₁]) v₁ (fun x₁ => v₂[x₁])
```
This parallel form leverages the efficient simplifier for lambdas in
`Sym.simp`. This form enables:
1. Independent simplification of each argument
2. Proof construction using standard congruence lemmas
3. Linear kernel type-checking time
The algorithm has three phases:
1. **`toBetaApp`**: Transform telescope → parallel beta-application
2. **`simpBetaApp`**: Simplify using `congr`/`congrArg`/`congrFun'` and
`simpLambda`
3. **`toHave`**: Convert back to `have` form
## Benchmark Results
### Benchmark 1: Chain with all variables used in body
| n | Before (simp) | Before (kernel) | After (simp) | After (kernel) |
|---|---------------|-----------------|--------------|----------------|
| 50 | 1.2ms | 32ms | 1.6ms | 4.4ms |
| 100 | 2.4ms | **225ms** | 3.5ms | **10ms** |
| 200 | 4.5ms | — | 8.4ms | 27ms |
| 500 | 11.7ms | — | 33.6ms | 128ms |
### Benchmark 3: Parallel declarations (simplified values)
| n | Before (simp) | Before (kernel) | After (simp) | After (kernel) |
|---|---------------|-----------------|--------------|----------------|
| 50 | 0.5ms | 24ms | 0.8ms | 1.8ms |
| 100 | 1.2ms | **169ms** | 1.8ms | **5.3ms** |
| 200 | 2.2ms | — | 3.9ms | 17ms |
| 500 | 5.9ms | — | 12.3ms | 93ms |
### Benchmark 5: Chain with single dependency
| n | Before (simp) | Before (kernel) | After (simp) | After (kernel) |
|---|---------------|-----------------|--------------|----------------|
| 100 | 1.6ms | 6.2ms | 1.8ms | 6.2ms |
| 200 | 2.8ms | 21.6ms | 4.4ms | 16.5ms |
| 500 | 7.3ms | **125ms** | 12.8ms | **72ms** |
Key observations:
- Kernel time is now **linear** in telescope depth (previously
quadratic)
- Simp time increases slightly due to the transformation overhead
- Total time (simp + kernel) is dramatically reduced for large
telescopes
- The improvement is most pronounced when the body depends on many
variables
## Trade-offs
- Proof sizes are larger (more congruence lemma applications)
- Simp time has ~1.5x overhead from the transformation
- For very small telescopes (n < 10), the overhead may not pay off
The optimization targets the critical path: kernel type-checking was the
bottleneck preventing scaling to realistic symbolic simulation
workloads.
This PR fixes a panic that occurred when a theorem had a docstring on an
auxiliary definition within a `where` clause.
Reproducer:
```lean
theorem foo : True := aux where /-- -/ aux := True.intro
```
The issue was that `asyncMayModify` used `.any` to check if a nested
declaration could have its extension state modified, which returned
`false` when the declaration wasn't yet in `asyncConsts`. Using `.all`
instead returns `true` for `none` (vacuously true), allowing
modification
of extension state for nested declarations that haven't been added to
`asyncConsts` yet.
Closes#11799🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR fixes library suggestions to include private proof-valued
structure fields.
Private proof-valued structure fields (like `private size_keys' :
keys.size = values.size`) generate projections with `_private.*` mangled
names. These were being filtered out by `isDeniedPremise` because
`isInternalDetail` returns true for names starting with `_`.
The fix allows private names through by checking `!isPrivateName name`,
following the pattern from #11946. This enables `grind +suggestions` to
discover and use private proof-valued structure fields from the current
module.
Soon I would like to fix the semantics of `isInternalDetail`, as the
current behaviour is clearly wrong, but as there are many call sites, I
would like to get the behaviour of tactics correct first.
Also switches `currentFile` to use `wasOriginallyTheorem` instead of
matching on `.thmInfo`, which correctly identifies both theorems and
proof-valued projections.
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds guidance for investigating CI failures promptly rather than
waiting for other jobs to complete.
---
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR moves the `deriving instance BEq for Option` from
`Init.Data.Option.Basic` to `Init.Core`, making `BEq (Option α)`
available earlier in the import chain.
This is preparatory work for adding `maxSuggestions : Option Nat` fields
to `Grind.Config` and `Simp.Config`, which need `BEq (Option Nat)` for
the `deriving BEq` clause.
The duplicate derivation in `Init.Data.Option.Basic` is kept because
proofs there need the definition to be exposed.
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds a new `first_par` tactic combinator that runs multiple
tactics in parallel and returns the first successful result (cancelling
the others).
The `try?` tactic's `atomicSuggestions` step now uses `first_par` to try
three grind variants in parallel:
- `grind? +suggestions` - uses library suggestion engine
- `grind? +locals` - unfolds local definitions from current file
- `grind? +locals +suggestions` - combines both
This leverages `TacticM.parFirst` which already provides the "first
success wins" parallel execution with cancellation.
### Depends on
- [x] depends on: #11946🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR provides a `Decidable` instance for `Nat.isPowerOfTwo` based on
the formula `(n ≠ 0) ∧ (n &&& (n - 1)) = 0`.
To do this it includes theorems about `Nat.testBit` to show that the
`n.log2`th bit is set in `n` and `n - 1` for non powers of two.
Bitwise lemmas are needed to reason about the `&&&` so the file
`Init.Data.Nat.Power2` is renamed to `Init.Data.Nat.Power2.Basic` and
`Init.Data.Nat.Power2.Lemmas` introduced that depends on
`Init.Data.Nat.Bitwise.Lemmas` to prevent circular includes.
---------
Co-authored-by: Kim Morrison <477956+kim-em@users.noreply.github.com>
This PR changes the runtime implementation of the `Decidable (xs = #[])`
and `Decidable (#[] = xs)` instances to use `Array.isEmpty`. Previously,
`decide (xs = #[])` would first convert `xs` into a list and then
compare it against `List.nil`.
This PR adds a `+locals` configuration option to the `simp`, `simp_all`,
and `dsimp` tactics that automatically adds all definitions from the
current file to unfold.
Example usage:
```lean
def foo (n : Nat) : Nat := n + 1
-- Without +locals, simp doesn't know about foo
example (n : Nat) : foo n = n + 1 := by simp -- fails
-- With +locals, simp can unfold foo
example (n : Nat) : foo n = n + 1 := by simp +locals -- succeeds
```
The implementation iterates over `env.constants.map₂` (which contains
constants defined in the current module) and adds definitions to unfold.
Instance definitions and internal details are filtered out.
**Note:** For local theorems, use `+suggestions` instead, which will
include relevant local theorems via the library suggestion engine.
🤖 Prepared with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds a `+locals` configuration option to the `grind` tactic that
automatically adds all definitions from the current file as e-match
theorems. This provides a convenient alternative to manually adding
`[local grind]` attributes to each definition. In the form `grind?
+locals`, it is also helpful for discovering which local declarations it
may be useful to add `[local grind]` attributes to.
Example usage:
```lean
def foo (n : Nat) : Nat := n + 1
-- Without +locals, grind doesn't know about foo
example (n : Nat) : foo n = n + 1 := by grind -- fails
-- With +locals, grind can use the equation
example (n : Nat) : foo n = n + 1 := by grind +locals -- succeeds
```
Instance definitions and internal details are filtered out.
🤖 Prepared with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This PR makes the external checker lean4checker available as the
existing `leanchecker` binary already known to elan, allowing for
out-of-the-box access to it.
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds utility functions for managing the message log during
tactic
evaluation, and refactors existing code to use them.
**New helpers in `Lean.Elab.Tactic`:**
- `withSuppressedMessages`: executes an action while suppressing new
messages
- `withCapturedMessages`: executes an action and returns any new
messages
- `hasErrorMessages`: checks if a message list contains errors
**Refactored to use these helpers:**
- `LibrarySearch.tryDischarger`: now uses `withSuppressedMessages`
- `Try.evalAndSuggest`: now uses `withSuppressedMessages`
- `Try.evalAndSuggestWithBy`: now uses `withSuppressedMessages`
These helpers provide a standard pattern for tactic validation that
needs to
inspect error messages (e.g., filtering out suggestions that produce
errors).
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR ensures that pretty-printing of unification hints inserts a
space after |- resp. ⊢.
All uses in Lean core and mathlib add a space after the |- or ⊢ symbol;
this makes the output match usage in practice.
This was discovered in leanprover-community/mathlib4#30658, adding a
formatting linter using pretty-printing as initial guide.
This PR filters deprecated lemmas from `exact?` and `rw?` suggestions.
Previously, both tactics would suggest deprecated lemmas, which could be
confusing for users since using the suggestion would trigger a
deprecation warning.
Now, lemmas marked with `@[deprecated]` are filtered out in the
`addImport` functions that populate the discrimination trees used by
these tactics.
**Example (before this PR):**
```lean
import Mathlib.Logic.Basic
example (h : ∃ n : Nat, n > 0) : True := by
choose (n : Nat) (hn : n > 0 + 0) using h
guard_hyp hn : n > 0 -- `rw?` would suggest `Eq.rec_eq_cast` which is deprecated
```
Zulip discussion:
https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/deprecated.20lemma.20from.20rw.3F/near/554106870🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR improves the error message when `initialize` (or `opaque`) fails
to find an `Inhabited` or `Nonempty` instance.
**Before:**
```
failed to synthesize
Inhabited Foo
```
**After:**
```
failed to synthesize 'Inhabited' or 'Nonempty' instance for
Foo
If this type is defined using the 'structure' or 'inductive' command, you can try adding a 'deriving Nonempty' clause to it.
```
Prompted by
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/initialize.20structure.20with.20IO.2ERef/near/564936030🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds a symbol to the runtime for marking `Array`
non-linearities. This should allow users to
spot them more easily in profiles or hunt them down using a debugger.
This PR adds a new option to the function `simpHaveTelescope` in which
the `have` telescope is simplified in two passes:
* In the first pass, only the values and the body are simplified.
* In the second pass, unused declarations are eliminated.
This new mode eliminates **superlinear** behavior in the benchmark
`simp_3.lean`. Note that the kernel type checker still **exhibits**
quadratic behavior in this example, because it **does not have support**
for expanding a `have`/`let` telescope in a single step.
This PR adds two features to the message testing commands:
## `#guard_panic` command
A new `#guard_panic` command that succeeds if the nested command
produces a panic message. Unlike `#guard_msgs`, it does not check the
exact message content, only that a panic occurred.
This is useful for testing commands that are expected to panic, where
the exact panic message text may be volatile. It is particularly useful
when minimizing a panic discovered "in the wild", while ensuring the
panic behaviour is preserved.
## `substring := true` option for `#guard_msgs`
Adds a `substring := true` option to `#guard_msgs` that checks if the
docstring appears as a substring of the output (after whitespace
normalization), rather than requiring an exact match. This is useful
when you only care about part of the message.
Example:
```lean
/-- Unknown identifier -/
#guard_msgs (substring := true) in
example : α := x
```
## Refactoring
Also refactors `runAndCollectMessages` as a shared helper function used
by both `#guard_msgs` and `#guard_panic`.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR factors out the `have`-telescope support used in `simp`, and
implements it using the `MonadSimp` interface. The goal is to
use this nice infrastructure for both `Meta.simp` and `Sym.simp`.
This PR covers tactic docstrings in the documentation style guide.
At the Mathlib Initiative we want to ensure that tactics have good
documentation. Since this will involve adding documentation to tactics
built into core Lean, I discussed with David that we should write a
shared set of documentation guidelines that allow me to do my work both
on the Lean and on the Mathlib repositories.
I have already shown an earlier version of this guideline to David who
made some helpful suggestions but would be away for a few days. So to
make sure the discussion doesn't get lost, I've made a PR with the
version I ended up with after the first round of comments.
---------
Co-authored-by: Robert J. Simmons <442315+robsimmons@users.noreply.github.com>
This PR reorganizes the monad hierarchy for symbolic computation in
Lean.
## Motivation
We want a clean layering where:
1. A foundational monad (`SymM`) provides maximally shared terms and
structural/syntactic `isDefEq`
2. `GrindM` builds on this foundation, adding E-graphs, congruence
closure, and decision procedures
3. Symbolic execution / VCGen uses `GrindM` directly without introducing
a third monad
## Changes
The core symbolic computation layer still lives in `Lean.Meta.Sym`. This
monad (`SymM`) provides:
- Maximally shared terms with pointer-based equality
- Structural/syntactic `isDefEq` and matching (no reduction, predictable
cost)
- Monotonic local contexts (no `revert` or `clear`), enabling O(1)
metavariable validation
- Efficient `intro`, `apply`, and `simp` implementations
The name "Sym" reflects that this is infrastructure for symbolic
computation: symbolic simulation, verification condition generation, and
decision procedures.
### Updated hierarchy
```
Lean.Meta.Sym -- SymM: shared terms, syntactic isDefEq, intro, apply, simp
Lean.Meta.Grind -- GrindM: E-graphs, congruence closure (extends SymM)
```
Symbolic execution is a usage pattern of `GrindM` operating on
`Grind.Goal`, not a separate monad. This keeps the API surface minimal:
users learn two monads, and VCGen is "how you use `GrindM`" (for users
that want to use `grind`) rather than a third abstraction to understand.
This PR implements `PersistentHashMap.findKeyD` and
`PersistentHashSet.findD`. The motivation is avoid two memory
allocations (`Prod.mk` and `Option.some`) when the collections contains
the key.
This PR fixes an issue where `grind` failed to prove `f ≠ 0` from `f * r
≠ 0` when using `Lean.Grind.CommSemiring`, but succeeded with
`Lean.Grind.Semiring`.
The `propagateMul` propagator handles `0 * a = 0` and `a * 0 = 0` rules
for semirings that don't have full ring support in grind. Previously,
`CommSemiring` was excluded because it uses a ring envelope for
normalization, but that approach doesn't propagate these equalities back
to the original terms. Now `CommSemiring` also uses `propagateMul`.
Reported as
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Grind.20failure.20for.20CommSemiring.2C.20not.20Semiring🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds `gcd_left_comm` lemmas for both `Nat` and `Int`:
- `Nat.gcd_left_comm`: `gcd m (gcd n k) = gcd n (gcd m k)`
- `Int.gcd_left_comm`: `gcd a (gcd b c) = gcd b (gcd a c)`
These lemmas establish the left-commutativity property for gcd,
complementing the existing `gcd_comm` and `gcd_assoc` lemmas.
Upstreamed from
https://github.com/leanprover-community/mathlib4/pull/33235🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds a `done` flag to the result returned by `Simproc`s in
`Sym.simp`.
The `done` flag controls whether simplification should continue after
the result:
- `done = false` (default): Continue with subsequent simplification
steps
- `done = true`: Stop processing, return this result as final
## Use cases for `done = true`
### In `pre` simprocs
Skip simplification of certain subterms entirely:
```
def skipLambdas : Simproc := fun e =>
if e.isLambda then return .rfl (done := true)
else return .rfl
```
### In `post` simprocs
Perform single-pass normalization without recursive simplification:
```
def singlePassNormalize : Simproc := fun e =>
if let some (e', h) ← tryNormalize e then
return .step e' h (done := true)
else return .rfl
```
With `done = true`, the result `e'` won't be recursively simplified.
This PR adds support for simplifying lambda expressions in `Sym.simp`.
It is much more efficient than standard simp for very large lambda
expressions with many binders. The key idea is to generate a custom
function extensionality theorem for the type of the lambda being
simplified.
This technique is compatible with the standard `simp` tactic, and will
be ported in a separate PR.
<img width="581" height="455" alt="image"
src="https://github.com/user-attachments/assets/5911dc6c-03f0-48ed-843b-b8cb4f67ee61"
/>
### `lambda` benchmark summary
| Lambda size | MetaM (ms) | SymM (ms) | Speedup |
|-------------|------------|-----------|---------|
| 50 | 22.7 | 0.74 | ~31× |
| 100 | 120.5 | 1.75 | ~69× |
| 150 | 359.6 | 2.90 | ~124× |
| 200 | 809.5 | 4.51 | ~180× |
This PR adds a guard to `TagDeclarationExtension.tag` to check if the
declaration name is anonymous and return early if so. This prevents a
panic that could occur when modifiers like `meta` or `noncomputable` are
used in combination with syntax errors.
Reproducer:
```lean
public meta section
def private
```
Previously this would panic with:
```
PANIC at Lean.EnvExtension.modifyState: called on `async` extension,
must set `asyncDecl` in that case
```
This follows the same pattern as the fix in #10131 for `addDocString`
and the existing guard in `markNotMeta`.
See
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/panic.20on.20doc-string/near/566110399🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR ensures that `Sym.simp` checks thresholds for maximum recursion
depth and maximum number of steps. It also invokes `checkSystem`.
Additionally, this PR simplifies the main loop. Assigned metavariables
and `zetaDelta` reduction are now handled by installing `pre`/`post`
methods.
This PR adds `getMatch` and `getMatchWithExtra` for retrieving patterns
from
discrimination trees in the symbolic simulation framework.
The PR also adds uses `DiscrTree` to implement indexing in `Sym.simp`.
This PR adds discrimination tree support for the symbolic simulation
framework.
The new `DiscrTree.lean` module converts `Pattern` values into
discrimination
tree keys, treating proof/instance arguments and pattern variables as
wildcards
(`Key.star`). Motivation: efficient pattern retrieval during rewriting.
This PR adds a `with_unfolding_none` tactic that sets the transparency
mode to `.none`, in which no definitions are unfolded. This complements
the existing `with_unfolding_all` tactic and provides tactic-level
access to the `TransparencyMode.none` added in
https://github.com/leanprover/lean4/pull/11810.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds the directory `Meta/DiscrTree` and reorganizes the code
into different files. Motivation: we are going to have new functions for
retrieving simplification theorems for the new structural simplifier.
This PR improves the performance of `getLine` by coalescing the locking
of the underlying `FILE*`.
Unfortunately we cannot use `getline` or `fgets` for this as our code
needs to handle `\0` chars
and Windows.
This PR makes `mvcgen with tac` fail if `tac` fails on one of the VCs,
just as `induction ... with tac` fails if `tac` fails on one of the
goals. The old behavior can be recovered by writing `mvcgen with try
tac` instead.
This PR adds configuration flag `Meta.Context.cacheInferType`. You can
use it to disable the `inferType` cache at `MetaM`. We use this flag to
implement `SymM` because it has its own cache based on pointer equality.
This PR adds `CongrInfo` analysis for function applications in the
symbolic simulator framework. `CongrInfo` determines how to build
congruence proofs for rewriting subterms efficiently, categorizing
functions into:
- `none`: no arguments can be rewritten (e.g., proofs)
- `fixedPrefix`: common case where implicit/instance arguments form a
fixed prefix and explicit arguments can be rewritten (e.g., `HAdd.hAdd`,
`Eq`)
- `interlaced`: rewritable and non-rewritable arguments alternate (e.g.,
`HEq`)
- `congrTheorem`: uses auto-generated congruence theorems for functions
with dependent proof arguments (e.g., `Array.eraseIdx`)
This PR changes `bv_decide`'s heuristic for what kinds of structures to
split on to also allow
splitting on structures where the fields have dependently typed widths.
For example:
```lean
structure Byte (w : Nat) where
/-- A two's complement integer value of width `w`. -/
val : BitVec w
/-- A per-bit poison mask of width `w`. -/
poison : BitVec w
```
This is to allow handling situations such as `(x : Byte 8)` where the
width becomes concrete after
splitting is done.
This PR adds an incremental variant of `shareCommon` for expressions
constructed from already-shared subterms. We use this when an expression
`e` was produced by a Lean API (e.g., `inferType`, `mkApp4`) that does
not preserve maximal sharing, but the inputs to that API were already
maximally shared. Unlike `shareCommon`, this function does not use a
local `Std.HashMap ExprPtr Expr` to track visited nodes. This is more
efficient when the number of new (unshared) nodes is small, which is the
common case when wrapping API calls that build a few constructor nodes
around shared inputs.
This PR changes the definition of the iterator combinators `takeWhileM`
and `dropWhileM` so that they use `MonadAttach`. This is only relevant
in rare cases, but makes it sometimes possible to prove such combinators
finite when the finiteness depends on properties of the monadic
predicate.
This PR fixes a bug in the new pattern matching procedure for the Sym
framework. It was not correctly handling assigned metavariables during
pattern matching.
It also improves the support for free variables.
This PR adds performance comparison tests between the new `SymM` monad
and the standard `MetaM` for `intros`/`apply` operations.
The tests solve problems of the form:
```lean
let z := 0; ∀ x, ∃ y, x = z + y ∧ let z := z + x; ∀ x, ∃ y, x = z + y ∧ ... ∧ True
```
using repeated `intros` and `apply` with `Exists.intro`, `And.intro`,
`Eq.refl`, and `True.intro`.
**Results show 10-20x speedup:**
| Size | MetaM | SymM | Speedup |
|------|-------|------|---------|
| 1000 | 226ms | 21ms | 10.8x |
| 2000 | 582ms | 44ms | 13.2x |
| 3000 | 1.08s | 72ms | 15.0x |
| 4000 | 1.72s | 101ms | 17.0x |
| 5000 | 2.49s | 125ms | 19.9x |
| 6000 | 3.45s | 157ms | 22.0x |
This PR adds `BackwardRule` for efficient goal transformation via
backward chaining in `SymM`.
`BackwardRule` stores a theorem expression, precomputed pattern for
fast unification, and argument indices that become new subgoals. The
subgoal ordering lists non-dependent goals first to match the behavior
of `MetaM.apply`.
`BackwardRule.apply` unifies the goal type with the rule's pattern,
assigns the goal metavariable to the theorem application, and returns
new subgoals for unassigned arguments.
This PR makes the `FinitenessRelation` structure, which is helpful when
proving the finiteness of iterators, part of the public API. Previously,
it was marked internal and experimental.
This PR expands the pull request creation section with detailed
formatting guidelines including title format (type prefixes, imperative
present tense) and body format requirements (starting with "This PR").
Adds a concrete example for reference.
All modifications were suggested by Claude.
This PR adds `num?` parameter to `mkPatternFromTheorem` to control how
many leading quantifiers are stripped when creating a pattern. This
enables matching theorems where only some quantifiers should be
converted to pattern variables.
For example, to match `mk_forall_and : (∀ x, P x) → (∀ x, Q x) → (∀ x, P
x ∧ Q x)` against a goal `∀ x, q x 0 ∧ q (f (f x)) y`, we use
`mkPatternFromTheorem ``mk_forall_and (some 5)` to create the pattern `∀
x, ?P x ∧ ?Q x`, keeping the outermost `∀` in the pattern rather than
converting it to a pattern variable.
This PR completes the new pattern matching and unification procedures
for the symbolic simulation framework using a two-phase approach.
**Phase 1 (Syntactic Matching):**
- Patterns use de Bruijn indices for expression variables and renamed
level params for universe variables
- Purely structural matching after reducible definitions are unfolded
- Universe levels treat `max`/`imax` as uninterpreted functions
- Proof arguments skipped via proof irrelevance
- Instance and binder constraints deferred to Phase 2
**Phase 2 (Pending Constraints):**
- Level constraints: structural equality with mvar assignment
- Instance constraints: `isDefEqI` (full `isDefEq` for TC synthesis)
- Expression constraints: `isDefEqS` with Miller pattern support
- Unassigned instance pattern variables synthesized via
`trySynthInstance`
**`isDefEqS` (Structural DefEq):**
- Miller pattern detection and assignment (`?m x y z := rhs` → `?m :=
fun x y z => rhs`)
- Scope checking via `maxFVar` to prevent out-of-scope assignments
- Optional zeta-delta reduction for let-declarations
- Proof irrelevance and instance delegation to `isDefEqI`
**Key optimizations:**
- `abstractFVars` skips metavariables and uses `maxFVar` for early
cutoff
- Per-pattern `ProofInstInfo` cache for fast argument classification
- Maximal sharing.
This PR implements `isDefEqS`, a lightweight structural definitional
equality for the symbolic simulation framework. Unlike the full
`isDefEq`, it avoids expensive operations while still supporting Miller
pattern unification.
**Key features:**
- Structural matching with optional zeta-delta reduction for
let-declarations
- Miller pattern detection and assignment (`?m x y z := rhs` → `?m :=
fun x y z => rhs`)
- Scope checking via `maxFVar` to prevent out-of-scope assignments
- Proof arguments skipped via proof irrelevance
- Instance arguments delegated to full `isDefEq` (need TC machinery)
- Universe levels treated structurally (`max`/`imax` as uninterpreted)
This PR adds optimized `abstractFVars` and `abstractFVarsRange` for
converting free variables to de Bruijn indices during pattern
matching/unification.
**Optimizations:**
- Metavariables are skipped (their contexts must not include abstracted
fvars)
- Subterms whose `maxFVar` is below the minimal abstracted fvar are
skipped via early cutoff
- Results are maximally shared via `AlphaShareBuilderM`
These optimizations are sound for Miller pattern matching where
metavariables are created before entering binders.
This PR implements `instantiateRevBetaS`, which is similar to
`instantiateRevS` but beta-reduces nested applications whose function
becomes a lambda after substitution.
For example, if `e` contains a subterm `#0 a` and we apply the
substitution `#0 := fun x => x + 1`, then `instantiateRevBetaS` produces
`a + 1` instead of `(fun x => x + 1) a`.
This is useful when applying theorems. For example, when applying
`Exists.intro`:
```lean
Exists.intro.{u} {α : Sort u} {p : α → Prop} (w : α) (h : p w) : Exists p
```
to a goal of the form `∃ x : Nat, p x ∧ q x`, we create metavariables
`?w` and `?h`. With `instantiateRevBetaS`, the type of `?h` becomes `p
?w ∧ q ?w` instead of `(fun x => p x ∧ q x) ?w`.
This PR introduces a fast pattern matching and unification module for
the symbolic simulation framework (`Sym`). The design prioritizes
performance by using a two-phase approach:
**Phase 1 (Syntactic Matching)**
- Patterns use de Bruijn indices for expression variables and renamed
level params (`_uvar.0`, `_uvar.1`, ...) for universe variables
- Matching is purely structural after reducible definitions are unfolded
during preprocessing
- Universe levels treat `max` and `imax` as uninterpreted functions (no
AC reasoning)
- Binders and term metavariables are deferred to Phase 2
**Phase 2 (Pending Constraints)** [WIP]
- Handles binders (Miller patterns) and metavariable unification
- Converts remaining de Bruijn variables to metavariables
- Falls back to `isDefEq` when necessary
**Key design decisions:**
- Preprocessing unfolds reducible definitions and performs beta/zeta
reduction
- Kernel projections are expected to be folded as projection
applications before matching
- Assignment conflicts are deferred to pending rather than invoking
`isDefEq` inline
- `instantiateRevS` ensures maximal sharing of result expressions
**TODO:**
- Skip instance arguments during matching, synthesize later
- Skip proof arguments (proof irrelevance)
- Implement `processPending` for Phase 2 constraints
This PR refactors the `Goal` type used in `grind`. The new
representation allows multiple goals with different metavariables to
share the same `GoalState`. This is useful for automation such as
symbolic simulator, where applying theorems create multiple goals that
inherit the same E-graph, congruence closure and solvers state, and
other accumulated facts.
This PR implements `intro` (and its variants) for `SymM`. These versions
do not use reduction or infer types, and ensure expressions are
maximally shared.
This PR adds the function `Sym.instantiateS` and its variants, which are
similar to `Expr.instantiate` but assumes the input is maximally shared
and ensures the output is also maximally shared.
This PR adds the function `Sym.replaceS`, which is similar to
`replace_fn` available in the kernel but assumes the input is maximally
shared and ensures the output is also maximally shared. The PR also
generalizes the `AlphaShareBuilder` API.
This PR simplifies `AlphaShareCommon.State` by separating the persistent
and transient parts of the state.
The `map` field caches visited sub-expressions during a single
`shareCommonAlpha` call to handle DAGs efficiently, the input expression
may contain shared sub-expressions that are not yet maximally shared.
However, this cache does not need to persist between different
`shareCommonAlpha` calls.
**Changes:**
- Moved `map` from the persistent `AlphaShareCommon.State` to a private
`State` used only within individual `shareCommonAlpha` calls.
- Replaced `PHashMap ExprPtr Expr` with (the more efficient)
`Std.HashMap ExprPtr Expr` for `map`, since it is now local to each call
and does not need persistence.
- The public `AlphaShareCommon.State` now only contains the `set` of
alpha-equivalent expressions that should persist
This PR adds functions for creating maximally shared terms from
maximally shared terms. It is more efficient than creating an expression
and then invoking `shareCommon`. We are going to use these functions for
implementing the symbolic simulation primitives.
This PR introduces `SymM`, a new monad for implementing symbolic
simulators (e.g., verification condition generators) in Lean. The monad
addresses performance issues found in symbolic simulators built on top
of user-facing tactics like `apply` and `intros`.
**Key features:**
- Goals are represented by `Grind.Goal` objects, enabling incremental
hypothesis processing
- No `revert` or `clear` operations, allowing O(1) local context checks
instead of O(n log n)
- Carries `GrindM` state across goals to avoid reprocessing shared
hypotheses
- Provides `mkGoal` for creating new goals within the monad
This is the foundational infrastructure for `SymM`. Future PRs will add
operations like `intro`, `apply`, and the optimized definitional
equality test.
This PR adds support for incrementally processing local declarations in
`grind`. Instead of processing all hypotheses at once during goal
initialization, `grind` now tracks which local declarations have been
processed via `Goal.nextDeclIdx` and provides APIs to process new
hypotheses incrementally.
This feature will be used by the new `SymM` monad for efficient symbolic
simulation.
This PR disables closed term extraction in the reflection terms used by
`bv_decide`. These terms do
not profit at all from closed term extraction but can in practice cause
thousands of new closed term
declarations which in turn slows down the compiler.
This PR improves the performance of and flattening in `bv_decide`.
The two main insights of this PR are:
1. When embedded constraint substitution is disabled it makes no sense
to have and flattening on in
the first place, given that we do not profit from it in any way.
2. The new fvars produced by and flattening can also be inserted into
the rewriting caches of the
preprocessing pipeline if the fvar they were derived from is already in
the cache. This
drastically decreases the amount of work we have to do in the second
rewriting pass after running
and flattening.
This PR adds the attributes `[grind norm]` and `[grind unfold]` for
controlling the `grind` normalizer/preprocessor.
The `norm` modifier instructs `grind` to use a theorem as a
normalization rule. That is, the theorem is applied during the
preprocessing step. This feature is meant for advanced users who
understand how the preprocessor and `grind`'s search procedure interact
with each other.
New users can still benefit from this feature by restricting its use to
theorems that completely eliminate a symbol from the goal. Example:
```lean
theorem max_def : max n m = if n ≤ m then m else n
```
For a negative example, consider:
```lean
opaque f : Int → Int → Int → Int
theorem fax1 : f x 0 1 = 1 := sorry
theorem fax2 : f 1 x 1 = 1 := sorry
attribute [grind norm] fax1
attribute [grind =] fax2
example (h : c = 1) : f c 0 c = 1 := by
grind -- fails
```
In this example, `fax1` is a normalization rule, but it is not
applicable to the input goal since `f c 0 c` is not an instance of `f x
0 1`. However, `f c 0 c` matches the pattern `f 1 x 1` modulo the
equality `c = 1`. Thus, `grind` instantiates `fax2` with `x := 0`,
producing the equality `f 1 0 1 = 1`, which the normalizer simplifies to
`True`. As a result, nothing useful is learned. In the future, we plan
to include linters to automatically detect issues like these. Example:
```lean
opaque f : Nat → Nat
opaque g : Nat → Nat
@[grind norm] axiom fax : f x = x + 2
@[grind norm ←] axiom fg : f x = g x
example : f x ≥ 2 := by grind
example : f x ≥ g x := by grind
example : f x + g x ≥ 4 := by grind
```
The `unfold` modifier instructs `grind` to unfold the given definition
during the preprocessing step. Example:
```lean
@[grind unfold] def h (x : Nat) := 2 * x
example : 6 ∣ 3*h x := by grind
```
This PR fixes a mismatch between the behavior of `foldlM` and
`foldlMUnsafe` in the three array
types. This mismatch is only exposed when manually specifying a `stop`
value greater than the size
of the array and only exploitable through `native_decide`.
The mismatch was introduced as part of
4ba21ea10c which introduced
`foldlMUnsafe` and thus likely a mistake when building the `unsafe`
implementation instead of a
specification mistake.
Closes#11773
This PR implements support for user-defined attributes at
`grind_pattern`. Suppose we have declared the `grind` attribute
```lean
register_grind_attr my_grind
```
Then, we can now write
```lean
opaque f : Nat → Nat
opaque g : Nat → Nat
axiom fg : g (f x) = x
grind_pattern [my_grind] fg => g (f x)
```
This PR uses the new support for user-defined `grind` attributes to
implement the default `[grind]` attribute.
A manual update-stage0 is required because it affects the .olean files.
This PR implements user-defined `grind` attributes. They are useful for
users that want to implement tactics using the `grind` infrastructure
(e.g., `progress*` in Aeneas). New `grind` attributes are declared using
the command
```lean
register_grind_attr my_grind
```
The command is similar to `register_simp_attr`. After the new attribute
is declared. Recall that similar to `register_simp_attr`, the new
attribute cannot be used in the same file it is declared.
```lean
opaque f : Nat → Nat
opaque g : Nat → Nat
@[my_grind] theorem fax : f (f x) = f x := sorry
example theorem fax2 : f (f (f x)) = f x := by
fail_if_success grind
grind [my_grind]
```
TODO: remove leftovers after update stage0
This PR allows `grind` to use `List.eq_nil_of_length_eq_zero` (and
`Array.eq_empty_of_size_eq_zero`), but only when it has already proved
the length is zero.
This PR moves the grind pattern from `Sublist.eq_of_length` to the
slightly more general `Sublist.eq_of_length_le`, and adds a grind
pattern guard so it only activates if we have a proof of the hypothesis.
This PR adds additional test coverage for #11758 (fix for #11745:
nonstandard instances in grind and simp +arith).
The existing test `grind_11745.lean` only covers Int LE with `grind
-order` and `lia -order`. This adds tests for:
- LT instances (Int and Nat)
- Nat LE instances
- Mixed canonical and non-canonical instances in the same goal
- Equality derived from two LE constraints
- `simp +arith` with non-canonical instances
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds a Python script that helps find which commit introduced a
behavior change in Lean. It supports multiple bisection modes and
automatically downloads CI artifacts when available.
- [x] depends on: #11735
## Usage
```
usage: lean-bisect [-h] [--timeout SEC] [--ignore-messages] [--verbose]
[--selftest] [--clear-cache] [--nightly-only]
[file] [RANGE]
Bisect Lean toolchain versions to find where behavior changes.
positional arguments:
file Lean file to test (must only import Lean.* or Std.*)
RANGE Range to bisect: FROM..TO, FROM, or ..TO
options:
-h, --help show this help message and exit
--timeout SEC Timeout in seconds for each test run
--ignore-messages Compare only exit codes, ignore stdout/stderr differences
--verbose, -v Show stdout/stderr from each test
--selftest Run built-in selftest to verify lean-bisect works
--clear-cache Clear CI artifact cache (~600MB per commit) and exit
--nightly-only Stop after finding nightly range (don't bisect individual
commits)
Range Syntax:
FROM..TO Bisect between FROM and TO
FROM Start from FROM, bisect to latest nightly
..TO Bisect to TO, search backwards for regression start
If no range given, searches backwards from latest nightly to find regression.
Identifier Formats:
nightly-YYYY-MM-DD Nightly build date (e.g., nightly-2024-06-15)
Uses pre-built toolchains from leanprover/lean4-nightly.
Fast: downloads via elan (~30s each).
v4.X.Y or v4.X.Y-rcN Version tag (e.g., v4.8.0, v4.9.0-rc1)
Converts to equivalent nightly range.
Commit SHA Git commit hash (short or full, e.g., abc123def)
Bisects individual commits between two points.
Tries CI artifacts first (~30s), falls back to building (~2-5min).
Commits with failed CI builds are automatically skipped.
Artifacts cached in ~/.cache/lean-bisect/artifacts/
Bisection Modes:
Nightly mode: Both endpoints are nightly dates.
Binary search through nightlies to find the day behavior changed.
Then automatically continues to bisect individual commits.
Use --nightly-only to stop after finding the nightly range.
Version mode: Either endpoint is a version tag.
Converts to equivalent nightly range and bisects.
Commit mode: Both endpoints are commit SHAs.
Binary search through individual commits on master.
Output: "Behavior change introduced in commit abc123"
Examples:
# Simplest: just provide the file, finds the regression automatically
lean-bisect test.lean
# Specify an endpoint if you know roughly when it broke
lean-bisect test.lean ..nightly-2024-06-01
# Full manual control over the range
lean-bisect test.lean nightly-2024-01-01..nightly-2024-06-01
# Only find the nightly range, don't continue to commit bisection
lean-bisect test.lean nightly-2024-01-01..nightly-2024-06-01 --nightly-only
# Add a timeout (kills slow/hanging tests)
lean-bisect test.lean --timeout 30
# Bisect commits directly (if you already know the commit range)
lean-bisect test.lean abc1234..def5678
# Only compare exit codes, ignore output differences
lean-bisect test.lean --ignore-messages
# Clear downloaded CI artifacts to free disk space
lean-bisect --clear-cache
```
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes an issue where `grind` fails when trying to unfold a
definition by pattern matching imported by `import all` (or from a
non-`module`).
Fixes#11715
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR turns even more commonly used bv_decide theorems that require
unification into fast simprocs
using syntactic equality. This pushes the overall performance across
sage/app7 to <= 1min10s for
every problem.
This PR replaces `ffi.md` with links to the corresponding sections of
the manual, so we don't have to keep two documents up to date.
A corresponding reference manual PR re-synchronizes them:
https://github.com/leanprover/reference-manual/pull/714
This PR upstreams dependency-management commands from Mathlib:
- `#import_path Foo` prints the transitive import chain that brings
`Foo` into scope
- `assert_not_exists Foo` errors if declaration `Foo` exists (for
dependency management)
- `assert_not_imported Module` warns if `Module` is transitively
imported
- `#check_assertions` verifies all pending assertions are eventually
satisfied
These commands help maintain the independence of different parts of a
library by catching unintended transitive dependencies early.
### Example usage
```lean
-- Find out how Nat got into scope
#import_path Nat
-- Declaration Nat is imported via
-- Init.Prelude,
-- which is imported by Init.Coe,
-- which is imported by Init.Notation,
-- ...
-- which is imported by this file.
-- Assert that a declaration should not be in scope yet
assert_not_exists SomeAdvancedType
-- Assert that a module should not be imported
assert_not_imported Some.Heavy.Module
-- Verify all assertions are eventually satisfied
#check_assertions
```
Addresses
https://lean-fro.zulipchat.com/#narrow/channel/398861-general/topic/path.20of.20an.20import🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds a standalone script to download pre-built CI artifacts from
GitHub Actions. This allows us to quickly switch commits without
rebuilding.
**Features:**
- Downloads artifacts for current HEAD or specified commit (`--sha`)
- Caches in `~/.cache/lean_build_artifact/` for reuse
- Platform detection (Linux/macOS, x86_64/aarch64)
**Usage:**
```
build_artifact.py # Download for current HEAD
build_artifact.py --sha abc1234 # Download for specific commit
build_artifact.py --clear-cache # Clear cache
```
This is extracted to be shared with `lean-bisect`.
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes an issue where `exact?` would not suggest private
declarations defined in the current module.
## Problem
When using `exact?` in a file with private declarations, those private
declarations were not being suggested even though they are valid and
accessible:
```lean
module
axiom P : Prop
private axiom p : P
example : P := by exact? -- error: could not find lemma
```
The problem was that `blacklistInsertion` in `LazyDiscrTree` was
filtering out all declarations whose names matched `isInternalDetail`,
which includes private names due to their `_private.Module.0.name`
structure.
## Solution
The fix adds a helper function `isPrivateNameOf` that checks if a
private declaration belongs to a specific module. The
`blacklistInsertion` function now allows private declarations belonging
to the current module (`env.header.mainModule`) to pass through the
filter.
Private declarations from imported modules are still filtered out, as
they may reference internal declarations that aren't accessible (which
would cause processing errors).
Zulip discussion:
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/.60exact.3F.60.20and.20private.20declarations/near/564586152🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR introduces some additional lemmas around `BitVec.extractLsb'`
and `BitVec.extractLsb`.
---------
Co-authored-by: Tobias Grosser <github@grosser.es>
Co-authored-by: Tobias Grosser <tobias@grosser.es>
This PR internalizes all arguments of Quot.lift during LCNF conversion,
preventing panics in certain
non trivial programs that use quotients.
Fixes#11719.
This PR improves the performance of the functions for generating
congruence lemmas, used by `simp`
and a few other components.
It is a followup to (though not dependent on) #11717 and improves the
performance of `bv_decide` on the benchmark
in question further down to 20 seconds (from 1min 23s in #11717 and 8min
originally). We are thus at approximately a 24x speedup from the
original run.
This PR improves the performance of `bv_decide`'s rewriter on large
problems.
The baseline for this PR is `QF_BV/sage/app7/bench_1222.smt2` on
`chonk3` at 8 minutes. After this
PR it takes about 1min and 23 seconds. This improvement is achieved by
turning frequently used simp
rules into simprocs in order to avoid spending time performing
unification to see if they are
applicable.
This PR renames the namespace `Std.Range` to `Std.Legacy.Range`. Instead
of using `Std.Range` and `[a:b]` notation, the new range type `Std.Rco`
and its corresponding `a...b` notation should be used. There are also
other ranges with open/closed/infinite boundary shapes in
`Std.Data.Range.Polymorphic` and the new range notation also works for
`Int`, `Int8`, `UInt8`, `Fin` etc.
This PR adds more MPL spec lemmas for all combinations of `for` loops,
`fold(M)` and the `filter(M)/filterMap(M)/map(M)` iterator combinators.
These kinds of loops over these combinators (e.g. `it.mapM`) are first
transformed into loops over their base iterators (`it`), and if the base
iterator is of type `Iter _` or `IterM Id _`, then another spec lemma
exists for proving Hoare triples about it using an invariant and the
underlying list (`it.toList`). The PR also fixes a bug that MPL always
assigns the default priority to spec lemmas if `Std.Tactic.Do.Syntax` is
not imported and a bug that low-priority lemmas are preferred about
high-priority ones.
For context, the MPL bug was related to the fact that the `Attr.spec`
syntax is not built-in. Therefore, Lean falls back to the `Attr.simple`
syntax, which *basically* also works, but which stores the priority at a
different position. The routine to extract the priority does not
consider this and so it falls back to the default priority given an
`Attr.simple` syntax object.
This PR improves the performance of autocompletion and fuzzy matching by
introducing an ASCII fast path into one of their core loops and making
Char.toLower/toUpper more efficient.
Co-authored-by: Rob23oba <152706811+Rob23oba@users.noreply.github.com>
This PR gives a focused error message when a user tries to name an
example, and tweaks error messages for attempts to define multiple
opaque names at once.
## Example errors
```
example x : 1 == 1 := by grind
```
Current message:
```
Failed to infer type of binder `x`
Note: Because this declaration's type has been explicitly provided, all parameter types and holes (e.g., `_`) in its header are resolved before its body is processed; information from the declaration body cannot be used to infer what these values should be
```
New message:
```
Failed to infer type of binder `x`
Note: Examples don't have names. The identifier `x` is being interpreted as a parameter `(x : _)`.
```
## Plural-aware identifier lists
Both the example errors and opaque errors understand pluralization and
use oxford commas.
```
opaque a b c : Nat
```
Current message:
```
Failed to infer type of binder `c`
Note: Multiple constants cannot be declared in a single declaration. The identifier(s) `b`, `c` are being interpreted as parameters `(b : _)`, `(c : _)`.
```
New message:
```
Failed to infer type of binder `c`
Note: Multiple constants cannot be declared in a single declaration. The identifiers `b` and `c` are being interpreted as parameters `(b : _)` and `(c : _)`.```
This PR extends the get-elem tactic for ranges so that it supports
subarrays. Example:
```lean
example {a : Array Nat} (h : a.size = 28) : Id Unit := do
let mut x := 0
for h : i in *...(3 : Nat) do
x := a[1...4][i]
```
This PR avoids invoking TC synthesis and other inference mechanisms in
the simprocs of bv_decide. This can give significant speedups on
problems that pressure these simprocs.
This PR enables the specializer to also recursively specialize in some
non trivial higher order situations.
The main motivation for this change is the upcoming changes to do
notation by sgraf. In there he uses combinators such as
```lean
@[specialize, expose]
def List.newForIn {α β γ} (l : List α) (b : β) (kcons : α → (β → γ) → β → γ) (knil : β → γ) : γ :=
match l with
| [] => knil b
| a :: l => kcons a (l.newForIn · kcons knil) b
```
in programs such as
```lean
def testing :=
let x := 42;
List.newForIn (β := Nat) (γ := Id Nat)
[1,2,3]
x
(fun i kcontinue s =>
let x := s;
List.newForIn
[i:10].toList x
(fun j kcontinue s =>
let x := s;
let x := x + i + j;
kcontinue x)
kcontinue)
pure
```
inspecting this IR right before we get to the specializer in the current
compiler we get:
```
[Compiler.eagerLambdaLifting] size: 22
def testing : Nat :=
fun _f.1 _y.2 : Nat :=
return _y.2;
let x := 42;
let _x.3 := 1;
fun _f.4 i kcontinue s : Nat :=
fun _f.5 j kcontinue s : Nat :=
let _x.6 := Nat.add s i;
let x := Nat.add _x.6 j;
let _x.7 := kcontinue x;
return _x.7;
let _x.8 := 10;
let _x.9 := Nat.sub _x.8 i;
let _x.10 := Nat.add _x.9 _x.3;
let _x.11 := 1;
let _x.12 := Nat.sub _x.10 _x.11;
let _x.13 := Nat.mul _x.3 _x.12;
let _x.14 := Nat.add i _x.13;
let _x.15 := @List.nil _;
let _x.16 := List.range'TR.go _x.3 _x.12 _x.14 _x.15;
let _x.17 := @List.newForIn _ _ _ _x.16 s _f.5 kcontinue;
return _x.17;
let _x.18 := 2;
let _x.19 := 3;
let _x.20 := @List.nil _;
let _x.21 := @List.cons _ _x.19 _x.20;
let _x.22 := @List.cons _ _x.18 _x.21;
let _x.23 := @List.cons _ _x.3 _x.22;
let _x.24 := @List.newForIn _ _ _ _x.23 x _f.4 _f.1;
return _x.24
```
Here the `kcontinue` higher order functions pose a special challenge
because they delay the discovery of new specialization opportunities.
Inspecting the IR after the current specializer (and a cleanup simp
step) we get functions that look as follows:
```
[simp] size: 7
def List.newForIn._at_.testing.spec_0 i kcontinue l b : Nat :=
cases l : Nat
| List.nil =>
let _x.1 := kcontinue b;
return _x.1
| List.cons head.2 tail.3 =>
let _x.4 := Nat.add b i;
let x := Nat.add _x.4 head.2;
let _x.5 := List.newForIn._at_.testing.spec_0 i kcontinue tail.3 x;
return _x.5
[simp] size: 14
def List.newForIn._at_.List.newForIn._at_.testing.spec_1.spec_1 _x.1 l b : Nat :=
cases l : Nat
| List.nil =>
return b
| List.cons head.2 tail.3 =>
fun _f.4 x.5 : Nat :=
let _x.6 := List.newForIn._at_.List.newForIn._at_.testing.spec_1.spec_1 _x.1 tail.3 x.5;
return _x.6;
let _x.7 := 10;
let _x.8 := Nat.sub _x.7 head.2;
let _x.9 := Nat.add _x.8 _x.1;
let _x.10 := 1;
let _x.11 := Nat.sub _x.9 _x.10;
let _x.12 := Nat.mul _x.1 _x.11;
let _x.13 := Nat.add head.2 _x.12;
let _x.14 := @List.nil _;
let _x.15 := List.range'TR.go _x.1 _x.11 _x.13 _x.14;
let _x.16 := List.newForIn._at_.testing.spec_0 head.2 _f.4 _x.15 b;
return _x.16
```
Observe that the specializer decided to abstract over `kcontinue`
instead of specializing further recursively. Thus this tight loop is now
going through an indirect call.
This PR now changes the specializer somewhat fundamentally to handle
situations like this. The most notable change is going to a fixpoint
loop of:
1. Specialize all current declarations in the worklist
2. If a declaration
- succeeded in specializing run the simplifier on it and put it back
onto the worklist
- if it didn't don't put it back onto the worklist anymore
3. Put all newly generated specialisations on the worklist
4. Recompute fixed parameters for the current SCC
5. Repeat until the worklist is empty
Furthermore, declarations that were already specialized:
- only consider `fixedHO` parameters for specialization, in order to
avoid termination issues with repeated specialization and abstraction of
type class parameters under binders
- recursively specialized declarations only allow specialization if at
least one of their fixedHO arguments is not a parameter itself. The
reason for allowing this in first generation specialization is that we
refrain from specializing inside the body of a declaration marked as
`@[specialize]`. Thus we need to specialize them even if their arguments
don't actually contain anything of interest in order to ensure that type
classes etc. are correctly cleaned up within their bodies.
There is one last trade-off to consider. When specializing code
generated by the new do elaborator we sometimes generate intermediate
specializations that are not actually part of any call graph after we
are done specializing. We could in principle detect these functions and
delete them but having them in cache is potentially helpful for further
specializations later. Once the new do elaborator lands we plan to test
this trade-off.
Closes#10924
This PR provides many lemmas about `Int` ranges, in analogy to those
about `Nat` ranges. A few necessary basic `Int` lemmas are added. The PR
also removes `simp` annotations on `Rcc.toList_eq_toList_rco`,
`Nat.toList_rcc_eq_toList_rco` and consorts.
This PR adds the definition of `BitVec.cpop`, which relies on the more
general `BitVec.cpopNatRec`, and build some theory around it. The name
`cpop` aligns with the [RISCV ISA
nomenclature](https://msyksphinz-self.github.io/riscv-isadoc/#_cpop).
Co-authored-by: @tobiasgrosser, @bollu
---------
Co-authored-by: Tobias Grosser <tobias@grosser.es>
Co-authored-by: Tobias Grosser <github@grosser.es>
Co-authored-by: Siddharth <siddu.druid@gmail.com>
This PR makes it possible to verify loops over iterators. It provides
MPL spec lemmas about `for` loops over pure iterators. It also provides
spec lemmas that rewrite loops over `mapM`, `filterMapM` or `filterM`
iterator combinators into loops over their base iterator.
This PR refactors match compilation, to handle “side-effect free”
patterns (`.var`, `.inaccessible`, `.as`) eagerly and for each
alternative separately. The idea is that there should be less interplay
between different alternatives, and prepares the ground for #11105.
This may cause some corner case match statements to compiler or fail
compile that behaved differently before. For example, it can now use a
sparse case where previously was using a full case, and pattern
completeness may not be clear to lean now. On the other hand, using a
sparse case can mean that match statements mixing matching in indicies
with matching on the indexed datatype can work.
This PR removes the unnecessary check for the batteries
`nightly-testing-YYYY-MM-DD` tag that blocks mathlib CI from running.
## Problem
Currently, when fixing mathlib's nightly-testing branch, the workflow
requires BOTH batteries and mathlib to have `nightly-testing-YYYY-MM-DD`
tags before mathlib CI can run on lean4 PRs. This creates a false
dependency:
1. Fix mathlib nightly-testing (including fixing batteries build)
2. Mathlib CI succeeds → creates mathlib tag → advances
`nightly-with-mathlib`
3. But batteries test suite fails → no batteries tag created
4. lean4 PR can't run mathlib CI because batteries tag doesn't exist
5. Bot suggests rebasing onto `nightly-with-mathlib`, but this doesn't
help
## Solution
Remove the batteries tag check because:
- Mathlib CI already depends on batteries (builds it as a dependency)
- If batteries is broken, mathlib CI will detect it
- The batteries testing branch creation already has fallback logic
(falls back to `nightly-testing` branch if tag doesn't exist)
This allows mathlib CI to run as soon as mathlib is ready, which is the
actual blocker.
See discussion at
https://leanprover.zulipchat.com/#narrow/channel/428973-nightly-testing/topic/Mathlib.20status.20updates/near/564136025🤖 Prepared with Claude Code
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This PR fixes `grind` to support dot notation on declarations in the
lemma list.
When using `grind only [foo.le]` where `foo.le` is dot notation applying
`LT.lt.le` to a theorem `foo`, grind previously failed with "Unknown
constant `foo.le`" because it tried to look up `foo.le` as a constant
name rather than elaborating it as a term.
The fix adds a fallback in `processParam`: when constant lookup fails,
it now falls back to `processTermParam` which elaborates the identifier
as a term. This allows dot notation expressions like `log_two_lt_d9.le`
to work correctly.
Closes#11690🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds the following repositories to the release configuration:
- lean4-unicode-basic
- BibtexQuery (depends on lean4-unicode-basic)
- verso-web-components (depends on verso)
It also updates dependencies:
- doc-gen4 now depends on BibtexQuery
- lean-fro.org now depends on verso-web-components
🤖 Prepared with Claude Code
This PR adds the new operation `MonadAttach.attach` that attaches a
proof that a postcondition holds to the return value of a monadic
operation. Most non-CPS monads in the standard library support this
operation in a nontrivial way. The PR also changes the `filterMapM`,
`mapM` and `flatMapM` combinators so that they attach postconditions to
the user-provided monadic functions passed to them. This makes it
possible to prove termination for some of these for which it wasn't
possible before. Additionally, the PR adds many missing lemmas about
`filterMap(M)` and `map(M)` that were needed in the course of this PR.
This PR improves `match` generalization such that it abstracts
metavariables in types of local variables and in the result type of the
match over the match discriminants. Previously, a metavariable in the
result type would silently default to the behavior of `generalizing :=
false`, and a metavariable in the type of a free variable would lead to
an error (#8099). Example of a `match` that elaborates now but
previously wouldn't:
```lean
example (a : Nat) (ha : a = 37) :=
(match a with | 42 => by contradiction | n => n) = 37
```
This is because the result type of the `match` is a metavariable that
was not abstracted over `a` and hence generalization failed; the result
is that `contradiction` cannot pick up the proof `ha : 42 = 37`.
The old behavior can be recovered by passing `(generalizing := false)`
to the `match`.
Furthermore, programs such as the following can now be elaborated:
```lean
example (n : Nat) : Id (Fin (n + 1)) :=
have jp : ?m := ?rhs
match n with
| 0 => ?jmp1
| n + 1 => ?jmp2
where finally
case m => exact Fin (n + 1) → Id (Fin (n + 1))
case jmp1 => exact jp ⟨0, by decide⟩
case jmp2 => exact jp ⟨n, by omega⟩
case rhs => exact pure
```
This is useful for the `do` elaborator.
Fixes#8099.
This PR makes `simpH`, used in the match equation generator, produce a
proof term. This is in preparation for a bigger refactoring in #11512.
This removes some cases, these are no longer necessary since #11196.
This PR fixes an inconsistency in the way Lake and Lean view the
transitivity of a `meta import`. Lake now works as Lean expects and
includes the meta segment of all transitive imports of a `meta import`
in its transitive trace.
This PR adds the `Context` type for cancellation with context
propagation. It works by storing a tree of forks of the main context,
providing a way to control cancellation.
This PR changes the "declaration uses 'sorry'" warning to use backticks
instead of single quotes, consistent with Lean's conventions for
formatting code identifiers in diagnostic messages.
Fix a typo in the error message when an unknown role is used in a
docstring.
- Changes "Unkown role" to "Unknown role" in
`src/Lean/Elab/DocString.lean`
This PR fixes the `grind` support for `Nat.ctorIdx`. Nat constructors
appear in `grind` as offsets or literals, and not as a node marked
`.constr`, so handle that case as well.
This PR moves many constants of the iterator API from `Std.Iterators` to
the `Std` namespace in order to make them more convenient to use. These
constants include, but are not limited to, `Iter`, `IterM` and
`IteratorLoop`. This is a breaking change. If something breaks, try
adding `open Std` in order to make these constants available again. If
some constants in the `Std.Iterators` namespace cannot be found, they
can be found directly in `Std` now.
This PR adds a CI step that fails if the `src/stdlib_flags.h` file was
modified, to alert PR authors that they most likely wanted to modify
`stage0/src/stdlib_flags.h` instead.
This PR adds basic support for equality propagation in `grind linarith`
for the `IntModule` case. This covers only the basic case. See note in
the code.
We remark this feature is irrelevant for `CommRing` since `grind ring`
already has much better support for equality propagation.
This PR fixes an issue where a `by` in the public scope could create an
auxiliary theorem for the proof whose type does not match the expected
type in the public scope.
Fixes#11672
This PR adds support for `Nat.cast` in `grind linarith`. It now uses
`Grind.OrderedRing.natCast_nonneg`. Example:
```lean
open Lean Grind Std
attribute [instance] Semiring.natCast
variable [Lean.Grind.CommRing R] [LE R] [LT R] [LawfulOrderLT R] [IsLinearOrder R] [OrderedRing R]
example (a : Nat) : 0 ≤ (a : R) := by grind
example (a b : Nat) : 0 ≤ (a : R) + (b : R) := by grind
example (a : Nat) : 0 ≤ 2 * (a : R) := by grind
example (a : Nat) : 0 ≥ -3 * (a : R) := by grind
```
This PR fixes the `grind` pattern validator. It covers the case where an
instance is not tagged with the implicit instance binder. This happens
in declarations such as
```lean
ZeroMemClass.zero_mem {S : Type} {M : outParam Type} {inst1 : Zero M} {inst2 : SetLike S M}
[self : @ZeroMemClass S M inst1 inst2] (s : S) : 0 ∈ s
```
This PR adds explicit guidance to the `/release` command that Claude
should never merge PRs autonomously during the release process - always
wait for the user to do it.
🤖 Prepared with Claude Code
This PR updates the release checklist script. The cslib repository no
longer has a docs subdirectory, so the release script was failing when
trying to update lakefile.toml and lean-toolchain in that nonexistent
directory.
This PR adds support for `Int.sign`, `Int.fdiv`, `Int.tdiv`, `Int.fmod`,
`Int.tmod`, and `Int.bmod` to `grind`. These operations are just
preprocessed away. We assume that they are not very common in practice.
Examples:
```lean
example {x y : Int} : y = 0 → (x.fdiv y) = 0 := by grind
example {x y : Int} : y = 0 → (x.tdiv y) = 0 := by grind
example {x y : Int} : y = 0 → (x.fmod y) = x := by grind
example {x y : Int} : y = 1 → (x.fdiv (2 - y)) = x := by grind
example {x : Int} : x > 0 → x.sign = 1 := by grind
example {x : Int} : x < 0 → x.sign = -1 := by grind
example {x y : Int} : x.sign = 0 → x*y = 0 := by grind
```
See #11622
This PR adds propagation rules corresponding to the `Semiring`
normalization rules introduced in #11628. The new rules apply only to
non-commutative semirings, since support for them in `grind` is limited.
The normalization rules introduced unexpected behavior in Mathlib
because they neutralize parameters such as `one_mul`: any theorem
instance associated with such a parameter is reduced to `True` by the
normalizer.
This PR teaches `grind` how to reduce `.ctorIdx` applied to
constructors. It can also handle tasks like
```
xs ≍ Vec.cons x xs' → xs.ctorIdx = 1
```
thanks to a `.ctorIdx.hinj` theorem (generated on demand).
This PR fixes a SIGFPE crash on x86_64 when evaluating `INT_MIN / -1` or
`INT_MIN % -1` for signed integer types.
On x86_64, the `idiv` instruction traps when the quotient overflows the
destination register. For signed integers, `INT_MIN / -1` produces a
result that overflows (e.g., `-2147483648 / -1 = 2147483648` which
doesn't fit in Int32). ARM64's `sdiv` instruction wraps instead of
trapping.
The fix:
- For Int8/Int16/Int32: widen to the next larger type before
dividing/modding, then truncate back
- For Int64: explicitly check for the overflow case and return the
wrapped result
Fixes#11612🤖 Prepared with Claude Code
This PR fixes a typo in the docstring of `LeanLibConfig.defaultFacets`
and the Lake README that erroneously referred to `LeanLib.sharedLib`
instead of `LeanLib.sharedFacet`.
See e.g. `tests/lake/tests/targets/lakefile.lean` to verify that
`LeanLib.sharedFacet` is correct usage; `LeanLib.sharedLib` does not
exist.
This PR adds support for `BitVec.ofNat` in `grind lia`. Example:
```lean
example (x y : BitVec 8) : y < 254#8 → x > 2#8 + y → x > 1#8 + y := by
grind
```
This PR implements a linter that warns when a deprecated coercion is
applied. It also warns when the `Option` coercion or the
`Subarray`-to-`Array` coercion is used in `Init` or `Std`. The linter is
currently limited to `Coe` instances; `CoeFun` instances etc. are not
considered.
The linter works by collecting the `Coe` instance declaration names that
are being expanded in `expandCoe?` and storing them in the info tree.
The linter itself then analyzes the info tree and checks for banned or
deprecated coercions.
This PR ensures the pattern normalizer used in `grind` does violate
assumptions made by the gadgets `Grind.genPattern` and
`Grind.getHEqPattern`.
Closes#11633
This PR adjusts the new `meta` keyword of the experimental module system
not to imply `partial` for general consistency.
As the previous behavior can create confusion return types that are not
known to be `Nonempty` and few `def`s should be `meta` in the first
case, this special case does not appear to be worth the minor
convenience.
This PR adds BEq instance for `DTreeMap`/`TreeMap`/`TreeSet` and their
extensional variants and proves lemmas relating it to the equivalence of
hashmaps/equality of extensional variants.
Stacked on top of #11266
This PR adds `@[suggest_for ℤ]` on `Int` and `@[suggest_for ℚ]` on
`Rat`, following the pattern established by `@[suggest_for ℕ]` on `Nat`
in #11554.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR causes Lean to search through `@[suggest_for]` annotations on
certain errors that look like unknown identifiers that got incorrectly
autobound. This will correctly identify that a declaration of type
`Maybe String` should be `Option String` instead.
## Example
```
example : Except String Unit := return .ok ()
```
```
Function expected at
Result
but this term has type
?m.1
Note: Expected a function because this term is being applied to the argument
String
Hint: The identifier `Result` is unknown, and Lean's `autoImplicit` option causes an unknown identifier to be treated as an implicitly bound variable with an unknown type. However, the unknown type cannot be a function, and a function is what Lean expects here. This is often the result of a typo or a missing `import` or `open` statement.
Perhaps you meant `Except` in place of `Result`?
```
The last line is added by this PR.
This PR allows Lean to present suggestions based on `@[suggest_for]`
annotations for unknown identifiers without internal dots. (The
annotations in #11554 only gave suggestion for dotted identifiers like
`Array.every`->`Array.all` and not for bare identifiers like
`Result`->`Except` or `ℕ`->`Nat`.)
This PR makes argument-less tactic invokations of `Std.Do` tactics such
as `mintro` emit a proper error message "`mintro` expects at least one
pattern" instead of claiming that `Std.Tactic.Do` needs to be imported.
Closes#11509.
This PR ensures we apply the ring normalizer to equalities being
propagated from the `grind` core module to `grind lia`. It also ensures
we use the safe/managed polynomial functions when normalizing.
Closes#11539
This PR improves the case-split heuristics in `grind`. In this PR, we do
not increment the number of case splits in the first case. The idea is
to leverage non-chronological backtracking: if the first case is solved
using a proof that doesn't depend on the case hypothesis, we backtrack
and close the original goal directly. In this scenario, the case-split
was "free", it didn't contribute to the proof. By not counting it, we
allow deeper exploration when case-splits turn out to be irrelevant.
The new heuristic addresses the second example in #11545
This PR removes the old ElimDeadBranches pass and shifts the new one
past lambda lifting.
The reason for dropping the old one is its general unsoundness and the
fact that we want to do refactorings on the IR part. The reason for
shifting the current pass past lambda lifting, is that its analysis is
imprecise in the presence of local function symbols. I experimented with
the exact placement for a while and it seems like it is optimal here.
Overall we observe a slight regression in the amount of C code
generated, likely because we don't propagate information into lambdas
before lifting them anymore. But generally measure a slight performance
improvement in general.
This PR fixes how theorems without parameters are handled in `grind`.
This is a better fix than #11579
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR moves Lake's `tests/lake/examples/targets` test from `examples`
to `tests` (and thus disabling it by default).
It is being
[flaky](https://github.com/leanprover/lean4/actions/runs/20111185289/attempts/1)
for some unknown reason, so I am disabling until I have a better
opportunity to debug it.
This PR ensures that ground theorems are properly handled as `grind`
parameters. Additionally, `grind [(thm)]` and `grind [thm]` should be
handled the same way.
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR fixes `grind?` to include term parameters (like `[show P by
tac]`) in its suggestions. Previously, these were being dropped because
term arguments are stored in `extraFacts` and not tracked via E-matching
like named lemmas.
For example, `grind? [show False by exact h]` now correctly suggests
`grind only [show False by exact h]` instead of just `grind only`.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds a `+all` option to `exact?` and `apply?` that collects all
successful lemmas instead of stopping at the first complete solution.
When `+all` is enabled:
- `exact?` shows all lemmas that completely solve the goal (admits the
goal with `sorry`)
- `apply?` shows all lemmas including both complete and partial
solutions
🤖 Prepared with Claude Code
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Adds a +all flag to exact? and apply? to collect all successful
lemmas, updates library search to support aggregation and proper
star-lemma fallback, and extends the discriminator tree to
extract/append dropped entries; includes tests.
>
> - **Tactics / UI**:
> - Add `LibrarySearchConfig.all` and `+all` flag to `exact?`/`apply?`
to collect all successful lemmas.
> - `exact?` now aggregates complete solutions (via
`addExactSuggestions`); `apply?` shows both complete and partial
suggestions.
> - Updated help texts and error/hint messages.
> - **Library Search Core (`Lean.Meta.Tactic.LibrarySearch`)**:
> - Thread new `collectAll` option through `tryOnEach`,
`librarySearch'`, and `librarySearch`.
> - `tryOnEach` continues collecting complete solutions when `collectAll
= true`.
> - Star-lemma fallback now runs even when primary search yields only
partial results; include complete solutions when aggregating.
> - Cache and retrieve star-indexed lemmas via
`droppedEntriesRef`/`getStarLemmas`.
> - **Lazy Discriminator Tree (`Lean.Meta.LazyDiscrTree`)**:
> - Add `extractKey(s)`/`collectSubtreeAux` to extract and drop entries,
returning them.
> - Modify import/module tree building to optionally append dropped
entries to a shared ref (for star-lemmas), and pass this through
`findMatches`/`createModuleTreeRef`.
> - Minor comment/logic tweaks (append vs set) when handling dropped
entries.
> - **Elaboration (`Lean.Elab.Tactic.LibrarySearch`)**:
> - Integrate `collectAll` into `exact?`/`apply?`; partition and present
complete vs incomplete suggestions; admit goals appropriately when
aggregating.
> - **Tests**:
> - Update existing expectations and add
`tests/lean/run/library_search_all.lean` to verify `+all`, aggregation,
and star-lemma behavior.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
cbfc9313af. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR documents that tests in `tests/lean/run/` run with
`-Dlinter.all=false`, and explains how to enable specific linters when
testing linter behavior.
🤖 Prepared with Claude Code
This PR fixes `grind` rejecting dot notation terms, mistaking them for
local hypotheses.
When a grind parameter like `n.triv` is given, where `n` is a local
variable and `triv` is a theorem that takes `n` as an argument (so
`n.triv` means `Nat.triv n`), grind was incorrectly rejecting it with
"redundant parameter" because it detected that the identifier resolved
to a local variable via `resolveLocalName`.
The fix checks if `resolveLocalName` returns field projections
(non-empty list), indicating dot notation. In that case, we process the
parameter as a term expression to let elaboration resolve the dot
notation properly, rather than trying to resolve it as a global constant
name.
### Minimal reproducer
```lean
theorem Nat.triv (n : Nat) : n = n := rfl
example (n : Nat) : n = n := by
grind [n.triv] -- Previously: "redundant parameter `n.triv`"
```
This also fixes the issue where `grind [x.exp_pos]` was rejected even
though `x.exp_pos` elaborates to `Real.exp_pos x`, a valid theorem
application.
🤖 Prepared with Claude Code
This PR adds missing lemmas about how `ReaderT.run`, `OptionT.run`,
`StateT.run`, and `ExceptT.run` interact with `MonadControl` operations.
This also leaves some comments noting that the lemmas may look less
general than expected; but this is because the instances are also not
very general.
This PR fixes an issue where `grind` did not display deprecation
warnings when deprecated lemmas were used in its argument list.
The fix adds explicit calls to `Linter.checkDeprecated` after resolving
theorem names in both `processParam` (for theorem arguments) and
`elabGrindParams` (for the `-` erase syntax).
Closes#11582🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This PR adds a lemma that the cast of a natural number into any ordered
ring is non-negative. We can't annotate this directly for `grind`, but
will probably add this to `grind`'s linarith interrnals.
This PR adds `@[suggest_for]` annotations to Lean, allowing lean to
provide corrections for `.every` or `.some` methods in place of `.all`
or `.any` methods for most default-imported types (arrays, lists,
strings, substrings, and subarrays, and vectors).
Due to the need for stage0 updates for new annotations, the
`suggest_for` annotation itself was introduced in previous PRs: #11367,
#11529, and #11590.
## Example
```
example := "abc".every (! ·.isWhitespace)
```
Error message:
```
Invalid field `every`: The environment does not contain `String.every`, so it is not possible to project the field `every` from an expression
"abc"
of type `String`
Hint: Perhaps you meant `String.all` in place of `String.every`:
.e̵v̵e̵r̵y̵a̲l̲l̲
```
(the hint is added by this PR)
## Additional changes
Adds suggestions that are not currently active but that can be used to
generate autocompletion suggestions in the reference manual:
- `Either` -> `Except` and `Sum`
- `Exception` -> `Except`
- `ℕ` -> `Nat`
- `Nullable` -> `Option`
- `Maybe` -> `Option`
- `Optional` -> `Option`
- `Result` -> `Except`
This PR switches the way olean files store identifier suggestions. The
ordering introduced in #11367 and #11529 made sense if we were only
storing incorrect -> correct mappings, but for the reference manual we
want to store the correct -> incorrect mappings as well, and so it is
more sensible to store just the correct -> incorrect mapping that mimics
the author-generated data better.
Also tweaks error messages further in preparation for public-facing
@[suggest_for] annotations and forbids suggestions on non-public names.
Does not make generally-visible changes as there are no introduced uses
of @[suggest_for] annotations yet.
These complement the existing `ExceptT.mk` and `OptionT.mk`, and provide
a symbol to key `simp` lemmas on, to prevent getting stuck on
`StateT.run (fun s => f s) s`.
A future PR could insert these new `mk`s into the implementation of many
definitions, such that unfolding the definitions leaves appropriate
casts behind; but this is invasive, and by itself having `mk` provides
value.
This PR improves indexing for `grind` patterns. We now include symbols
occurring in nested ground patterns. This important to minimize the
number of activated E-match theorems.
This PR makes the noConfusion principles even more heterogeneous, by
allowing not just indices but also parameters to be differ.
This is a breaking change for manual use of `noConfusion` for types with
parameters. Pass suitable `rfl` arguments, and use `eq_of_heq` on the
resulting equalities as needed.
This fixes#11560.
This PR adds `BEq` instance for `DHashMap`/`HashMap`/`HashSet` and their
extensional variants and proves lemmas relating it to the equivalence of
hashmaps/equality of extensional variants.
This PR allows projections on `tagged` values in the IR type system.
While executing this branch of code should indeed never happen in
practice, enforcing this through
the type system would require the compiler to always optimize code to
the point where this is not
possible. For example in the code:
```
cases x with
| none => ....
| some =>
let val : obj := proj[0] x
...
```
static analysis might learn that `x` is always none and transform this
to:
```
let x : tagged := none
cases x with
| none => ....
| some =>
let val : obj := proj[0] x
...
```
Which would be type incorrect if projections on `tagged` were
illegitimate. However, we don't want
to force static analysis to always simplify code far enough on its own
to enforce this invariant.
This PR prevents `try` swallowing heartbeat errors from nested `simp`
calls, and more generally ensures the `isRuntime` flag is propagated by
`throwNestedTacticEx`. This prevents the behavior of proofs (especially
those using `aesop`) being affected by the current recursion depth or
heartbeat limit.
This breaks a single caller in Mathlib where `simp` uses a lemma of the
form `x = f (g x)` and stack overflows, which can be fixed by
generalizing over `g x`.
Closes#7811.
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR fixes the tactic framework reporting file progress bar ranges
that cover up progress inside tactic blocks nested in tactic
combinators. This is a purely visual change, incremental re-elaboration
inside supported combinators was not affected.
Also adds a test though it is not elaborate enough to test proper timing
of progress events per se; see moddoc there.

This PR scans the environment for viable replacements for a dotted
identifier (like `.zero`) and suggests concrete alternatives as
replacements.
## Example
```
#example .zero
```
Error message:
```
Invalid dotted identifier notation: The expected type of `.cons` could not be determined
```
Additional hint added by this PR:
```
Hint: Using one of these would be unambiguous:
[apply] `BitVec.cons`
[apply] `List.cons`
[apply] `List.Lex.cons`
[apply] `List.Pairwise.cons`
[apply] `List.Perm.cons`
[apply] `List.Sublist.cons`
[apply] `List.Lex.below.cons`
[apply] `List.Pairwise.below.cons`
[apply] `List.Perm.below.cons`
[apply] `List.Sublist.below.cons`
[apply] `Lean.Grind.AC.Seq.cons`
```
## Additional changes
This PR also brings several related error message descriptions and code
actions more in line with each other, changing several "Suggested
replacement: " code actions to the more common "Change to " wording, and
sorts suggestions obtained from searching the context by the default
sort for Names (which prefers names with fewer segments).
This PR adds some information to Grove: a check that all
string/slice-transforming functions are tracked properly (which finds
dozens of missed cases), and some documentation of design designs around
naming in the string library.
The PR also bumps the Grove version to the latest version which contains
many new features and also processes the data a lot faster (40s to 2.5s
for the test project).
This PR ensures that `Nat`s in `.olean` files use a deterministic
serialization in the case where `LEAN_USE_GMP` is not set.
This is a simplified version of
https://github.com/leanprover/lean4/pull/2908.
This PR reviews the docstrings for `Std.Do` that will appear in the Lean
reference manual and adds those that were missing.
---------
Co-authored-by: Sebastian Graf <sgraf1337@gmail.com>
This PR adds a workspace-index to the name of the package used by build
target. To clarify the distinction between the different uses of a
package's name, this PR also deprecates `Package.name` for more
use-specific variants (e.g., `Package.keyName`, `Package.prettyName`,
`Package.origName`).
More to come. (WIP)
This PR introduces a new fixpoint combinator,
`WellFounded.extrinsicFix`. A termination proof, if provided at all, can
be given extrinsically, i.e., looking at the term from the outside, and
is only required if one intends to formally verify the behavior of the
fixpoint. The new combinator is then applied to the iterator API.
Consumers such as `toList` or `ForIn` no longer require a proof that the
underlying iterator is finite. If one wants to ensure the termination of
them intrinsically, there are strictly terminating variants available
as, for example, `it.ensureTermination.toList` instead of `it.toList`.
This PR introduces the new `tagged_return` attribute. It allows users to
mark `extern` declarations to be guaranteed to always return `tagged`
return values. Unlike with `object` or `tobject` the compiler does not
emit reference counting operations for them. In the future information
from this attribute will be used for a more powerful analysis to remove
reference counts when possible.
This PR ensures the auxiliary definitions created by
`register_try?_tactic` are internal implementation details that should
not be visible to user-facing linters.
🤖 Generated with Claude Code
This PR adds support for underscores as digit separators in
String.toNat?, String.toInt?, and related parsing functions. This makes
the string parsing functions consistent with Lean's numeric literal
syntax, which already supports underscores for readability (e.g.,
100_000_000).
The implementation validates that underscores:
- Cannot appear at the start or end of the number
- Cannot appear consecutively
- Are ignored when calculating the numeric value
This resolves a common source of friction when parsing user input from
command-line arguments, environment variables, or configuration files,
where users naturally expect to use the same numeric syntax they use in
source code.
## Examples
Before:
```lean
#eval "100_000_000".toNat? -- none
```
After:
```lean
#eval "100_000_000".toNat? -- some 100000000
#eval "1_000".toInt? -- some 1000
#eval "-1_000_000".toInt? -- some (-1000000)
```
## Testing
Added comprehensive tests in
`tests/lean/run/string_toNat_underscores.lean` covering:
- Basic underscore support
- Edge cases (leading/trailing/consecutive underscores)
- Both `toNat?` and `toInt?` functions
- String, Slice, and Substring types
All existing tests continue to pass.
Closes#11538🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This PR makes it so that in the issue template a line about how to check
boxes is in comment form you can only see it when you are creating the
issue and it does not need to be displayed to everyone.
Hi, these are just some spelling corrections.
There is one I wasn't completely sure about in
src/Init/Data/List/Lemmas.lean:
> See also
> ...
> Also
> \* \`Init.Data.List.Monadic\` for **addiation** _(additional?)_ lemmas
about \`List.mapM\` and \`List.forM\`
This PR fixes a syntax-pattern-matching issue from #11367 that prevented
the addition of suggestions in Init prior to Lean.Parser being
introduced, which was a significant shortcoming. It preserves the
ability to have multiple suggestions for one annotation later in the
process.
Additionally, tweaks a (not-yet-user-visible) error message and modifies
the attribute declaration to store a wrongIdentifier ->
correctIdentifier mapping instead of a correctIdentifier ->
wrongIdentifier mapping.
This PR makes the LCNF simplifier eliminate cases where all alts are
`.unreach` to just an `.unreach`.
an `.unreach`
We considered dropping a cases in a situation like this but decided
against it because it might hinder reuse.
```
def test x : Bool :=
cases x : Bool
| Except.error a.1 =>
⊥
| Except.ok a.2 =>
let _x.3 := true;
return _x.3
```
This PR avoids generating hyps when not needed (i.e. if there is a
catch-all so no completeness checking needed) during matching on values.
This tweak was made possible by #11220.
This PR adds a difference operation on
`ExtDTreeMap`/`ExtTreeMap`/`TreeSet` and proves several lemmas about it.
Stacked on top of #11407
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
This PR implements new flags and annotations for `shake` for use in
Mathlib:
> Options:
> --keep-implied
> Preserves existing imports that are implied by other imports and thus
not technically needed
> anymore
>
> --keep-prefix
> If an import `X` would be replaced in favor of a more specific import
`X.Y...` it implies,
> preserves the original import instead. More generally, prefers
inserting `import X` even if it
> was not part of the original imports as long as it was in the original
transitive import closure
> of the current module.
>
> --keep-public
> Preserves all `public` imports to avoid breaking changes for external
downstream modules
>
> --add-public
> Adds new imports as `public` if they have been in the original public
closure of that module.
> In other words, public imports will not be removed from a module
unless they are unused even
> in the private scope, and those that are removed will be re-added as
`public` in downstream
> modules even if only needed in the private scope there. Unlike
`--keep-public`, this may
> introduce breaking changes but will still limit the number of inserted
imports.
>
> Annotations:
> The following annotations can be added to Lean files in order to
configure the behavior of
> `shake`. Only the substring `shake: ` directly followed by a directive
is checked for, so multiple
> directives can be mixed in one line such as `-- shake:
keep-downstream, shake: keep-all`, and they
> can be surrounded by arbitrary comments such as `-- shake: keep
(metaprogram output dependency)`.
>
> * `module -- shake: keep-downstream`:
> Preserves this module in all (current) downstream modules, adding new
imports of it if needed.
>
> * `module -- shake: keep-all`:
> Preserves all existing imports in this module as is. New imports now
needed because of upstream
> changes may still be added.
>
> * `import X -- shake: keep`:
> Preserves this specific import in the current module. The most common
use case is to preserve a
> public import that will be needed in downstream modules to make sense
of the output of a
> metaprogram defined in this module. For example, if a tactic is
defined that may synthesize a
> reference to a theorem when run, there is no way for `shake` to detect
this by itself and the
> module of that theorem should be publicly imported and annotated with
`keep` in the tactic's
> module.
> ```
> public import X -- shake: keep (metaprogram output dependency)
>
> ...
>
> elab \"my_tactic\" : tactic => do
> ... mkConst ``f -- `f`, defined in `X`, may appear in the output of
this tactic
> ```
This PR implements `grind` propagators for `Nat` operators that have a
simproc associated with them, but do not have any theory solver support.
Examples:
```lean
example (a b : Nat) : a = 3 → b = 6 → a &&& b = 2 := by grind
example (a b : Nat) : a = 3 → b = 6 → a ||| b = 7 := by grind
example (a b : Nat) : a = 3 → b = 6 → a ^^^ b = 5 := by grind
example (a b : Nat) : a = 3 → b = 6 → a <<< b = 192 := by grind
example (a b : Nat) : a = 1135 → b = 6 → a >>> b = 17 := by grind
```
Closes#11498
This PR marks `Nat` power and divisibility theorems for `grind`. We use
the new `grind_pattern` constraints to control theorem instantiation.
Examples:
```lean
example {x m n : Nat} (h : x = 4 ^ (m + 1) * n) : x % 4 = 0 := by
grind
example (a m n o p : Nat) : a ∣ n → a ∣ m * n * o * p := by
grind
example {a b x m n : Nat}
: n > 0 → x = b * 4^m * a → a = 9^n → m > 0 → x % 6 = 0 := by
grind
example {a n : Nat}
: m > 4 → a = 2^(m^n) → a % 2 = 0 := by
grind
```
Closes#11515
Remark: We are adding support for installing extra theorems to `lia`
(aka `cutsat`). The example at #11515 can already be solved by `grind`
with this PR, but we still need to add the new theorems to the set for
`lia`.
cc @kim-em
This PR provides an additional hint when the type of an autobound
implicit is required to have function type or equality type — this
fails, and the existing error message does not address the fact that the
source of the error is an unknown identifier that was automatically
bound.
## Example
```
import Lean
example : MetaM String := pure ""
```
Current error message:
```
Function expected at
MetaM
but this term has type
?m
Note: Expected a function because this term is being applied to the argument
String
```
Additional error message provided by this PR:
```
Hint: The identifier `MetaM` is unknown, and Lean's `autoImplicit` option
causes an unknown identifier to be treated as an implicitly bound variable
with an unknown type. However, the unknown type cannot be a function, and a
function is what Lean expects here. This is often the result of a typo or a
missing `import` or `open` statement.
```
This PR re-enables star-indexed lemmas as a fallback for `exact?` and
`apply?`.
Star-indexed lemmas (those with overly-general discrimination tree keys
like `[*]`)
were previously dropped entirely for performance reasons. This caused
useful lemmas
like `Empty.elim`, `And.left`, `not_not.mp`, `Sum.elim`, and
`Function.mtr` to be
unfindable by library search.
The implementation adds a two-pass search strategy:
1. First, search using concrete discrimination keys (the current
behavior)
2. If no results are found, fall back to trying star-indexed lemmas
The star-indexed lemmas are extracted during tree initialization and
cached in an
environment extension, avoiding repeated computation.
Users can disable the fallback with `-star`:
```lean
example {α : Sort u} (h : Empty) : α := by apply? -star -- error: no lemmas found
example {α : Sort u} (h : Empty) : α := by apply? -- finds Empty.elim
```
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds support for the difference operation for
`ExtDHashMap`/`ExtHashMap`/`ExtHashSet` and proves several lemmas about
it.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
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.
This PR introduces a new annotation that allows definitions to describe
plausible-but-wrong name variants for the purpose of improving error
messages.
This PR just adds the notation and extra functionality; a stage0 update
will allow standard Lean functions to have suggestion annotations.
(Hence the changelog-no tag: this should go in the changelog when some
preliminary annotations are actually added.)
## Example
```lean4
inductive MyBool where | tt | ff
attribute [suggest_for MyBool.true] MyBool.tt
attribute [suggest_for MyBool.false] MyBool.ff
@[suggest_for MyBool.not]
def MyBool.swap : MyBool → MyBool
| tt => ff
| ff => tt
/--
error: Unknown constant `MyBool.true`
Hint: Perhaps you meant `MyBool.tt` in place of `MyBool.true`:
M̵y̵B̵o̵o̵l̵.̵t̵r̵u̵e̵M̲y̲B̲o̲o̲l̲.̲t̲t̲
-/
#guard_msgs in
example := MyBool.true
/--
error: Invalid field `not`: The environment does not contain `MyBool.not`, so it is not possible to project the field `not` from an expression
MyBool.tt
of type `MyBool`
Hint: Perhaps you meant one of these in place of `MyBool.not`:
[apply] `MyBool.swap`: MyBool.tt.swap
-/
#guard_msgs in
example := MyBool.tt.not
```
This PR marks `Char -> Bool` patterns as default instances for string
search. This means that things like `" ".find (·.isWhitespace)` can now
be elaborated without error.
Previously, it was necessary to write `" ".find Char.isWhitespace`.
Thank you to David Christiansen for the idea of using a default
instance.
This PR gives suggestions based on the currently-available constants
when projecting from an unknown type.
## Example: single suggestion in namespace
This was the originally motivating example, as the string refactor led
to a number of anonymous-lambda-expressions with `Char` functions that
were no longer recognized as such.
```lean4
example := (·.isWhitespace)
```
Before:
```
Invalid field notation: Type of
x✝
is not known; cannot resolve field `isWhitespace`
```
The message is unchanged, but this PR adds a hint:
```
Hint: Consider replacing the field projection `.isWhitespace` with a call to the function `Char.isWhitespace`.
```
## Example: single suggestion in namespace
```lean4
example := fun n => n.succ
```
Before:
```
Invalid field notation: Type of
n
is not known; cannot resolve field `succ`
```
The message is unchanged, but this PR adds a hint:
```
Hint: Consider replacing the field projection with a call to one of the following:
• `Fin.succ`
• `Nat.succ`
• `Std.PRange.succ`
```
This PR adds a heterogeneous version of the constructor injectivity
theorems. These theorems are useful for indexed families, and will be
used in `grind`.
This PR adds a module resolution procedure to Lake to disambiguate
modules that are defined in multiple packages.
On an `import`, Lake will now check if multiple packages within the
workspace define the module. If so, it will verify that modules have
sufficiently similar definitions (i.e., artifacts with the same content
hashes). If not, Lake will report an error.
This verification is currently only done for direct imports. Transitive
imports are not checked for consistency. An overhaul of transitive
imports will come later.
This PR fixes a bug in `grind?`. The suggestion using the `grind`
interactive mode was dropping the configuration options provided by the
user. In the following account, the third suggestion was dropping the
`-reducible` option.
```lean
/--
info: Try these:
[apply] grind -reducible only [Equiv.congr_fun, #5103]
[apply] grind -reducible only [Equiv.congr_fun]
[apply] grind -reducible => cases #5103 <;> instantiate only [Equiv.congr_fun]
-/
example :
(Equiv.sigmaCongrRight e).trans (Equiv.sigmaEquivProd α₁ β₂)
= (Equiv.sigmaEquivProd α₁ β₁).trans (prodCongrRight e) := by
grind? -reducible [Equiv.congr_fun]
```
This PR adds the `grind` option `reducible` (default: `true`). When
enabled, definitional equality tests expand only declarations marked as
`@[reducible]`.
Use `grind -reducible` to allow expansion of non-reducible declarations
during definitional equality tests.
This option affects only definitional equality; the canonicalizer and
theorem pattern internalization always unfold reducible declarations
regardless of this setting.
This PR refines several error error messages, mostly involving invalid
use of field notation, generalized field notation, and numeric
projection. Provides a new error explanation for field notation.
## Error message changes
In general:
- Uses a slightly different convention for expression-type pairs, where
the expression is always given `indentExpr` and the type is given
`inlineExpr` treatment. This is something of a workaround for the fact
that the `Format` type is awkward for embedding possibly-linebreaking
expressions in not-linebreaking text, which may be a separate issue
worth addressing.
- Tries to give slightly more "why" reasoning — the environment does not
contain `String.parse`, and _therefore you can't project `.parse` from a
`String`_.
Some specific examples:
### No such projection function
```lean4
#check "".parse
```
before:
```
error: Invalid field `parse`: The environment does not contain `String.parse`
""
has type
String
```
after:
```
error: Invalid field `parse`: The environment does not contain `String.parse`, so it is not possible to project the field `parse` from an expression
""
of type `String`
```
### Type does not have the correct form
```lean4
example (x : α) := (foo x).foo
```
before:
```
error: Invalid field notation: Type is not of the form `C ...` where C is a constant
foo x
has type
α
```
after:
```
error: Invalid field notation: Field projection operates on types of the form `C ...` where C is a constant. The expression
foo x
has type `α` which does not have the necessary form.
```
## Refactoring
Includes some refactoring changes as well:
- factors out multiple uses of number (1, 2, 3, 212, 222) to ordinal
("first", "second", "third", "212th", "222nd") conversion into
Lean.Elab.ErrorUtils
- significant refactoring of `resolveLValAux` in `Lean.Elab.App` — in
place of five helper functions, a special-case function case analysis,
and a case analysis on the projection type and structure, there's now a
single case analysis on the projection type and structure. This allows
several error messages to be more explicit (there were a number of cases
where index projection was being described as field projection in an
error messages) and gave the opportunity to slightly improve positining
for several errors: field *notation* errors should appear on `foo.bar`,
but field *projection* errors should appear only on the `bar` part of
`foo.bar`.
This PR moves the processing of options passed to the CLI from
`shell.cpp` to `Shell.lean`.
As with previous ports, this attempts to mirror as much of the original
behavior as possible, Benefits to be gained from the ported code can
come in later PRs. There should be no significant behavioral changes
from this port. Nonetheless, error reporting has changed some, hopefully
for the better. For instance, errors for improper argument
configurations has been made more consistent (e.g., Lean will now error
if numeric arguments fall outside the expected range for an option).
(Redo of #11345 to fix Windows issue.)
This PR generalizes the `noConfusion` constructions to heterogeneous
equalities (assuming propositional equalities between the indices). This
lays ground work for better support for applying injection to
heterogeneous equalities in grind.
The `Meta.mkNoConfusion` app builder shields most of the code from these
changes.
Since the per-constructor noConfusion principles are now more
expressive, `Meta.mkNoConfusion` no longer uses the general one.
In `Init.Prelude` some proofs are more pedestrian because `injection`
now needs a bit more machinery.
This is a breaking change for whoever uses the `noConfusion` principle
manually and explicitly for a type with indices.
Fixes#11450.
This PR adds lemmas stating that if a get operation returns a value,
then the queried key must be contained in the collection. These lemmas
are added for HashMap and TreeMap-based collections, with a similar
lemma also added for `Init.getElem`.
This PR adapts the lambda lifter in LCNF to eta contract instead of
lambda lift if possible. This prevents the creation of a few hundred
unnecessary lambdas across the code base.
This PR moves the `Inhabited` instances in constant `DTreeMap` (and
related) queries, such as `Const.get!`, where the `Inhabited` instance
can be provided before proving a key.
This PR fixes a panic in `getEqnsFor?` when called on matchers generated
from match expressions in theorem types.
When a theorem's type contains a match expression (e.g., `theorem bar :
(match ... with ...) = 0`), the compiler generates a matcher like
`bar.match_1`. Calling `getEqnsFor?` on this matcher would panic with:
```
PANIC: duplicate normalized declaration name bar.match_1.eq_1 vs. _private...bar.match_1.eq_1
```
This also affected the `try?` tactic, which internally uses
`getEqnsFor?`.
We make `shouldGenerateEqnThms` return `false` for matchers, since their
equations are already generated separately by
`Lean.Meta.Match.MatchEqs`. This prevents the equation generation
machinery from attempting to create duplicate equation theorems.
Closes#11461Closes#10390🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes various typos across the codebase in documentation and
comments.
- `infered` → `inferred` (ParserCompiler.lean)
- `declartation` → `declaration` (Cleanup.lean)
- `certian` → `certain` (CasesInfo.lean)
- `wil` → `will` (Cache.lean)
- `the the` → `the` (multiple files - PrefixTree.lean, Sum/Basic.lean,
List/Nat/Perm.lean, Time.lean, Bounded.lean, Lake files)
- `to to` → `to` (MutualInductive.lean, simp_bubblesort_256.lean)
- Grammar improvements in Bounded.lean and Time.lean
All changes are to comments and documentation only - no functional
changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds `+suggestions` support to `solve_by_elim`, following the
pattern established by `grind +suggestions` and `simp_all +suggestions`.
Gracefully handles invalid/nonexistent suggestions by filtering them out
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds `solve_by_elim` as a fallback in the `try?` tactic's simple
tactics. When `rfl` and `assumption` both fail but `solve_by_elim`
succeeds (e.g., for goals requiring hypothesis chaining or
backtracking), `try?` will now suggest `solve_by_elim`.
The structure is `first | (attempt_all | rfl | assumption) |
solve_by_elim`, so `solve_by_elim` only runs when the faster tactics
fail.
This is a prerequisite for removing the "first pass" `solve_by_elim`
from `apply?`. Currently `apply?` calls `solve_by_elim` twice: once
before library search, and once after each lemma application. The first
pass can be removed once `try?` includes `solve_by_elim`.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR removes the "first pass" behavior where `exact?` and `apply?`
would try `solve_by_elim` on the original goal before doing library
search. This simplifies the `librarySearch` API and focuses these
tactics on their primary purpose: finding library lemmas.
Users who want to find proofs using local hypotheses should use `try?`
instead, which now includes `solve_by_elim` in its pipeline (see
https://github.com/leanprover/lean4/pull/11462).
Changes:
- Removed first pass from `librarySearch`
- Simplified `tactic` parameter from `Bool → List MVarId → MetaM (List
MVarId)` to `List MVarId → MetaM (List MVarId)`
- Updated test expectations
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR improves the error message when no library suggestions engine is
registered to recommend importing `Lean.LibrarySuggestions.Default` for
the built-in engine.
**Before:**
```
No library suggestions engine registered. (Note that Lean does not provide a default library suggestions engine, these must be provided by a downstream library, and configured using `set_library_suggestions`.)
```
**After:**
```
No library suggestions engine registered. (Add `import Lean.LibrarySuggestions.Default` to use Lean's built-in engine, or use `set_library_suggestions` to configure a custom one.)
```
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds recording functionality such that `shake` can more
precisely track whether an import should be preserved solely for its
`attribute` commands.
This PR adds the difference operation on `DTreeMap`/`TreeMap`/`TreeSet`
and proves several lemmas about it.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
The bench script expected no output on stdout from `compile.sh`, which
was not always the case. Now, it separates the compilation and size
measurement steps.
This PR slightly improves the types involved in creating boxed
declarations. Previously the type of
the vdecl used for the return was always `tobj` when returning a boxed
scalar. This is not the most
precise annotation we can give.
This PR modifies the error message for type synthesis failure for the
case where the type class in question is potentially derivable using a
`deriving` command. Also changes the error explanation for type class
instance synthesis failure with an illustration of this pattern.
## Example
```lean4
inductive MyColor where
| chartreuse | sienna | thistle
def forceColor (oc : Option MyColor) :=
oc.get!
```
Before this PR, this gives the potentially confusing impression that
Lean may have decided that `MyColor` is _not_ inhabited — people used to
Rust may be especially inclined towards this confusion.
```
failed to synthesize instance of type class
Inhabited MyColor
Hint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.
```
After this PR, a targeted hint suggests precisely the command that will
fix the issue:
```
error: failed to synthesize instance of type class
Inhabited MyColor
Hint: Adding the command `deriving instance Inhabited for MyColor` may allow Lean to derive the missing instance.
```
This PR lets recursive functions defined by well-founded recursion use a
different `fix` function when the termination measure is of type `Nat`.
This fix-point operator use structural recursion on “fuel”, initialized
by the given measure, and is thus reasonable to reduce, e.g. in `by
decide` proofs.
Extra provisions are in place that the fixpoint operator only starts
reducing when the fuel is fully known, to prevent “accidential” defeqs
when the remaining fuel for the recursive calls match the initial fuel
for that recursive argument.
To opt-out, the idiom `termination_by (n,0)` can be used.
We still use `@[irreducible]` as the default for such recursive
definitions, to avoid unexpected `defeq` lemmas. Making these functions
`@[semireducible]` by default showed performance regressions in lean.
When the measure is of type `Nat`, the system will accept an explicit
`@[semireducible]` without the usual warning.
Fixes#5234. Fixes: #11181.
This PR performs minor maintenance on the String API
- Rename `String.Pos.toCopy` to `String.Pos.copy` to adhere to the
naming convention
- Rename `String.Pos.extract` to `String.extract` to get sane dot
notation again
- Add `String.Slice.Pos.extract`
This PR reduces the memory consumption of the language server (the
watchdog process in particular). In Mathlib, it reduces memory
consumption by about 1GB.
It also fixes two bugs in the call hierarchy:
- When an open file had import errors (e.g. from a transitive build
failure), the call hierarchy would not display any usages in that file.
Now we use the reference information from the .ilean instead.
- When a command would not set a parent declaration (e.g. `#check`), the
result was filtered from the call hierarchy. Now we display it as
`[anonymous]` instead.
This PR documents the `grind_pattern` command for manually selecting
theorem instantiation patterns, including multi-patterns and the
constraint system (`=/=`, `=?=`, `size`, `depth`, `is_ground`,
`is_value`, `is_strict_value`, `gen`, `max_insts`, `guard`, `check`).
This PR implements support for **guards** in `grind_pattern`. The new
feature provides additional control over theorem instantiation. For
example, consider the following monotonicity theorem:
```lean
opaque f : Nat → Nat
theorem fMono : x ≤ y → f x ≤ f y := ...
```
We can use `grind_pattern` to instruct `grind` to instantiate the
theorem for every pair `f x` and `f y` occurring in the goal:
```lean
grind_pattern fMono => f x, f y
```
Then we can automatically prove the following simple example using
`grind`:
```lean
/--
trace: [grind.ematch.instance] fMono: f a ≤ b → f (f a) ≤ f b
[grind.ematch.instance] fMono: f a ≤ c → f (f a) ≤ f c
[grind.ematch.instance] fMono: f a ≤ a → f (f a) ≤ f a
[grind.ematch.instance] fMono: f a ≤ f (f a) → f (f a) ≤ f (f (f a))
[grind.ematch.instance] fMono: f a ≤ f a → f (f a) ≤ f (f a)
[grind.ematch.instance] fMono: f (f a) ≤ b → f (f (f a)) ≤ f b
[grind.ematch.instance] fMono: f (f a) ≤ c → f (f (f a)) ≤ f c
[grind.ematch.instance] fMono: f (f a) ≤ a → f (f (f a)) ≤ f a
[grind.ematch.instance] fMono: f (f a) ≤ f (f a) → f (f (f a)) ≤ f (f (f a))
[grind.ematch.instance] fMono: f (f a) ≤ f a → f (f (f a)) ≤ f (f a)
[grind.ematch.instance] fMono: a ≤ b → f a ≤ f b
[grind.ematch.instance] fMono: a ≤ c → f a ≤ f c
[grind.ematch.instance] fMono: a ≤ a → f a ≤ f a
[grind.ematch.instance] fMono: a ≤ f (f a) → f a ≤ f (f (f a))
[grind.ematch.instance] fMono: a ≤ f a → f a ≤ f (f a)
[grind.ematch.instance] fMono: c ≤ b → f c ≤ f b
[grind.ematch.instance] fMono: c ≤ c → f c ≤ f c
[grind.ematch.instance] fMono: c ≤ a → f c ≤ f a
[grind.ematch.instance] fMono: c ≤ f (f a) → f c ≤ f (f (f a))
[grind.ematch.instance] fMono: c ≤ f a → f c ≤ f (f a)
[grind.ematch.instance] fMono: b ≤ b → f b ≤ f b
[grind.ematch.instance] fMono: b ≤ c → f b ≤ f c
[grind.ematch.instance] fMono: b ≤ a → f b ≤ f a
[grind.ematch.instance] fMono: b ≤ f (f a) → f b ≤ f (f (f a))
[grind.ematch.instance] fMono: b ≤ f a → f b ≤ f (f a)
-/
#guard_msgs in
example : f b = f c → a ≤ f a → f (f a) ≤ f (f (f a)) := by
set_option trace.grind.ematch.instance true in
grind
```
However, many unnecessary theorem instantiations are generated.
With the new `guard` feature, we can instruct `grind` to instantiate the
theorem **only if** `x ≤ y` is already known to be true in the current
`grind` state:
```lean
grind_pattern fMono => f x, f y where
guard x ≤ y
x =/= y
```
If we run the example again, only three instances are generated:
```lean
/--
trace: [grind.ematch.instance] fMono: a ≤ f a → f a ≤ f (f a)
[grind.ematch.instance] fMono: f a ≤ f (f a) → f (f a) ≤ f (f (f a))
[grind.ematch.instance] fMono: a ≤ f (f a) → f a ≤ f (f (f a))
-/
#guard_msgs in
example : f b = f c → a ≤ f a → f (f a) ≤ f (f (f a)) := by
set_option trace.grind.ematch.instance true in
grind
```
Note that `guard` does **not** check whether the expression is
*implied*. It only checks whether the expression is *already known* to
be true in the current `grind` state. If this fact is eventually
learned, the theorem will be instantiated.
If you want `grind` to check whether the expression is implied, you
should use:
```lean
grind_pattern fMono => f x, f y where
check x ≤ y
x =/= y
```
Remark: we can use multiple `guard`/`check`s in a `grind_pattern`
command.
This PR adds per-module `.ilean` and `.olean` file size metrics, global
and per-module cycle counting, and adds back `lean --stat`-based
metrics. It also renames some `size/*` metrics to get rid of the name
`stdlib`.
This PR clarifies the bootstrap documentation to explain that to trigger
the automatic stage0 update mechanism, you should modify
`stage0/src/stdlib_flags.h` (not `src/stdlib_flags.h`). The existing
text was ambiguous about which file to modify.
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR reverts https://github.com/leanprover/lean4/pull/11396, which
changed `set_library_suggestions` to create an auxiliary definition
marked with `@[library_suggestions]`, rather than storing `Syntax`
directly in the environment extension.
It wasn't tested properly.
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes a kernel type mismatch error in grind's denominator
cleanup feature. When generating proofs involving inverse numerals (like
`2⁻¹`), the proof context is compacted to only include variables
actually used. This involves renaming variable indices - e.g., if
original indices were `{0: r, 1: 2⁻¹}` and only `2⁻¹` is used, it gets
renamed to index 0.
The bug was that polynomials were correctly renamed via `varRename`, but
the variable index `x` stored in `cancelDen` constraints was passed
directly to the proof without renaming, causing a mismatch between the
polynomial's variable references and the theorem's variable argument.
Added `ringVarDecls` to track ring variable indices that need renaming,
similar to how `ringPolyDecls` tracks polynomials. The `mkRingContext`
function now also renames these variable indices.
See zulip discussion at [#nightly-testing > Mathlib status updates @
💬](https://leanprover.zulipchat.com/#narrow/channel/428973-nightly-testing/topic/Mathlib.20status.20updates/near/560575295).
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR changes `set_library_suggestions` to create an auxiliary
definition marked with `@[library_suggestions]`, rather than storing
`Syntax` directly in the environment extension. This enables better
persistence and consistency of library suggestions across modules.
The change requires a stage0 update before tests can be restored. After
CI updates stage0, a follow-up PR will restore the test cases.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
This PR fixes an issue where `grind` would fail after multiple
`norm_cast`
calls with the error "unexpected metadata found during internalization".
The `norm_cast` tactic adds mdata nodes to expressions, and when called
multiple times it creates nested mdata. The `eraseIrrelevantMData`
preprocessing function was using `.continue e` when stripping mdata,
which causes `Core.transform` to reconstruct the mdata node around the
visited children. By changing to `.visit e`, the inner expression is
passed back to `pre` for another round of processing, allowing all
nested mdata layers to be stripped.
Closes#11411🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This PR sorts the declarations fed into ElimDeadBranches in increasing
size. This can improve performance when we are dealing with a lot of
iterations.
The motivation for this change is as follows. Currently the algorithm
for doing one step of abstract interpretation is:
```
for decl in scc do
interpDecl
if summaryChanged decl then
return true
return false
```
whenever we return true we run another step. Now suppose we are in a
situation where we have an SCC with one big decl in the front and then
`n` small ones afterwards. For each time that the small ones change
their summary, we will re-run analysis of the big one in the front.
Currently the ordering is basically at "random" based on how other
compilers inject things into the SCC. This change ensures the behavior
is consistent and at least somewhat intelligent. By putting the small
declarations first, whenever we trigger a rerun of the loop we bias
analyzing the small declarations first, thus decreasing run time.
Note that this change does not have much effect on the current pipeline
because: We usually construct the SCCs in a way such that small ones
happen to be in front anyways. However, with upcomping changes on
specialization this is about to change.
This PR implements the following `grind_pattern` constraints:
```lean
grind_pattern fax => f x where
depth x < 2
grind_pattern fax => f x where
is_ground x
grind_pattern fax => f x where
size x < 5
grind_pattern fax => f x where
gen < 2
grind_pattern fax => f x where
max_insts < 4
grind_pattern gax => g as where
as =?= _ :: _
```
This PR adds support for difference operation for
`DHashMap`/`HashMap`/`HashSet` and proves several lemmas about it.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
This PR implements new kinds of constraints for the `grind_pattern`
command. These constraints allow users to control theorem instantiation
in `grind`.
It requires a manual `update-stage0` because the change affects the
`.olean` format, and the PR fails without it.
Not tested carefully: I will shake out any problems during the next
release. This script would have detected the mistakes I made in recent
releases of `v4.24.1` / `v4.25.1` and `v4.25.2`. (And #11374 would have
prevented these mistakes.)
This PR fixes the compilation of structure projections with unboxed
arguments marked `extern`, adding missing `dec` instructions. It led to
leaking single allocations when such functions were used as closures or
in the interpreter.
This is the minimal working fix; `extern` should not replicate parts of
the compilation pipeline, which will be possible via #10291.
This PR is a followup of #11381 and enforces the invariants on ordering
of closed terms and constants required by the EmitC pass properly by
toposorting before saving the declarations into the Environment.
This PR adds `ofArray` to `DHashMap`/`HashMap`/`HashSet` and proves a
simp lemma allowing to rewrite `ofArray` to `ofList`.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
This PR adds a release note draft for the next major release, where the
module system will cease being experimental.
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR adds missing docstrings for constants that occur in the
reference manual.
---------
Co-authored-by: Johannes Tantow <44068763+jt0202@users.noreply.github.com>
This PR fixes a bug where the closed term extraction does not respect
the implicit invariant of the
c emitter to have closed term decls first, other decls second, within an
SCC. This bug has not yet
been triggered in the wild but was unearthed during work on upcoming
modifications of the
specializer.
This PR renames `String.Slice.Pos.ofSlice` to `String.Pos.ofToSlice` to
adhere with the (yet-to-be documented) naming convention for mapping
positions to positions. It then adds several new functions so that for
every way to construct a slice from a string and slice, there are now
functions for mapping positions forwards and backwards along this
construction.
This PR sets `@[macro_inline]` on the (trivial) `.ctorIdx` for inductive
types with one constructor, to reduce the number of symbols generated by
the compiler.
This PR aims to improve the performance of `String.contains`,
`String.find`, etc. when using patterns of type `Char` or `Char -> Bool`
by moving the needle out of the iterator state and thus working around
missing unboxing in the compiler.
This PR makes the library suggestions extension state available when
importing from `module` files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds support for cleaning up denominators in `grind linarith`
when the type is a `Field`.
Examples:
```lean
open Std Lean.Grind
section
variable {α : Type} [Field α] [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α] [OrderedRing α]
example (a b : α) (h : a < b / 2) : 2 * a < b := by grind
example (a b : α) (_ : 0 ≤ a) (h : a ≤ b) : a / 7 ≤ b / 2 := by grind
example (a b : α) (_ : b < 0) (h : a < b) : (3/2) * a < (5/4) * b := by grind
example (a b : α) (h : a = b * (3⁻¹)^2) : 9 * a ≤ b := by grind
example (a b : α) (h : a / 2 ≠ b / 9) : 9 * a < 2 * b ∨ 9 * a > 2 * b := by grind
example (a b : α) (h : a < b / (2^2 - 3/2 + -1 + 1/2)) : 2 * a < b := by grind
end
example (a b : Rat) (h : a < b / 2) : a + a < b := by grind
example (a b : Rat) (h : a < b / 2) : a + a ≤ b := by grind
example (a b : Rat) (h : a ≠ b * (3⁻¹)^2) : 9 * a < b ∨ 9 * a > b := by grind
example (a b : Rat) (h : a / 2 ≠ b / 9) : 9 * a < 2 * b ∨ 9 * a > 2 * b := by grind
```
This PR makes the `Std.Time.Format` import in
`Lean.Elab.Tactic.Grind.Annotated` private rather than public,
preventing the entire `Std.Time` infrastructure (including timezone
databases) from being re-exported through `import Lean`.
The `grindAnnotatedExt` extension is kept private, with a new public
accessor function `isGrindAnnotatedModule` exposed for use by
`LibrarySuggestions.Basic`.
This should address the +2.5% instruction increase on `import Lean`
observed after merging #11332.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR enables parallelism in `try?`. Currently, we replace the
`attempt_all` stages (there are two, one for builtin tactics including
`grind` and `simp_all`, and a second one for all user extensions) with
parallel versions. We do not (yet?) change the behaviour of `first`
based stages.
This PR moves the processing of options passed to the CLI from
`shell.cpp` to `Shell.lean`.
As with previous ports, this attempts to mirror as much of the original
behavior as possible, Benefits to be gained from the ported code can
come in later PRs. There should be no significant behavioral changes
from this port. Nonetheless, error reporting has changed some, hopefully
for the better. For instance, errors for improper argument
configurations has been made more consistent (e.g., Lean will now error
if numeric arguments fall outside the expected range for an option).
This PR accelerates termination of the ElimDeadBranches compiler pass.
The implementation addresses situations such as `choice [none, some
top]` which can be summarized to
`top` because `Option` has only two constructors and all constructor
arguments are `top`.
This PR implements a helper simproc for `grind`. It is part of the
infrastructure used to cleanup denominators in `grind linarith`.
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR adds a focused error explanation aimed at the case where someone
tries to use Natural-Numbers-Game-style `induction` proofs directly in
Lean, where such proofs are not syntactically valid.
## Discussion
The natural numbers game uses a syntax that overlaps with Lean's
`induction` syntax despite having more structural similarity to
`induction'`. This means that fully correct proofs in the natural
numbers game, like this...
```lean4
import Mathlib
theorem zero_mul (m : ℕ) : 0 * m = 0 := by
induction m with n n_ih
rw [mul_zero]
rfl
rw [mul_succ]
rw [add_zero]
rw [n_ih]
rfl
```
...have completely baffling error messages from a newcomers'
perspective:
```
notNaturalNumbersGame.lean:3:20: error: unknown tactic
notNaturalNumbersGame.lean:3:2: error: Alternative `zero` has not been provided
notNaturalNumbersGame.lean:3:2: error: Alternative `succ` has not been provided
```
(the Mathlib import here only provides the `ℕ` syntax here; equivalently
`ℕ` could be renamed to `Nat` and the import could be removed, [like
this](https://live.lean-lang.org/#codez=C4Cwpg9gTmC2AEAvMUIH1YFcA28AUCAXPAHICGwAlPMQAzwBU8CAvPPYWwEYCeAUPHgBLAHYATTAGNgQiCObwA7kNDx5ItEJAD4URfADaWbGmSoAujqgAzbFf1GcaAM5TJlwXsNkxY0yggPXQcNLSCbbCA))
There are many problems with this proof from the perspective of "stock"
Lean, but the error messages in the `induction` case are particularly
unfriendly and provide no guidance from a NNG learner's perspective.
This PR provides more information about what is wrong:
```
notNaturalNumbersGame.lean:3:20: error: unknown tactic
notNaturalNumbersGame.lean:3:14: error(lean.inductionWithNoAlts): Invalid syntax for induction tactic: The `with` keyword must followed by a tactic or by an alternative (e.g. `| zero =>`), but here it is followed by the identifier `n`.
```
The error explanation it links to explicitly flags the transition of
NNG-style proofs to Lean as the likely culprit, and gives an example of
an effective translation.
This PR updates the `foldr`, `all`, `any` and `contains` functions on
`String` to be defined in terms of their `String.Slice` counterparts.
This is the last one in a long series of PRs. After this, all `String`
operations are polymorphic in the pattern, and no `String` operation
falls back to `String.Pos.Raw` internally (except those in the
`String.Pos.Raw` and `String.Substring.Raw` namespaces of course, which
still play a role in metaprogramming and will stay for the foreseeable
future).
This PR adds a new [radar]-based [temci]-less bench suite that replaces
the `stdlib` benchmarks from the old suite and also measures per-module
instruction counts. All other benchmarks from the old suite are
unaffected.
The readme at `tests/bench-radar/README.md` explains in more detail how
the bench suite is structured and how it works. The readmes in the
benchmark subdirectories explain what each benchmark does and which
metrics it collects.
All metrics except `stdlib//max dynamic symbols` were ported to the new
suite, though most have been renamed.
[radar]: https://github.com/leanprover/radar
[temci]: https://github.com/parttimenerd/temci
This PR changes the interface of the `ForIn`, `ForIn'`, and `ForM`
typeclasses to not take a `Monad m` parameter. This is a breaking change
for most downstream `instance`s, which will will now need to assume
`[Monad m]`.
The rationale is that if the provider of an instance requires `m` to be
a Monad, they should assume this up front. This makes it possible for
the instanve to assume `LawfulMonad m` or some other stronger
requirement, and also to provided a concrete instance for a particular
`m` without assuming a non-canonical `Monad` structure on it.
Zulip: [#lean4 > Monad assumptions in fields of other typeclasses @
💬](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Monad.20assumptions.20in.20fields.20of.20other.20typeclasses/near/537102158)
This PR activates the `grind_annotated` command in
`Init.Data.List.Lemmas` by removing the TODO comment and uncommenting
the command.
This PR depends on #11346 (implement `grind_annotated` command) and
should be merged after that PR (and after CI has done an
`update-stage0`.
This PR enables the syntax `use [ns Foo]` and `instantiate only [ns
Foo]` inside a `grind` tactic block, and has the effect of activating
all grind patterns scoped to that namespace. We can use this to
implement specialized tactics using `grind`, but only controlled subsets
of theorems.
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR upstreams the `with_weak_namespace` command from Mathlib:
`with_weak_namespace <id> <cmd>` changes the current namespace to `<id>`
for the duration of executing command `<cmd>`, without causing scoped
things to go out of scope. This is in preparation for upstreaming the
`scoped[Foo.Bar]` syntax from Mathlib, which will be useful now that we
are adding `grind` annotations in scopes.
This PR adds a `grind_annotated "YYYY-MM-DD"` command that marks files
as manually annotated for grind.
When LibrarySuggestions is called with `caller := "grind"` (as happens
with `grind +suggestions`), theorems from grind-annotated files are
filtered out from premise selection. The date argument validates using
Std.Time and is informational only for now, but could be used later to
detect files that need re-review.
There's no need for the library suggestions tools to suggest `grind`
theorems from files that have already been carefully annotated by hand.
This PR adds infrastructure for parallel execution across Lean's tactic
monads.
- Add IO.waitAny' to Init/System/IO.lean for waiting on task completion
- Add `Lean.Elab.Task` with `asTask` utilities for `CoreM`, `MetaM`,
`TermElabM`, `TacticM`
- Add `Lean.Elab.Parallel` with parallel execution strategies:
* `par`/`par'` - collect results in original order
* `parIter`/`parIterGreedy` - iterate over results (original or
completion order) (also variants with a cancellation token)
* `parFirst` - return first successful result
This does *not* attempt to be a monad-polymorphic framework for
parallelism. It's intentionally hard-coded to the Lean tactic monads
which I need to work with. If there's desire to make this polymorphic,
hopefully that can be done separately.
This PR renames `String.bytes` to `String.toByteArray`.
This is for two reasons: first, `toByteArray` is a better name, and
second, we have something else that wants to use the name `bytes`,
namely the function that returns in iterator over the string's bytes.
This PR documents that `backward.*` options are only temporary
migration aids and may disappear without further notice after 6 months
after their introduction. Users are kindly asked to report if they rely
on these options.
This PR adds a coercion from `String` to `String.Slice`.
In our envisioned future, most functions operating on strings will
accept `String.Slice` parameters by default (like `str` in Rust), and
this enables calling such functions with arguments of type `String`.
Closes#11298.
This PR renames `String.ValidPos` to `String.Pos`, `String.endValidPos`
to `String.endPos` and `String.startValidPos` to `String.startPos`.
Accordingly, the deprecations of `String.Pos` to `String.Pos.Raw` and
`String.endPos` to `String.rawEndPos` are removed early, after an
abbreviated deprecation cycle of two releases.
This PR removes the `group` field from option descriptions. It is
unused, does not have a clear meaning and often matches the first
component of the option name.
Given its run time of >2hrs, the job is added as a secondary job for
nightly releases and a primary job for full releases. A new check level
for differentiating between nightlies and full releases is added for
this.
(Trying to) reactivate lsan will happen in a follow-up PR.
This PR fixes freeing memory accidentally retained for each document
version in the language server on certain elaboration workloads. The
issue must have existed since 4.18.0.
This PR adds an explicit normalization layer for ring constraints in the
`grind linarith` module. For example, it will be used to clean up
denominators when the ring is a field.
This PR renames the `cutsat` tactic to `lia` for better alignment with
standard terminology in the theorem proving community.
`cutsat` still works but now emits a deprecation warning and suggests
using `lia` instead via "Try this:". Both tactics have identical
behavior.
Co-authored-by: Claude <noreply@anthropic.com>
This PR cleans up the API around `String.find` and moves it uniformly to
the new position types `String.ValidPos` and `String.Slice.Pos`
Overview:
- To search for a character, character predicate, string or slice in a
string or slice `s`, use `s.find?` or `s.find`.
- To do the same, but starting at a position `p` of a string or slice,
use `p.find?` or `p.find`.
- To do the same but between two positions `p` and `q`, construct the
slice from `p` to `q` and then use `find?` or `find` on that.
- To search backwards, all of the above applies, except that the
function is called `revFind?`, there is no non-question-mark version
(use `getD` if there is a sane default return value in your specific
application), and that you can only search for characters and character
predicates, not strings or slices.
This PR ensures that users can provide `grind` proof parameters whose
types are not `forall`-quantified. Examples:
```lean
opaque f : Nat → Nat
axiom le_f (a : Nat) : a ≤ f a
example (a : Nat) : a ≤ f a := by
grind [le_f a]
example (a b : α) (h : ∀ x y : α, x = y) : a = b := by
grind [h a b]
```
This PR redefines `front` and `back` on `String` to go through
`String.Slice` and adds the new `String` functions `front?`, `back?`,
`positions`, `chars`, `revPositions`, `revChars`, `byteIterator`,
`revBytes`, `lines`.
This PR adds `CoreM.toIO'`, the analogue of `CoreM.toIO` dropping the
state from the return type, and similarly for `TermElabM.toIO'` and
`MetaM.toIO'`.
This PR introduces a new `grind` option, `funCC` (enabled by default),
which extends congruence closure to *function-valued* equalities. When
`funCC` is enabled, `grind` tracks equalities of **partially applied
functions**, allowing reasoning steps such as:
```lean
a : Nat → Nat
f : (Nat → Nat) → (Nat → Nat)
h : f a = a
⊢ (f a) m = a m
g : Nat → Nat
f : Nat → Nat → Nat
h : f a = g
⊢ f a b = g b
```
Given an application `f a₁ a₂ … aₙ`, when `funCC := true` and function
equality is enabled for `f`, `grind` generates and tracks equalities for
all partial applications:
* `f a₁`
* `f a₁ a₂`
* …
* `f a₁ a₂ … aₙ`
This allows equalities such as `f a₁ = g` to propagate through further
applications.
**When is function equality enabled for a symbol?**
Function equality is enabled for `f` in the following cases:
1. `f` is **not a constant** (e.g., a lambda, a local function, or a
function parameter).
2. `f` is a **structure field projection**, provided the structure is
**not a `class`**.
3. `f` is a constant marked with `@[grind funCC]`
Users can also enable function equality for specific constants in a
single call using:
```lean
grind [funCC f, funCC g]
```
**Examples:**
```lean
example (m : Nat) (a : Nat → Nat) (f : (Nat → Nat) → (Nat → Nat)) (h : f a = a) :
f a m = a m := by
grind
example (m : Nat) (a : Nat → Nat) (f : (Nat → Nat) → (Nat → Nat)) (h : f a = a) :
f a m = a m := by
fail_if_success grind -funCC -- fails if `funCC` is disabled
grind
```
```lean
example (a b : Nat) (g : Nat → Nat) (f : Nat → Nat → Nat) (h : f a = g) :
f a b = g b := by
grind
example (a b : Nat) (g : Nat → Nat) (f : Nat → Nat → Nat) (h : f a = g) :
f a b = g b := by
fail_if_success grind -funCC
grind
```
**Enabling per-symbol with parameters or attributes**
```lean
opaque f : Nat → Nat → Nat
opaque g : Nat → Nat
example (a b c : Nat) : f a = g → b = c → f a b = g c := by
grind [funCC f, funCC g]
attribute [grind funCC] f g
example (a b c : Nat) : f a = g → b = c → f a b = g c := by
grind
```
This feature substantially improves `grind`’s support for higher-order
and partially-applied function equalities, while preserving
compatibility with first-order SMT behavior when `funCC` is disabled.
Closes#11309
This PR significantly changes the signature of the `ToIterator` type
class. The obtained iterators' state is no longer dependently typed and
is an `outParam` instead of being bundled inside the class. Among other
benefits, `simp` can now rewrite inside of `Slice.toList` and
`Slice.toArray`. The downside is that we lose flexibility. For example,
the former combinator-based implementation of `Subarray`'s iterators is
no longer feasible because the states are dependently typed. Therefore,
this PR provides a hand-written iterator for `Subarray`, which does not
require a dependently typed state and is faster than the previous one.
Converting a family of dependently typed iterators into a simply typed
one using a `Sigma`-state iterator generates forbiddingly bad code, so
that we do provide such a combinator. This PR adds a benchmark for this
problem.
This PR improves the support for `Fin n` in `grind` when `n` is not a
numeral.
- `toInt (0 : Fin n) = 0` in `grind lia`.
- `Fin.mk`-applications are treated as interpreted terms in `grind lia`.
- `Fin.val` applications are suppressed from `grind lia`
counterexamples.
This PR fixes a breakage in Lake's TOML test caused by String API
changes. It also removes a JSON parser workaround that has since been
fixed, and it more generally polishes up the code.
This PR fixes an issue affecting `grind -revert`. In this mode, assigned
metavariables in hypotheses were not being instantiated. This issue was
affecting two files in Mathlib.
This PR fixes a local declaration internalization in `grind` that was
exposed when using `grind -revert`. This bug was affecting a `grind`
proof in Mathlib.
This PR makes the specializer (correctly) share more cache keys across
invocations, causing us to produce less code bloat.
We observed that in functions with lots of specialization, sometimes
cache keys are defeq but not BEq because one has unused let decls
(introduced by specialization) that the other doesn't. This PR resolves
this conflict by erasing unused let decls from specializer cache keys.
This PR improves the error message encountered in the case of a type
class instance resolution failure, and adds an error explanation that
discusses the common new-user case of binary operation overloading and
points to the `trace.Meta.synthInstance` option for advanced debugging.
## Example
```lean4
def f (x : String) := x + x
```
Before:
```
failed to synthesize
HAdd String String ?m.5
Hint: Additional diagnostic information may be available using the `set_option diagnostics true` command.
```
After:
```
failed to synthesize instance of type class
HAdd String String ?m.5
Hint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.
Error code: lean.failedToSynthesizeTypeclassInstance
[View explanation](https://lean-lang.org/doc/reference/latest/find/?domain=Manual.errorExplanation&name=lean.failedToSynthesizeTypeclassInstance)
```
The error message is changed in three important ways:
* Explains *what* failed to synthesize, using the "type class"
terminology that's more likely to be recognized than the "instance"
terminology
* Points to the `trace.Meta.synthInstance` option which is otherwise
nearly undiscoverable but is quite powerful (see also
leanprover/reference-manual#663 which is adding commentary on this
option)
* Gives an error explanation link (which won't actually work until the
next release after this is merged) which prioritizes the common-case
explanation of using the wrong binary operation
This PR removes all code that sets the `Option.Decl.group` field, which
is unused and has no clearly documented meaning.
The actual removal of the field would be #11305.
This PR renames the CTests tests to use filenames as test names. So
instead of
```
2080 - leanruntest_issue5767.lean (Failed)
```
we get
```
2080 - tests/lean/run/issue5767.lean (Failed)
```
which allows Ctrl-Click’ing on them in the VSCode terminal.
This PR renames congruence lemmas for union on
`DHashMap`/`HashMap`/`HashSet`/`DTreeMap`/`TreeMap`/`TreeSet` to fit the
convention of being in the `Equiv` namespace.
This PR fixes a bug in the propagation rules for `ite` and `dite` used
in `grind`. The bug prevented equalities from being propagated to the
satellite solvers. Here is an example affected by this issue.
```lean
example
[LE α] [LT α] [Std.IsLinearOrder α] [Std.LawfulOrderLT α]
[Lean.Grind.CommRing α] [DecidableLE α] [Lean.Grind.OrderedRing α]
(a b c : α) :
(if a - b ≤ -(a - b) then -(a - b) else a - b) ≤
((if a - c ≤ -(a - c) then -(a - c) else a - c) + if c - d ≤ -(c - d) then -(c - d) else c - d) +
if b - d ≤ -(b - d) then -(b - d) else b - d := by
grind
```
This PR adds support for decidable equality of empty lists and empty
arrays. Decidable equality for lists and arrays is suitably modified so
that all diamonds are definitionally equal.
Following #9302, the strong condition of definitionally equal under
`with_reducible_and_instances` is tested. This also moves some of the
comments added in #9302 out of docstrings.
---------
Co-authored-by: Aaron Liu <aaronliu2008@outlook.com>
Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
This PR renames `String.replaceStartEnd` to `String.slice`,
`String.replaceStart` to `String.sliceFrom`, and `String.replaceEnd` to
`String.sliceTo`, and similar for the corresponding functions on
`String.Slice`.
This PR adds several lemmas that relate
`getMin`/`getMin?`/`getMin!`/`getMinD` and insertion to the empty
(D)TreeMap/TreeSet and their extensional variants.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
Global `attribute` commands on non-local declarations are impossible to
track granularly a priori and so should be preserved by `shake` by
default. A new `shake` option could be added to ignore these
dependencies for evaluation.
This PR adds `Std.Slice.Pattern` instances for `p : Char -> Prop` as
long as `DecidablePred p`, to allow things like `"hello".dropWhile (· =
'h')`.
To achieve this, we refactor `ForwardPattern` and friends to be
"non-uniform", i.e., the class is now `ForwardPattern pat`, not
`ForwardPattern ρ` (where `pat : ρ`).
This PR provides intersection operation for
`ExtDHashMap`/`ExtHashMap`/`ExtHashSet` and proves several lemmas about
it.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
This PR provides intersection on `DTreeMap`/`TreeMap`/`TreeSet`and
provides several lemmas about it.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
This PR adds a function `String.Slice.length`, with the following
deprecation string: There is no constant-time length function on slices.
Use `s.positions.count` instead, or `isEmpty` if you only need to know
whether the slice is empty.
This PR adds the alias `String.Slice.any` for `String.Slice.contains`.
It would probably be even better to only have one, but we don't have a
good mechanism for pointing people looking for one towards the other, so
an alias it is for now.
This PR splits the single grind_lint.lean test (50+ seconds) into 7
separate files that each run in under 7 seconds:
- grind_lint_list.lean (5.7s): List namespace with exceptions
- grind_lint_array.lean (4.6s): Array namespace
- grind_lint_bitvec.lean (3.9s): BitVec namespace with exceptions
- grind_lint_std_hashmap.lean (6.8s): Std hash map/set namespaces
- grind_lint_std_treemap.lean (~6s): Std tree map/set namespaces
- grind_lint_std_misc.lean (~5s): Std.Do, Std.Range, Std.Tactic
- grind_lint_misc.lean (5.5s): All other non-Lean namespaces
Each file maintains complete namespace coverage and preserves all
existing exceptions. The split enables better CI parallelization and
faster feedback.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This PR implements support for arbitrary `grind` parameters. The feature
is similar to the one available in `simp`, where a proof term is treated
as a local universe-polymorphic lemma. This feature relies on `grind
-revert` (see #11248). For example, users can now write:
```lean
def snd (p : α × β) : β := p.2
theorem snd_eq (a : α) (b : β) : snd (a, b) = b := rfl
/--
trace: [grind.ematch.instance] snd_eq (a + 1): snd (a + 1, Type) = Type
[grind.ematch.instance] snd_eq (a + 1): snd (a + 1, true) = true
-/
#guard_msgs (trace) in
set_option trace.grind.ematch.instance true in
example (a : Nat) : (snd (a + 1, true), snd (a + 1, Type), snd (2, 2)) = (true, Type, snd (2, 2)) := by
grind [snd_eq (a + 1)]
```
Note that in the example above, `snd_eq` is instantiated only twice, but
with different universe parameters.
As described in #11248, the new feature cannot be used with `grind
+revert`.
This PR marks the automatically generated `sizeOf` theorems as `grind`
theorems.
closes#11259
Note: Requested update stage0, we need it to be able to solve example in
the issue above.
```lean
example (a: Nat) (b: Nat): sizeOf a < sizeOf (a, b) := by
grind
```
This PR fixes several memory leaks in the new `String` API.
These leaks are mostly situations where we forgot to put borrowing
annotations. The single
exception is the new `String` constructor `ofByteArray`. It cannot take
the `ByteArray` as
a borrowed argument anymore and must thus free it on its own.
This PR continues the homogenization between matchers and splitters,
following up on #11256. In particular it removes the ambiguity whether
`numParams` includes the `discrEqns` or not.
This PR replaces `MatcherInfo.numAltParams` with a more detailed data
structure that allows us, in particular, to distinguish between an
alternative for a constructor with a `Unit` field and the alternative
for a nullary constructor, where an artificial `Unit` argument is
introduced.
This PR introduces a function `String.split` which is based on
`String.Slice.split` and therefore supports all pattern types and
returns a `Std.Iter String.Slice`.
This supersedes the functions `String.splitOn` and `String.splitToList`,
and we remove all all uses of these functions from core. They will be
deprecated in a future PR.
Migrating from `String.splitOn` and `String.splitToList` is easy: we
introduce functions `Iter.toStringList` and `Iter.toStringArray` that
can be used to conveniently go from `Std.Iter String.Slice` to `List
String` and `Array String`, so for example `s.splitOn "foo"` can be
replaced by `s.split "foo" |>.toStringList`.
This PR adds a `Unit` assumption to alternatives of the splitter that
would otherwise not have arguments. This fixes#11211.
In practice these argument-less alternatives did not cause wrong
behavior, as the motive when used with `split` is always a function
type. But it is better to be safe here (maybe someone uses splitters in
other ways), it may increase the effectiveness of #10184 and simplifies
#11220.
The perf impact is insignificant in the grand scheme of things on
stdlib, but the change is effective:
```
~/lean4 $ build/release/stage1/bin/lean tests/lean/run/matchSplitStats.lean
969 splitters found
455 splitters are const defs
~/lean4 $ build/release/stage2/bin/lean tests/lean/run/matchSplitStats.lean
969 splitters found
829 splitters are const defs
```
This PR implements the option `revert`, which is set to `false` by
default. To recover the old `grind` behavior, you should use `grind
+revert`. Previously, `grind` used the `RevSimpIntro` idiom, i.e., it
would revert all hypotheses and then re-introduce them while simplifying
and applying eager `cases`. This idiom created several problems:
* Users reported that `grind` would include unnecessary parameters. See
[here](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Grind.20aggressively.20includes.20local.20hypotheses.2E/near/554887715).
* Unnecessary section variables were also being introduced. See the new
test contributed by Sebastian Graf.
* Finally, it prevented us from supporting arbitrary parameters as we do
in `simp`. In `simp`, I implemented a mechanism that simulates local
universe-polymorphic theorems, but this approach could not be used in
`grind` because there is no mechanism for reverting (and re-introducing)
local universe-polymorphic theorems. Adding such a mechanism would
require substantial work: I would need to modify the local context
object. I considered maintaining a substitution from the original
variables to the new ones, but this is also tricky, because the mapping
would have to be stored in the `grind` goal objects, and it is not just
a simple mapping. After reverting everything, I would need to keep a
sequence of original variables that must be added to the mapping as we
re-introduce them, but eager case splits complicate this quite a bit.
The whole approach felt overly messy.
The new behavior `grind -revert` addresses all these issues. None of the
`grind` proofs in our test suite broke after we fixed the bugs exposed
by the new feature. That said, the traces and counterexamples produced
by `grind` are different. The new proof terms are also different.
This PR introduces a clarifying note to "undefined identifier" error
messages when the undefined identifier is in a syntactic position where
autobinding might generally apply, but where and autobinding is
disabled. A corresponding note is made in the `lean.unknownIdentifier`
error explanation.
The core intended audience for this error message change is "newcomer
who would otherwise be baffled why the thing that works in this Mathlib
project gets 'unknown identifier' errors in this non-Mathlib project."
## Modified behavior
### Example 1
```lean4
set_option autoImplicit true in
set_option relaxedAutoImplicit false in
def thisBreaks (x : α₂) (y : size₂) := ()
```
Before:
```
Unknown identifier `size₂`
```
After:
```
Unknown identifier `size₂`
Note: It is not possible to treat `size₂` as an implicitly bound variable here because it has multiple characters while the `relaxedAutoImplicit` option is set to `false`.
```
### Example 2
```lean4
set_option autoImplicit false in
def thisAlsoBreaks (x : α₃) (y : size₃) := ()
```
Before:
```
Unknown identifier `α₃`
Unknown identifier `size₃`
```
After:
```
Unknown identifier `α₃`
Note: It is not possible to treat `α₃` as an implicitly bound variable here because the `autoImplicit` option is set to `false`.
Unknown identifier `size₃`
Note: It is not possible to treat `size₃` as an implicitly bound variable here because the `autoImplicit` option is set to `false`.
```
## How this works
The elaboration process knows whether it is considering syntax where we
be able to auto-bind implicits thanks to information in the
`Lean.Elab.Term.Context`.
Before this PR, this contains:
* `autoBoundImplicit`, a boolean that is true when we are considering
syntax that might be able to auto-bind implicit AND when the
`autoImplicit` flag is set to true
* `autoBoundImplicits`, an array of `Expr` variables that we've
autobound
After this PR, this contains:
* `autoBoundImplicitCtx`, an option which is `some` **whenever** we are
considering syntax that might be able to auto-bind implicit, and carries
the array of exprs as well as a copy of the `autoImplicit` flag's value.
(The latter lets us re-implement the `autoBoundImplicit` flag for
backward compatibility.)
Therefore, rather than having access to "elaboration is in an
autobinding context && flag is enabled", it's possible to recover both
of those individual values, and give different information to the user
in cases where we didn't attempt autobinding but would have if different
options had been set.
## Rationale
The revised error message avoids offering much guidance — it doesn't
actively suggest setting the option to a different value or suggest
adding an implicit binding. Care needs to be taken here to make sure
advice is not misleading; as the accepted RFC in #6462 points out, a
substantial portion of autobinding failures are just going to be
misspellings.
I considered and then rejected a code action here to that would add a
local `set_option autoImplicit true`. This seems undesirable or
counterproductive — if a project like Mathlib has proactively disabled
`autoImplicit`, its odd to be pushing local exceptions.
A hint prompting the user to add an implicit binding would be more
proper, but only in certain circumstances — we want to be conservative
in suggesting specific code actions! In a situation like this one, we'd
want to _avoid_ giving the suggestion of adding a `{HasArr}` binding,
which I think either requires tricky heuristics or means we'd want the
elaboration to play through the consequences of auto-binding and make
sure it doesn't cause any follow-on errors before suggesting adding an
implicit binding.
```
set_option autoImplicit true
set_option relaxedAutoImplicit false
instance has_arr : HasArr Preorder := { Arr := Function }
```
Additionally, it seems like it would make the most sense to offer to
auto-bind _all_ the relevant unknown identifiers at once. To avoid being
misleading, this too would seem to require playing through the
consequences of autobinding before being able to safely suggest the
change. This is enough additional complexity that I'm leaving it for
future work.
---------
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
This PR prevents symbol clashes between (non-`@[export]`) definitions
from different Lean packages.
Previously, if two modules define a function with the same name and were
transitively imported (even privately) by some downstream module,
linking would fail due to a symbol clash. Similarly, if a user defined a
symbol with the same name as one in the `Lean` library, Lean would use
the core symbol even if one did not import `Lean`.
This is solved by changing Lean's name mangling algorithm to include an
optional package identifier. This identifier is provided by Lake via
`--setup` when building a module. This information is weaved through the
elaborator, interpreter, and compiler via a persistent environment
extension that associates modules with their package identifier.
With a package identifier, standard symbols have the form
`lp_<pkg-id>_<mangled-def>`. Without one, the old scheme is used (i.e.,
`l_<mangled-def>`). Module initializers are also prefixed with package
identifier (if any). For example, the initializer for a module `Foo` in
a package `test` is now `initialize_test_Foo` (instead of
`initialize_Foo`). Lake's default for native library names has also been
adjusted accordingly, so that libraries can still, by default, be used
as plugins. Thus, the default library name of the `lean_lib Foo` in
`package test` will now be `libtest_Foo`.
When using Lake to build the Lean core (i.e., `bootstrap = true`), no
package identifier will be used. Thus, definitions in user packages can
never have symbol clashes with core.
Closes#222.
This PR adds a test that covers importing modules defined in multiple
packages.
Currently, will resolve the module to its first occurrence in the its
search order. However, this will soon change, so this test is designed
to analyze that behavior.
This PR redefines `String.take` and variants to operate on
`String.Slice`. While previously functions returning a substring of the
input sometimes returned `String` and sometimes returned
`Substring.Raw`, they now uniformly return `String.Slice`.
This is a BREAKING change, because many functions now have a different
return type. So for example, if `s` is a string and `f` is a function
accepting a string, `f (s.drop 1)` will no longer compile because
`s.drop 1` is a `String.Slice`. To fix this, insert a call to `copy` to
restore the old behavior: `f (s.drop 1).copy`.
Of course, in many cases, there will be more efficient options. For
example, don't write `f <| s.drop 1 |>.copy |>.dropEnd 1 |>.copy`, write
`f <| s.drop 1 |>.dropEnd 1 |>.copy` instead. Also, instead of `(s.drop
1).copy = "Hello"`, write `s.drop 1 == "Hello".toSlice` instead.
This PR adds `Std.Tricho r`, a typeclass for relations which identifies
them as trichotomous. This is preferred to `Std.Antisymm (¬ r · ·)` in
all cases (which it is equivalent to).
This PR is split from a future PR and adds the function
`String.Pos.next`, an alias (and soon to be correct name) of
`String.ValidPos.next`.
This is for boring bootstrapping reasons.
This PR extracts two modules from `Match.MatchEqs`, in preparation of
#11220
and to use the module system to draw clear boundaries between concerns
here.
This PR registers a node kind for `Lean.Parser.Term.elabToSyntax` in
order to support the `Lean.Elab.Term.elabToSyntax` functionality without
registering a dedicated parser for user-accessible syntax.
This PR adds intersection operation on `DHashMap`/`HashMap`/`HashSet`
and provides several lemmas about its behaviour.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
This PR removes duplicated instance parameters in the standard library
and flips lemmas of the form `toList_eq_toListIter` into a form that is
suitable for `simp`.
This PR implements `elabToSyntax` for creating scoped syntax `s :
Syntax` for an arbitrary elaborator `el : Option Expr -> TermElabM Expr`
such that `elabTerm s = el`.
Roundtripping example implementing an elaborator imitating `let`:
```lean
elab "lett " decl:letDecl ";" e:term : term <= ty? => do
let elabE (ty? : Option Expr) : TermElabM Expr := do elabTerm e ty?
elabToSyntax elabE fun body => do
elabTerm (← `(let $decl:letDecl; $body)) ty?
#guard lett x := 42; (x + 1) = 43
```
This PR ensures that the `text` argument of `computeArtifact` is always
provided in Lake code, fixing a hashing bug with
`buildArtifactUnlessUpToDate` in the process.
Closes#11209
This PR avoids match splitter calculation from testing all quadratically
many pairs of alternatives for overlaps, by keeping track of possible
overlaps during matcher calculation, storing that information in the
`MatcherInfo`, and using that during matcher calculation.
This PR fixes fallout of the closure allocator changes in #10982. As far
as we know
this bug only meaningfully manifests in non default build configurations
without mimalloc such as:
`cmake --preset release -DUSE_MIMALLOC=OFF`
The issue is that I forgot to update the deallocation functions for
closures. However, this only
seems to matter if we disable mimalloc which is why this slipped through
testing.
This PR provides a polymorphic `ForIn` instance for slices and an MPL
`spec` lemma for the iteration over slices using `for ... in`. It also
provides a version specialized to `Subarray`.
This PR fixes an error message in Lake which suggested incorrect
lakefile syntax.
The error message (which was very helpful by the way) looked like this:
```
error: TwoFX/batteries: package not found on Reservoir.
If the package is on GitHub, you can add a Git source. For example:
require ...
from git "https://github.com/TwoFX/batteries" @ git "main"
or, if using TOML:
[[require]]
git = "https://github.com/TwoFX/batteries"
rev = "main"
...
```
The suggested Lakefile syntax does not work. The correct syntax,
according to the reference manual and according to my tests, is
```
require ...
from git "https://github.com/TwoFX/batteries" @ "main"
```
without the second `git`.
This PR fixes a bug in the LCNF simplifier unearthed while working on
#11078. In some situations caused by `unsafeCast`, the simplifier would
record incorrect information about `cases`, leading to further bugs down
the line.
Suppose we have `v : NonScalar` due to an `unsafeCast` and we run
`cases` on it, expecting `Prod.mk fst snd`. The current code attempts to
record both the arguments from the constructor application in the case
arm `fst`, `snd` and the parameters for the type by inspecting the discr
`v`. However, `NonScalar` does of course not have any parameters,
causing the simplifier to record wrong information. This patch makes the
`cases` infrastructure more cautious when extracting information from
the type of `v`.
This PR changes how sparse case expressions represent the
none-of-the-above information. Instead of of many `x.ctorIdx ≠ i`
hypotheses, it introduces a single `Nat.hasNotBit mask x.ctorIdx`
hypothesis which compresses that information into a bitmask. This avoids
a quadratic overhead during splitter generation, where all n assumptions
would be refined through `.subst` and `.cases` constructions for all n
assumption of the splitter alternative.
The definition of `Nat.hasNotBit` uses `Nat.rightShift` which is fiddly
to get to reduce well, especially on open terms and with `Meta.whnf`.
Some experimentation was needed to find proof terms that work, these are
all put together in the `Lean.Meta.HasNotBit` module.
Fixes#11183
---------
Co-authored-by: Rob23oba <152706811+Rob23oba@users.noreply.github.com>
This PR fixes the `reduceArity` compiler pass to consider
over-applications to functions that have their arity reduced.
Previously, this pass assumed that the amount of arguments to
applications was always the same as the number of parameters in the
signature. This is usually true, since the compiler eagerly introduces
parameters as long as the return type is a function type, resulting in a
function with a return type that isn't a function type. However, for
dependent types that sometimes are function types and sometimes not,
this assumption is broken, resulting in the additional parameters to be
dropped.
Closes#11131
This ensures that no `grind` annotated theorem, simply by being
instantiated, causes a chain of >20 further instantiations, with a small
list of documented exceptions.
This PR modifies the `try?` framework, so each subsidiary tactic runs
with a separate `maxHeartbeats` budget.
---------
Co-authored-by: Rob23oba <152706811+Rob23oba@users.noreply.github.com>
This PR has `#grind_list check` produce a "Try this:" suggestion with
`#grind_list inspect` commands, as this is usually the next step in
dealing with problematic cases. We also fix the grind pattern for one
theorem, as part of testing the workflow. More to follow.
This PR fixes a few minor issues in the new `Action` framework used in
`grind`. The goal is to eventually delete the old `SearchM`
infrastructure. The main `solve` function used by `grind` is now based
on the `Action` framework. The PR also deletes dead code in `SearchM`.
Creates an inductive data type with 100 constructors, and a function
that does
matches on half of its constructors, with a catch-all for the other
half, and generates the splitter.
Related to #11183.
This PR renames `Substring` to `Substring.Raw`.
This is to signify its status as a second-class citizen (not deprecated,
but no real plans for verification, like `String.Pos.Raw`) and to free
up the name `Substring` for a possible future type `String.Substring :
String -> Type` so that `s.Substring` is the type of substrings of `s`.
The functions `String.toSubstring` and `String.toSubstring'` will remain
for now for bootstrapping reasons.
This PR implements `try?` using the new `finish?` infrastructure. It
also removes the old tracing infrastructure, which is now obsolete.
Example:
```lean
/--
info: Try these:
[apply] grind
[apply] grind only [findIdx, insert, = mem_indices_of_mem, = getElem?_neg, = getElem?_pos, = HashMap.mem_insert,
= HashMap.getElem_insert, #1bba]
[apply] grind only [findIdx, insert, = mem_indices_of_mem, = getElem?_neg, = getElem?_pos, = HashMap.mem_insert,
= HashMap.getElem_insert]
[apply] grind =>
instantiate only [findIdx, insert, = mem_indices_of_mem]
instantiate only [= getElem?_neg, = getElem?_pos]
cases #1bba
· instantiate only [findIdx]
· instantiate only
instantiate only [= HashMap.mem_insert, = HashMap.getElem_insert]
-/
#guard_msgs in
example (m : IndexMap α β) (a : α) (b : β) :
(m.insert a b).findIdx a = if h : a ∈ m then m.findIdx a else m.size := by
try?
```
This PR modifies the error message that is returned when more than one
synthetic metavariable can't be resolved.
The two heuristics used for prioritization are:
- prefer typeclass problems associated with small ranges over typeclass
problems associated with large ranges (I'm pretty confident in this
heuristic)
- do not prefer typeclass problems over other kinds of errors (not as
confident in this heuristic)
This PR uses the new `grind_pattern` constraints to fix cases where an
unbounded number of theorem instantiations would be generated for
certain theorems in the standard library.
This PR implements `grind_pattern` constraints. They are useful for
controlling theorem instantiation in `grind`. As an example, consider
the following two theorems:
```lean
theorem extract_empty {start stop : Nat} :
(#[] : Array α).extract start stop = #[] := …
theorem extract_extract {as : Array α} {i j k l : Nat} :
(as.extract i j).extract k l = as.extract (i + k) (min (i + l) j) := …
```
If both are used for theorem instantiation, an unbounded number of
instances is generated as soon as we add the term `#[].extract i j` to
the `grind` context.
We can now prevent this by adding a `grind_pattern` constraint to
`extract_extract`:
```lean
grind_pattern extract_extract => (as.extract i j).extract k l where
as =/= #[]
```
With this constraint, only one instance is generated, as expected:
```lean
/-- trace: [grind.ematch.instance] extract_empty: #[].extract i j = #[] -/
#guard_msgs (drop error, trace) in
set_option trace.grind.ematch.instance true in
example (as : Array Nat) (h : #[].extract i j = as) : False := by
grind only [= extract_empty, usr extract_extract]
```
This PR changes all module build keys in Lake to be scoped by their
package. This enables building modules with the same name in different
packages (something previously only well-supported for executable
roots).
API-wise, the `BuildKey` definitions `module` and `moduleFacet` have
been deprecated and replaced with `packageModule` and
`packageModuleFacet`. The `moduleTargetIndicator` has also been removed
(with its purpose subsumed by `packageModule`).
This PR adds syntax for specifying `grind_pattern` constraints and
extends the `EMatchTheorem` object.
---
Note: We need a manual stage0 update because it affects the .olean
files.
This PR removes most cases where an error message explained that it was
"probably due to metavariables," giving more explanation and a hint.
## Example
```
def square x := x * x
```
Before:
```lean4
typeclass instance problem is stuck, it is often due to metavariables
HMul ?m.9 ?m.9 (?m.3 x)
```
After:
```
typeclass instance problem is stuck
HMul ?m.9 ?m.9 (?m.3 x)
Note: Lean will not try to resolve this typeclass instance problem because the
first and second type arguments to `HMul` are metavariables. These arguments
must be fully determined before Lean will try to resolve the typeclass.
Hint: Adding type annotations and supplying implicit arguments to functions
can give Lean more information for typeclass resolution. For example, if you
have a variable `x` that you intend to be a `Nat`, but Lean reports it as
having an unresolved type like `?m`, replacing `x` with `(x : Nat)` can get
typeclass resolution un-stuck.
```
In addition to providing beginner-and-intermediate-friendly explanation
about **why** typeclass instance problems are treated as "stuck" when
metavariables appear in output positions, this PR provides
potentially-valuable improvement even to expert users: it explains
**which of the typeclass arguments are inputs** and therefore need to be
fully specified before typeclass resolution will be attempted. This
information can be tricky to find otherwise.
## Next steps, but probably after this PR
* error explanation
* detecting when the syntactic source is a binop and giving a
special-cased explanation on the binary operators and their associated
typeclasses
* detecting when the syntactic source is a function call, inspecting the
function call's type somewhat, and replacing the generic "replace `x`
with `(x : Nat)` hint with a specialized "replace `foo` with `foo (tyArg
:= Nat)`" hint
This PR introduces slices of lists that are available via slice notation
(e.g., `xs[1...5]`).
* Moved the `take` combinator and the `List` iterator producer to
`Init`.
* Introduced a `toTake` combinator: `it.toTake` behaves like `it`, but
it has the same type as `it.take n`. There is a constant cost per
iteration compared to `it` itself.
* Introduced `List` slices. Their iterators are defined as
`suffixList.iter.take n` for upper-bounded slices and
`suffixList.iter.toTake` for unbounded ones.
Performance characteristics of using the slice `list[a...b]`:
* when creating it: `O(a)`
* every iterator step: `O(1)`
* `toList`: `O(b - a + 1)` (given that a <= b)
Because the slice only stores a suffix of `xs` internally, two slices
can be equal even though the underlying lists differ in an irrelevant
prefix. Because the `stop` field is allowed to be beyond the list's
upper bound, the slices `[1][0...1]` and `[1][0...2]` are not equal,
even though they effectively cover the same range of the same list.
Improving this would require us to call `List.length` when building the
slice, which would iterate through the whole list.
This PR replaces #11138, which just added a `@[csimp]` lemma for
`Int.pow`, this time actually replacing the definition. This means we
not only get fast runtime behaviour, but take advantage of the special
kernel support for `Nat.pow`.
---------
Co-authored-by: Rob23oba <152706811+Rob23oba@users.noreply.github.com>
This PR adds tactic and term mode macros for `∎` (typed `\qed`) which
expand to `try?`. The term mode version captures any produced
suggestions and prepends `by`.
Co-authored-by: Claude <noreply@anthropic.com>
This PR removes `simp_all? +suggestions` from `try?` for now. It's
really slow out in Mathlib; too often the suggestions cause `simp` to
loop. Until we have the ability for `try?` to move past a timeing-out
tactic (or maybe even until we have parallelism), it needs to be
removed.
Alternatively, we could try modifying `simp` so that e.g. it won't use a
premise more than once. This might help avoid loops, but it would
produce less-reproducible proofs.
Co-authored-by: Claude <noreply@anthropic.com>
This PR ensures that tactics using library suggestions set the caller
field, so the premise selection engine has access to this. We'll later
use this to filter out some modules for grind, which we know have
already been fully annotated.
Co-authored-by: Claude <noreply@anthropic.com>
This PR implements support for `#grind_lint check in module <module>`.
Mathlib does not use namespaces, so we need to restrict the
`#grind_lint` search space using module (prefix) names. Example:
```lean
/--
info: instantiating `Array.filterMap_some` triggers more than 100 additional `grind` theorem instantiations
---
info: Array.filterMap_some
[thm] instances
[thm] Array.filterMap_filterMap ↦ 94
[thm] Array.size_filterMap_le ↦ 5
[thm] Array.filterMap_some ↦ 1
---
info: instantiating `Array.range_succ` triggers 22 additional `grind` theorem instantiations
-/
#guard_msgs in
#grind_lint check (min := 20) in module Init.Data.Array
```
This PR changes the default library suggestions (e.g. for `grind
+suggestions` or `simp_all? +suggestions) to include the theorems from
the current file in addition to the output of Sine Qua Non.
This PR implements the following improvements to the `#grind_lint`
command:
1. More informative messages when the number of instances exceeds the
minimum threshold.
2. A code action for `#grind_lint inspect` that inserts
`set_option trace.grind.ematch.instance true` whenever the number of
instances exceeds
the minimum threshold.
3. Displaying doc strings for `grind` configuration options in
`#grind_lint`.
4. Improve doc strings for `#grind_lint inspect` and `#grind_lint
check`.
Example:
```lean
/--
info: instantiating `Array.filterMap_some` triggers more than 100 additional `grind` theorem instantiations
---
info: Array.filterMap_some
[thm] instances
[thm] Array.filterMap_filterMap ↦ 94
[thm] Array.size_filterMap_le ↦ 5
[thm] Array.filterMap_some ↦ 1
---
info: Try this to display the actual theorem instances:
[apply] set_option trace.grind.ematch.instance true in
#grind_lint inspect Array.filterMap_some
-/
#guard_msgs in
#grind_lint inspect Array.filterMap_some
```
This PR renames `String.Iterator` to `String.Legacy.Iterator`.
From the docstring of `String.Legacy.Iterator`:
> This is a no-longer-supported legacy API that will be removed in a
future release. You should use
> `String.ValidPos` instead, which is similar, but safer. To iterate
over a string `s`, start with
> `p : s.startValidPos`, advance it using `p.next`, access the current
character using `p.get` and
> check if the position is at the end using `p = s.endValidPos` or
`p.IsAtEnd`.
This PR adds a test replicating Kim's diamond dependency example.
The top-level package, `D`, depends on two intermediate packages, `B`
and `C`, which each require semantically different versions of another
package, `A`. The portion of `A` that `B` and `C` publicly use is
unchanged across the versions, but they both privately make use of
changed API. Currently, this causes a version clash. This will be made
to work without error later this quarter.
This PR fixes some details in the Markdown renderings of Verso
docstrings, and adds tests to keep them correct. Also adds tests for
Verso docstring metadata.
This PR implements the `#grind_lint` command, a diagnostic tool for
analyzing the behavior of theorems annotated for theorem instantiation.
The command helps identify problematic theorems that produce excessive
or unbounded instance generation during E-matching, which can lead to
performance issues.
The main entry point is:
```
#grind_lint check
```
which analyzes all theorems marked with the `@[grind]` attribute.
For each theorem, it creates an artificial goal and runs `grind`,
collecting statistics about the number of instances produced.
Results are summarized using info messages, and detailed breakdowns are
shown for lemmas exceeding a configurable threshold.
Additional subcommands are provided for targeted inspection and control:
* `#grind_lint inspect thm`: analyzes one or more specific theorems in
detail
* `#grind_lint mute thm`: excludes a theorem from instantiation during
analysis
* `#grind_lint skip thm`: omits a theorem from being analyzed by
`#grind_lint check`
This PR adds a user-extension mechanism for the `try?` tactic. You can
either use the `@[try_suggestion]` attribute on a declaration with
signature ``MVarId -> Try.Info -> MetaM (Array (TSyntax `tactic))`` to
produce suggestions, or the `register_try?_tactic <stx>` command with a
fixed piece of syntax. User-extensions are only tried *after* the
built-in try strategies have been tried and failed.
I wanted to ensure that if the user provides a tactic that produces a
"Try this:" suggestion, we both emit the original tactic and the
suggested replacement (this is what we already do with `grind` and
`simp`). I have this working, but it is quite hacky: we grab the message
log and parse it. I fear this will break when the "Try this:" format is
inevitably changed in the future.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Adds user-defined suggestion generators for `try?` via
`@[try_suggestion]` and `register_try?_tactic`, executed after built-ins
with priority and double-suggestion handling.
>
> - **Parser/Command**:
> - Add command syntax `register_try?_tactic (priority := n)?
<tacticSeq>` in `Lean.Parser.Command`.
> - **Suggestion registry**:
> - Introduce `@[try_suggestion (prio)]` attribute with a scoped env
extension to register generators (`MVarId → Try.Info → MetaM (Array
(TSyntax `tactic))`).
> - Priority ordering (higher first); supports local/global scope.
> - **Tactic engine (`try?`)**:
> - New unsafe pipeline to collect and run user generators after
built-in tactics; expands nested "Try this" outputs from user tactics.
> - `mkTryEvalSuggestStx` now takes `(goal, info)`; integrates user
tactics as fallback via `attempt_all`.
> - Suppress intermediate "Try this" messages during `evalAndSuggest` by
restoring the message log.
> - **Imports**:
> - Add `meta import Lean.Elab.Command` for command elaboration.
> - **Tests**:
> - `try_register_builtin.lean`: command availability and warning
without import.
> - `try_user_suggestions.lean`: basic, priority, built-in fallback,
double-suggestion, and command registration cases.
> - Update `versoDocMissing.lean.expected.out` to include
`register_try?_tactic` in expected commands.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
302dc94544. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This PR replaces `Iter(M).size` with the `Iter(M).count`. While the
former used a special `IteratorSize` type class, the latter relies on
`IteratorLoop`. The `IteratorSize` class is deprecated. The PR also
renames lemmas about ranges be replacing `_Rcc` with `_rcc`, `_Rco` with
`_roo` (and so on) in names, in order to be more consistent with the
naming convention.
This PR adds a new, inactive and unused `doElem_elab` attribute that
will allow users to register custom elaborators for `doElem`s in the
form of the new type `DoElab`. The old `do` elaborator is active by
default but can be switched off by disabling the new option
`backward.do.legacy`.
This PR fixes a bug in #11125. Added a test this time ...
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Exclude deprecated declarations from library suggestions and add a
test verifying they are filtered out.
>
> - **Library Suggestions**:
> - Update `isDeniedPremise` in `src/Lean/LibrarySuggestions/Basic.lean`
to treat `Lean.Linter.isDeprecated` as denied (`true`), filtering
deprecated constants from suggestions.
> - **Tests**:
> - Add `tests/lean/run/library_suggestions_deprecated.lean` to verify
deprecated theorems (e.g., `deprecatedTheorem`) are not suggested by
`currentFile`, while non-deprecated ones are.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ef7e546dbc. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This PR adds iterators and slices for `DTreeMap`/`TreeMap`/`TreeSet`
based on zippers and provides basic lemmas about them.
---------
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
This PR aims to bring the performance of `String.ValidPos` closer to
that of `String.Pos.Raw` by adding/correcting `extern` annotations as
needed.
This is in response to a regression observed after #11127. The changes
to the `String` `Parsec` module lead to different compiler behavior for
functions like `strCore` and `natCore`. The new IR *looks* better than
the old IR, but the
[numbers](1e438647ba)
are a bit mixed.
This PR removes all uses of `String.Iterator` from core, preferring
`String.ValidPos` instead.
In an upcoming PR, `String.Iterator` will be renamed to
`String.Legacy.Iterator`.
This PR adds support for `try?` to use induction; it will only perform
induction on inductive types defined in the current namespace and/or
module; so in particular for now it will not induct on built-in
inductives such as `Nat` or `List`.
This is stacked on top of #11132, and there are overlapping changes.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Adds vanilla induction suggestions to `try?`, updates collection of
inductive candidates, and tests the new behavior on custom inductive
types.
>
> - **Try tactic pipeline**:
> - Add vanilla induction generators (`mkIndStx`, `mkAllIndStx`) that
try `induction <var> <;> …`, with fallback via `expose_names` when
needed.
> - Integrate induction into `mkTryEvalSuggestStx`, alongside existing
atomic, suggestions, and function-induction options.
> - **Collector updates (`Try/Collect.lean`)**:
> - Enhance `checkInductive` to `whnf` the type and use `getAppFn` to
detect inductive heads, populating `indCandidates`.
> - **Tests**:
> - New `tests/lean/run/try_induction.lean` covering suggestions for
`induction` on custom inductives, interaction with `grind`, and
coexistence with `fun_induction`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b357990c97. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR adds a `csimp` lemma for faster runtime evaluation of `Int.pow`
in terms of `Nat.pow`.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Replaces `Int.pow` evaluation with a `@[csimp]` lemma using `Nat.pow`
and adds supporting lemmas (`pow_mul`, `neg_pow`, nonneg results).
>
> - **Performance/runtime**:
> - Introduce `powImp` and `@[csimp]` theorem `pow_eq_powImp` to
evaluate `Int.pow` via `Nat.pow` with sign handling.
> - **Math lemmas (supporting)**:
> - `Int.pow_mul`: `a ^ (n * m) = (a ^ n) ^ m`.
> - `Int.sq_nonnneg`: nonnegativity of `m ^ 2`.
> - `Int.pow_nonneg_of_even`: nonnegativity for even exponents.
> - `Int.neg_pow`: `(-m)^n = (-1)^(n % 2) * m^n`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
66ac236db7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This PR adds support for `grind +suggestions` and `simp_all?
+suggestions` in `try?`. It outputs `grind only [X, Y, Z]` or `simp_all
only [X, Y, Z]` suggestions (rather than just `+suggestions`).
Co-authored-by: Claude <noreply@anthropic.com>
This PR fixes disequality propagation for constructor applications in
`grind`. The equivalence class representatives may be distinct
constructor applications, but we must ensure they have the same type.
Examples that were panic'ing before this PR:
```lean
example (a b : List Nat)
: a ≍ ([] : List Int) → b ≍ ([1] : List Int) → a = b ∨ p → p := by
grind
example (a b : List Nat)
: a = [] → a ≍ ([] : List Int) → b = [1] → a = b ∨ p → p := by
grind
example (a b : List Nat)
: a = [] → a ≍ ([] : List Int) → b = [1] → b ≍ [(1 : Int)] → a = b ∨ p → p := by
grind
example (a b : List Nat)
: a = [] → b = [1] → a = b ∨ p → p := by
grind
example (a b : List Nat)
: a = [] → a ≍ ([] : List Int) → b = [1] → a = b ∨ p → p := by
grind
```
Closes#11124
This PR fixes a typo in the doc string of `List.finIdxOf?`. The first
line of the doc string previously says the function returns the size of
the list if no element equal to `a`, but both the examples in the doc
string and real run-time behavior indicate it returns `none` in this
case.
Closes#11110
This PR fixes a problem for structures with diamond inheritance: rather
than copying doc-strings (which are not available unless `.server.olean`
is loaded), we link to them. Adds tests.
This PR adds `Job.sync` as a standard way of declaring a synchronous
job.
It makes some non-behavior changes to related Job APIs to improve
compilation.
This PR lets the match compilation procedure use sparse case analysis
when the patterns only match on some but not all constructors of an
inductive type. This way, less code is produce. Before, code handling
each of the other cases was then optimized and commoned-up by later
compilation pipeline, but that is wasteful to do.
In some cases this will prevent Lean from noticing that a match
statement is complete
because it performs less case-splitting for the unreachable case. In
this case, give explicit
patterns to perform the deeper split with `by contradiction` as the
right-hand side.
At least temporarily, there is also the option to disable this behaviour
with
```
set_option backwards.match.sparseCases false
```
This PR removes the `verifyEnum` functions from the bv_decide frontend.
These functions looked at the implementation of matchers to see if they
really do the matching that they claim to do. This breaks that
abstraction barrier, and should not be necessary, as only functions with
a `MatcherInfo` env entry are considered here, which should all play
nicely.
This PR adds `theorem Int.ediv_pow {a b : Int} {n : Nat} (hab : b ∣ a) :
(a / b) ^ n = a ^ n / b ^ n` and related lemmas.
---------
Co-authored-by: Bhavik Mehta <bhavikmehta8@gmail.com>
This PR adds “sparse casesOn” constructions. They are similar to
`.casesOn`, but have arms only for some constructors and a catch-all
(providing `t.ctorIdx ≠ 42` assumptions). The compiler has native
support for these constructors and now (because of the similarity) also
the per-constructor elimination principles.
This PR ensures that the `denote` functions used to implement
proof-by-reflection terms in `grind` are abbreviations. This change
eliminates the need for the `withAbstractAtoms` gadget.
This PR fixes a panic during equality propagation in the `grind ring`
module. If the maximum number of steps has been reached, the polynomials
may not be fully simplified.
Closes#11073
This PR adds union operations on DTreeMap/TreeMap/TreeSet and their raw
variants and provides lemmas about union operations.
---------
Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
This PR enables Lake users to require Reservoir dependencies by a
semantic version range. On a `lake update`, Lake will fetch the
package's version information from Reservoir and select the newest
version of the package that satisfies the range.
### Using Version Ranges
Version ranges can be specified through the `version` field of a TOML
`require` or the `@` clause of a Lean `require`. They are only
meaningful on Reservoir dependencies.
**lakefile.lean**
```lean-4
require "Seasawher" / "mdgen" @ "2.*"
```
**lakefile.toml**
```toml
[[require]]
name = "mdgen"
scope = "Seasawher"
version = "2.*"
```
The syntax for these versions ranges is a mix of
[Rust's](https://doc.rust-lang.org/stable/cargo/reference/specifying-dependencies.html?highlight=caret#version-requirement-syntax)
and
[Node's](https://github.com/npm/node-semver/tree/v7.7.3?tab=readme-ov-file#ranges)
with some Lean-friendly deviations.
### Comparators
The basic unit of semantic version ranges are version comparators. They
take a base version and a comparison operator and match versions which
compare positively with their base. Lake supports the following
comparison operators.
* `<`, `<=` / `≤`, `>`, `>=` / `≥`, `=`, `!=` / `≠`
Unlike Rust and Node, Lake supports Unicode alternatives for the
operators. It also adds the not-equal operator (`!=` / `≠`) to make
excluding broken versions easier.
Comparators can be combined into clauses via conjunction or disjunction:
* **AND clauses**: Rust-style `≥1.2.3, <1.8.0` or Node-style `1.2.3
<1.8.0`
* **OR clauses**: Node-style `1.2.7 || >=1.2.9, <2.0.0`
When the base version of a comparator has a `-` suffix (e.g.,
`>1.2.3-alpha.3`) it will match versions of the same core (`1.2.3`) with
suffixes that lexicographically compare (e.g., `1.2.3-alpha.7` or
`1.2.3-beta.2`) but will not match suffixed versions of different cores
(e.g., `3.4.5-rc5`). An empty `-` suffix can be used to disable this
behavior. For example, `<2.0.0-` will match `1.2.3-beta.2` and
`2.0.0-alpha.1`.
### Range Macros
In addition to the basic comparators, Lake also supports standard
shorthand for specifying more complex ranges. Namely, it supports the
caret (`^`) and tilde (`~`) operator along with wildcard ranges.
**Caret Ranges**
* `^1` => `≥1.0.0, <2.0.0-`
* `^1.2` => `≥1.2.0, <2.0.0-`
* `^1.2.3` => `≥1.2.3, <2.0.0-`
* `^1.2.3-beta.2` => `≥1.2.3-beta.2, <2.0.0-`
* `^0.2` => `≥0.0.0, <0.3.0-`
* `^0.2.3` => `≥0.2.3, <0.3.0-`
* `^0.0.3` => `≥0.0.3, <0.0.4-`
* `^0` => `≥0.0.0, <1.0.0-`
* `^0.0` => `≥0.0.0, <0.1.0-`
**Tilde Ranges**
* `~1` => `≥1.0.0, <2.0.0-`
* `~1.2` => `≥1.2.0, <1.3.0-`
* `~1.2.3` => `≥1.2.3, <1.3.0-`
* `~1.2.3-beta.2` => `≥1.2.3-beta.2, <1.3.0-`
* `^0` => `≥0.0.0, <1.0.0-`
* `^0.2.3` => `≥0.2.3, <0.3.0-`
* `^0.0.3` => `≥0.0.3, <0.0.4-`
* `~0` => `≥0.0.0, <1.0.0-`
* `~0.0` => `≥0.0.0, <0.1.0-`
* `~0.0.0` => `≥0.0.0, <0.1.0-`
**Wildcard Ranges**
* `*` => `≥0.0.0`
* `1.x` => `≥1.0.0, <2.0.0-`
* `1.*.x` => `≥1.0.0, <2.0.0-`
* `1.2.*` => `≥1.2.0, <1.3.0-`
These ranges closely follow Rust's and Node's syntax. Like Node but
unlike Rust, wildcard ranges support `x` and `X` as alternative syntax
for wildcards.
This PR implements `simp? +suggestions`, which uses the configured
library suggestion engine to add relevant theorems to the `simp` call.
`simp +suggestions` without the `?` prints a message requiring adding
the `?`.
This PR changes Lake's debug build type to use `-O0` instead of `-Og`
when compiling C code. `-Og` was found to be insufficient for debugging
compiled Lean code -- relevant code was stilled optimized out.
This PR changes `Nat.ble` by joining the two `Nat.ble Nat.zero _` cases
into one, allowing `decide (0 <= x) = true` and `decide (0 < succ x) =
true` to be solvable by `rfl`.
This PR fixes `ST.Ref.ptrEq` to act as described in the docs. This fixes
two bugs:
1. The recent `IO.RealWorld` elimination PR overlooked this function
(afaik this is the only one),
causing its return value to be generally wrong.
2. The implementation of `ptrEq` would previously always consider two
different cells with pointer
equivalent value to be pointer equal. However, the function is supposed
to check whether two
`Ref` are the same cell, not whether the contained elements are.
This PR implements equality propagation for `Nat` in `grind order`.
`grind order` supports offset equalities for rings, but it has an
adapter for `Nat`. Example:
```lean
example (a b : Nat) (f : Nat → Int) : a ≤ b + 1 → b + 1 ≤ a → f (1 + a) = f (1 + b + 1) := by
grind -offset -mbtc -lia -linarith (splits := 0)
```
This PR implements (nested term) equality propagation in `grind order`.
That is, it propagates implied equalities from `grind order` back to the
`grind` core. Examples:
```lean
open Lean Grind Std
example [LE α] [IsPartialOrder α] (a b : α) (f : α → Nat) : a ≤ b → b ≤ c → c ≤ a → f a = f b := by
grind (splits := 0)
example [CommRing α] [LE α] [LT α] [LawfulOrderLT α] [IsPartialOrder α] [OrderedRing α]
(a b : α) (f : α → Int) : a ≤ b + 1 → b ≤ a - 1 → f a = f (2 + b - 1) := by
grind -mbtc -lia -linarith (splits := 0)
example (a b : Int) (f : Int → Int) : a ≤ b + 1 → b ≤ a - 1 → f a = f (2 + b - 1) := by
grind -mbtc -lia -linarith (splits := 0)
```
`prelude-injectivity.lean` was testing inj thm generation for all
inductives in core, including private ones, which could lead to name
clashes that should not be able to occur in actual files. Put it under
the module system to not load private decls in the first place.
This PR enforces users of the constant folder API to provide proofs of
their algebraic properties,
thus hopefully avoiding bugs such as #11042 and #11043 in the future.
This PR fixes a case of overeager constant folding on Nat where the
compiler would mistakenly assume `0 - x = x` (see also #11042 for the
same bug on UInts).
This PR adds a new suggestion to `finish?`. It now generates the `grind`
tactic script as before, and a `finish only` tactic. Example:
```lean
/--
info: Try these:
[apply] ⏎
instantiate only [findIdx, insert, = mem_indices_of_mem]
instantiate only [= getElem?_neg, = getElem?_pos]
cases #1bba
· instantiate only [findIdx]
· instantiate only
instantiate only [= HashMap.mem_insert, = HashMap.getElem_insert]
[apply] finish only [findIdx, insert, = mem_indices_of_mem, = getElem?_neg, = getElem?_pos, = HashMap.mem_insert,
= HashMap.getElem_insert, #1bba]
-/
example (m : IndexMap α β) (a : α) (b : β) :
(m.insert a b).findIdx a = if h : a ∈ m then m.findIdx a else m.size := by
grind => finish?
```
This PR establishes `String.ofList` and `String.toList` as the preferred
method for converting between strings and lists of characters and
deprecates the alternatives `String.mk`, `List.asString` and
`String.data`.
This PR updates the `pr-title` CI check to enforce that the commit
message does not start with a capital letter followed by a non-capital
letter.
This should ensure that messages do not start with a capitalized word,
but allow messages that start with an acronym.
This PR adds a library suggestion engine for local theorems. To be
useful, I still need to write more combinators to re-rank and combine
suggestions from multiple engines.
This is stacked on top of #11029.
This PR changes the terminology used from "premise selection" to
"library suggestions". This will be more understandable to users (we
don't assume anyone is familiar with the premise selection literature),
and avoids a conflict with the existing use of "premise" in Lean
terminology (e.g. "major premise" in induction, as well as generally the
synonym for "hypothesis"/"argument").
This PR improves match compilation: Branch on variables in the order
suggested by the first remaining alternative, and do not branch when the
first remaining alternative does not require it. This fixes
https://github.com/leanprover/lean4/issues/10749. With `set_option
backwards.match.rowMajor false` the old behavior can be turned on.
(For now this is an experiment to get familiar with the code and the
whole
problem domain. It is likely overly naive.)
This PR renames theorems that use `sorted` in their name to instead use
`pairwise`.
Closes#10742.
---------
Co-authored-by: Markus Himmel <markus@lean-fro.org>
This PR improves the detection of situations where we branch multiple
times on the same value in the
code generator. Previously this would only consider repeated branching
on function arguments, now on
arbitrary values.
Closes: #11018
When documenting smul : M → α → α, it is unintuitive and confusing to
use variables a:M and b:α. It is better to use m:M and a:α. I also
specified the types of all involved terms in the documentation text.
This PR improves join point finding in the compiler through two means:
1. We now handle situations where a function `f` can only become a join
point when a function `g`
becomes a join point as well correctly.
2. We introduce a second join point finding pass after specialisation
and before the following
simplification pass, as the specialiser might have introduced new join
point opportunities for
the simplifier to exploit.
Notably in the code from #10995 we now correctly detect the missing join
point which required both
of these changes to be made.
Closes: #10995
This PR extracts some refactorings from #10763, including dropping dead
code and not failing in `inaccessibleAsCtor`, which leadas to (slightly)
better error messages, and also on the grounds that the failing
alternative may actually be unreachable.
This PR makes the eager lambda lifting heuristic more predictable by
blocking it from lifting from
any kind of inlineable function, not just `@[inline]`. It also adapts
the doc-string to describe
what is actually going on.
This PR inlines several Decidable instances for performance reasons.
Unlike the previous #10934 it does not attempt to also simplify the
Decidable instance system as
that has proven to have non trivial performance impact.
Co-authored-by: Rob23oba <152706811+Rob23oba@users.noreply.github.com>
This PR fixes a memleak caused by the Lean based `IO.waitAny`
implementation by reverting it.
This the faulty Lean implementation:
```lean
def IO.waitAny (tasks : @& List (Task α)) (h : tasks.length > 0 := by exact Nat.zero_lt_succ _) :
BaseIO α := do
have : Nonempty α := ⟨tasks[0].get⟩
let promise : IO.Promise α ← IO.Promise.new
tasks.forM <| fun t => BaseIO.chainTask (sync := true) t promise.resolve
return promise.result!.get
```
In a situation where we call this function repeatedly in a loop with a
pair of tasks `[t1, t2]`
where `t2` is a long lived task that we pass every time and `t1` is
fresh a short lived task, `t2` will
accumlate more and more children from `BaseIO.chainTask` that fill
memory over time. The old C++
implementation did not have this issue so we are reverting.
This PR defines `String.Slice.replace` and redefines `String.replace` to
use the `Slice` version.
The new implementation is generic in the pattern, so it supports things
like `"education".replace isVowel "☃!" = "☃!d☃!c☃!t☃!☃!n"`. Since it
uses the `ForwardSearcher` infrastructure, `String` patterns are
searched using KMP, unlike the previous implementation which had
quadratic runtime. As a side effect, the behavior when replacing an
empty string now matches that of most other programming languages,
namely `"abc".replace "" "k" = "kakbkck"`.
This PR fixes the KMP implementation, which did incorrect bookkeeping of
the backtracking process, leading to incorrect starting ranges of
matches.
The new implementation does not require `partial` anywhere.
This PR adds support for specifying anchors to restrict the search space
in `grind` when using `grind only`. Anchors can limit which case splits
are performed and which local lemmas are instantiated.
This PR adds the `set_config` tactic for setting `grind` configuration
options. It uses the same syntax used for setting configuration options
in the `grind` main tactic.
This PR tries to preserve names of pattern variables in match
alternatives in `decreasing_by`, by telescoping into the concrete
alternative rather than the type of the matcher's alt. Fixes#10976.
This PR ensures that searching for an empty string returns the expected
pattern of alternating size-zero matches and size-one rejects.
In particular, splitting by an empty string returns an array formed of
the empty string, all of the string's characters as singleton strings,
followed by another empty string. This matches the [Rust
behavior](https://doc.rust-lang.org/std/primitive.str.html#method.split),
for example.
This PR adds inline annotations to several `Decidable` instances.
Additionally, it removes the `Decidable` instance for `p → q` which is
made redundant by `forall_prop_decidable`.
This PR changes the closure allocator to use the general allocator
instead of the small object one.
This is because users may create closures with a gigantic amount of
closed variables which in turn
boost the size of the closure beyond the small object threshold.
This issue was uncovered by #10979. Detecting that the small object
threshold is at fault requires
building mimalloc in debug mode at which point it yields:
```
mimalloc: assertion failed: at "/home/henrik/lean4/build/debug/mimalloc/src/mimalloc/src/alloc.c":132, mi_heap_malloc_small_zero
assertion: "size <= MI_SMALL_SIZE_MAX"
```
The generated code at fault here looks as follows:
```c
LEAN_EXPORT lean_object* l_initExec___at___00res_spec__0(lean_object* x_1) {
_start:
{
lean_object* x_2; lean_object* x_3; lean_object* x_4; lean_object* x_5; lean_object* x_6; lean_object* x_7; lean_object* x_8; lean_object* x_9; lean_object* x_10; lean_object* x_11; lean_object* x_12; lean_object* x_13; lean_object* x_14;
x_2 = lean_alloc_closure((void*)(l_initializer_ext___at___00initExec___at___00res_spec__0_spec__0___lam__0___boxed), 3, 0);
x_3 = l_initExec___redArg___closed__0;
x_4 = l_initExec___redArg___closed__1;
x_5 = l_instMonadLiftNonDetT___closed__0;
x_6 = l_initExec___redArg___closed__2;
x_7 = l_initExec___at___00res_spec__0___closed__0;
lean_inc_ref(x_2);
x_8 = lean_alloc_closure((void*)(l_initExec___at___00res_spec__0___lam__29___boxed), 213, 212);
lean_closure_set(x_8, 0, x_3);
lean_closure_set(x_8, 1, x_2);
lean_closure_set(x_8, 2, x_4);
lean_closure_set(x_8, 3, x_3);
lean_closure_set(x_8, 4, x_4);
lean_closure_set(x_8, 5, x_3);
lean_closure_set(x_8, 6, x_4);
lean_closure_set(x_8, 7, x_3);
lean_closure_set(x_8, 8, x_4);
lean_closure_set(x_8, 9, x_3);
lean_closure_set(x_8, 10, x_4);
lean_closure_set(x_8, 11, x_3);
lean_closure_set(x_8, 12, x_4);
lean_closure_set(x_8, 13, x_3);
lean_closure_set(x_8, 14, x_4);
lean_closure_set(x_8, 15, x_5);
lean_closure_set(x_8, 16, x_6);
lean_closure_set(x_8, 17, x_5);
lean_closure_set(x_8, 18, x_5);
lean_closure_set(x_8, 19, x_5);
lean_closure_set(x_8, 20, x_5);
lean_closure_set(x_8, 21, x_5);
lean_closure_set(x_8, 22, x_5);
...
```
With the crash happening in `lean_alloc_closure` where we
unconditionally invoke the small allocator
which cannot cope with closures this large. Hopefully changing this to
the general purpose allocator
doesn't have too much of an impact on performance.
Closes: #10979
This PR adds the basic infrastructure to perform termination proofs
about `String.ValidPos` and `String.Slice.Pos`.
We choose approach where the intended way to do termination arguments is
to argue about the position itself rather than some projection of it
like `remainingBytes`.
The types `String.ValidPos` and `String.Slice.Pos` are equipped with a
`WellFoundedRelation` instance given by the greater-than relation. This
means that if a function takes a position `p` and performs a recursive
call on `q`, then the decreasing obligation will be `p < q`. This works
well in the common case where `q` is `p.next h`, in which case the goal
`p < p.next h` is solved by the simplifier.
For stepping through a string backwards, we introduce a type synonym
with a `WellFoundedRelation` instance given by the less-than relation.
This means that if a function takes a position `p` and performs a
recursive call on `q` and specifies `termination_by p.down`, then the
decreasing obligation will be `q < p`. This works well in the case where
`q` is `p.prev h`, in which case the goal `p.prev h < p` is solved by
the simplifier.
For termination arguments invoving multiple strings, the lower-level
primitive `p.remainingBytes` (landing in `Nat`) is also available.
In a future PR, we will additionally provide the necessary typeclasses
instances to register `String.ValidPos` and `String.Slice.Pos` with
`grind` to make complex termination arguments more convenient in user
code.
This PR performs more widening in ElimDeadBranches in an attempt to
improve performance in situations with a lot of local precision.
While this is not enough to make the compilation instant it pushes
compilation time from 12s to 3s for the example in #10857 and barely
introduces regressions so it seems like a good first step in this
direction.
Closes: #10857
This PR implements the following `grind` improvements:
1. `set_option` can now be used to set `grind` configuration options in
the interactive mode.
2. Fixes a bug in the repeated theorem instantiation detection.
3. Adds the macro `use [...]` as a shorthand for `instantiate only
[...]`.
This PR adds the combinator ` · t_1 ... t_n` to the `grind` interactive
mode. The `finish?` tactic now generates scripts using this combinator
to conform to Mathlib coding standards. The new format is also more
compact. Example:
```lean
/--
info: Try this:
[apply] ⏎
instantiate only [= mem_indices_of_mem, insert, = getElem_def]
instantiate only [= getElem?_neg, = getElem?_pos]
cases #f590
· cases #ffdf
· instantiate only
instantiate only [= Array.getElem_set]
· instantiate only
instantiate only [size, = HashMap.mem_insert, = HashMap.getElem_insert, = Array.getElem_push]
· instantiate only [= mem_indices_of_mem, = getElem_def]
instantiate only [usr getElem_indices_lt]
instantiate only [size]
cases #ffdf
· instantiate only [=_ WF]
instantiate only [= getElem?_neg, = getElem?_pos, = Array.getElem_set]
instantiate only [WF']
· instantiate only
instantiate only [= HashMap.mem_insert, = HashMap.getElem_insert, = Array.getElem_push]
-/
#guard_msgs in
example (m : IndexMap α β) (a a' : α) (b : β) (h : a' ∈ m.insert a b) :
(m.insert a b)[a'] = if h' : a' == a then b else m[a'] := by
grind => finish?
```
This PR ensures that model-based theory combination in `grind cutsat`
considers nonlinear terms. Nonlinear multiplications such as `x * y` are
treated as uninterpreted symbols in `cutsat`.
Closes#10885
This PR adds support for scientific literals for `Rat` in `grind`.
`grind` does not yet add support for this kind of literal in arbitrary
fields.
closes#10489
This PR fixes a bug in the equality propagation procedure in
`grind.order`. Specifically, it affects the procedure that asserts
equalities in the `grind` core state that are implied by (ring)
inequalities in the `grind.order` module.
closes#10622
This is a guard against #10705; if a kernel error is raised when the
return value of this function is eventually checked, it is often
silenced downstream, making it hard to spot the failure.
If we panic here via `assert!`, then the diagnostic cannot be missed.
This PR adds the `mbtc` tactic to the `grind` interactive mode. It
implements model-based theory combination. It also ensures `finish?` is
capable of generating it.
This PR ensures that solver propagation steps are necessary in the
generated tactic script to close the goal.
It produces more compact proof scripts, but this is not just an
optimization, if we include an unnecessary step, we may fail to replay
the generated script when `cases` steps are pruned using
non-chronological backtracking (NCB). For example, when executing
`finish?`, we may have performed a `cases #<anchor>` step that enabled
`ring` to propagate a new fact. If this fact is not used in the final
proof, and the corresponding `cases #<anchor>` step is pruned by NCB,
the `ring` step will fail during replay.
This PR ensures that `finish?` produces partial tactic scripts
containing `sorry`s.
We may add an option to disable this feature in the future.
It is enabled by default because it provides a useful way to debug
`grind` failures.
This PR topologically sorts abstracted vars in
`Meta.Closure.mkValueTypeClosure` if MVars are being abstracted.
Fixes#10705
---------
Co-authored-by: Eric Wieser <efw@google.com>
This PR fixes a regression introduced by the `ST` redefinition by making
the definition of `ST` as
reducible as previously. The key issue here is that in the previous
state it would reduce to a
function at which point the monad lifting mechanisms don't kick in in
the same fashion anymore.
This PR fixes another instance of the “default parameter value in
constructor” footgun, which was affecting the `cases` tactic in the
`grind` interactive mode.
This PR adds a warning to `wf_preproces` that these lemmas can be used
to introduce hidden partiality.
---------
Co-authored-by: Rob23oba <152706811+Rob23oba@users.noreply.github.com>
This PR uses hashmaps for the symbol lookups in the IR interpreter
instead of the existing rbmaps.
Thus reducing the constant overhead per function call.
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR fixes name mangling to be unambiguous / injective by adding `00`
for disambiguation where necessary. Additionally, the inverse function,
`Lean.Name.unmangle` has been added which can be used to unmangle a
mangled identifier. This unmangler has been added to demonstrate the
injectivity but also to allow unmangling identifiers e.g. for debugging
purposes.
Closes#10724
This PR adds support for `grind +premises`, calling the currently
configured premise selection algorithm and including the results as
parameters to `grind`. (Recall that there is not currently a default
premise selector provided by Lean4: you need a downstream premise
selector to make use of this.)
This PR adds a test for depending on two packages which privately import
modules that define the same Lean definition. It verifies the current
behavior of a symbol clash. This behavior will be fixed later this
quarter.
This PR adds a `+lax` configuration option for `grind`, causing it to
ignore parameters referring to non-existent theorems, or to theorems for
which we can't generate a pattern. This allows throwing large sets of
theorems (e.g. from a premise selection enginre) into `grind` to see
what happens.
This PR implements the `have <ident>? : <prop>` tactic for the `grind`
interactive mode. The proposition is proved using the default `grind`
search strategy. This tactic is also useful for inspecting or querying
the current `grind` state.
This PR implements parameter optimization for the generated
`instantiate` tactics produced by `finish?`.
We use a simple parameter optimizer that takes two sets as input: the
lower and upper bounds.
The lower bound consists of the theorems actually used in the proof
term, while the upper bound includes all the theorems instantiated in a
particular theorem instantiation step.
The lower bound is often sufficient to replay the proof, but in some
cases, additional theorems must be included because a theorem
instantiation may contribute to the proof by providing terms and many
not be present in the final proof term.
This PR makes minor changes to the MePo premise selection algorithm.
I'm increasingly believing that MePo will not work well in Lean; I've
tried a few things without success. Alistair Geesing's thesis from 2023
had similar conclusions.
My intention is to reach the point we can properly benchmark premise
selection algorithms before doing any more work here.
This PR optimizes two `String` proofs and makes sure that
`MkIffOfInductiveProp` does not import `Lean.Elab.Tactic`, which
previously pushed it to the very end of the import graph.
This PR splits some low-hanging fruit out of `Init.Data.String.Basic`:
basic material about `String.Pos.Raw`, `String.Substrig`, and
`String.Iterator`.
More splitting required and the remaining material is quite unorganized,
but it's a start.
This PR implements zero cost `BaseIO` by erasing the `IO.RealWorld`
parameter from argument lists and structures. This is a **major breaking
change for FFI**.
Concretely:
- `BaseIO` is defined in terms of `ST IO.RealWorld`
- `EIO` (and thus `IO`) is defined in terms of `EST IO.RealWorld`
- The opaque `Void` type is introduced and the trivial structure
optimization updated to account for it. Furthermore, arguments of type
`Void s` are removed from the argument lists of the C functions.
- `ST` is redefined as `Void s -> ST.Out s a` where `ST.Out` is a pair
of `Void s` and `a`
This together has the following major effects on our generated code:
- Functions that return `BaseIO`/`ST`/`EIO`/`IO`/`EST` now do not take
the dummy world parameter anymore. To account for this FFI code needs to
delete the dummy world parameter from the argument lists.
- Functions that return `BaseIO`/`ST` now return their wrapped value
directly. In particular `BaseIO UInt32` now returns a `uint32_t` instead
of a `lean_object*`. To account for this FFI code might have to change
the return type and does not need to call `lean_io_result_mk_ok` anymore
but can instead just `return` values right away (same with extracting
values from `BaseIO` computations.
- Functions that return `EIO`/`IO`/`EST` now only return the equivalent
of an `Except` node which reduces the allocation size. The
`lean_io_result_mk_ok`/`lean_io_result_mk_error` functions were updated
to account for this already so no change is required.
Besides improving performance by dropping allocation (sizes) we can now
also do fun new things such as:
```lean
@[extern "malloc"]
opaque malloc (size : USize) : BaseIO USize
```
This PR renames the cast functions on `String.ValidPos` for `set` and
`modify` to adhere to the established naming convention.
It also fixes two typos and very slighly tweaks the import graph,
shortening the critical path by a negligible amount.
This PR fixes a bug with Lake's cache where revisions were stored at the
incorrect path. Revisions were stored at `<rev>/<pkg>.jsonl` rather than
the correct `<pkg>/<rev>.jsonl`.
This PR fixes a proof instability source in `grind`.
We say a proof is *unstable* if minor changes in the `.lean` file
containing the proof **affect** it.
This PR adds a missing move assignment operator, and deletes the copy
assignment operator.
C++ types should not implement move constructors without also
implementing move assignment. This also ensures that `m_fn` is correctly
emptied after a move, which is not guaranteed by the standard.
This change is also needed to allow `lean::optional` to be eventually
replaced by `std::optional`.
This PR improves the performance of `mvcgen` by an optimized
implementation for `try (mpure_intro; trivial)`. This tactic sequence is
used to eagerly discharge VCs and in the process instantiates schematic
variables.
This PR renames `String.endPos` to `String.rawEndPos`, as in a future
release the name `String.endPos` will be taken by the function that is
currently called `String.endValidPos`.
This PR fixes a bug in `String.Slice.takeWhile` which caused it to get
its bookkeeping wrong and panic. The new version only uses safe
operations on `String.Slice.Pos`.
This PR reduces the amount of symbols in our DLLs by cutting open a
linking cycle of the shape:
`Environment -> Compiler -> Meta -> Environment`
This is achieved by introducing a dynamic call to the compiler hidden
behind a `Ref` as previously
done in the pretty printer.
This PR adds a field `isDisplayableTerm` to `TermInfo` and all utility
functions which create `TermInfo` that can be set to force the language
server to render the term in hover popups.
This PR fixes `input_dir` tracking to also recurse through
subdirectories. The `filter` of an `input_dir` will be applied to each
file in the directory tree (the path names of directories will not be
checked).
Closes#10827.
This PR improves the release automation. We link to CI output for
building the release tag, don't give instructions for bumping downstream
repositories until the release it ready, and improve documentation and
prompts.
This PR lets match compilation use exfalso as soon as no alternatives
are left. This way, the compiler does not have to look at subsequent
case splits.
This PR shows that the iterators returned by `String.Slice.split` and
`String.Slice.splitInclusive` are finite as long as the forward matcher
iterator for the pattern is finite (which we already know for all of our
patterns).
At actually also completely redefines the iterators to avoid the inner
loop in `Internal.nextMatch` which generates inefficient code. Instead,
when encountering a mismach from the matcher, we `skip` the split
iterator.
This PR improves the `grind` tactic generated by the `instantiate`
action in tracing mode. It also updates the syntax for the `instantiate`
tactic, making it similar to `simp`. For example:
* `instantiate only [thm1, thm2]` instantiates only theorems `thm1` and
`thm2`.
* `instantiate [thm1, thm2]` instantiates theorems marked with the
`@[grind]` attribute **and** theorems `thm1` and `thm2`.
The action produces `instantiate only [...]` tactics. Example:
```lean
/--
info: Try this:
[apply] ⏎
instantiate only [= Array.getElem_set]
instantiate only [= Array.getElem_set]
-/
#guard_msgs in
example (as bs cs : Array α) (v₁ v₂ : α)
(i₁ i₂ j : Nat)
(h₁ : i₁ < as.size)
(h₂ : bs = as.set i₁ v₁)
(h₃ : i₂ < bs.size)
(h₄ : cs = bs.set i₂ v₂)
(h₅ : i₁ ≠ j ∧ i₂ ≠ j)
(h₆ : j < cs.size)
(h₇ : j < as.size) :
cs[j] = as[j] := by
grind => finish?
```
Recall that `finish?` replays generated tactics before suggesting them.
The `instantiate` action inspects the generated proof term to decide
which theorems to include as parameters in the `instantiate only [...]`
tactic. However, in some cases, a theorem contributes only by adding a
term to the state. In such cases, the generated tactic cannot be fully
replayed, and the action uses
`instantiate approx [<thms instantiated>]` to indicate which parts of
the tactic script are approximate. The `approx` is just a hint for
users.
This PR implements the `finish?` tactic for the `grind` interactive
mode. When it successfully closes the goal, it produces a code action
that allows the user to close the goal using explicit grind tactic
steps, i.e., without any search. It also makes explicit which solvers
have been used.
This is just the first version, we will add many "bells and whistles"
later. For example, `instantiate` steps will clearly show which theorems
have been instantiated.
Example:
```lean
/--
info: Try this:
[apply] ⏎
cases #b0f4
next => cases #50fc
next => cases #50fc <;> lia
-/
#guard_msgs in
example (p : Nat → Prop) (x y z w : Int) :
(x = 1 ∨ x = 2) →
(w = 1 ∨ w = 4) →
(y = 1 ∨ (∃ x : Nat, y = 3 - x ∧ p x)) →
(z = 1 ∨ z = 0) → x + y ≤ 6 := by
grind => finish?
```
The anchors in the generated script are based on stable hash codes.
Moreover, users can hover over them to see the exact term used in the
case split. `grind?` will also be implemented using the new framework.
This PR implements support for `Action` in the `grind` solver extensions
(`SolverExtension`). It also provides the `Solvers.mkAction` function
that constructs an `Action` using all registered solvers. The generated
action is "fair," that is, a solver cannot prevent other solvers from
making progress.
This PR implements infrastructure for evaluating `grind` tactics in the
`GrindM` monad. We are going to use it to check whether auto-generated
tactics can effectively close the original goal.
This PR moves many operations involving `String.Pos.Raw` to a the
`String.Pos.Raw` namespace with the eventual aim of freeing up the
`String` namespace to contain operations using `String.ValidPos` (to be
renamed to `String.Pos`) instead.
This PR adds the `String.ValidPos.set` and `String.ValidPos.modify`
functions.
After this PR, `String.pos_lt_eq` is no longer a `simp` lemma. Add
`String.Pos.Raw.lt_iff` as a `simp` lemma if your proofs break.
This PR renames `String.split` to `String.splitToList`, because soon the
name `String.split` will be used by a new implementation which is
superior because it is polymorphic over the pattern kind and it returns
an iterator of slices instead of a list of strings.
This PR implements a compact notation for inspecting the `grind` state
in interactive mode. Within a `grind` tactic block, each tactic may
optionally have a suffix of the form `| filter?`.
Examples:
```lean
instantiate | gen > 0 -- Displays terms in the `grind` state after executing `instantiate` with generation greater than zero
```
```lean
instantiate | -- Displays the `grind` state after executing `instantiate`
```
Remark: If the user places the cursor one space before `|`, the state
*before* executing `instantiate` is displayed.
This PR removes the code that was silently displaying the `grind` state
after each tactic step, as it was too noisy.
It also updates the notation for the `first` combinator in the `grind`
tactic mode to avoid conflicts with the new syntax.
This PR changes match compilation to reject some pattern matches that
were previously accepted due to inaccessible patterns sometimes treated
like accessible ones. Fixes#10794.
This PR adds more selectors for TCP and Signals.
It also fixes a problem with `Selectors` that they cannot be closures
over a promise, otherwise it causes the waiter promise to never be
dropped.
This PR introduces the `backward.privateInPublic` option to aid in
porting projects to the module system by temporarily allowing access to
private declarations from the public scope, even across modules. A
warning will be generated by such accesses unless
`backward.privateInPublic.warn` is disabled.
This PR fixes `getHexNumSize` to consider underscores. Previously, only
the amount of bytes was counted, making it output 9 for `1234_abcd`
instead of the actual number of digits, which is 8.
the tested situation (kernel runs into deep recursion but elaborator is
happy) is not very stable and depends on, for example, stack size. This
test is not worth that hassle.
This PR adds adds union operation on `DHashMap`/`HashMap`/`HashSet` and
their raw variants and provides lemmas about union operations.
---------
Co-authored-by: Paul-Lez <paul.lezeau@gmail.com>
Co-authored-by: Markus Himmel <markus@lean-fro.org>
Co-authored-by: Markus Himmel <markus@himmel-villmar.de>
This PR adds `.vscode/settings.json` to our `.gitignore`, which allows
Lean 4 developers to set local workspace settings. We already use the
the workspace file for settings in core, so this shouldn't cause any
problems.
This PR fixes a bug in the unknown identifier code actions where the
identifiers wouldn't be correctly minimized in nested namespaces. It
also fixes a bug where identifiers would sometimes be minimized to
`[anonymous]`.
The first bug was introduced in #10619.
This PR adds a silent info message with the `grind` state in its
interactive mode. The message is shown only when there is exactly one
goal in the grind interactive mode. The condition is a workaround for
current limitations of our `InfoTree`.
This PR lets match compilation look only at the first remaining
alternative in `processLeaf`. At this point we have no further variables
we can split on, so if the first one isn’t applicable, match compilation
should fail.
This PR fixes a regression introduced by #10307, where hovering the name
of an inductive type or constructor in its own declaration didn't show
the docstring. In the process, a bug in docstring handling for
coinductive types was discovered and also fixed. Tests are added to
prevent the regression from repeating in the future.
This PR ensures that `grind` interactive mode is hygienic. It also adds
tactics for renaming inaccessible names: `rename_i h_1 ... h_n` and
`next h_1 ... h_n => ..`, and `expose_names` for automatically generated
tactic scripts. The PR also adds helper functions for implementing
case-split actions.
This PR improves the scripts assisting with cutting Lean releases (by
reporting CI status of open PRs, and adding documentation), and adds a
`.claude/commands/release.md` prompt file so Claude can assist.
This PR introduces a no-op version of `Shrink`, a type that should allow
shrinking small types into smaller universes given a proof that the type
is small enough, and uses it in the iterator library. Because this type
would require special compiler support, the current version is just a
wrapper around the inner type so that the wrapper is equivalent, but not
definitionally equivalent.
While `Shrink` is unable to shrink universes right now, but introducing
it now will allow us to generalize the universes in the iterator library
with fewer breaking changes as soon as an actual `Shrink` is possible.
This PR fixes a bug in combination with VS Code where Lean code that
looks like CSS color codes would display a color picker decoration.
VS Code displays this decoration by default for all languages, not just
CSS. Due to https://github.com/microsoft/vscode/issues/91533, this
setting cannot be disabled in the client on a per-language basis.
However, we can override the default behavior by providing a color
provider of our own. This PR implements an empty color provider to
override the VS Code one.
This PR adds support for interactivity to the combined "try this"
messages that were introduced in #9966. In doing so, it moves the link
to apply a suggestion to a separate `[apply]` button in front of the
suggestion. Hints with diffs remain unchanged, as they did not
previously support interacting with terms in the diff, either.
<img width="379" height="256" alt="Suggestion with interactive message"
src="https://github.com/user-attachments/assets/7838ebf6-0613-46e7-bc88-468a05acbf51"
/>
This PR restores the change in #8656, which removed `autoImplicit =
false` from the default lake template (per previous discussions linked
there). This was accidentally reverted in #8866.
This PR fixes a performance regression introduced in #10518. More
generally, it ensures both message log and info state are per-command,
which has been the case in practice ever since the asynchronous language
driver was introduced.
This PR fixes a bug where partially up-to-date files built with `--old`
could be stored in the cache as fully up-to-date. Such files are no
longer cached. In addition, builds without traces now only perform an
modification time check with `--old`. Otherwise, they are considered
out-of-date.
This PR changes the Lake's remote cache interface to scope cache outputs
by toolchain and/or platform were useful.
Packages that set `platformIndependent = true` will not be scoped by
platform and the core build (i.e., `bootstrap = true`) will not be
scoped by toolchain. Lake's detected platform and toolchain can be
overridden with the new `--platform` and `--toolchain` options to `cache
get` and `cache put`.
Lake no longer accepts the `--scope` option when using `cache get` with
Reservoir.. The `--repo` option must be used instead.
This PR follows upon #10606 and creates equational theorems uniformly
from the unfold theorem, there is only one handler registered in
`registerGetEqnsFn`.
For now we keep `registerGetEqnsFn`, because it’s used by mathlib’s
`irreducible_def`, but I’d like to get rid of it in the long term,
relying only on `registerGetUnfoldEqnFn` for constructions that should
unfold differently.
This PR improves the tactics `ac`, `linarith`, `lia`, `ring` tactics in
`grind` interactive mode. They now fail if no progress has been made.
They also generate an info message with counterexample/basis if the goal
was not closed.
This PR provides range support for the signed finite number types
`Int{8,16,32,64}` and `ISize`. The proof obligations are handled by
reducing all of them to proofs about an internal `UpwardEnumerable`
instance for `BitVec` interpreted as signed numbers.
This PR changes where errors are displayed when trying to use
`coinductive` keyword when targeting things that do not live in `Prop`.
Instead of displaying the error above the first element of the mutual
block, it is displayed above the erroneous definition.
---------
Co-authored-by: Rob23oba <152706811+Rob23oba@users.noreply.github.com>
This PR removes support for reducible well-founded recursion, a Breaking
Change. Using `@[semireducible]` on a definition by well-founded
recursion prints a warning that this is no longer effective.
With the upcoming module system, proofs are often not available. With
this change, we remove a fringe use case hat may require proofs, and
that would not be supported under the module system anyways.
At least for now, direct use of `WellFounded.fix` is not affected.
This fixes: #5192
This PR re-enables semantic tokens for Verso docstrings, after a prior
change accidentally disabled them. It also adds a test to prevent this
from happening again.
In the process, it became clear that there was a bug. The highlighting
strategy led to overlapping but not identical tokens, but the code had
previously assumed that this couldn't happen at the delta-encoding step.
So this PR additionally replaces the removal of duplicate tokens with
priority-based handling of overlapping tokens.
---------
Co-authored-by: Marc Huisinga <mhuisi@protonmail.com>
This PR adds the following tactics to the `grind` interactive mode:
- `focus <grind_tac_seq>`
- `next => <grind_tac_seq>`
- `any_goals <grind_tac_seq>`
- `all_goals <grind_tac_seq>`
- `grind_tac <;> grind_tac`
- `cases <anchor>`
- `tactic => <tac_seq>`
Example:
```lean
def g (as : List Nat) :=
match as with
| [] => 1
| [_] => 2
| _::_::_ => 3
example : g bs = 1 → g as ≠ 0 := by
grind [g.eq_def] =>
instantiate
cases #ec88
next => instantiate
next => finish
tactic =>
rw [h_2] at h_1
simp [g] at h_1
```
This PR enforces rules around arithmetic of `String.Pos.Raw`.
Specifically, it adopts the following conventions:
- Byte indices ("ordinals") in strings should be represented using
`String.Pos.Raw`
- Amounts of bytes ("cardinals") in strings should be represented using
`Nat`.
For example, `String.Slice.utf8ByteSize` now returns `Nat` instead of
`String.Pos.Raw`, and there is a new function `String.Slice.rawEndPos`.
Finally, the `HAdd` and `HSub` instances for `String.Pos.Raw` are
reorganized. This is a **breaking change**.
The `HAdd/HSub String.Pos.Raw String.Pos.Raw String.Pos.Raw` instances
have been removed. For the use case of tracking positions relative to
some other position, we instead provide `offsetBy` and `unoffsetBy`
functions. For the use case of advancing/unadvancing a position by an
arbitrary number of bytes, we instead provide `increaseBy` and
`decreaseBy` functions. For
offsetting/unoffsetting/advancing/unadvancing a position `p` by the size
of a string `s` (resp. character `c`), use `s + p`/`p - s`/`p + s`/`p -
s` (resp. `c + p`/`p - c`/`p + c`/`p - c`).
This PR re-enables the "experimental" warning for `mvcgen` by changing
its default. The official release has been postponed to justify small
breaking changes in the semantic foundations in the near future.
This PR adds a new helper parser for implementing parsers that contain
hexadecimal numbers. We are going to use it to implement anchors in the
`grind` interactive mode.
This PR aims to fix the Timer API selector to make it finish as soon as
possible when unregistered. This change makes the `Selectable.one`
function drop the `selectables` array as soon as possible, so when
combined with finalizers that have some effects like the TCP socket
finalizer, it runs it as soon as possible.
This PR fixes several causes of test flakiness and re-enables the tests
that were disabled in #10665, #10669 and #10673.
Specifically, it fixes:
- A race condition in the file worker that caused it to report an
incomplete snapshot prefix in the inlay hint request (confirmed to be
the cause of #10665)
- A bug in the test runner where it didn't correctly account for
non-deterministic message ordering inducing different RPC pointer
numbering (confirmed to be the cause of #10673)
- A race condition in the watchdog that would sometimes cause the module
hierarchy to be empty (likely the cause of #10669, but not confirmed as
this issue only reproduced again once in tens of thousands of test runs
on various machines, including CI)
- An unrelated bug in the module hierarchy implementation that would
cause it to report an empty module hierarchy when the file was changed
It also replaces some calls to `Task.get` in the language server with
`IO.wait` to protect the code against unfortunate compiler re-ordering.
This PR adds auto-completion for identifiers after `end`. It also fixes
a bug where completion in the whitespace after `set_option` would not
yield the full option list.
Closes#3885.
### Breaking changes
The `«end»` syntax is adjusted to take an `identWithPartialTrailingDot`
instead of an `ident`.
This PR adds the `USE_LAKE_CACHE` option to the core CMake build
(defaults to `OFF`). When enabled, the Lake artifact cache will be
enabled (via `enableArtifactCache`) for stage 1 builds (which includes
interactive use).
This PR implements *anchors* (also known as stable hash codes) for
referencing terms occurring in a `grind` goal. It also introduces the
commands `show_splits` and `show_state`. The former displays the anchors
for candidate case splits in the current `grind` goal.
This PR adds a new `allowImportAll` configuration option for packages
and libraries. When enabled by an upstream package or library,
downstream packages will be able to `import all` modules of that package
or library. This enables package authors to selectively choose which
`private` elements, if any, downstream packages may have access to.
This PR adds the `have` tactic for the `grind` interactive mode.
Example:
```lean
example {a b c d e : Nat}
: a > 0 → b > 0 → 2*c + e <= 2 → e = d + 1 → a*b + 2 > 2*c + d := by
grind =>
have : a*b > 0 := Nat.mul_pos h h_1
lia
```
This PR adds lemmas `forall_fin_zero` and `exists_fin_zero`. It also
marks lemmas `forall_fin_zero`, `forall_fin_one`, `forall_fin_two`,
`exists_fin_zero`, `exists_fin_one`, `exists_fin_two` with `simp`
attribute.
Closes#10629
This PR introduces a `coinductive` keyword, that can be used to define
coinductive predicates via a syntax identical to the one for `inductive`
keyword. The machinery relies on the implementation of elaboration of
inductive types and extracts an endomap on the appropriate space of the
predicates from the definition that is then fed to the
`PartialFixpoint`. Upon elaborating definitions, all the constructors
are declared through automatically generated lemmas.
For example, infinite sequence of transitions in a relation, can be
given by the following:
```lean4
section
variable (α : Type)
coinductive infSeq (r : α → α → Prop) : α → Prop where
| step : r a b → infSeq r b → infSeq r a
/--
info: infSeq.coinduct (α : Type) (r : α → α → Prop) (pred : α → Prop) (hyp : ∀ (x : α), pred x → ∃ b, r x b ∧ pred b)
(x✝ : α) : pred x✝ → infSeq α r x✝
-/
#guard_msgs in
#check infSeq.coinduct
/--
info: infSeq.step (α : Type) (r : α → α → Prop) {a b : α} : r a b → infSeq α r b → infSeq α r a
-/
#guard_msgs in
#check infSeq.step
end
```
The machinery also supports `mutual` blocks, as well as mixing inductive
and coinductive predicate definitions:
```lean4
mutual
coinductive tick : Prop where
| mk : ¬tock → tick
inductive tock : Prop where
| mk : ¬tick → tock
end
/--
info: tick.mutual_induct (pred_1 pred_2 : Prop) (hyp_1 : pred_1 → pred_2 → False) (hyp_2 : (pred_1 → False) → pred_2) :
(pred_1 → tick) ∧ (tock → pred_2)
-/
#guard_msgs in
#check tick.mutual_induct
```
---------
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
This PR renames `Nat.and_distrib_right` to `Nat.and_or_distrib_right`.
This is to make the name consistent with other theorems in the same file
(e.g. `Nat.and_or_distrib_left`).
This PR changes how Lean proves the equational theorems for structural
recursion. The core idea is to let-bind the `f` argument to `brecOn` and
rewriting `.brecOn` with an unfolding theorem. This means no extra case
split for the `.rec` in `.brecOn` is needed, and `simp` doesn't change
the `f` argument which can break the definitional equality with the
defined function. With this, we can prove the unfolding theorem first,
and derive the equational theorems from that, like for all other ways of
defining recursive functions.
Backs out the changes from #10415, the old strategy works well with the
new goals.
Fixes#5667Fixes#10431Fixes#10195Fixes#2962
This PR fixes a broken link to the firefox profile definitions in one of
the comments.
The `profile.js` file was renamed to `profile.ts` while the rest of the
url remained the same.
This PR adds the StreamMap type that enables multiplexing in
asynchronous streams.
This PR depends on: #10366, #10367 and #10370.
---------
Co-authored-by: Markus Himmel <markus@lean-fro.org>
This PR fixes an oversight in the RC insertion phase in the code
generator.
If the code generator encounters a `let` that is unused (which is
perfectly reasonable as at this
phase we are in an impure IR and as such allow for side effects to
happen so we cannot remove all
unused `let`) it didn't insert a `dec` instruction for this variable.
This has previously gone
unnoticed because at this point in the compiler basically all unused
lets are removed already
anyways. However with the `IO`/`ST` token erasure coming up they will be
very frequent.
This PR renames some declarations in the range API for better
consistency and readability. For example,
`UpwardEnumerable.succMany?_succ?` is now called `succMany?_add_one`, in
order to (a) correct the erroneous use of `succ?` instead of `succ`
(=`Nat.succ`) and (b) distinguish the successor of natural numbers
(`add_one`) from the successor of the upward-enumerable type (`succ?` or
`succ`).
This PR adds the `IO.FS.hardLink` function, which can be used to create
hard links.
This is implemented via libuv's `uv_fs_link` function.
Lake hopes to make use of this function to decrease the storage cost of
restoring artifacts.
This PR also fixes some C implementation issues found in nearby similar
functions.
This PR adds a multi-consumer, multi-producer channel to Std.Sync.
This PR depends on: #10366, #10367 and #10370.
---------
Co-authored-by: Markus Himmel <markus@lean-fro.org>
This PR implements the basic tactics for the new `grind` interactive
mode. While many additional `grind` tactics will be added later, the
foundational framework is already operational. The following `grind`
tactics are currently implemented: `skip`, `done`, `finish`, `lia`, and
`ring`.
This PR also removes the notion of `grind` fallback procedure since it
is subsumed by the new framework. Examples:
```lean
example (x y : Nat) : x ≥ y + 1 → x > 0 := by
grind => skip; lia; done
open Lean Grind
example [CommRing α] (a b c : α)
: a + b + c = 3 →
a^2 + b^2 + c^2 = 5 →
a^3 + b^3 + c^3 = 7 →
a^4 + b^4 + c^4 = 9 := by
grind => ring
```
This PR records extra mod uses that previously caused wrong unnecessary
import reports from shake.
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR fixes one potential source of inlay hint flakiness.
In the old `IO.waitAny` implementation, we could rely on the fact that
if all tasks in the list were finished, `IO.waitAny` would pick the
first finished one. In the new implementation (#9732), this isn't the
case anymore for fairness reasons, but this also means that in
`IO.AsyncList.getFinishedPrefixWithTimeout`, it can happen that we don't
scan the full finished command snapshot prefix because we pick the
timeout task before the finished snapshot task. This is likely the cause
of a flaky test failure
[here](https://github.com/leanprover/lean4/actions/runs/18215430028/job/51863870111),
where the inlay hint test yielded no result (the timeout task has an
edit delay of 0ms in the first inlay hint request that is emitted,
finishes immediately and can thus immediately cause the finished prefix
to be skipped with the new `waitAny` implementation).
This PR fixes this issue by adding a `hasFinished` check before the
`waitAny` to ensure that we always scan the finished prefix and don't
need to rely on a brittle invariant that doesn't hold anymore. It also
converts some `Task.get`s to `IO.wait` for safety so that the compiler
can't re-order them.
This PR disables `{name}` suggestions for `.anonymous` and adds syntax
suggestions.
When the provided name can't be resolved, the `{name}` role suggests
fully-qualified variants. But if the name is a syntax error, it
attempted to suggest names that had `.anonymous` as a suffix; the
resulting list of suggestions of all names in Lean's environment
overloaded the language server.
This PR "monomorphizes" the structure `Std.PRange shape α`, replacing it
with nine distinct structures `Std.Rcc`, `Std.Rco`, `Std.Rci` etc., one
for each possible shape of a range's bounds. This change was necessary
because the shape polymorphism is detrimental to attempts of automation.
**BREAKING CHANGE:** While range/slice notation itself is unchanged,
this essentially breaks the entire remaining (polymorphic) range and
slice API except for the dot-notation(`toList`, `iter`, ...). It is not
possible to deprecate old declarations that were formulated in a
shape-polymorphic way that is not available anymore.
This PR explicitly tries to synthesize synthetic MVars in `mspec`. Doing
so resolves a bug triggered by use of the loop invariant lemma for
`Std.PRange`.
This PR exposes the definitions about `Int*`. The main reason is that
the `SInt` simprocs require many of them to be exposed. Furthermore,
`decide` now works with `Int*` operations. This fixes#10631.
This PR defines `ByteArray.validateUTF8`, uses it to show that
`ByteArray.IsValidUtf8` is decidable and redefines `String.fromUTF8` and
friends to use it.
The functions `String.validateUTF8` and `String.utf8DecodeChar?` are
deprecated in favor of the identically named functions in the
`ByteArray` namespace.
This PR reduces the aggressiveness of the dead let eliminator from
lambda RC.
The motivation for this is that all other passes in lambda RC respect
impurity but the dead let eliminator still operates under the assumption
of purity. There is a couple of motivations for the elim dead let
elaborator:
- unused projections introduced by the ToIR translation
- the elim dead branch pass introducing new opportunities
- closed term extraction introducing new opportunities
This PR significantly improves the test coverage of the language server,
providing at least a single basic test for every request that is used by
the client. It also implements infrastructure for testing all of these
requests, e.g. the ability to run interactive tests in a project context
and refactors the interactive test runner to be more maintainable.
Finally, it also fixes a small bug with the recently implemented unknown
identifier code actions for auto-implicits (#10442) that was discovered
in testing, where the "import all unambiguous unknown identifiers" code
action didn't work correctly on auto-implicit identifiers.
This PR alters the Lake directory detection so that the core build
(i.e., `bootstrap = true`) is stored in the user cache directory (if
available) and never in a toolchain-specific directory.
It is also fixes some issues with cache environment configuration
discovered along the way.
This PR switches the core build Lake configuration file to use
`libPrefixOnWindows` rather than a CMake hack.
It also removes some dead TOML variables from the CMake configuration.
This PR cuts some edges from the import graph.
Specifically:
- `TreeMap` and `HashMap` no longer depend on `String`, so now the
expensive things are all in parallel instead of partially in sequence
- `Omega` no longer relies on `List` lemmas
- The section of the import graph between `Init.Omega` and
`Init.Data.Bitvec.Lemmas` is cleaned up a bit
This PR fixes a bug in the unknown identifier code actions where it
would yield non-sensical suggestions for nested `open` declarations like
`open Foo.Bar`.
This PR removes superfluous `Monad` instances from the spec lemmas of
the `MonadExceptOf` lifting framework.
It also adds a bit of documentation and more tracing to `mvcgen`.
Fixes#10564.
This PR ensures that even if a type is marked as `irreducible` the
compiler can see through it in
order to discover functions hidden behind type aliases.
This PR fixes a bad error message due to elaborating partial syntax with
Verso docstrings.
When elaborating partial syntax, the elaborator sometimes attempts to
add a docstring for a declaration that it didn't parse a name for. The
name defaults to anonymous, but inserting the docs for the anonymous
name throws a panic about being on the wrong async branch.
With this change, the reported error is the expected parser error
instead, which is much friendlier.
This PR adds infrastructure for the upcoming `grind` tactic mode, which
will be similar to the `conv` mode. The goal is to extend `grind` from a
terminal tactic into an interactive mode: `grind => …`.
It will serve as the foundation for `ungrind`, the process of converting
an expensive (and potentially fragile) `grind` proof into a robust
script. This mode will include tactics for expensive reasoning steps
such as cutsat model-based search, Gröbner basis computation,
E-matching, case splits, and more.
It will also provide robust, succinct references to facts and terms:
labels, structural matches, and anchors (e.g., `#abcd`).
This PR adds the necessary infrastructure for recording elaboration
dependencies that may not be apparent from the resulting environment
such as notations and other metaprograms. An adapted version of `shake`
from Mathlib is added to `script/` but may be moved to another location
or repo in the future.
This PR implements support for negative constraints in `grind order`.
Examples:
```lean
open Lean Grind
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α]
(a b c d : α) : a ≤ b → ¬ (c ≤ b) → ¬ (d ≤ c) → d < a → False := by
grind -linarith (splits := 0)
example [LE α] [Std.IsLinearPreorder α]
(a b c d : α) : a ≤ b → ¬ (c ≤ b) → ¬ (d ≤ c) → ¬ (a ≤ d) → False := by
grind -linarith (splits := 0)
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearPreorder α] [CommRing α] [OrderedRing α]
(a b c d : α) : a - b ≤ 5 → ¬ (c ≤ b) → ¬ (d ≤ c + 2) → d ≤ a - 8 → False := by
grind -linarith (splits := 0)
```
This PR implements support for positive constraints in `grind order`.
The new module can already solve problems such as:
```lean
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α]
(a b c : α) : a ≤ b → b ≤ c → c < a → False := by
grind
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α]
(a b c d : α) : a ≤ b → b ≤ c → c < d → d ≤ a → False := by
grind
example [LE α] [Std.IsPreorder α]
(a b c : α) : a ≤ b → b ≤ c → a ≤ c := by
grind
example [LE α] [Std.IsPreorder α]
(a b c d : α) : a ≤ b → b ≤ c → c ≤ d → a ≤ d := by
grind
```
It also generalizes support for offset constraints in `grind` to rings.
The new module implements theory propagation and reduces the number of
case splits required to solve problems:
```lean
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b : α) : a ≤ 5 → b ≤ 8 → a > 6 ∨ b > 10 → False := by
grind -linarith (splits := 0)
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [CommRing α] [OrderedRing α]
(a b c : α) : a + b*c + 2*c ≤ 5 → a + c > 5 - c - c*b → False := by
grind -linarith (splits := 0)
example (a b : Int) (h : a + b > 5) : (if a + b ≤ 0 then b else a) = a := by
grind -linarith -cutsat (splits := 0)
```
We still need to implement support for negated constraints.
This PR implements the function for adding new edges to the graph used
by `grind order`. The graph maintains the transitive closure of all
asserted constraints.
This PR ensures that Lake only receives recognized CMake build types
from CMake. This fixes an issue with #10581 which broke the
`RelWithAssert` build.
This PR makes Lake no longer error if build outputs found in a trace
file (or in the artifact cache) are ill-formed.
This is caused a problem with the CI cache and is just generally too
strict.
This PR alters `libPrefixOnWindows` behavior to add the `lib` prefix to
the library's `libName` rather than just the file path. This means that
Lake's `-l` will now have the prefix on Windows. While this should not
matter to a MSYS2 build (which accepts both `lib`-prefixed and
unprefixed variants), it should ensure compatibility with MSVC (if that
is ever an issue).
This PR invalidates the CI cache for the Linux Lake build job by bumping
the version of the CI cache key.
The CI cache is broken due to a change in the output format in build
traces. This will be fixed in #10586, but this should prevent further
breakages of PRs in the meantime.
This PR adds a new package configuration option: `restoreAllArtifacts`.
When set to `true` and the Lake local artifact cache is enabled, Lake
will copy all cached artifacts into the build directory. This ensures
they are available for external consumers who expect build results to be
in the build directory.
This PR enables Reservoir packages to be required as dependencies at a
specific package version (i.e., the `version` specified in the package's
configuration file).
This file is essentially just for me and can cause problems with the
language server, so I have removed it from the committed code (and left
an ignored version on my own setup).
* Wrap proof subterms in `by exact` so dependencies can be demoted to
private `import`s
* Remove trivial instance re-definitions that may cause name collisions
on import changes
* Remove unused `open`s that may fail on import removals
This PR ensures that `SPred` proof mode tactics such as `mspec`,
`mintro`, etc. immediately replace the main goal when entering the proof
mode. This prevents `No goals to be solved` errors.
This PR ensures private declarations are accessible from the private
scope iff they are local or imported through an `import all` chain,
including for anonymous notation and structure instance notation.
This PR adds support for case label like syntax in `mvcgen invariants`
in order to refer to inaccessible names. Example:
```lean
def copy (l : List Nat) : Id (Array Nat) := do
let mut acc := #[]
for x in l do
acc := acc.push x
return acc
theorem copy_labelled_invariants (l : List Nat) : ⦃⌜True⌝⦄ copy l ⦃⇓ r => ⌜r = l.toArray⌝⦄ := by
mvcgen [copy] invariants
| inv1 acc => ⇓ ⟨xs, letMuts⟩ => ⌜acc = l.toArray⌝
with admit
```
This PR improves `mvcgen invariants?` to suggest concrete invariants
based on how invariants are used in VCs.
These suggestions are intentionally simplistic and boil down to "this
holds at the start of the loop and this must hold at the end of the
loop":
```lean
def mySum (l : List Nat) : Nat := Id.run do
let mut acc := 0
for x in l do
acc := acc + x
return acc
/--
info: Try this:
invariants
· ⇓⟨xs, letMuts⟩ => ⌜xs.prefix = [] ∧ letMuts = 0 ∨ xs.suffix = [] ∧ letMuts = l.sum⌝
-/
#guard_msgs (info) in
theorem mySum_suggest_invariant (l : List Nat) : mySum l = l.sum := by
generalize h : mySum l = r
apply Id.of_wp_run_eq h
mvcgen invariants?
all_goals admit
```
It still is the user's job to weaken this invariant such that it
interpolates over all loop iterations, but it *is* a good starting point
for iterating. It is also useful because the user does not need to
remember the exact syntax.
This PR simplifies the `grind order` module, and internalizes the order
constraints. It removes the `Offset` type class because it introduced
too much complexity. We now cover the same use cases with a simpler
approach:
- Any type that implements at least `Std.IsPreorder`
- Arbitrary ordered rings.
- `Nat` by the `Nat.ToInt` adapter.
This PR refactors the Lake log monads to take a `LogConfig` structure
when run (rather than multiple arguments). This breaking change should
help minimize future breakages due to changes in configurations options.
In addition, the CLI logging monad stack has been polished up and
`LogIO` now supports the `failLv` configuration option.
This PR adds support for remote artifact caches (e.g., Reservoir) to
Lake. As part of this support, a new suite of `lake cache` CLI commands
has been introduced to help manage Lake's cache. Also, the existing
local cache support has been overhauled for better interplay with the
new remote support.
**Cache CLI**
Artifacts are uploaded to a remote cache via `lake cache put`. This
command takes a JSON Lines input-to-outputs file which describes the
output artifacts for a build (indexed by its input hash). This file can
be produced by a run of `lake build` with the new `-o` option. Lake will
write the input-to-outputs mappings of thee root package artifacts
traversed by the build to the file specified via `-o`. This file can
then be passed to `lake cache put` to upload both it and the built
artifacts from the local cache to the remote cache.
The remote cache service can be customized using the following
environment variables:
* `LAKE_CACHE_KEY`: This is the authorization key for the remote cache.
Lake uploads artifacts via `curl` using the AWS Signature Version 4
protocol, so this should be the S3 `<key>:<secret>` pair expected by
`curl`.
* `LAKE_CACHE_ARTIFACT_ENDPOINT`: This is the base URL to upload (or
download) artifacts to a given remote cache. Artifacts will be stored at
`<endpoint>/<scope/<content-hash>.art`.
* `LAKE_CACHE_REVISION_ENDPOINT`: This is the base URL to upload (or
download) input-to-output mappings to a given remote cache. Mappings are
indexed by the Git revision of the package, and are stored at
`<endpoint>/<scope/<rev>.jsonl`.
The `<scope>` is provided through the `--scope` option to `lake cache
put`. This option is used to prevent one package from overwriting the
artifacts/mappings of another. Lake artifact hashes and Git revisions
hashes are not cryptographically secure, so it is not safe for a service
to store untrusted files across packages in a single flat store.
Once artifacts are available in a remote cache, the `lake cache get`
command can be used to retrieve them. By default, it will fetch
artifacts for the root package's dependencies from Reservoir using its
API. But, like `cache put`, it can be configured to use a custom
endpoint with the above environment variables and an explicit `--scope`.
When so configured, `cache get` will instead download artifacts for the
root package. Lake only downloads artifacts for a single package in this
case, because it cannot deduce the necessary package scopes without
Reservoir.
**Significant local cache changes**
* Lake now always has a cache directory. If Lake cannot find a good
candidate directory on the system for the cache, it will instead store
the cache at `.lake/cache` within the workspace.
* If the local cache is disabled, Lake will not save built artifacts to
the cache. However, Lake will, nonetheless, always attempt to lookup
build artifacts in the cache. If found, the cached artifact will be
copied to the the build location ("restored").
* Input-to-outputs mappings in the local cache are no longer stored in a
single file for a package, but rather in individual files per input (in
the `outputs` subdirectory of the cache).
* Outputs in a trace file, outputs file, or mappings file are now an
`ArtifactDescr`, which is currently composed of both the content hash
and the file extension.
* Trace files now contain a date-based `schemaVersion` to help make
version to version migration easier. Hashes in JSON and in artifacts
names now use a 16-digit hexadecimal encoding (instead of a variable
decimal encoding).
* `buildArtifactUnlessUpToDate` now returns an `Artifact` instead of a
`FilePath`.
**NOTE:** The Lake local cache is still disabled by default. This means
that built artifacts, by default, will not be placed in the cache
directory, and thus will not be available for `lake cache put` to
upload. Users must first explicitly enable the cache by either setting
the `LAKE_ARTIFACT_CACHE` environment variable to a truthy value or by
setting the `enableArtifactCache` package configuration option to
`true`.
This PR changes the way that scientific numerals are parsed in order to
give better error messages for (invalid) syntax like `32.succ`.
Example:
```lean4
#check 32.succ
```
Before, the error message is:
```
unexpected identifier; expected command
```
This is because `32.` parses as a complete float, and `#check 32.`
parses as a complete command, so `succ` is being read as the start of a
new command.
With this change, the error message will move from the `succ` token to
the `32` token (which isn't totally ideal from my perspective) but gives
a less misleading error message and corresponding suggestion:
```
unexpected identifier after decimal point; consider parenthesizing the number
```
This PR refactors Lake's package naming procedure to allow packages to
be renamed by the consumer. With this, users can now require a package
using a different name than the one it was defined with.
This is support will be used in the future to enable seamlessly
including the same package at multiple different versions within the
same workspace.
In a Lake package configuration file written in Lean, the current
package's assigned name is now accessed through `__name__` instead of
the previous `_package.name`. A deprecation warning has been added to
`_package.name` to assist in migration.
This PR adds a `.` in front of `pass` in the `#guard_msgs`
implementation.
Previously, the match arm read `| pass => ...`. Presumably, `pass` was
intended to mean `SpecResult.pass`, but, this isn't in scope, so instead
`pass` here is a catch-all variable. By adding a dot, we ensure we
actually refer to the constant. Note that this was the last case in the
pattern-match, and since all other constructors were correctly
referenced, the only case that went to the fallback was
`SpecResult.pass`, so the code did the right thing. Still, by fixing
this, we prevent a surprise in the event that a new `SpecResult`
constructor is added.
This PR ensures that `Substring.beq` is reflexive, and in particular
satisfies the equivalence `ss1 == ss2 <-> ss1.toString = ss2.toString`.
Closes#10511.
Note: I also fixed a strange line in the `String.extract` documentation
which looks like it may have been a copypasta, and added another example
to show how invalid UTF8 positions work, but the doc also makes a point
of saying that it is unspecified so maybe it would be better not to have
the example? 🤷
This PR fixes deadlocking `exit` calls in the language server.
We have previously observed deadlocking calls to `exit` inside of the
language server and deemed them irrelevant. However, child processes of
these deadlocking exiting processes can continue to consume a large
amount of CPU as they try to compile a library etc. Hence, this PR
switches to the MT safe `_Exit` inside of the language server,
in order to ensure the server finishes when it is told to.
This PR introduces safe alternatives to `String.Pos` and `Substring`
that can only represent valid positions/slices.
Specifically, the PR
- introduces the predicate `String.Pos.IsValid`;
- proves several nontrivial equivalent conditions for
`String.Pos.IsValid`;
- introduces `String.ValidPos`, which is a `String.Pos` with an
`IsValid` proof;
- introduces `String.Slice`, which is like `Substring` but made from
`String.ValidPos` instead of `Pos`;
- introduces `String.Pos.IsValidForSlice`, which is like
`String.Pos.IsValid` but for slices;
- introduces `String.Slice.Pos`, which is like `String.ValidPos` but for
slices;
- introduces various functions for converting between the two types of
positions.
The API added in this PR is not complete. It will be expanded in future
PRs with addional operations and verification.
This PR prevents some nonsensical code from crashing the server.
Specifically, the kernel is changed to
- properly check that passed expressions do not contain loose bvars,
which could lead to a segmentation fault on a well-crafted input
(discovered through fuzzing), and
- check that constants generated when creating a new inductive type do
not overwrite each other, which could lead to the kernel taking
something out of the environment and then casting it to something it
isn't.
Partially addresses #8258, but let's keep that one open until the error
message is a little better.
Fixes#10492.
This PR disables `trace.profiler` in `bench/riskv-ast.lean`. We don't
want to optimize the trace profiler, but normal code.
While at it, I removed the `#exit` to cover more of the file.
While at it, also import the latest from from upstream.
This PR allows `.congr_simp` theorems to be created not just for
definitoins, but any constant. This is important to make the machinery
work across module boundaries.
It also moves the `enableRealizationsForConst` for constructors to a
more sensible
place, and enables it for axioms.
This PR adds some helper functions for the premise selection API, to
assist implementers.
---------
Co-authored-by: Thomas Zhu <thomas.zhu.sh@hotmail.com>
This PR introduces a simple script that adjusts module headers in a
package for use of the module system, without further minimizing import
or annotation use.
---------
Co-authored-by: Kim Morrison <477956+kim-em@users.noreply.github.com>
This PR fixes `simp` in `-zeta -zetaUnused` mode from producing
incorrect proofs if in a `have` telescope a variable occurrs in the
type of the body only transitively. Fixes#10353.
This PR adds a docstring role for module names, called `module`. It also
improves the suggestions provided for code elements, making them more
relevant and proposing `lit`.
This PR modifies the "issues" grind diagnostics prints. Previously we
would just describe synthesis failures. These messages were confusing to
users, as in fact the linarith module continues to work, but less
capably. For most of the issues, we now explain the resulting change in
behaviour. There is a still a TODO to explain the change when
`IsOrderedRing` is not available.
This PR adds `Notify` that is a structure that is similar to `CondVar`
but it's used for concurrency. The main difference between
`Std.Sync.Notify` and `Std.Condvar` is that depends on a `Std.Mutex` and
blocks the entire thread that the `Task` is using while waiting. If I
try to use it with async and a lot of `Task`s like this:
```lean
def condvar : Async Unit := do
let condvar ← Std.Condvar.new
let mutex ← Std.Mutex.new false
for i in [0:threads] do
background do
IO.println s!"start {i + 1}"
await =<< (show IO (ETask _ _) from IO.asTask (mutex.atomically (condvar.wait mutex)))
IO.println s!"end {i + 1}"
IO.sleep 2000
condvar.notifyAll
```
It causes some weird behavior because some tasks start running and get
notified, while others don’t, because `condvar.wait` blocks the `Task`
entire task and right now afaik it blocks an entire thread and cannot be
paused while doing blocking operations like that.
`Notify` uses `Promise`s so it’s better suited for concurrency. The
`Task` is not blocked while waiting for a notification which makes it
simpler for use cases that just involve notifying:
```lean
def notify : Async Unit := do
let notify ← Std.Notify.new
for i in [0:threads] do
background do
IO.println s!"start {i}"
notify.wait
IO.println s!"end {i}"
IO.sleep 2000
notify.notify
```
This PR depends on: #10366, #10367 and #10370.
This PR removes some `grind` annotations for `Array.attach` and related
functions. These lemmas introduce lambda on the right hand side which
`grind` can't do much with. I've added a test file that verifies that
the theorems with removed annotations can actually be proved already by
grind. Removing the annotations will help with excessive instantiation.
The radar bench scripts at
https://github.com/leanprover/radar-bench-lean4/ split up the benchmarks
between the two runners based on the tags: One runner filters by the tag
`stdlib` while the other filters by the tag `other`. Only benchmarks
using one of these tags will be run, and any benchmark tagged with both
will waste electricity.
As far as I know, the tags are unused otherwise, so I just replaced all
the old tags.
This also exposed an issue with `#guard_msgs` in Verso mode where the
docstring would log parse errors as if it contained Verso, even though
it actually worked. This has been fixed, and error messages improved as
well.
Hi, the doc of `String.fromUTF8` previously said invalid characters are
replaced with 'A'. But the parameter `h : validateUTF8 a` guarantees
there are no invalid characters, so that explanation doesn't make sense
to me. This PR deletes that explanation (and fixes some unrelated
typos).
I also have a patch that uses `h` to prove each of the characters is
valid, eliminating the need for a default character
([pr/chore-String-fromUTF8-prove-valid](27f1ff36b2)),
would you be interested in merging that?
<details>
<summary>Notes on invalid characters from unchecked C++</summary>
I don't know if this function may be called from unchecked C++ with
invalid characters. If it may, I'm not sure what would happen with my
patched function... I'm not familiar with Lean's safety model, but it
seems like a bad idea to have a Lean function that takes a proof of a
proposition but is expected to operate in a certain way even if the
proposition is false. I think the safe approach is to have two functions
-- one that takes a proof and is only called from Lean, and another that
doesn't take a proof and replaces invalid chars (for use from C++, not
sure whether it's useful from Lean); I'd prefer to go even further and
report an error instead of silently replacing invalid characters (I'm
not sure if there is any easy way to report errors/panic in Lean code
called from C++).
</details>
This PR resolves a potential bad interaction between the compiler and
the module system where references to declarations not imported are
brought into scope by inlining or specializing. We now proactively check
that declarations to be inlined/specialized only reference public
imports. The intention is to later resolve this limitation by moving out
compilation into a separate build step with its own import/incremental
system.
This PR annotates the shadowing main definitions of `bv_decide`,
`mvcgen` and similar tactics in `Std` with the semantically richer
`tactic_alt` attribute so that `verso` will not warn about overloads.
This fixesleanprover/verso#535.
This PR adds a simple implementation of MePo, from "Lightweight
relevance filtering for machine-generated resolution problems" by Meng
and Paulson.
This needs tuning, but is already useful as a baseline or test case.
---------
Co-authored-by: Thomas Zhu <thomas.zhu.sh@hotmail.com>
This PR fixes constant folding for UIntX in the code generator. This
optimization was previously simply dead code due to the way that uint
literals are encoded.
This PR implements module docstrings in Verso syntax, as well as adding
a number of improvements and fixes to Verso docstrings in general. In
particular, they now have language server support and are parsed at
parse time rather than elaboration time, so the snapshot's syntax tree
includes the parsed documentation.
This PR adds vectored write for TCP and UDP (that helps a lot with not
copying the arrays over and over) and fix a RC issue in TCP and UDP
cancel functions with the line `lean_dec((lean_object*)udp_socket);` and
a similar one that tries to decrement the object inside of the `socket`.
This PR adds a code action for `grind` parameters. We need to use
`set_option grind.param.codeAction true` to enable the option. The PR
also adds a modifier to instruct `grind` to use the "default" pattern
inference strategy.
This PR reduces noise in the 'Equivalence classes' section of the
`grind` diagnostics. It now uses a notion of *support expressions*.
Right now, it is hard-coded, but we will probably make it extensible in
the future. The current definition is
- `match`, `ite` and `dite`-applications. They have builtin support in
`grind`.
- Cast-like applications used by `grind`: `toQ`, `toInt`, `Nat.cast`,
`Int.cast`, and `cast`
- `grind` gadget applications (e.g., `Grind.nestedDecidable`)
- Projections of constructors (e.g., `{ x := 1, y := 2}.x`)
- Auxiliary arithmetic terms constructed by solvers such as `cutsat` and
`ring`.
If an equivalence class contains at most one non-support term, it goes
into the “others” bucket. Otherwise, we display the non-support elements
and place the support terms in a child node.
**BEFORE**:
<img width="1397" height="1558" alt="image"
src="https://github.com/user-attachments/assets/4fd4de31-7300-4158-908b-247024381243"
/>
**AFTER**:
<img width="840" height="340" alt="image"
src="https://github.com/user-attachments/assets/05020f34-4ade-49bf-8ccc-9eb0ba53c861"
/>
**Remark**: No information is lost; it is just grouped differently."
This PR adds an alternative implementation of `Deriving Ord` based on
comparing `.ctorIdx` and using a dedicated matcher for comparing same
constructors (added in #10152). The new option
`deriving.ord.linear_construction_threshold` sets the constructor count
threshold (10 by default) for using the new construction.
It also (unconditionally) changes the implementation for enumeration
types to simply compare the `ctorIdx`.
This PR implements `mvcgen invariants?` for providing initial invariant
skeletons for the user to flesh out. When the loop body has an early
return, it will helpfully suggest `Invariant.withEarlyReturn ...` as a
skeleton.
```lean
def mySum (l : List Nat) : Nat := Id.run do
let mut acc := 0
for x in l do
acc := acc + x
return acc
/--
info: Try this:
invariants
· ⇓⟨xs, acc⟩ => _
-/
#guard_msgs (info) in
theorem mySum_suggest_invariant (l : List Nat) : mySum l = l.sum := by
generalize h : mySum l = r
apply Id.of_wp_run_eq h
mvcgen invariants?
all_goals admit
def nodup (l : List Int) : Bool := Id.run do
let mut seen : HashSet Int := ∅
for x in l do
if x ∈ seen then
return false
seen := seen.insert x
return true
/--
info: Try this:
invariants
· Invariant.withEarlyReturn (onReturn := fun r acc => _) (onContinue := fun xs acc => _)
-/
#guard_msgs (info) in
theorem nodup_suggest_invariant (l : List Int) : nodup l ↔ l.Nodup := by
generalize h : nodup l = r
apply Id.of_wp_run_eq h
mvcgen invariants?
all_goals admit
```
This PR fixes a potential miscompilation when using non-exposed type
definitions using the module system by turning it into a static error. A
future revision may lift the restriction by making the compiler metadata
independent of the current module.
This PR makes `mvcgen` reduce through `let`s, so that it progresses over
`(have t := 42; fun _ => foo t) 23` by reduction to `have t := 42; foo
t` and then introducing `t`.
This PR ensures that issues reported by the E-matching module are
displayed only when `set_option grind.debug true` is enabled. Users
reported that these messages are too distracting and not very useful.
They are more valuable for library developers when annotating their
libraries.
This PR adds an alternative implementation of `DerivingBEq` based on
comparing `.ctorIdx` and using a dedicated matcher for comparing same
constructors (added in #10152), to avoid the quadratic overhead of the
default match implementation. The new option
`deriving.beq.linear_construction_threshold` sets the constructor count
threshold (10 by default) for using the new construction. Such instances
also allow `deriving ReflBEq, LawfulBeq`, although these proofs for
these properties are still quadratic.
This PR adds the `reduceCtorIdx` simproc which recognizes and reduces
`ctorIdx` applications. This is not on by default yet because it does
not use the discrimination tree (yet).
This PR redefines `String` to be the type of byte arrays `b` for which
`b.IsValidUtf8`.
This moves the data model of strings much closer to the actual data
representation at runtime.
In the near future, we will
- provide variants of `String.Pos` and `Substring` that only allow for
valid positions
- redefine all `String` functions to be much closer to their C++
implementations
In the near-to-medium future we will then provide comprehensive
verification of `String` based on these refactors.
This PR adds support the Count Trailing Zeros operation `BitVec.ctz` to
the bitvector library and to `bv_decide`, relying on the existing `clz`
circuit. We also build some theory around `BitVec.ctz` (analogous to the
theory existing for `BitVec.clz`) and introduce lemmas
`BitVec.[ctz_eq_reverse_clz, clz_eq_reverse_ctz, ctz_lt_iff_ne_zero,
getLsbD_false_of_lt_ctz, getLsbD_true_ctz_of_ne_zero,
two_pow_ctz_le_toNat_of_ne_zero, reverse_reverse_eq,
reverse_eq_zero_iff]`.
`ctz` operation is common in numerous compiler intrinsics (see
[here](https://clang.llvm.org/docs/LanguageExtensions.html#intrinsics-support-within-constant-expressions))
and architectures (see
[here](https://en.wikipedia.org/wiki/Find_first_set)).
---------
Co-authored-by: Siddharth <siddu.druid@gmail.com>
This PR adds `reprove N by T`, which effectively elaborates `example
type_of% N := by T`. It supports multiple identifiers. This is useful
for testing tactics.
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
This PR enables the new E-matching pattern inference heuristic for
`grind`, implemented in PR #10422.
**Important**: Users can still use the old pattern inference heuristic
by setting:
```lean
set_option backward.grind.inferPattern true
```
In PR #10422, we introduced the new modifier `@[grind!]` for enabling
the minimal indexable subexpression condition. This option can now also
be set in `grind` parameters. Example:
```lean
opaque f : Nat → Nat
opaque fInv : Nat → Nat
axiom fInv_f : fInv (f x) = x
/-- trace: [grind.ematch.pattern] fInv_f: [f #0] -/
#guard_msgs in
set_option trace.grind.ematch.pattern true in
example {x y} : f x = f y → x = y := by
/-
The modifier `!` instructs `grind` to use the minimal indexable subexpression
(i.e., `f x` in this case).
-/
grind [!fInv_f]
```
This PR refines and clarifies the `meta` phase distinction in the module
system.
* `meta import A` without `public` now has the clarified meaning of
"enable compile-time evaluation of declarations in or above `A` in the
current module, but not downstream". This is now checked statically by
enforcing that public meta defs, which therefore may be referenced from
outside, can only use public meta imports, and that global evaluating
attributes such as `@[term_parser]` can only be applied to public meta
defs.
* `meta def`s may no longer reference non-meta defs even when in the
same module. This clarifies the meta distinction as well as improves
locality of (new) error messages.
* parser references in `syntax` are now also properly tracked as meta
references.
* A `meta import` of an `import` now properly loads only the `.ir` of
the nested module for the purposes of execution instead of also making
its declarations available for general elaboration.
* `initialize` is now no longer being run on import under the module
system, which is now covered by `meta initialize`.
This PR ensures users can select the "minimal indexable subexpression"
condition in `grind` parameters. Example, they can now write `grind [!
-> thmName]`. `grind?` will include the `!` modifier whenever users had
used `@[grind!]`. This PR also fixes a missing case in the new pattern
inference procedure.
It also adjusts some `grind` annotations and tests in preparation for
setting the new pattern inference heuristic as the new default.
This PR changes the order of steps tried when proving equational
theorems for structural recursion. In order to avoid goals that `split`
cannot handle, avoid unfolding the LHS of the equation to `.brecOn` and
`.rec` until after the RHS has been split into its final cases.
Fixes: #10195
This PR lets the `split` tactic generalize discriminants that are not
free variables and proofs using `generalize`. If the only
non-fvar-discriminants are proofs, then this avoids the more elaborate
generalization strategy of `split`, which can fail with dependent
motives, thus mitigating issue #10424.
This PR changes the defeq algorithm to perform `whnf` on the `String.mk`
expression it creates for string literals.
This is currently a no-op, but will no longer be one once `String` is
redefined so that `String.mk` is a regular function instead of a
constructor.
This PR implements the new E-matching pattern inference heuristic for
`grind`. It is not enabled yet. You can activate the new behavior using
`set_option backward.grind.inferPattern false`. Here is a summary of the
new behavior.
* `[grind =]`, `[grind =_]`, `[grind _=_]`, `[grind <-=]`: no changes;
we keep the current behavior.
* `[grind ->]`, `[grind <-]`, `[grind =>]`, `[grind <=]`: we stop using
the *minimal indexable subexpression* and instead use the first
indexable one.
* `[grind! <mod>]`: behaves like `[grind <mod>]` but uses the minimal
indexable subexpression restriction. We generate an error if the user
writes `[grind! =]`, `[grind! =_]`, `[grind! _=_]`, or `[grind! <-=]`,
since there is no pattern search in these cases.
* `[grind]`: it tries `=`, `=_`, `<-`, `->`, `<=`, `=>` with and without
the minimal indexable subexpression restriction. For the ones that work,
we generate a code action to encourage users to select the one they
prefer.
* `[grind!]`: it tries `<-`, `->`, `<=`, `=>` using the minimal
indexable subexpression restriction. For the ones that work, we generate
a code action to encourage users to select the one they prefer.
* `[grind? <mod>]`: where `<mod>` is one of the modifiers above, it
behaves like `[grind <mod>]` but also displays the pattern.
Example:
```lean
/--
info: Try these:
• [grind =] for pattern: [f (g #0)]
• [grind =_] for pattern: [r #0#0]
• [grind! ←] for pattern: [g #0]
-/
#guard_msgs in
@[grind] axiom fg₇ : f (g x) = r x x
```
This PR adds a normalizer for non-commutative semirings to `grind`.
Examples:
```lean
open Lean.Grind
variable (R : Type u) [Semiring R]
example (a b c : R) : a * (b + c) = a * c + a * b := by grind
example (a b : R) : (a + 2 * b)^2 = a^2 + 2 * a * b + 2 * b * a + 4 * b^2 := by grind
example (a b : R) : b^2 + (a + 2 * b)^2 = a^2 + 2 * a * b + b * (1+1) * a * 1 + 5 * b^2 := by grind
example (a b : R) : a^3 + a^2*b + a*b*a + b*a^2 + a*b^2 + b*a*b + b^2*a + b^3 = (a+b)^3 := by grind
```
This PR adds the helper theorem `eq_normS_nc` for normalizing
non-commutative semirings. We will use this theorem to justify
normalization steps in the `grind ring` module.
This PR changes the automation in `deriving_LawfulEq_tactic_step` to use
`with_reducible` when asserting the shape of the goal using `change`, so
that we do not accidentally unfold `x == x'` calls here. Fixes#10416.
This PR adds the ability to do `deriving ReflBEq, LawfulBEq`. Both
classes have to listed in the `deriving` clause. For `ReflBEq`, a simple
`simp`-based proof is used. For `LawfulBEq`, a dedicated,
syntax-directed tactic is used that should work for derived `BEq`
instances. This is meant to work with `deriving BEq` (but you can try to
use it on hand-rolled `@[methods_specs] instance : BEq…` instances).
Does not support mutual or nested inductives.
This PR fixes a bug where definitions with nested proofs that contain
`sorry` might not report "warning: declaration uses 'sorry'" if the
proof has the same type as another nested proof from a previous
declaration. The bug only affected log messages; `#print axioms` would
still correctly report uses of `sorryAx`.
The fix is that now the abstract nested proofs procedure does not
consult the aux lemma cache if the proof contains a `sorry`.
Closes#10196
This PR gives anonymous constructor notation (`⟨x,y⟩`) an error recovery
mechanism where if there are not enough arguments then synthetic sorries
are inserted for the missing arguments and an error is logged, rather
than outright failing.
Closes#9591.
This PR fixes an issue with the `if` tactic where errors were not placed
at the correct source ranges. It also adds some error recovery to avoid
additional errors about unsolved goals on the `if` token when the tactic
has incomplete syntax.
Closes#7972
This PR adds the `reduceBEq` and `reduceOrd` simprocs. They rewrite
occurrences of `_ == _` resp. `Ord.compare _ _` if both arguments are
constructors and the corresponding instance has been marked with
`@[method_specs]` (introduced in #10302), which now by default is the
case for derived instances.
This PR introduces the `@[specs]` attribute. It can be applied to
(certain) type class instances and define “specification theorems” for
the class’ operations, by taking the equational theorems of the
implementation function mentioned in the type class instance and
rephrasing them in terms of the overloaded operations. Fixes#5295.
Example:
```
inductive L α where
| nil : L α
| cons : α → L α → L α
def L.beqImpl [BEq α] : L α → L α → Bool
| nil, nil => true
| cons x xs, cons y ys => x == y && L.beqImpl xs ys
| _, _ => false
@[method_specs] instance [BEq α] : BEq (L α) := ⟨L.beqImpl⟩
/--
info: theorem instBEqL.beq_spec_2.{u_1} : ∀ {α : Type u_1} [inst : BEq α] (x_2 : α) (xs : L α) (y : α) (ys : L α),
(L.cons x_2 xs == L.cons y ys) = (x_2 == y && xs == ys)
-/
#guard_msgs(pass trace, all) in
#print sig instBEqL.beq_spec_2
```
It also introduces the `method_specs_norm` simpset to allow registering
further normalization of the theorems. The intended use of this is to
rewrite, say, `Append.append` to the `HAppend.hAppend` (i.e. `++`) that
the user wants to see. Library annotations to follow in a separate PR.
This PR makes the builtin Verso docstring elaborators bootstrap
correctly, adds the ability to postpone checks (which is necessary for
resolving forward references and bootstrapping issues), and fixes a
minor parser bug.
This PR includes some improvements to the release process, making the
updating of `stable` branches more robust, and including `cslib` in the
release checklist.
This PR implements sanity checks in the `grind ring` module to ensure
the instances synthesized by type class resolution are definitionally
equal to the corresponding ones in the `grind` core classes. The
definitional equality test is performed with reduction restricted to
reducible definitions and instances.
This PR fixes an issue where the "eta feature" in the app elaborator,
which is invoked when positional arguments are skipped due to named
arguments, results in variables that can be captured by those named
arguments. Now the temporary local variables that implement this feature
get fresh names. The names used for the closed lambda expression still
use the original parameter names.
Closes#6373
This PR enables using `notation` items in
`infix`/`infixl`/`infixr`/`prefix`/`postfix`. The motivation for this is
to enable being able to use `pp.unicode`-aware parsers. A followup PR
can combine core parsers as such:
```lean
infixr:30 unicode(" ∨ ", " \\/ ") => Or
```
Continuation of #10373.
This PR modifies the syntax for tactic configurations. Previously just
`(ident` would commit to tactic configuration item parsing, but now it
needs to be `(ident :=`. This enables reliably using tactic
configurations before the `term` category. For example, given `syntax
"my_tac" optConfig term : tactic`, it used to be that `my_tac (x + y)`
would have an error on `+` with "expected `:=`", but now it parses the
term.
An additional rationale is that these are like named arguments; (1)
terms can't begin with named arguments so now there is no parsing
ambiguity and (2) `Parser.Term.namedArgument` indeed already includes
`:=` in the atomic part.
This PR modifies pretty printing of `fun` binders, suppressing the safe
shadowing feature among the binders in the same `fun`. For example,
rather than pretty printing as `fun x x => 0`, we now see `fun x x_1 =>
0`. The calculation is done per `fun`, so for example `fun x => id fun x
=> 0` pretty prints as-is, taking advantage of safe shadowing.
The motivation for this change is that many users have reported that
safe shadowing within the same `fun` is confusing.
This PR adds support for non-commutative ring normalization in `grind`.
The new normalizer also accounts for the `IsCharP` type class. Examples:
```lean
open Lean Grind
variable (R : Type u) [Ring R]
example (a b : R) : (a + 2 * b)^2 = a^2 + 2 * a * b + 2 * b * a + 4 * b^2 := by grind
example (a b : R) : (a + 2 * b)^2 = a^2 + 2 * a * b + -b * (-4) * a - 2*b*a + 4 * b^2 := by grind
variable [IsCharP R 4]
example (a b : R) : (a - b)^2 = a^2 - a * b - b * 5 * a + b^2 := by grind
example (a b : R) : (a - b)^2 = 13*a^2 - a * b - b * 5 * a + b*3*b*3 := by grind
```
This PR adds the options `pp.piBinderNames` and
`pp.piBinderNames.hygienic`. Enabling `pp.piBinderNames` causes
non-dependent pi binder names to be pretty printed, rather than be
omitted. When `pp.piBinderNames.hygienic` is false (the default) then
only non-hygienic such biner names are pretty printed. Setting `pp.all`
enables `pp.piBinderNames` if it is not otherwise explicitly set.
Implementation note: this is exposing the secret pretty printer option
`pp.piBinderNames` that was being used within the signature pretty
printer.
Closes#1134.
This PR fixes a few bugs in the `rw` tactic: it could "steal" goals
because they appear in the type of the rewrite, it did not do an occurs
check, and new proof goals would not be synthetic opaque. This PR also
lets the `rfl` tactic assign synthetic opaque metavariables so that it
is equivalent to `exact rfl`.
Implementation note: filtering old vs new is not sufficient. This PR
partially addresses the bug where the rw tactic creates natural
metavariables for each of the goals; now new proof goals are synthetic
opaque.
Metaprogramming API: Instead of `Lean.MVarId.rewrite` prefer
`Lean.Elab.Tactic.elabRewrite` for elaborating rewrite theorems and
applying rewrites to expressions.
Closes#10172
This PR adds a `pp.unicode` option and a `unicode("→", "->")` syntax
description alias for the lower-level `unicodeSymbol "→" "->"` parser.
The syntax is added to the `notation` command as well. When `pp.unicode`
is true (the default) then the first form is used when pretty printing,
and otherwise the second ASCII form is used. A variant, `unicode("→",
"->", preserveForPP)` causes the `->` form to be preferred; delaborators
can insert `→` directly into the syntax, which will be pretty printed
as-is; this allows notations like `fun` to use custom options such as
`pp.unicode.fun` to opt into the unicode form when pretty printing.
Additionally:
- Adds more documentation for the `symbol` and `nonReservedSymbol`
parser descriptions.
- Adds documentation for the
`infix`/`infixr`/`infixl`/`prefix`/`postfix` commands.
- The parenthesizers for symbols are improved to backtrack if the atom
doesn't match.
- Fixes a bug where `&"..."` symbols aren't validated.
This is partial progress for issue #1056. What remains is enabling
`unicode(...)` for mixfix commands and then making use of it for core
notation.
This PR explicitly imports `Lake.Util` submodules in `Lake`, ensuring
Lake utilities are consistently available by default in configuration
files.
It also simplifies the Lake globs for the core build to ensure all Lake
submodules are built (even if they are not imported).
This PR ensures that the infotree recognizes `Classical.propDecidable`
as an instance, when below a `classical` tactic.
The `classical` tactic modifies the environment that the subsequent
sequence of tactics runs in (by making `Classical.propDecidable` an
instance). However, it does not add a corresponding `InfoTree.context`
node, so its effects are not visible when we want to replay a tactic
sequence (for example when running a tactic in the tactic analysis
framework). We should add a call to `Lean.Elab.withSafeInfoContext` to
remedy this issue.
There are two potential places to add this class: in the meta-level
`Lean.Elab.Tactic.classical` wrapper, or the tactic-level
`evalClassical` tactic elaborator. I chose the latter since meta-level
does not have access to info tree operations (unless we add many
parameters to `Lean.Elab.Tactic.classical`: `[MonadNameGenerator m]
[MonadOptions m] [MonadMCtx m] [MonadResolveName m] [MonadFileMap m]`).
A testcase that uses the tactic analysis framework is available here:
https://github.com/leanprover-community/mathlib4/pull/29501
This PR adds syntax for defining compile-time initializers under the
module system, with other initializers to be restricted from running at
compile time in a follow-up PR.
This PR uses the per-constructor `noConfusion` principles (from #10315)
in the `mkNoConfusion` app builder, if possible. This means they are
used by `injection`, `grind`, `simp` and other places. This brings
notable performance improvements when dealing with inductives with a
large number of constructors.
This PR adds `T.ctor.noConfusion` declarations, which are
specializations of `T.noConfusion` to equalities between `T.ctor`. The
point is to avoid reducing the `T.noConfusionType` construction every
time we use `injection` or a similar tactic.
```lean
Vec.cons.noConfusion.{u_1, u} {α : Type u} (P : Sort u_1) {n : Nat}
(x : α) (xs : Vec α n) (x' : α) (xs' : Vec α n)
(h : Vec.cons x xs = Vec.cons x' xs')
(k : n = n → x = x' → xs ≍ xs' → P) : P
```
The constructions are not as powerful as `T.noConfusion` when the
indices of the inductive type are not just constructor parameters (or
constructor applications of these parameters), so the full
`T.noConfusion` construction is still needed as a fallback.
It may seem costly to generate these eagerly, but given that we eagerly
generate injectivity theorems already, and we will use them there, it
seems reasonable for now.
To further reduce the cost, we only generate them for constructors with
fields (for others, the `T.noConfusion` theorem doesn't provide any
information), and we use `macro_inline` to prevent the compiler from
creating code for these, given that the compiler has special support for
`T.noConfusion` that we want it to use).
An earlier version of this PR also removed trivial equations and
un-HEq-ed others, leading to
```
(k : x = x' → xs = xs' → P)
```
in the example above. I backed out of that change, as it makes it harder
for tactics like `injectivity` to know how often to `intro`, so better
to keep things uniform.
This PR adds range support to`BitVec` and the `UInt*` types. This means
that it is now possible to write, for example, `for i in (1 : UInt8)...5
do`, in order to loop over the values 1, 2, 3 and 4 of type `UInt8`.
This PR adds more lemmas about the `toList` and `toArray` functions on
ranges and iterators. It also renames `Array.mem_toArray` into
`List.mem_toArray`.
This PR adds the type `Std.Internal.Parsec.Error`, which contains the
constructors `.eof` (useful for checking if parsing failed due to not
having enough input and then retrying when more input arrives that is
useful in the HTTP server) and `.other`, which describes other errors.
It also adds documentation to many functions, along with some new
functions to the `ByteArray` Parsec, such as `peekWhen?`, `octDigit`,
`takeWhile`, `takeUntil`, `skipWhile`, and `skipUntil`.
This PR is followup to the change in grind pattern heuristics from
#10342, typically resolving the discrepancy by writing out an explicit
`grind_pattern` for the intended pattern. The new behaviour is more
aggressive, because it selects smaller patterns.
This PR allows the interpreter to jump to native code of `[export]`
declarations, which can increase performance as well as the
effectiveness of `interpreter.prefer_native=true` during bootstrapping.
This PR reimplements `mkNoConfusionType` in lean, thus removing the
remaining C code related to this construction.
Also uses the ctor elimination principles only when there are more than
three ctors.
This PR completes the review of `@[grind]` annotations without a sigil
(e.g. `=` or `←`), replacing most of them with more specific annotations
or patterns.
---------
Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
This PR implements a new E-matching pattern inference procedure that is
faithful to the behavior documented in the reference manual regarding
minimal indexable subexpressions. The old inference procedure was
failing to enforce this condition. For example, the manual documents
`[grind ->]` as follows
`[@grind →]` selects a multi-pattern from the hypotheses of the theorem.
In other words, `grind` will use the theorem for forwards reasoning.
To generate a pattern, it traverses the hypotheses of the theorem from
left to right. Each time it encounters a **minimal indexable
subexpression** which covers an argument which was not previously
covered, it adds that subexpression as a pattern, until all arguments
have been covered.
That said, the new procedure is currently disabled, and the following
option must be used to enable it.
```
set_option backward.grind.inferPattern false
```
Users can inspect differences between the old a new procedures using the
option
```
set_option backward.grind.checkInferPatternDiscrepancy true
```
Example:
```lean
/--
warning: found discrepancy between old and new `grind` pattern inference procedures, old:
[@List.length #2 (@toList _ #1#0)]
new:
[@toList #2#1#0]
use `set_option backward.grind.inferPattern true` to force old procedure
-/
#guard_msgs in
set_option backward.grind.checkInferPatternDiscrepancy true in
@[grind] theorem Vector.length_toList' (xs : Vector α n) : xs.toList.length = n := by sorry
```
This PR moves the definitions and basic facts about `Function.Injective`
and `Function.Surjective` up from Mathlib. We can do a better job of
arguing via injectivity in `grind` if these are available.
This PR updates `@[grind]` annotations which should be `@[grind =]`, for
robustness (and, presumably, in some fraction of cases the existing
heuristic for `@[grind]` is already too liberal).
This PR shares common functionality relate to equalities between same
constructors, and when these are type-correct. In particular it uses the
more complete logic from `mkInjectivityThm` also in other places, such
as `CasesOnSameCtor` and the deriving code for `BEq`, `DecidableEq`,
`Ord`, for more consistency and better error messages.
This PR implements `mkNoConfusionImp` in Lean rather than in C. This
reduces our reliance on C, and may bring performance benefits from not
reducing `noConfusionType` during elaboration time (it still gets
reduced by the kernel when type-checking).
This PR makes it possible to write custom interpolation notation which
treats interpolated `String`s specially.
Sometimes it is desirable for `let w := "world"; foo!"hello {w}"` and
`foo!"hello world"` to mean different things; for instance, if debugging
and wanting to show all interpolands with `repr`. The current approach
forces `hello` to also be rendered with `repr`, which is not desirable.
This doesn't modify any existing formatters.
Requested in [#lean4 > ✔ dbg_trace should use `Repr` instance @
💬](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/.E2.9C.94.20dbg_trace.20should.20use.20.60Repr.60.20instance/near/495082575)
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR upstreams the Verso parser and adds preliminary support for
Verso in docstrings. This will allow the compiler to check examples and
cross-references in documentation.
After a `stage0` update, a follow-up PR will add the appropriate
attributes that allow the feature to be used. The parser tests from
Verso also remain to be upstreamed, and user-facing documentation will
be added once the feature has been used on more internals.
This PR fixes a performance issue in `grind linarith`. It was creating
unnecessary `NatModule`/`IntModule` structures for commutative rings
without an order. This kind of type should be handled by `grind ring`
only.
This PR implements model-based theory combination for types `A` which
implement the `ToInt` interface. Examples:
```lean
example {C : Type} (h : Fin 4 → C) (x : Fin 4)
: 3 ≤ x → x ≤ 3 → h x = h (-1) := by
grind
example {C : Type} (h : UInt8 → C) (x y z w : UInt8)
: y + 1 + w ≤ x + w → x + w ≤ z → z ≤ y + w + 1 → h (x + w) = h (y + w + 1) := by
grind
example {C : Type} (h : Fin 8 → C) (x y w r : Fin 8)
: y + 1 + w ≤ r → r ≤ y + w + x → x = 1 → h r = h (y + w + 1) := by
grind
```
This PR removes `grind →` annotations that fire too often, unhelpfully.
It would be nice for `grind` to instantiate these lemmas, but only if
they already see `xs ++ ys` and `#[]` in the same equivalence class, not
just as soon as it sees `xs ++ ys`.
In the meantime, let's see what is using these.
This PR introduces limited functionality frontends `cutsat` and
`grobner` for `grind`. We disable theorem instantiation (and case
splitting for `grobner`), and turn off all other solvers. Both still
allow `grind` configuration options, so for example one can use `cutsat
+ring` (or `grobner +cutsat`) to solve problems that require both.
For `cutsat`, it is helpful to instantiate a limited set of theorems
(e.g. `Nat.max_def`). Currently this isn't supported, but we intend to
add this later.
This PR fixes the `grind` canonicalizer for `OfNat.ofNat` applications.
Example:
```lean
example {C : Type} (h : Fin 2 → C) :
-- `0` in the first `OfNat.ofNat` is not a raw literal
h (@OfNat.ofNat (Fin (1 + 1)) 0 Fin.instOfNat) = h 0 := by
grind
```
This PR ensures that the auxiliary temporary metavariable IDs created by
the E-matching module used in `grind` are not affected by what has been
executed before invoking `grind`. The goal is to increase `grind`’s
robustness.
For example, in the E-matching module we use `Expr.quickLt` to sort
candidates. `Expr.quickLt` depends on the `Expr` hash code, which in
turn depends on metavariable IDs. Thus, before this change, the initial
next metavariable ID at the time of `grind` invocation could affect the
order in which instances were generated, and consequently the `grind`
search.
This PR changes the string interpolation procedure to omit redundant
empty parts. For example `s!"{1}{2}"` previously elaborated to `toString
"" ++ toString 1 ++ toString "" ++ toString 2 ++ toString ""` and now
elaborates to `toString 1 ++ toString 2`.
- [x] Updated docstrings for `simp!`, `simp_all!`, `dsimp!` to use
user-friendly language
- [x] Updated docstrings for `autoUnfold` fields to use user-friendly
language
- [x] Fixed broken test by updating expected output for simp! hover
documentation
- [x] Replaced technical terms with clear language: "will unfold
applications of functions defined by pattern matching, when one of the
patterns applies"
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nomeata <148037+nomeata@users.noreply.github.com>
This PR adds missing the lemmas `ofList_eq_insertMany_empty`,
`get?_eq_some_iff`, `getElem?_eq_some_iff` and `getKey?_eq_some_iff` to
all container types.
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 4 to 5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@nebuk89</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/407">actions/download-artifact#407</a></li>
<li>BREAKING fix: inconsistent path behavior for single artifact
downloads by ID by <a
href="https://github.com/GrantBirki"><code>@GrantBirki</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/416">actions/download-artifact#416</a></li>
</ul>
<h2>v5.0.0</h2>
<h3>🚨 Breaking Change</h3>
<p>This release fixes an inconsistency in path behavior for single
artifact downloads by ID. <strong>If you're downloading single artifacts
by ID, the output path may change.</strong></p>
<h4>What Changed</h4>
<p>Previously, <strong>single artifact downloads</strong> behaved
differently depending on how you specified the artifact:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (direct)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/my-artifact/</code> (nested)</li>
</ul>
<p>Now both methods are consistent:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (unchanged)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/</code> (fixed - now direct)</li>
</ul>
<h4>Migration Guide</h4>
<h5>✅ No Action Needed If:</h5>
<ul>
<li>You download artifacts by <strong>name</strong></li>
<li>You download <strong>multiple</strong> artifacts by ID</li>
<li>You already use <code>merge-multiple: true</code> as a
workaround</li>
</ul>
<h5>⚠️ Action Required If:</h5>
<p>You download <strong>single artifacts by ID</strong> and your
workflows expect the nested directory structure.</p>
<p><strong>Before v5 (nested structure):</strong></p>
<pre lang="yaml"><code>- uses: actions/download-artifact@v4
with:
artifact-ids: 12345
path: dist
# Files were in: dist/my-artifact/
</code></pre>
<blockquote>
<p>Where <code>my-artifact</code> is the name of the artifact you
previously uploaded</p>
</blockquote>
<p><strong>To maintain old behavior (if needed):</strong></p>
<pre lang="yaml"><code></tr></table>
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="634f93cb29"><code>634f93c</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/416">#416</a>
from actions/single-artifact-id-download-path</li>
<li><a
href="b19ff43027"><code>b19ff43</code></a>
refactor: resolve download path correctly in artifact download tests
(mainly ...</li>
<li><a
href="e262cbee4a"><code>e262cbe</code></a>
bundle dist</li>
<li><a
href="bff23f9308"><code>bff23f9</code></a>
update docs</li>
<li><a
href="fff8c148a8"><code>fff8c14</code></a>
fix download path logic when downloading a single artifact by id</li>
<li><a
href="448e3f862a"><code>448e3f8</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/407">#407</a>
from actions/nebuk89-patch-1</li>
<li><a
href="47225c44b3"><code>47225c4</code></a>
Update README.md</li>
<li>See full diff in <a
href="https://github.com/actions/download-artifact/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This PR adds missing `grind` normalization rules for `natCast` and
`intCast` Examples:
```
open Lean.Grind
variable (R : Type) (a b : R)
section CommSemiring
variable [CommSemiring R]
example (m n : Nat) : (m + n) • a = m • a + n • a := by grind
example (m n : Nat) : (m * n) • a = m • (n • a) := by grind
end CommSemiring
section CommRing
variable [CommRing R]
example (m n : Nat) : (m + n) • a = m • a + n • a := by grind
example (m n : Nat) : (m * n) • a = m • (n • a) := by grind
example (m n : Int) : (m * n) • (a * b) = (m • a) * (n • b) := by grind
end CommRing
```
This PR makes `IO.RealWorld` opaque. It also adds a new compiler -only
`lcRealWorld` constant to represent this type within the compiler. By
default, an opaque type definition is treated like `lcAny`, whereas we
want a more efficient representation. At the moment, this isn't a big
difference, but in the future we would like to completely erase
`IO.RealWorld` at runtime.
This PR offers an alternative `noConfusion` construction for the
off-diagonal use (i.e. for different constructors), based on comparing
the `.ctorIdx`. This should lead to faster type checking, as the kernel
only has to reduce `.ctorIdx` twice, instead of the complicate
`noConfusionType` construction.
This PR changes the "declaration uses 'sorry'" error to pretty print an
actual `sorry` expression in the message. The effect is that the `sorry`
is hoverable and, if it's labeled, you can "go to definition" to see
where it came from.
The implementation prefers reporting synthetic sorries. These can appear
even if there are no error messages if a declaration refers to a
declaration that has elaboration errors. Users should focus on
elaboration errors before worrying about user-written `sorry`s.
In the future we could have some more precise logic for sorry reporting.
All the sorries in a declaration should be considered to be reported,
and we should not re-report sorries in later declarations. Some
elaborators use `warn.sorry` to avoid re-reporting sorries in auxiliary
declarations.
This PR changes the implementation of a function `unfoldPredRel` used in
(co)inductive predicate machinery, that unfolds pointwise order on
predicates to quantifications and implications. Previous implementation
relied on `withDeclsDND` that could not deal with types which depend on
each other. This caused the following example to fail:
```lean4
inductive infSeq_functor1.{u} {α : Type u} (r : α → α → Prop) (call : {α : Type u} → (r : α → α → Prop) → α → Prop) : α → Prop where
| step : r a b → infSeq_functor1 r call b → infSeq_functor1 r call a
def infSeq1 (r : α → α → Prop) : α → Prop := infSeq_functor1 r (infSeq1)
coinductive_fixpoint monotonicity by sorry
#check infSeq1.coinduct
```
Closes#10234.
This test involves re-running the compiler on decls that have already
been compiled, which can cause all sorts of issues. I just hit these
issues on a PR, so it's time to retire this test like others that hit
the same issues.
This PR completes the `grind` solver extension design and ports the
`grind ac` solver to the new framework. Future PRs will document the API
and port the remaining solvers. An additional benefit of the new design
is faster build times.
The proof of the instWPMonad instance relies on the equality of any two
terms of type `IO.RealWorld`, which is only a side effect of the current
transparent definition. Ignoring the questions around the utility of
proving things about programs in `IO`, the semantic validity of this
instance in the intended model of the IO monad is also unclear.
I tried a few things to axiomatize this instance so it could be put into
the test file to preserve the one test section that relies on it, but I
was unsuccessful; everything I attempted caused errors.
This PR adds infrastructure for registering new `grind` solvers. `grind`
already includes many solvers, and this PR is the first step toward
modularizing the design and supporting user-defined solvers.
This PR prepares for a future reorganization of the import hierarchy so
that `Init.Data.String.Basic` can import `Init.Data.UInt.Bitwise` and
`Init.Data.Array.Lemmas`.
This PR moves `String.utf8EncodeChar` to the prelude to prepare for the
imminent redefinition of `String`.
The definition in the prelude uses modulo and division operations on
natural numbers. In `String.Extra`, a `csimp` lemma is provided, showing
that the new definition is equal to the previous one (which is now
called `utf8EncodeCharFast`) which uses bitwise operations on `UInt8`.
This PR implements diagnostic information for the `grind ac` module. It
now displays the basis, normalized disequalities, and additional
properties detected for each associative operator.
This PR improves the counterexamples produced by `grind linarith` for
`NatModule`s. `grind` now hides occurrences of the auxiliary function
`Grind.IntModule.OfNatModule.toQ`.
This PR implements `NatModule` normalization when the `AddRightCancel`
instance is not available. Note that in this case, the embedding into
`IntModule` is not injective. Therefore, we use a custom normalizer,
similar to the `CommSemiring` normalizer used in the `grind ring`
module. Example:
```lean
open Lean Grind
example [NatModule α] (a b c : α)
: 2•a + 2•(b + 2•c) + 3•a = 4•a + c + 2•b + 3•c + a := by
grind
```
This PR adds the auxiliary theorem `Lean.Grind.Linarith.eq_normN` for
normalizing `NatModule` equations when the instance `AddRightCancel` is
not available.
This PR changes the implementation of the linear `DecidableEq`
implementation to use `match decEq` rather than `if h : ` to compare the
constructor tags. Otherwise, the “smart unfolding” machinery will not
let `rfl` decide that different constructors are different.
This PR adds support for `NatModule` equalities and inequalities in
`grind linarith`. Examples:
```lean
open Lean Grind Std
example [NatModule α] [LE α] [LT α]
[LawfulOrderLT α] [IsLinearOrder α] [OrderedAdd α]
(x y : α) : x ≤ y → 2 • x + y ≤ 3 • y := by
grind
example [NatModule α] [AddRightCancel α] [LE α] [LT α]
[LawfulOrderLT α] [IsLinearOrder α] [OrderedAdd α]
(a b c d : α) : a ≤ b → a ≥ c + d → d ≤ 0 → d ≥ 0 → b = c → a = b := by
grind
```
This PR changes the naming of the internal functions in deriving
instances like BEq to use accessible names. This is necessary to
reasonably easily prove things about these functions. For example after
`deriving BEq` for a type `T`, the implementation of `instBEqT` is in
`instBEqT.beq`.
This PR adds a new option `maxErrors` that limits the number of errors
printed from a single `lean` run, defaulting to 100. Processing is
aborted when the limit is reached, but this is tracked only on a
per-command level.
Smaller values can be useful when making changes that break a lot of
files and would otherwise scroll the actual root failures out of the
terminal view.
This PR implements the infrastructure for supporting `NatModule` in
`grind linarith` and uses it to handle disequalities. Another PR will
add support for equalities and inequalities. Example:
```lean
open Lean Grind
variable (M : Type) [NatModule M] [AddRightCancel M]
example (x y : M) : 2 • x + 3 • y + x = 3 • (x + y) := by
grind
```
This PR fixes a panic in `grind ring` exposed by #10242. `grind ring`
should not assume that all normalizations have been applied, because
some subterms cannot be rewritten by `simp` due to typing constraints.
Moreover, `grind` uses `preprocessLight` in a few places, and it skips
the simplifier/normalizer.
Closes#10242
This PR improves the names of definitions and lemmas in the polymorphic
range API. It also introduces a recommended spelling. For example, a
left-closed, right-open range is spelled `Rco` in analogy with Mathlib's
`Ico` intervals.
This PR speeds up auto-completion by a factor of ~3.5x through various
performance improvements in the language server. On one machine, with
`import Mathlib`, completing `i` used to take 3200ms and now instead
yields a result in 920ms.
Specifically, the following improvements are made:
- The watchdog process no longer de-serializes and re-serializes most
messages from the file worker before passing them on to the user - a
fast partial de-serialization procedure is now used to determine whether
the message needs to be de-serialized in full or not.
- `escapePart` is optimized to perform better on ASCII strings that do
not need escaping.
- `Json.compress` is optimized to allocate fewer objects.
- A faster JSON compression specifically for completion responses is
implemented that skips allocating `Json` altogether.
- The JSON compression has been moved to the task where we convert a
request response to `Json` so that converting to a string won't block
the output task of the FileWorker and so the `Json` value is not marked
as multi-threaded when we compress is, which drastically increases the
cost of reference-counting.
- The JSON representation of the `data?` field of each completion item
is optimized.
- Both the completion kind and the set of completion tags for each
imported completion item is now cached.
- The filtering of duplicate completion items is optimized.
Other adjustments:
- `LT UInt8` and `LE UInt8` are moved to Prelude so that they can be
used in `Init.Meta` for the name part escaping fast path.
- `Array.usize` is exposed since it was marked as `@[simp]`.
This PR moves the `PackageConfig` definition from `Lake.Config.Package`
into its own module. This enables a significant reduction in the `meta
import` tree of the `Lake.CLI.Translate` modules.
This PR fixes a bug in the `LinearOrderPackage.ofOrd` factory. If there
is a `LawfulEqOrd` instance available, it should automatically use it
instead of requiring the user to provide the `eq_of_compare` argument to
the factory. The PR also solves a hygiene-related problem making the
factories fail when `Std` is not open.
This PR adds some test cases for `grind` working with `Fin`. There are
many still failing tests in `tests/lean/grind/grind_fin.lean` which I'm
intending to triage and work on.
This PR fixes the E-matching procedure for theorems that contain
universe parameters not referenced by any regular parameter. This kind
of theorem seldom happens in practice, but we do have instances in the
standard library. Example:
```
@[simp, grind =] theorem Std.Do.SPred.down_pure {φ : Prop} : (⌜φ⌝ : SPred []).down = φ := rfl
```
closes#10233
This PR fixes a missing case in the `grind` canonicalizer. Some types
may include terms or propositions that are internalized later in the
`grind` state.
closes#10232
This PR adds `MonoBind` for more monad transformers. This allows using
`partial_fixpoint` for more complicated monads based on `Option` and
`EIO`. Example:
```lean-4
abbrev M := ReaderT String (StateT String.Pos Option)
def parseAll (x : M α) : M (List α) := do
if (← read).atEnd (← get) then
return []
let val ← x
let list ← parseAll x
return val :: list
partial_fixpoint
```
This PR is the result of analyzing the elaborator performance regression
introduced by #10005. It makes the `workspaceSymboldNewRanges` and
`iterators` benchmarks less noisy. It also replaces some range-related
instances for `Nat` with shortcuts to the general-purpose instances.
This is a trade-off between the ergonomics and the synthesis cost of
having general-purpose instances.
This PR generalizes the monadic operations for `HashMap`, `TreeMap`, and
`HashSet` to work for `m : Type u → Type v`.
This upstreams [a workaround from
Aesop](66a992130e/Aesop/Util/Basic.lean (L57-L66)),
and seems to continue a pattern already established in other files, such
as:
```lean
Array.forM.{u, v, w} {α : Type u} {m : Type v → Type w} [Monad m] (f : α → m PUnit) (as : Array α) (start : Nat := 0)
(stop : Nat := as.size) : m PUnit
```
This PR introduces an alternative construction for `DecidableEq`
instances that avoids the quadratic overhead of the default
construction.
The usual construction uses a `match` statement that looks at each pair
of constructors, and thus is necessarily quadratic in size. For
inductive data type with dozens of constructors or more, this quickly
becomes slow to process.
The new construction first compares the constructor tags (using the
`.ctorIdx` introduced in #9951), and handles the case of a differing
constructor tag quickly. If the constructor tags match, it uses the
per-constructor-eliminators (#9952) to create a linear-size instance. It
does so by creating a custom “matcher” for a parallel match on the data
types and the `h : x1.ctorIdx = x2.ctorIdx` assumption; this behaves
(and delaborates) like a normal `match` statement, but is implemented in
a bespoke way. This same-constructor-matcher will be useful for
implementing other instances as well.
The new construction produces less efficient code at the moment, so we
use it only for inductive types with 10 or more constructors by default.
The option `deriving.decEq.linear_construction_threshold` can be used to
adjust the threshold; set it to 0 to always use the new construction.
This PR implements equality propagation from the new AC module into the
`grind` core. Examples:
```lean
example {α β : Sort u} (f : α → β) (op : α → α → α) [Std.Associative op] [Std.Commutative op]
(a b c d : α) : op a (op b b) = op d c → f (op (op b a) (op b c)) = f (op c (op d c)) := by
grind only
example (a b c : Nat) : min a (max b (max c 0)) = min (max c b) a := by
grind -cutsat only
example {α β : Sort u} (bar : α → β) (op : α → α → α) [Std.Associative op] [Std.IdempotentOp op]
(a b c d e f x y w : α) :
op d (op x c) = op a b →
op e (op f (op y w)) = op (op d a) (op b c) →
bar (op d (op x c)) = bar (op e (op f (op y w))) := by
grind only
```
This PR adds the extra critical pairs to ensure the `grind ac` procedure
is complete when the operator is associative and idempotent, but not
commutative. Example:
```lean
example {α : Sort u} (op : α → α → α) [Std.Associative op] [Std.IdempotentOp op] (a b c d e f x y w : α)
: op d (op x c) = op a b →
op e (op f (op y w)) = op a (op b c) →
op d (op x c) = op e (op f (op y w)) := by
grind only
example {α : Sort u} (op : α → α → α) [Std.Associative op] [Std.IdempotentOp op] (a b c d e f x y w : α)
: op a (op d x) = op b c →
op e (op f (op y w)) = op a (op b c) →
op a (op d x) = op e (op f (op y w)) := by
grind only
```
This PR makes `saveModuleData` throw an IO.Error instead of panicking,
if given something that cannot be serialized. This doesn't really matter
for saving modules, but is handy when writing tools to save auxiliary
date in olean files via Batteries' `pickle`.
The caller of this C++ function already is guarded in a `try`/`catch`
that promotes from a `lean::exception` to an `IO.userError`.
A simple test of this in the web editor is
```
import Batteries
#eval pickle "/tmp/foo.txt" fun x : Nat => x
```
which crashes before this change.
---------
Co-authored-by: Laurent Sartran <lsartran@google.com>
This PR adds the extra critical pairs to ensure the `grind ac` procedure
is complete when the operator is AC and idempotent. Example:
```lean
example {α : Sort u} (op : α → α → α) [Std.Associative op] [Std.Commutative op] [Std.IdempotentOp op]
(a b c d : α) : op a (op b b) = op d c → op (op b a) (op b c) = op c (op d c) := by
grind only
```
This PR adds the inverse of a dyadic rational, at a given precision, and
characterising lemmas. Also cleans up various parts of the `Int.DivMod`
and `Rat` APIs, and proves some characterising lemmas about
`Rat.toDyadic`.
---------
Co-authored-by: Rob23oba <152706811+Rob23oba@users.noreply.github.com>
This PR adds superposition for associative (but non-commutative)
operators in `grind ac`. Examples:
```lean
example {α} (op : α → α → α) [Std.Associative op] (a b c d : α)
: op a b = c →
op b a = d →
op (op c a) (op b c) = op (op a d) (op d b) := by
grind
example {α} (a b c d : List α)
: a ++ b = c →
b ++ a = d →
c ++ a ++ b ++ c = a ++ d ++ d ++ b := by
grind only
```
This PR adds superposition for associative and commutative operators in
`grind ac`. Examples:
```lean
example (a b c d e f g h : Nat) :
max a b = max c d → max b e = max d f → max b g = max d h →
max (max f d) (max c g) = max (max e (max d (max b (max c e)))) h := by
grind -cutsat only
example {α} (op : α → α → α) [Std.Associative op] [Std.Commutative op] (a b c d : α)
: op a b = op b c → op c c = op d c →
op (op d a) (op b d) = op (op a a) (op b d) := by
grind only
```
This PR almost completely rewrites the inductive predicate recursion
algorithm; in particular `IndPredBelow` to function more consistently.
Historically, the `brecOn` generation through `IndPredBelow` has been
very error-prone -- this should be fixed now since the new algorithm is
very direct and doesn't rely on tactics or meta-variables at all.
Additionally, the new structural recursion procedure for inductive
predicates shares more code with regular structural recursion and thus
allows for mutual and nested recursion in the same way it was possible
with regular structural recursion. For example, the following works now:
```lean-4
mutual
inductive Even : Nat → Prop where
| zero : Even 0
| succ (h : Odd n) : Even n.succ
inductive Odd : Nat → Prop where
| succ (h : Even n) : Odd n.succ
end
mutual
theorem Even.exists (h : Even n) : ∃ a, n = 2 * a :=
match h with
| .zero => ⟨0, rfl⟩
| .succ h =>
have ⟨a, ha⟩ := h.exists
⟨a + 1, congrArg Nat.succ ha⟩
termination_by structural h
theorem Odd.exists (h : Odd n) : ∃ a, n = 2 * a + 1 :=
match h with
| .succ h =>
have ⟨a, ha⟩ := h.exists
⟨a, congrArg Nat.succ ha⟩
termination_by structural h
end
```
Closes#1672Closes#10004
This PR implements the proof terms for the new `grind ac` module.
Examples:
```lean
example {α : Sort u} (op : α → α → α) [Std.Associative op] (a b c d : α)
: op a (op b b) = op c d → op c (op d c) = op (op a b) (op b c) := by
grind only
example {α : Sort u} (op : α → α → α) [Std.Associative op] [Std.Commutative op] (a b c d : α)
: op a (op b b) = op d c → op (op b a) (op b c) = op c (op d c) := by
grind only
example {α : Sort u} (op : α → α → α) [Std.Associative op] [Std.Commutative op]
(one : α) [Std.LawfulIdentity op one] (a b c d : α)
: op a (op (op b one) b) = op d c → op (op b a) (op (op b one) c) = op (op c one) (op d c) := by
grind only
```
The `grind ac` module is not complete yet, we still need to implement
critical pair computation and fix the support for idempotent operators.
This PR fixes `grind` instance normalization procedure.
Some modules in grind use builtin instances defined directly in core
(e.g., `cutsat`), while others synthesize them using `synthInstance`
(e.g., `ring`). This inconsistency is problematic, as it may introduce
mismatches and result in two different representations for the same
term. This PR fixes the issue.
This PR modifies macros, which implement non-atomic definitions and
```$cmd1 in $cmd2``` syntax. These macros involve implicit scopes,
introduced through ```section``` and ```namespace``` commands. Since
sections or namespaces are designed to delimit local attributes, this
has led to unintuitive behaviour when applying local attributes to
definitions appearing in the above-mentioned contexts. This has been
causing the following examples to fail:
```lean4
axiom A : Prop
namespace ex1
open Nat in
@[local simp] axiom a : A ↔ True
example : A := by simp
end ex1
namespace ex2
@[local simp] axiom Foo.a : A ↔ True
example : A := by simp
end ex2
```
This PR adds an internal-only piece of syntax,
```InternalSyntax.end_local_scope```, that influences the
```ScopedEnvExtension.addLocalEntry``` used in implementing local
attributes, to avoid delimiting local entries in the current scope. This
command is used in the above-mentioned macros.
Closes [#9445](https://github.com/leanprover/lean4/issues/9445).
---------
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
This PR changes the construction of a `CompleteLattice` instance on
predicates (maps intro `Prop`) inside of
`coinductive_fixpoint`/`inductive_fixpoint` machinery.
Consider a following endomap on predicates of the type ` α → Prop`:
```lean4
def DefFunctor (r : α → α → Prop) (infSeq : α → Prop) : α → Prop :=
λ x : α => ∃ y, r x y ∧ infSeq y
```
The following eta-reduced expression failed to elaborate:
```lean4
def def1 (r : α → α → Prop) : α → Prop := DefFunctor r (def1 r)
coinductive_fixpoint monotonicity sorry
```
At the same time, eta-expanded variant would elaborate correctly:
```lean4
def def2 (r : α → α → Prop) : α → Prop := fun x => DefFunctor r (def2 r) x
coinductive_fixpoint monotonicity sorry
```
This PR fixes the above issue, by changing the way how `CompleteLattice`
instance on the space of predicates is constructed, to allow for the
eta-reduced case, as outlined above.
This PR reviews the expected-to-fail-right-now tests for `grind`, moving
some (now passing) tests to the main test suite, updating some tests,
and adding some tests about normalisation of exponents.
Re-enables `Suggestion.messageData?` after it was deprecated in #9966
since it is needed for the workaround described in #10150. We will
hopefully be able to clean up with API once #10150 is properly fixed.
This PR adds benchmarks for deriving `DecidableEq` on inductives with
many constructors. (Although at the moment, many is “many” as we timeout
for more than 30 or 40 constructors.)
This PR ensures `where finally` tactics can access private data under
the module system even when the corresponding holes are in the public
scope as long as all of them are of proposition types.
This PR adds “non-branching case statements”: For each inductive
constructor `T.con` this adds a function `T.con.with` that is similar
`T.casesOn`, but has only one arm (the one for `con`), and an additional
`t.toCtorIdx = 12` assumption.
For example:
```lean
inductive Vec (α : Type) : Nat → Type where
| nil : Vec α 0
| cons {n} : α → Vec α n → Vec α (n + 1)
/--
info: @[reducible] protected def Vec.cons.elim.{u} : {α : Type} →
{motive : (a : Nat) → Vec α a → Sort u} →
{a : Nat} →
(t : Vec α a) →
t.ctorIdx = 1 → ({n : Nat} → (a : α) → (a_1 : Vec α n) → motive (n + 1) (Vec.cons a a_1)) → motive a t
-/
#guard_msgs in
#print sig Vec.cons.elim
```
This is a building block for non-quadratic implementations of `BEq` and
`DecidableEq` etc.
Builds on top of #9951.
The compiled code for a these functions could presumably, without
branching on the inductive value, directly access the fields. Achieving
this optimization (and achieving it without a quadratic compilation
cost) is not in scope for this PR.
Visibility is now handled implicitly for all deriving handlers by
adjusting section visibility according to the presence of private types
while removing exposition on presence of private constructors can be
opted in on a per-handler level via the new combinator
`withoutExposeFromCtors`.
Fixes#10062#10063#10064#10065
This PR adds support for pretty printing using generalized field
notation (dot notation) for private definitions on public types. It also
modifies dot notation elaboration to resolve names after removing the
private prefix, which enables using dot notation for private definitions
on private imported types.
It won't pretty print with dot notation for definitions on inaccessible
private types from other modules.
Closes#7297
This PR implements the basic infrastructure for the new procedure
handling AC operators in grind. It already supports normalizing
disequalities. Future PRs will add support for simplification using
equalities, and computing critical pairs. Examples:
```lean
example {α : Sort u} (op : α → α → α) [Std.Associative op] (a b c : α)
: op a (op b c) = op (op a b) c := by
grind only
example {α : Sort u} (op : α → α → α) (u : α) [Std.Associative op] [Std.LawfulIdentity op u] (a b c : α)
: op a (op b c) = op (op a b) (op c u) := by
grind only
example {α : Type u} (op : α → α → α) (u : α) [Std.Associative op] [Std.Commutative op]
[Std.IdempotentOp op] [Std.LawfulIdentity op u] (a b c : α)
: op (op a a) (op b c) = op (op (op b a) (op (op u b) b)) c := by
grind only
example {α} (as bs cs : List α) : as ++ (bs ++ cs) = ((as ++ []) ++ bs) ++ (cs ++ []) := by
grind only
example (a b c : Nat) : max a (max b c) = max (max b 0) (max a c) ∧ min a b = min b a := by
grind only [cases Or]
```
This PR ports more of the post-initialization C++ shell code to Lean.
All that remains is the initialization of the profiler and task manager.
As initialization tasks rather than main shell code, they were left in
C++ (where the rest of the initialization code currently is).
The `max_memory` and `timeout` Lean options used by the the `--memory`
and `--timeout` command-line options are now properly registered. The
server defaults for max memory and max heartbeats (timeout) were removed
as they were not actually used (because the `server` option that was
checked was neither set nor exists).
This PR also makes better use of the module system in `Shell.lean` and
fixes a minor bug in a previous port where the file name check was
dependent on building the `.ilean` rather than the `.c` file (as was
originally the case).
Fixes#9879.
This PR adds a private `Lean.Name.getUtf8Byte'` to `Init.Meta` for a
future PR that optimizes `Lean.Name.escapePart`.
`Lean.Name.getUtf8Byte'` should be replaced with `String.getUtf8Byte`
once the string refactor is through.
This PR implements the fast circuit for overflow detection in unsigned
multiplication used by Bitwuzla and proposed in:
https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=987767
The theorem is based on three definitions:
* `uppcRec`: the unsigned parallel prefix circuit for the bits until a
certain `i`
* `aandRec`: the conjunction between the parallel prefix circuit at of
the first operand until a certain `i` and the `i`-th bit in the second
operand
* `resRec`: the preliminary overflow flag computed with these two
definitions
To establish the correspondence between these definitiions and their
meaning in `Nat`, we rely on `clz` and `clzAuxRec` definitions.
Therefore, this PR contains the `clz`- and `clzAuxRec`-related
infrastructure that was necessary to get the proofs through.
An additional change this PR contains is the moving of `### Count
leading zeros` section in `BitVec.Lemmas` downwards. In fact, some of
the proofs I wrote required introducing `Bitvec.toNat_lt_iff` and
`BitVec.le_toNat_iff` which I believe should live in the `Inequalities`
section. Therefore, to put these in the appropriate section, I decided
to move the whole `clz` section downwards (while it's small and
relatively self contained. Specifically, the theorems I moved are:
`clzAuxRec_zero`, `clzAuxRec_succ`, `clzAuxRec_eq_clzAuxRec_of_le`,
`clzAuxRec_eq_clzAuxRec_of_getLsbD_false`.
The fast circuit is not yet the default one in the bitblaster, as it's
performance is not yet competitive due to some missing rewrites that
bitwuzla supports but are not in Lean yet.
co-authored-by: @bollu
---------
Co-authored-by: Tobias Grosser <tobias@grosser.es>
This PR lets the `ctorIdx` definition for single constructor inductives
avoid the pointless `.casesOn`, and uses `macro_inline` to avoid
compiling the function and wasting symbols.
This PR adjusts the "try this" widget to be rendered as a widget message
under 'Messages', not a separate widget under a 'Suggestions' section.
The main benefit of this is that the message of the widget is not
duplicated between 'Messages' and 'Suggestions'.
Since widget message suggestions were already implemented by @jrr6 for
the new hint infrastructure, this PR replaces the old "try this"
implementation with the new hint infrastructure. In doing so, the
`style?` field of suggestions is deprecated, since the hint
infrastructure highlights hints using diff colors, and `style?` also
never saw much use downstream. Additionally, since the message and the
suggestion are now the same component, the `messageData?` field of
suggestions is deprecated as well. Notably, the "Try this:" message
string now also contains a newline and indentation to separate the
suggestion from the rest of the message more clearly and the `postInfo?`
field of the suggestion is now part of the message.
Finally, this PR changes the diff colors used by the hint infrastructure
to be more color-blindness-friendly (insertions are now blue, not green,
and text that remains unchanged is now using the editor foreground color
instead of blue).
### Breaking changes
Tests that use `#guard_msgs` to test the "Try this:" message may need to
be adjusted for the new formatting of the message.
This PR makes the generation of functional induction principles more
robust when the user `let`-binds a variable that is then `match`'ed on.
Fixes#10132.
This PR creates the deprecated `.toCtorIdx` alias only for enumeration
types, which are the types that used to have this function. No need
generating an alias for types that never had it. Should reduce the
number of symbols in the standard library.
This PR prevents `rcases` and `obtain` from creating absurdly long case
tag names when taking single constructor types (like `Exists`) apart.
Fixes#6550
The change does not affect `cases` and `induction`, it seems (where the
user might be surprised to not address the single goal with a name),
because I make the change in Lean/`Meta/Tactic/Induction.lean`, not
`Lean/Elab/Tactic/Induction.lean`. Yes, that's confusing.
This PR defines the dyadic rationals, showing they are an ordered ring
embedding into the rationals. We will use this for future interval
arithmetic tactics.
Many thanks to @Rob23oba, who did most of the implementation work here.
---------
Co-authored-by: Rob23oba <robin.arnez@web.de>
This PR fixes an issue where private definitions recursively invoked
using generalized field notation (dot notation) would give an "invalid
field" errors. It also fixes an issue where "invalid field notation"
errors would pretty print the name of the declaration with a `_private`
prefix.
Closes#10044
this PR reorders the `DiscrTree.Key` constructors to match the order
given in the manually written `DiscrTree.Key.ctorIdx`. This allows us to
use the auto-generated one, and moreover lets this code benefit from
special compiler support for `.ctorIdx`, once that lands.
This PR normalizes the published diagnostics in the test runner so that
messages published out of order (due to parallelism) cannot cause test
failures. Clients can handle out-of-order messages just fine.
This PR generates `.ctorIdx` functions for all inductive types, not just
enumeration types. This can be a building block for other constructions
(`BEq`, `noConfusion`) that are size-efficient even for large
inductives.
It also renames it from `.toCtorIdx` to `.ctorIdx`, which is the more
idiomatic naming.
The old name exists as an alias, with a deprecation attribute to be
added after the next
stage0 update.
These functions can arguably compiled down to a rather efficient tag
lookup, rather than a `case` statement. This is future work (but
hopefully near future).
For a fair number of basic types the compiler is not able to compile a
function using `casesOn` until further definitions have been defined.
This therefore (ab)uses the `genInjectivity` flag and
`gen_injective_theorems%` command to also control the generation of this
construct.
For (slightly) more efficient kernel reduction one could use `.rec`
rather than `.casesOn`. I did not do that yet, also because it
complicates compilation.
This PR fixes a bug that caused the Lean server process tree to survive
the closing of VS Code.
The cause of this issue was that the file worker main task was blocked
on waiting for the result of `lake setup-file` because the blocking call
was lifted outside of the dedicated server task that was supposed to
contain it by the compiler.
This PR upstreams lemmas about `Rat` from `Mathlib.Data.Rat.Defs` and
`Mathlib.Algebra.Order.Ring.Unbundled.Rat`, specifically enough to get
`Lean.Grind.Field Rat` and `Lean.Grind.OrderedRing Rat`. In addition to
the lemmas, instances for `Inv Rat`, `Pow Rat Nat` and `Pow Rat Int`
have been upstreamed.
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR adds support for detecting associative operators in `grind`. The
new AC module also detects whether the operator is commutative,
idempotent, and whether it has a neutral element. The information is
cached.
This PR allows for more fine-grained control over what derived instances
have exposed definitions under the module system: handlers should not
expose their implementation unless either the deriving item or a
surrounding section is marked with `@[expose]`. Built-in handlers to be
updated after a stage 0 update.
This PR adds the modules in `Lake.Util` to core's Lake configuration to
ensure all utilities are built. With the module system port, they were
no longer all transitively imported.
Specifically, `Lake.Util.Lock` is unused because Lake does not currently
use a lock file for the build.
This PR allows Lean's parser to run with a final position prior to the
end of the string, so it can be invoked on a sub-region of the input.
This has applications in Verso proper, which parses Lean syntax in
contexts such as code blocks and docstrings, and it is a prerequisite to
parsing the contents of Lean docstrings.
This PR replaces `Std.Internal.Rat` with the new public `Rat` upstreamed
from Batteries.
The time library was depending on some defeqs which are no longer true,
so I have inserted some casts.
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
Co-authored-by: Sofia Rodrigues <sofia@algebraic.dev>
This PR contains lemmas about `Int` (minor amendments for BitVec and
Nat) that are being used in preparing the dyadics. This is all work of
@Rob23oba, which I'm pulling out of #9993 early to keep that one
manageable.
This PR fixes the compilation of `noConfusion` by repairing an oversight
made when porting this code from the old compiler. The old compiler only
repeatedly expanded the major for each non-`Prop` field of the inductive
under consideration, mirroring the construction of `noConfusion` itself,
whereas the new compiler erroneously counted all fields.
Fixes#9971.
This PR improves support for `a^n` in `grind cutsat`. For example, if
`cutsat` discovers that `a` and `b` are equal to numerals, it now
propagates the equality. This PR is similar to #9996, but `a^b`.
Example:
```lean
example (n : Nat) : n = 2 → 2 ^ (n+1) = 8 := by
grind
```
With #10022, it also improves the support for `BitVec n` when `n` is not
numeral. Example:
```lean
example {n m : Nat} (x : BitVec n)
: 2 ≤ n → n ≤ m → m = 2 → x = 0 ∨ x = 1 ∨ x = 2 ∨ x = 3 := by
grind
```
This PR refactors the Lake codebase to use the new module system
throughout. Every module in `Lake` is now a `module`.
As this was already a large-scale refactor, a general cleanup of the
code has also been bundled in.
This PR also uses workarounds for currently outstanding module system
issues: #10061, #10062, #10063, #10064, #10065, #10067, and #10068.
**Breaking change:** Since the module system encourages a
`private`-by-default design, the Lake API has switched from its previous
`public`-by-default approach. As such, many definitions that were
previously public are now private. The newly private definitions are not
expected to have had significant user use, Nonetheless, important use
cases could be missed. If a key API is now inaccessible but seems like
it should be public, users are encouraged to report this as an issue on
GitHub.
This PR reverts parts of #10005 that surprisingly turned out to cause a
performance regression in the benchmarks. The slowdown seems to be
related to elaboration, not inefficiencies in the generated code. This
is just a quick fix. I will take a closer look in a week.
This PR adds a stop position field to parser input contexts, allowing
the parser to be instructed to stop parsing prior to the end of a file.
This is step 1, prior to a stage0 update, to make run-time data
structures sufficiently compatible to avoid segfaults. After the update,
the actual code to stop parsing can be merged.
This PR implements the necessary typeclasses so that range notation
works for integers. For example, `((-2)...3).toList = [-2, -1, 0, 1, 2]
: List Int`.
This PR changes macro scope numbering from per-module to per-command,
ensuring that unrelated changes to other commands do not affect macro
scopes generated by a command, which improves `prefer_native` hit rates
on bootstrapping as well as avoids further rebuilds under the module
system.
In detail, instead of always using the current module name as a macro
scope prefix, each command now introduces a new macro scope prefix
(called "context") of the shape `<main module>._hygCtx_<uniq>` where
`uniq` is a `UInt32` derived from the command but automatically
incremented in case of conflicts (which must be local to the current
module). In the current implementation, `uniq` is the hash of the
declaration name, if any, or else the hash of the full command's syntax.
Thus, it is always independent of syntactic changes to other commands
(except in case of hash conflicts, which should only happen in practice
for syntactically identical commands) and, in the case of declarations,
also independent of syntactic changes to any private parts of the
declaration.
This PR replaces the implementation of `Nat.log2` with a version that
reduces faster.
The new version can handle:
```lean-4
example : Nat.log2 (1 <<< 500) = 500 := rfl
```
This PR enables core's `LakeMain` to be a `module` when core is built
without `USE_LAKE`.
This was a problem when porting Lake to the module system (#9749).
This PR shortens the work necessary to make a type compatible with the
polymorphic range notation. In the concrete case of `Nat`, it reduces
the required lines of code from 150 to 70.
This PR adds useful declarations to the `LawfulOrderMin/Max` and
`LawfulOrderLeftLeaningMin/Max` API. In particular, it introduces
`.leftLeaningOfLE` factories for `Min` and `Max`. It also renames
`LawfulOrderMin/Max.of_le` to .of_le_min_iff` and `.of_max_le_iff` and
introduces a second variant with different arguments.
This PR changes the `toMono` pass to replace decls with their `_redArg`
equivalent, which has the consequence of not considering arguments
deemed useless by the `reduceArity` pass for the purposes of the
`noncomputable` check.
This PR adds support for correctly handling computations on fields in
`casesOn` for inductive predicates that support large elimination. In
any such predicate, the only relevant fields allowed are those that are
also used as an index, in which case we can find the supplied index and
use that term instead.
This PR improves support for `Fin n` in `grind cutsat` when `n` is not a
numeral. For example, the following goals can now be solved
automatically:
```lean
example (p d : Nat) (n : Fin (p + 1))
: 2 ≤ p → p ≤ d + 1 → d = 1 → n = 0 ∨ n = 1 ∨ n = 2 := by
grind
example (s : Nat) (i j : Fin (s + 1)) (hn : i ≠ j) (hl : ¬i < j) : j < i := by
grind
example {n : Nat} (j : Fin (n + 1)) : j ≤ j := by
grind
example {n : Nat} (x y : Fin ((n + 1) + 1)) (h₂ : ¬x = y) (h : ¬x < y) : y < x := by
grind
```
This PR adds `@[expose]` to `Lean.ParserState.setPos`. This makes it
possible to prove in-boundedness for a state produced by `setPos` for
functions like `next'` and `get'` without needing to `import all`.
This came up while porting Lake to the module system (#9749).
This PR changes the handling of overapplied constructors when lowering
LCNF to IR from a (slightly implicit) assertion failure to producing
`unreachable`. Transformations on inlined unreachable code can produce
constructor applications with additional arguments.
In the old compiler, these additional arguments were silently ignored,
but it seems more sensible to replace them with `unreachable`, just in
case they arise due to a compiler error.
Fixes#9937.
This PR derives `BEq` and `Hashable` for `Lean.Import`. Lake already did
this later, but it now done when defining `Import`.
Doing this in Lake became problematic when porting it to the module
system (#9749).
This PR exposes the bodies of `Name.append`, `Name.appendCore`, and
`Name.hasMacroScopes`. This enables proof by reflection of the
concatenation of name literals when using the module system.
```lean
example : `foo ++ `bar = `foo.bar := rfl
```
This is necessary for Lake as part of the port to using `module`
(#9749).
This PR make some minor changes to the grind annotation analysis script,
including sorting results and handling errors. Still need to add an
external UI.
This PR changes Lake to not set `LEAN_GITHASH` when in core (i.e.
`bootstrap = true`). This avoids Lake rebuilding modules when the Lake
watchdog is on one build of Lean/Lake and the command line is on a
different one.
The current reuse analysis is greedy in that every function attempts to
reuse a value. However, this means that if the last use is an owned
argument, it will be `inc`'d prior to this last use, in order to prevent
reuse from happening in the callee. In many cases, it makes more sense
to give the callee the chance to reuse it instead. The benchmark results
indicate that this is a much better default.
This PR improves support for nonlinear `/` and `%` in `grind cutsat`.
For example, given `a / b`, if `cutsat` discovers that `b = 2`, it now
propagates that `a / b = b / 2`. This PR is similar to #9996, but for
`/` and `%`. Example:
```lean
example (a b c d : Nat)
: b > 1 → d = 1 → b ≤ d + 1 → a % b = 1 → a = 2 * c → False := by
grind
```
This PR fixes a bug in `#eval` where clicking on the evaluated
expression could show errors in the Infoview. This was caused by `#eval`
not saving the temporary environment that is used when elaborating the
expression.
This PR provides factories that derive order typeclasses in bulk, given
an `Ord` instance. If present, existing instances are preferred over
those derived from `Ord`. It is possible to specify any instance
manually if desired.
This PR reduces the number of `Nat.Bitwise` grind annotations we have
the deal with distributivity. The new smaller set encourages `grind` to
rewrite into DNF. The old behaviour just resulted in saturating up to
the instantiation limits.
This PR improves support for nonlinear monomials in `grind cutsat`. For
example, given a monomial `a * b`, if `cutsat` discovers that `a = 2`,
it now propagates that `a * b = 2 * b`.
Recall that nonlinear monomials like `a * b` are treated as variables in
`cutsat`, a procedure designed for linear integer arithmetic.
Example:
```lean
example (a : Nat) (ha : a < 8) (b c : Nat) : 2 ≤ b → c = 1 → b ≤ c + 1 → a * b < 8 * b := by
grind
example (x y z w : Int) : z * x * y = 4 → x = z + w → z = 1 → w = 2 → False := by
grind
```
This PR registers a parser alias for `Lean.Parser.Command.visibility`.
This avoids having to import `Lean.Parser.Command` in simple command
macros that use visibilities.
This PR provides the means to quickly provide all the order instances
associated with some high-level order structure (preorder, partial
order, linear preorder, linear order). This can be done via the factory
functions `PreorderPackage.ofLE`, `PartialOrderPackage.ofLE`,
`LinearPreorderPackage.ofLE` and `LinearOrderPackage.ofLE`.
This PR makes `IsPreorder`, `IsPartialOrder`, `IsLinearPreorder` and
`IsLinearOrder` extend `BEq` and `Ord` as appropriate, adds the
`LawfulOrderBEq` and `LawfulOrderOrd` typeclasses relating `BEq` and
`Ord` to `LE`, and adds many lemmas and instances.
Note: This PR contains a refactoring where `Init.Data.Ord` is moved to
`Init.Data.Ord.Basic`. If I added `Init.Data.Ord` simply importing all
submodules, git would not be able to determine that `Init.Data.Ord` was
renamed to `Init.Data.Ord.Basic`. This could lead to unnecessary merge
conflicts in the future. Hence, I chose the name `Init.Data.OrdRoot`
instead of `Init.Data.Ord` temporarily. After this PR, I will rename
this module back to `Init.Data.Ord` in a separate PR.
(This is a copy of #9430: I will not touch that PR because it currently
allows to debug a CI problem and pushing commits might break the
reproducibility.)
This PR eliminates uses of `intros x y z` (with arguments) and updates
the `intros` docstring to suggest that `intro x y z` should be used
instead. The `intros` tactic is historical, and can be traced all the
way back to Lean 2, when `intro` could only introduce a single
hypothesis. Since 2020, the `intro` tactic has superceded it. The
`intros` tactic (without arguments) is currently still useful.
This PR upstreams the definition of Rat from Batteries, for use in our
planned interval arithmetic tactic.
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR adds two test cases extracted from Mathlib, that `grind` cannot
solve but `omega` can. Originally the multiplication instance came from
`Nat.instSemiring` and `Int.instSemiring`, in minimizing I found that
`Distrib` is already enough.
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
This PR fixes an issue when running Mathlib's `FintypeCat` as code,
where an erased type former is passed to a polymorphic function. We were
lowering the arrow type to`object`, which conflicts with the runtime
representation of an erased value as a tagged scalar.
This PR modifies the generation of induction and partial correctness
lemmas for `mutual` blocks defined via `partial_fixpoint`. Additionally,
the generation of lattice-theoretic induction principles of functions
via `mutual` blocks is modified for consistency with `partial_fixpoint`.
The lemmas now come in two variants:
1. A conjunction variant that combines conclusions for all elements of
the mutual block. This is generated only for the first function inside
of the mutual block.
2. Projected variants for each function separately
## Example 1
```lean4
axiom A : Type
axiom B : Type
axiom A.toB : A → B
axiom B.toA : B → A
mutual
noncomputable def f : A := g.toA
partial_fixpoint
noncomputable def g : B := f.toB
partial_fixpoint
end
```
Generated `fixpoint_induct` lemmas:
```lean4
f.fixpoint_induct (motive_1 : A → Prop) (motive_2 : B → Prop) (adm_1 : admissible motive_1)
(adm_2 : admissible motive_2) (h_1 : ∀ (g : B), motive_2 g → motive_1 g.toA)
(h_2 : ∀ (f : A), motive_1 f → motive_2 f.toB) : motive_1 f
g.fixpoint_induct (motive_1 : A → Prop) (motive_2 : B → Prop) (adm_1 : admissible motive_1)
(adm_2 : admissible motive_2) (h_1 : ∀ (g : B), motive_2 g → motive_1 g.toA)
(h_2 : ∀ (f : A), motive_1 f → motive_2 f.toB) : motive_2 g
```
Mutual (conjunction) variant:
```lean4
f.mutual_fixpoint_induct (motive_1 : A → Prop) (motive_2 : B → Prop) (adm_1 : admissible motive_1) (adm_2 : admissible motive_2)
(h_1 : ∀ (g : B), motive_2 g → motive_1 g.toA) (h_2 : ∀ (f : A), motive_1 f → motive_2 f.toB) :
motive_1 f ∧ motive_2 g
```
## Example 2
```lean4
mutual
def f (n : Nat) : Option Nat :=
g (n + 1)
partial_fixpoint
def g (n : Nat) : Option Nat :=
if n = 0 then .none else f (n + 1)
partial_fixpoint
end
```
Generated `partial_correctness` lemmas (in a projected variant):
```lean4
f.partial_correctness (motive_1 motive_2 : Nat → Nat → Prop)
(h_1 :
∀ (g : Nat → Option Nat),
(∀ (n r : Nat), g n = some r → motive_2 n r) → ∀ (n r : Nat), g (n + 1) = some r → motive_1 n r)
(h_2 :
∀ (f : Nat → Option Nat),
(∀ (n r : Nat), f n = some r → motive_1 n r) →
∀ (n r : Nat), (if n = 0 then none else f (n + 1)) = some r → motive_2 n r)
(n r✝ : Nat) : f n = some r✝ → motive_1 n r✝
g.partial_correctness (motive_1 motive_2 : Nat → Nat → Prop)
(h_1 :
∀ (g : Nat → Option Nat),
(∀ (n r : Nat), g n = some r → motive_2 n r) → ∀ (n r : Nat), g (n + 1) = some r → motive_1 n r)
(h_2 :
∀ (f : Nat → Option Nat),
(∀ (n r : Nat), f n = some r → motive_1 n r) →
∀ (n r : Nat), (if n = 0 then none else f (n + 1)) = some r → motive_2 n r)
(n r✝ : Nat) : g n = some r✝ → motive_2 n r✝
```
Mutual (conjunction) variant:
```
f.mutual_partial_correctness (motive_1 motive_2 : Nat → Nat → Prop)
(h_1 :
∀ (g : Nat → Option Nat),
(∀ (n r : Nat), g n = some r → motive_2 n r) → ∀ (n r : Nat), g (n + 1) = some r → motive_1 n r)
(h_2 :
∀ (f : Nat → Option Nat),
(∀ (n r : Nat), f n = some r → motive_1 n r) →
∀ (n r : Nat), (if n = 0 then none else f (n + 1)) = some r → motive_2 n r) :
(∀ (n r : Nat), f n = some r → motive_1 n r) ∧ ∀ (n r : Nat), g n = some r → motive_2 n r
```
This PR modifies `intro` to create tactic info localized to each
hypothesis, making it possible to see how `intro` works
variable-by-variable. Additionally:
- The tactic supports `intro rfl` to introduce an equality and
immediately substitute it, like `rintro rfl` (recall: the `rfl` pattern
is like doing `intro h; subst h`). The `rintro` tactic can also now
support `HEq` in `rfl` patterns if `eq_of_heq` applies.
- In `intro (h : t)`, elaboration of `t` is interleaved with unification
with the type of `h`, which prevents default instances from causing
unification to fail.
- Tactics that change types of hypotheses (including `intro (h : t)`,
`delta`, `dsimp`) now update the local instance cache.
In `intro x y z`, tactic info ranges are `intro x`, `y`, and `z`. The
reason for including `intro` with `x` is to make sure the info range is
"monotonic" while adding the first argument to `intro`.
This PR adds lemmas for the `TreeMap` operations `filter`, `map` and
`filterMap`. These lemmas existed already for hash maps and are simply
ported over from there.
This PR allows most of the `List.lookup` lemmas to be used when
`LawfulBEq α` is not available.
`LawfulBEq` is very strong. Most of the lemmas don't actually require it
-- some only require `ReflBEq`, and only `List.lookup_eq_some_iff`
actually requires `LawfulBEq`.
This PR moves arithmetic of `String.Pos` out of the prelude.
Other `String` declarations are part of the prelude because they are
generated by macros, but this does not seem to be the case for these.
This PR cleans up `optParam`/`autoParam`/etc. annotations before
elaborating definition bodies, theorem bodies, `fun` bodies, and `let`
function bodies. Both `variable`s and binders in declaration headers are
supported.
There are no changes to `inductive`/`structure`/`axiom`/etc. processing,
just `def`/`theorem`/`example`/`instance`.
This PR ensures that equations in the `grind cutsat` module are
maintained in solved form. That is, given an equation `a*x + p = 0` used
to eliminate `x`, the linear polynomial `p` must not contain other
eliminated variables. Before this PR, equations were maintained in
triangular form. We are going to use the solved form to linearize
nonlinear terms.
This PR removes the option `grind +ringNull`. It provided an alternative
proof term construction for the `grind ring` module, but it was less
effective than the default proof construction mode and had effectively
become dead code.
This PR also optimizes semiring normalization proof terms using the
infrastructure added in #9946.
**Remark:** After updating stage0, we can remove several background
theorems from the `Init/Grind` folder.
This PR optimizes the proof terms produced by `grind linarith`. It is
similar to #9945, but for the `linarith` module in `grind`.
It removes unused entries from the context objects when generating the
final proof, significantly reducing the amount of junk in the resulting
terms.
This PR optimizes the proof terms produced by `grind cutsat`. It removes
unused entries from the context objects when generating the final proof,
significantly reducing the amount of junk in the resulting terms.
Example:
```lean
/--
trace: [grind.debug.proof] fun h h_1 h_2 h_3 h_4 h_5 h_6 h_7 h_8 =>
let ctx := RArray.leaf (f 2);
let p_1 := Poly.add 1 0 (Poly.num 0);
let p_2 := Poly.add (-1) 0 (Poly.num 1);
let p_3 := Poly.num 1;
le_unsat ctx p_3 (eagerReduce (Eq.refl true)) (le_combine ctx p_2 p_1 p_3 (eagerReduce (Eq.refl true)) h_8 h_1)
-/
#guard_msgs in -- Context should contain only `f 2`
open Lean Int Linear in
set_option trace.grind.debug.proof true in
example (f : Nat → Int) :
f 1 <= 0 → f 2 <= 0 → f 3 <= 0 → f 4 <= 0 → f 5 <= 0 →
f 6 <= 0 → f 7 <= 0 → f 8 <= 0 → -1 * f 2 + 1 <= 0 → False := by
grind
```
This PR expands `mvcgen using invariants | $n => $t` to `mvcgen; case
inv<$n> => exact $t` to avoid MVar instantiation mishaps observable in
the test case for #9581.
Closes#9581.
This PR implements extended `induction`-inspired syntax for `mvcgen`,
allowing optional `using invariants` and `with` sections.
```lean
mvcgen
using invariants
| 1 => Invariant.withEarlyReturn
(onReturn := fun ret seen => ⌜ret = false ∧ ¬l.Nodup⌝)
(onContinue := fun traversalState seen =>
⌜(∀ x, x ∈ seen ↔ x ∈ traversalState.prefix) ∧ traversalState.prefix.Nodup⌝)
with mleave -- mleave is a no-op here, but we are just testing the grammar
| vc1 => grind
| vc2 => grind
| vc3 => grind
| vc4 => grind
| vc5 => grind
```
This PR guards the `Std.Tactic.Do.MGoalEntails` delaborator by a check
ensuring that there are at least 3 arguments present, preventing
potential panics.
This PR fixes the `forIn` function, that previously caused the resulting
Promise to be dropped without a value when an exception was thrown
inside of it. It also corrects the parameter order of the `background`
function.
This PR changes `internalizeCode` to replace all substitutions with
non-param-bound fvars in `Expr`s (which are all types) with `lcAny`,
preserving the invariant that there are no such dependencies. The
violation of this invariant across files caused test failures in a
pending PR, but it is difficult to write a direct test for it. In the
future, we should probably change the LCNF checker to detect this.
This change also speeds up some compilation-heavy benchmarks much more
than I would've expected, which is a pleasant surprise. This indicates
we might get more speedups from reducing the amount of type information
we preserve in LCNF.
This PR fixes a panic in the delaborator for `Std.PRange`. It also
modifies the delaborators for both `Std.Range` and `Std.PRange` to not
use `let_expr`, which cleans up annotations and metadata, since
delaborators must follow the structures of expressions. It adds support
for `pp.notation` and `pp.explicit` options. It also adds tests for
these delaborators.
---------
Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: Kyle Miller <kmill31415@gmail.com>
This PR adds a guard for a delaborator that is causing panics in
doc-gen4. This is a band-aid solution for now, and @sgraf812 will take a
look when they're back from leave.
This PR ensures `grind cutsat` does not rely on div/mod terms to have
been normalized. The `grind` preprocessor has normalizers for them, but
sometimes they cannot be applied because of type dependencies.
Closes#9907
This PR addresses a missing check in the module system where private
names that remain in the public environment map for technical reasons
(e.g. inductive constructors generated by the kernel and relied on by
the code generator) accidentally were accessible in the public scope.
This PR reviews `grind` annotations for `Option`, preferring to use
`@[grind =]` instead of `@[grind]` (and fixing a few problems revealed
by this), and making sure `@[grind =]` theorems are "fully applied".
This PR lets the unused simp argument linter explain that the given hint
of removing `←` arguments may be too strong, and that replacing them
with `-` arguments can be needed. Fixes#9909.
This PR adds a JSON schema for `lakefile.toml`. Importantly, this schema
is *not* intended for validating `lakefile.toml`, but is instead
optimized for auto-completion and hovers using the [Even Better
TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml)
VS Code extension.
Once merged, I will attempt to contribute a link to this schema to the
[JSON Schema store](https://github.com/SchemaStore/schemastore). When
that is done, we can integrate the Lean 4 VS Code extension with Even
Better TOML, providing us with language server support in
`lakefile.toml`.
The schema contributed by this PR has the following known deficiencies:
- Superfluous properties do not produce an error.
- The structure of complicated structures (e.g. path or version
patterns) is deliberately not accurately reflected in the schema. Even
Better TOML doesn't seem to handle these structures well in
auto-completion.
- Due to the lack of an accurate declarative spec of the lakefile.toml
format and several deviations from the format to provide better
auto-completions, this schema will have to be kept in sync manually with
the code in Lake, at least for now.
This PR ensures that `Nat.cast` and `Int.cast` of numerals are
normalized by `grind`.
It also adds a `simp` flag for controlling how bitvector literals are
represented. By default, the bitvector simprocs use `BitVec.ofNat`. This
representation is problematic for the `grind ring` and `grind cutsat`
modules. The new flag allows the use of `OfNat.ofNat` and `Neg.neg` to
represent literals, consistent with how they are represented for other
commutative rings.
Closes#9321
This PR improves the heuristic used to select patterns for local
`forall` expressions occurring in the goal being solved by `grind`. It
now considers all singleton patterns in addition to the selected
multi-patterns. Example:
```lean
example (p : Nat → Prop) (h₁ : x < n) (h₂ : ¬ p x) : ∃ i, i < n ∧ ¬ p i := by
grind
```
This PR makes `mvcgen` aggressively eta-expand before trying to apply a
spec. This ensures that `mspec` will be able to frame hypotheses
involving uninstantiated loop invariants in goals for the inductive step
of a loop instead of losing them in a destructive world update.
This PR moves `List.range'_elim` to `List.eq_of_range'_eq_append_cons`
and adds a couple of `grind` annotations for `List.range'`. This will
make it more convenient to work with proof obligations produced by
`mvcgen`.
This PR is initially motivated by noticing `Lean.Grind.Preorder.toLE`
appearing in long Mathlib typeclass searches; this change will prevent
these searches. These changes are also helpful preparation for
potentially dropping the custom `Lean.Grind.*` typeclasses, and unifying
with the new typeclasses introduced in #9729.
This PR adds improved support for proof-by-reflection to the kernel type
checker. It addresses the performance issue exposed by #9854. With this
PR, whenever the kernel type-checks an argument of the form `eagerReduce
_`, it enters "eager-reduction" mode. In this mode, the kernel is more
eager to reduce terms. The new `eagerReduce _` hint is often used to
wrap `Eq.refl true`. The new hint should not negatively impact any
existing Lean package.
---------
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
This PR adds new variants of `Array.getInternal` and
`Array.get!Internal` that return their argument borrowed, i.e. without a
reference count increment. These are intended for use by the compiler in
cases where it can determine that the array will continue to hold a
valid reference to the element for the returned value's lifetime.
In the future, this will likely be replaced by a return value borrow
annotation, in which case the special variant of the functions could be
removed, with the compiler inserting an extra `inc` in the non-borrow
cases.
This PR ensures `grind` can E-match patterns containing universe
polymorphic ground sub-patterns. For example, given
```
set_option pp.universes true in
attribute [grind?] Id.run_pure
```
the pattern
```
Id.run_pure.{u_1}: [@Id.run.{u_1} #1 (@pure.{u_1, u_1} `[Id.{u_1}] `[Applicative.toPure.{u_1, u_1}] _ #0)]
```
contains two nested universe polymorphic ground patterns
- `Id.{u_1}`
- `Applicative.toPure.{u_1, u_1}`
This kind of pattern is not common, but it occurs in core.
This PR removes the `inShareCommon` quick filter used in `grind`
preprocessing steps. `shareCommon` is no longer used only for fully
preprocessed terms.
closes#9830
This PR makes `mvcgen` produce deterministic case labels for the
generated VCs. Invariants will be named `inv<n>` and every other VC will
be named `vc<n>.*`, where the `*` part serves as a loose indication of
provenance.
This PR introduces a canonical way to endow a type with an order
structure. The basic operations (`LE`, `LT`, `Min`, `Max`, and in later
PRs `BEq`, `Ord`, ...) and any higher-level property (a preorder, a
partial order, a linear order etc.) are then put in relation to `LE` as
necessary. The PR provides `IsLinearOrder` instances for many core types
and updates the signatures of some lemmas.
**BREAKING CHANGES:**
* The requirements of the `lt_of_le_of_lt`/`le_trans` lemmas for
`Vector`, `List` and `Array` are simplified. They now require an
`IsLinearOrder` instance. The new requirements are logically equivalent
to the old ones, but the `IsLinearOrder` instance is not automatically
inferred from the smaller typeclasses.
* Hypotheses of type `Std.Total (¬ · < · : α → α → Prop)` are replaced
with the equivalent class `Std.Asymm (· < · : α → α → Prop)`. Breakage
should be limited because there is now an instance that derives the
latter from the former.
* In `Init.Data.List.MinMax`, multiple theorem signatures are modified,
replacing explicit parameters for antisymmetry, totality, `min_ex_or`
etc. with corresponding instance parameters.
This PR migrates the ⌜p⌝ notation for embedding pure p : Prop into SPred
σs to expand into a simple, first-order expression SPred.pure p that can
be supported by e-matching in grind.
Doing so deprives ⌜p⌝ notation of its idiom-bracket-like support for
#selector and ‹Nat›ₛ syntax which is thus removed.
This PR replaces some `HashSet Expr`-typed collections of facts in
`omega`'s implementation with plain lists. This change makes some
`omega` calls faster, some slower, but the advantage is that `omega`'s
performance is more independent the state of the name generator that
produces fvar IDs.
I've created this PR for discussion and am happy to hear opinions on
whether this should be merged or not. A good reason *not* to merge is
that it causes regressions in some places and `grind` is expected to
supersede `omega` either way. A good reason to merge is that `omega` is
used all over the place and its flaky performance increases the noise in
future benchmarks.
This PR fixes a bug in `mvcgen` triggered by excess state arguments to
the `wp` application, a situation which arises when working with
`StateT` primitives.
This PR improves the delta deriving handler, giving it the ability to
process definitions with binders, as well as the ability to recursively
unfold definitions. Furthermore, delta deriving now tries all explicit
non-out-param arguments to a class, and it can handle "mixin" instance
arguments. The `deriving` syntax has been changed to accept general
terms, which makes it possible to derive specific instances with for
example `deriving OfNat _ 1` or `deriving Module R`. The class is
allowed to be a pi type, to add additional hypotheses; here is a Mathlib
example:
```lean
def Sym (α : Type*) (n : ℕ) :=
{ s : Multiset α // Multiset.card s = n }
deriving [DecidableEq α] → DecidableEq _
```
This underscore stands for where `Sym α n` may be inserted, which is
necessary when `→` is used. The `deriving instance` command can refer to
scoped variables when delta deriving as well. Breaking change: the
derived instance's name uses the `instance` command's name generator,
and the new instance is added to the current namespace.
This closes
[mathlib4#380](https://github.com/leanprover-community/mathlib4/issues/380).
This PR reorganizes the directory structure of Lake's module test and
renames some of the files to be more descriptive.
Originally, this was meant to be combined with a fix, but that fix
appears to be incorrect, so this is just a refactor.
This PR fixes a bug where the `DecidableEq` deriving handler did not
take universe levels into account for enumerations (inductive types
whose constructors all have no fields). Closes#9541.
This PR adds a script for analyzing `grind` E-matching annotations. The
script is useful for detecting matching loops. We plan to add
user-facing commands for running the script in the future.
This PR allows trailing comma in the argument list of `simp?`, `dsimp?`,
`simpa`, etc... Previously, it was only allowed in the non `?` variants
of `simp`, `dsimp`, `simp_all`.
Closes#7383.
This PR improves the API for invariants and postconditions and as such
introduces a few breaking changes to the existing pre-release API around
`Std.Do`. It also adds Markus Himmel's `pairsSumToZero` example as a
test case.
This PR changes the IR RC pass to take "implied borrows" from
projections into account. If a projected value's lifetime is contained
in that of its parent (or any projection ancestor), then it does not
need its reference count incremented (or later decremented).
I believe that this same technique should generalize to both the
reset/reuse and borrow signature inference passes.
This PR splits out an implementation detail of
MVarId.getMVarDependencies into a top-level function. Aesop was relying
on the function defined in the where clause, which is no longer possible
after #9759.
This PR modifies the pretty printing of anonymous metavariables to use
the index rather than the internal name. This leads to smaller numerical
suffixes in `?m.123` since the indices are numbered within a given
metavariable context rather than across an entire file, hence each
command gets its own numbering. This does not yet affect pretty printing
of universe level metavariables.
For debugging purposes, metavariables that are not defined now pretty
print as `?_mvar.123` rather than cause pretty printing to fail.
This PR combines the simplification and unfold-reducible-constants steps
in `grind` to ensure that no potential normalization steps are missed.
Closes#9610
This PR fixes a bug in the projection over constructor propagator used
in `grind`. It may construct type incorrect terms when a equivalence
class contains heterogeneous equalities.
closes#9769
We compute the liveness information for the join point body, so the only
thing that updateJPLiveVarMap should be adding is the binding of the
params, which we can easily do ourselves.
If we supported recursive join points, I believe this would actually be
a correctness issue, but as-is it doesn't affect the output.
This PR fixes the documentation of the pipe operator |>, which is
currently (emphasis mine):
> Haskell-like pipe operator `|>`. `x |> f` means **the same as the same
as** `f x`,
> and it chains such that `x |> f |> g` is interpreted as `g (f x)`.
This PR implements the option `mvcgen +jp` to employ a slightly lossy VC
encoding for join points that prevents exponential VC blowup incurred by
naïve splitting on control flow.
```lean
def ifs_pure (n : Nat) : Id Nat := do
let mut x := 0
if n > 0 then x := x + 1 else x := x + 2
if n > 1 then x := x + 3 else x := x + 4
if n > 2 then x := x + 1 else x := x + 2
if n > 3 then x := x + 1 else x := x + 2
if n > 4 then x := x + 1 else x := x + 2
if n > 5 then x := x + 1 else x := x + 2
return x
theorem ifs_pure_triple : ⦃⌜True⌝⦄ ifs_pure n ⦃⇓ r => ⌜r > 0⌝⦄ := by
unfold ifs_pure
mvcgen +jp
/-
...
h✝⁵ : if n > 0 then x✝⁵ = 0 + 1 else x✝⁵ = 0 + 2
h✝⁴ : if n > 1 then x✝⁴ = x✝⁵ + 3 else x✝⁴ = x✝⁵ + 4
h✝³ : if n > 2 then x✝³ = x✝⁴ + 1 else x✝³ = x✝⁴ + 2
h✝² : if n > 3 then x✝² = x✝³ + 1 else x✝² = x✝³ + 2
h✝¹ : if n > 4 then x✝¹ = x✝² + 1 else x✝¹ = x✝² + 2
h✝ : if n > 5 then x✝ = x✝¹ + 1 else x✝ = x✝¹ + 2
⊢ x✝ > 0
-/
grind
```
This PR does what #9234 regrettably failed to do: actually reintroduce
the signatures of some `Subarray` functions that are now implemented via
slices (see #9017) in order to ensure backward compatibility and
consistency. With this PR, the old interface is restored. As an added
benefit, `Subarray.forIn` is no longer opaque.
This PR re-implements `IO.waitAny` using Lean instead of C++. This is to
reduce the size and
complexity of `task_manager` in order to ease future refactorings.
There is an import behavioral change of `IO.waitAny` in this PR.
Consider a situation where we have
two promises `p1`, `p2` and call `IO.waitAny [p1.result!, p2.result!]`
and `p1` resolves instantly.
Previously this would just return the result of `p1` and require nothing
else. With the new
implementation if `p2` is released before being resolved this can cause
a panic, even if
`IO.waitAny` has already finished. I argue that this is reasonable
behavior, given that an
invocation of `result!` promises that the promise will eventually be
resolved.
This PR moves the validation of cross-package `import all` to Lake and
the syntax validation of import keywords (`public`, `meta`, and `all`)
to the two import parsers.
It also fixes the error reporting of the fast import parser
(`Lean.parseImports`) and adds positions to its errors.
This PR addresses an outstanding feature in the module system to
automatically mark `let rec` and `where` helper declarations as private
unless they are defined in a public context such as under `@[expose]`.
This PR removes an error which implicitly assumes that the sort of type
dependency between erased types present in the test being added can not
occur. It would be difficult to refine the error using only the
information present in LCNF types, and it is of very little ongoing
value (I don't recall it ever finding an actual problem), so it makes
more sense to delete it.
Fixes#9692.
This PR changes the LCNF `elimDeadBranches` pass so that it considers
all non-`Nat` literal types to be `⊤`. It turns out that fixing this to
correctly handle all of these types with the current abstract value
representation is surprisingly nontrivial, and it's better to just land
the fix first.
This PR adds a version of `CommRing.Expr.toPoly` optimized for kernel
reduction. We use this function not only to implement `grind ring`, but
also to interface the ring module with `grind cutsat`.
This PR updates `release_repos.yml` to reflect that `import-graph` no
longer depends on `batteries`, and reorders the repositories to better
reflect dependencies.
This PR adds propagation rules for functions that take singleton types.
This feature is useful for discharging verification conditions produced
by `mvcgen`. For example:
```lean
example (h : (fun (_ : Unit) => x + 1) = (fun _ => 1 + y)) : x = y := by
grind
```
This removes the early call to `contradiction` from `simpH`, and
replaces it with a quick check if the pattern start with different
constructors.
We already call `simpH` quadratically often (unavoidable), so we want it
to be quick. Most common contradictions are found later on, so maybe we
don't want to the expensive `contradiction` tactic to be run early.
May help with #9598.
This PR adjusts the formatting type classes for `lake query` to no
longer require both a text and JSON form and instead work with any
combination of the two. The classes have also been renamed. In addition,
the query formatting of a text module header has been improved to only
produce valid headers.
This PR restricts Lake's production of thin archives to only the Windows
core build (i.e., `bootstrap = true`). The unbundled `ar` usually used
for core builds on macOS does not support `--thin`, so we avoid using it
unless necessary.
* Have asynchronous environment extensions specify whether they are
manipulate data for declarations from the "outside"/main branch (e.g.
attributes) or from the "inside"/async branch (e.g. data collected from
body elaboration) in order to avoid unnecessary waiting.
* Merge `findStateAsync?` into `getState` via a new, optional
`asyncDecl` parameter.
* Make `mayContainAsync` check an automatic part of `modifyState`.
This PR uses a more simple approach to proving the unfolding theorem for
a function defined by well-founded recursion. Instead of looping a bunch
of tactics, it uses simp in single-pass mode to (try to) exactly undo
the changes done in `WF.Fix`, using a dedicated theorem that pushes the
extra argument in for each matcher (or `casesOn`).
Improves performance for recursive functions with large `match`
statements, as in #9598.
This PR fixes a regression introduced by an optimization in the
`unfoldReducible` step used by the `grind` normalizer. It also ensures
that projection functions are not reduced, as they are folded in a later
step.
This PR adds build times to each build step of the build monitor (under
`-v` or in CI) and delays exiting on a `--no-build` until after the
build monitor finishes. Thus, a `--no-build` failure will now report
which targets blocked Lake by needing a rebuild.
This PR adds normalizers for nonstandard arithmetic instances. The types
`Nat` and `Int` have built-in support in `grind`, which uses the
standard instances for these types and assumes they are the ones in use.
However, users may define their own alternative instances that are
definitionally equal to the standard ones. This PR normalizes such
instances using simprocs. This situation actually occurs in Mathlib.
Example:
```lean
class Distrib (R : Type _) extends Mul R where
namespace Nat
instance instDistrib : Distrib Nat where
mul := (· * ·)
theorem odd_iff.extracted_1_4 {n : Nat} (m : Nat)
(hm : n =
@HMul.hMul _ _ _ (@instHMul Nat instDistrib.toMul)
2 m + 1) :
n % 2 = 1 := by
grind
end Nat
```
This PR adds support for `Fin.val` in `grind cutsat`. Examples:
```lean
example (a b : Fin 2) (n : Nat) : n = 1 → ↑(a + b) ≠ n → a ≠ 0 → b = 0 → False := by
grind
example (m n : Nat) (i : Fin (m + n)) (hi : m ≤ ↑i) : ↑i - m < n := by
grind
example {n : Nat} (m : Nat) (i : Fin n) ⦃j : Fin (n + m)⦄
(this : ↑i + m ≤ ↑j) : ↑j - m < n := by
grind
example {n : Nat} (i : Fin n) (j : Nat) (hj : j < ↑i) : j < n := by
grind
```
This PR ensures that `grind cutsat` processes `ToInt.toInt` applications
provided by the user. Example:
```lean
open Lean Grind
example (x : Fin 3) : ToInt.toInt x ≠ 0 → ToInt.toInt x ≠ 1 → ToInt.toInt x ≠ 2 → False := by
grind -ring
example (x y z : Fin 5) : ToInt.toInt (x + z) = ToInt.toInt y → z = 0 → x = y := by
grind -ring
```
This PR fixes support for `SMul.smul` in `grind ring`. `SMul.smul`
applications are now normalized. Example:
```lean
example (x : BitVec 2) : x - 2 • x + x = 0 := by
grind
```
This PR add constructors `.intCast k` and `.natCast k` to
`CommRing.Expr`. We need them because terms such as `Nat.cast (R := α)
1` and `(1 : α)` are not definitionally equal. This is pervaise in
Mathlib for the numerals `0` and `1`.
```lean
import Mathlib
example {α : Type} [AddMonoidWithOne α] : Nat.cast (R := α) 0 = (0 : α) := rfl -- not defeq
example {α : Type} [AddMonoidWithOne α] : Nat.cast (R := α) 1 = (1 : α) := rfl -- not defeq
example {α : Type} [AddMonoidWithOne α] : Nat.cast (R := α) 2 = (2 : α) := rfl -- defeq from here
-- Similarly for everything past `AddMonoidWithOne` in the Mathlib hierarchy, e.g. `Ring`.
```
This PR adjusts the import graph, primarily of `Lean`, such that the
worst case rebuild time of core (`lean` only) is below 3 minutes on the
speedcenter machine (not captured by benchmark yet).
This PR performs some micro optimizations on fuzzy matching for a `~20%`
instructions win.
The three key changes are:
- try to remove some unnecessary allocations of things such as tuples
- change `containsInOrderLower` to use the efficient `get'` and `next'`
primitives. I hope that we can replace these with iterators on strings
in the second half of this quarter
- Do the same thing as clangd and use `Int16` with the `minValue` being
used for "worst score" while this does have the potential to
over/underflow, if the user is working with a score in the 10000s
something weird is certainly going on already (the score usually seems
to be in the 2 digit area based on some).
As an additional bonus, once we finally have unboxed arrays we will get
some additional cache wins on the 16 bit arrays!
This PR introduces checks to make sure that the IO functions produce
errors when inputs contain NUL bytes (instead of ignoring everything
after the first NUL byte).
This PR continues #9644 , fixing the core build when using an older
system libuv.
This only affected users building Lean from scratch, since the lean
binaries we ship as part of toolchains statically link their own copy of
libuv 1.50+.
---------
Co-authored-by: Markus Himmel <markus@lean-fro.org>
This PR changes `lake setup-file` to use the server-provided header for
workspace modules.
This also reverts #9163 as the underlying issue is now fixed.
This PR modifies dot identifier notation so that `(.a : T)` resolves
`T.a` with respect to the root namespace, like for generalized field
notation. This lets the notation refer to private names, follow aliases,
and also use open namespaces. The LSP completions are improved to follow
how dot ident notation is resolved, but it doesn't yet take into account
aliases or open namespaces.
Closes#9629
This PR adds error explanations for two common errors caused by large
elimination from `Prop`. To support this functionality, "nested" named
errors thrown by sub-tactics are now able to display their error code
and explanation.
This PR fixes the core build when using an older system libuv.
This only affected users building Lean from scratch, since the `lean`
binaries we ship as part of toolchains statically link their own copy of
libuv 1.50+.
This PR introduces a `mutual_induct` variant of the generated
(co)induction proof principle for mutually defined (co)inductive
predicates. Unlike the standard (co)induction principle (which projects
conclusions separately for each predicate), `mutual_induct` produces a
conjunction of all conclusions.
## Example
Given the following mutual definition:
```lean4
mutual
def f : Prop := g
coinductive_fixpoint
def g : Prop := f
coinductive_fixpoint
end
```
Standard coinduction principles:
```lean4
f.coind : ∀ (pred_1 pred_2 : Prop), (pred_1 → pred_2) → (pred_2 → pred_1) → pred_1 → f
g.coind : ∀ (pred_1 pred_2 : Prop), (pred_1 → pred_2) → (pred_2 → pred_1) → pred_2 → g
```
New `mutual_induct`principle:
```lean4
f.mutual_induct: ∀ (pred_1 pred_2 : Prop), (pred_1 → pred_2) → (pred_2 → pred_1) → (pred_1 → f) ∧ (pred_2 → g)
```
---------
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
This PR adds support for generating lattice-theoretic (co)induction
proof principles for predicates defined via `mutual` blocks using
`inductive_fixpoint`/`coinductive_fixpoint` constructs.
### Key Changes
- The order on product lattices (used to define fixpoints of mutual
blocks) is unfolded.
- Hypotheses in generated principles are curried.
- Conclusions are projected to focus only on the predicate of interest
(rather than being a conjunction of conclusions for all functions
defined in the `mutual` block.
### Example
Given:
```lean4
mutual
def f : Prop :=
g
coinductive_fixpoint
def g : Prop :=
f
coinductive_fixpoint
end
```
The system now generates these coinduction principles:
```lean4
f.coinduct (pred_1 pred_2 : Prop) (hyp_1 : pred_1 → pred_2) (hyp_2 : pred_2 → pred_1) : pred_1 → f
```
and
```lean4
g.coinduct (pred_1 pred_2 : Prop) (hyp_1 : pred_1 → pred_2) (hyp_2 : pred_2 → pred_1) : pred_2 → g
```
---------
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
This PR adds the separate directions of
`List.pairwise_iff_forall_sublist` as named lemmas.
I want to explore how they could/should be used by `grind` in Mathlib.
This PR brings the Mac OSX build instructions up to date slightly. (They
currently refer to facts "...as of November 2014...")
- Remove specific OS version number from the title as it is out of date
with respect to filename.
- Nonetheless don't change filename for the sake of not breaking
incoming links.
- Update C++ language version to C++14, which I believe is what is
currently required, based on other platform documentation.
- Bump versions of C++ compilers that seem to be current. I expect the
exact values of these version numbers aren't crucial but maybe good for
the reader calibrating a vague sense of whether their compiler is in the
right ballpark.
- Add `lld` to the homebrew clang instructions, because homebrew changed
the way they package llvm tools, spinning the linker off into its own
package.
This PR updates the styling and wording of error messages produced in
inductive type declarations and anonymous constructor notation,
including hints for inferable constructor visibility updates.
This PR optimizes `Lean.Name.toString`, giving a 10% instruction
benefit.
Crucially this is a breaking change as the old `Lean.Name.toString`
method used to support a method for identifying tokens. This method is
now available as `Lean.Name.toStringWithToken` in order to allow for
specialization of the (highly common) `toString` code path which sets
this function to just return `false`.
This PR simplifies the docstring for `propext` significantly.
The old docstring explained general concepts of axioms that are now
covered in the reference manual, and had a large example that was out of
date and has been subsumed by reference manual content.
This PR adds `@[grind =]` to `Prod.lex_def`. Note that `omega` has
special handling for `Prod.Lex`, and this is needed for `grind`'s cutsat
module to achieve parity.
The `isUnderBinder` check is intended to avoid inlining repeated
computations into specializations, but this doesn’t apply to local
function decls whose bodies are already delayed.
This PR adds lemmas about `UIntX.toBitVec` and `UIntX.ofBitVec` and `^`.
These match the existing lemas for `*`.
After #7887 these can be made true by `rfl`.
This PR ensures `ite` and `dite` are to selected as E-matching patterns.
They are bad patterns because the then/else branches are only
internalized after `grind` decided whether the condition is
`True`/`False`.
The issue reported by #9572 has been fixed, but the fix exposed another
issue. The patterns for `List.Pairwise` produce an unbounded number of
E-matching instances.
```lean
example (l : List α) : l.Pairwise R := by
grind
```
This PR fixes an issue in `grind`'s disequality proof construction. The
issue occurs when an equality is merged with the `False` equivalence
class, but it is not the root of its congruence class, and its
congruence root has not yet been merged into the `False` equivalence
class yet.
closes#9562
This PR optimizes the proof terms generated by `grind ring`. For
example, before this PR, the kernel took 2.22 seconds (on a M4 Max) to
type-check the proof in the benchmark `grind_ring_5.lean`; it now takes
only 0.63 seconds.
This PR generalizes `Process.output` and `Process.run` with an optional
`String` argument that can be piped to `stdin`.
To date we have been using shims `Process.runCmdWithInput` in Batteries.
This PR fixes a bug introduced in #7830 where if the cursor is at the
indicated position
```lean
example (as bs : List Nat) : (as.append bs).length = as.length + bs.length := by
induction as with
| nil => -- cursor
| cons b bs ih =>
```
then the Infoview would show "no goals" rather than the `nil` goal. The
PR also fixes a separate bug where placing the cursor on the next line
after the `induction`/`cases` tactics like in
```lean
induction as with
| nil => sorry
| cons b bs ih => sorry
I -- < cursor
```
would report the original goal in the goal list. Furthermore, there are
numerous improvements to error recovery (including `allGoals`-type logic
for pre-tactics) and the visible tactic states when there are errors.
Adds `Tactic.throwOrLogErrorAt`/`Tactic.throwOrLogError` for throwing or
logging errors depending on the recovery state.
This PR restores the feature where in `induction`/`cases` for `Nat`, the
`zero` and `succ` labels are hoverable. This was added in #1660, but
broken in #3629 and #3655 when custom eliminators were added. In
general, if a custom eliminator `T.elim` for an inductive type `T` has
an alternative `foo`, and `T.foo` is a constant, then the `foo` label
will have `T.foo` hover information.
This PR consolidates common attribute-related error messages into
reusable functions and updates the wording and formatting of relevant
error messages.
This extends the specialization behavior of functions taking instance
implicits to ordinary implicit arguments that are of instance type. The
choice between the two is often made for subtle inference-related
reasons. It also affects visibility of these functions, because the
module system makes template-like decls visible to the compiler in other
modules.
This PR makes the second instance of the `inferVisibility` pass run
after the `saveMono` pass. As the comment above the first instance of
the pass indicates, this needs to be after `saveMono` in order to see
all decls with their updated bodies.
This PR upstreams some helper instances for `NameSet` from Batteries.
(These could be generalized to an arbitrary TreeSet, but I'll leave that
for someone else.)
This PR changes `Lean.Grind.NoNatZeroDivisors` so that it is
parametrised by a `NatModule` instance rather than just a `HMul`
instance. This is sufficiently general for our purposes, and is a
band-aid (~40% improvement) for the performance problems we've been
seeing coming from inference here. The problems observed in Mathlib may
not see much improvement, however.
This PR lets the equation compiler unfold abstracted proofs again if
they would otherwise hide recursive calls.
This fixes#8939.
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR fixes Lake's handling of a module system `import all`.
Previously, Lake treated `import all` the same a non-module `import`,
importing all private data in the transitive import tree. Lake now
distinguishes the two, with `import all M` just importing the private
data of `M`. The direct private imports of `M` are followed, but they
are not promoted.
This also fixes some other Lake bugs with module system imports that
were discovered in the process.
In the early days of the new compiler, it was common to make tests that
manually compiled a definition with the new compiler. The arity
reduction pass in LCNF deliberately does not compute a fixed point to
find a minimal set of used parameters for performance reasons, but
running it a second time can lead to different decisions being made and
a decl arity mismatch. This has been an issue for multiple people during
development. Removing the tests fixes the problem.
Fixes#9186.
This PR uses `withAbstractAtoms` to prevent the kernel from accidentally
reducing the atoms in the arith normlizer while typechecking. This PR
also sets `implicitDefEqProofs := false` in the `grind` normalizer
This PR corrects the changes to `Lean.Grind.Field` made in #9500.
(The lack of examples of fields in the core repository is a problem! I
guess it is likely that for interval arithmetic we will at least need
`Rat` soon.)
(Almost) only typos in constant names and doc-strings were considered;
grammar was not considered. Also, along others,
`mkDefinitionValInferrringUnsafe` has been fixed :-)
This PR adds a benchmark for the persistent hashmap, in particular also
covering the non
linear insert case which is often hit in practical uses. Furthermore the
same test case is also
added to the treemap benchmark.
This PR makes `mframe`, `mspec` and `mvcgen` respect hygiene.
Inaccessible stateful hypotheses can now be named with a new tactic
`mrename_i` that works analogously to `rename_i`.
This PR surfaces kernel diagnostics even in `example`.
The problem was that the kernel checking happens asynchronously. We
cannot use `reportDiag` in `addDecl`, which spawns that task, due to the
module hierarchy. For non `example`-declaration, `reportDiag` is called
somewhere else later, but for `example`, the `withoutModifyingEnv` in
`elabMutualDef` hid the kernel diagnostics. (But only the kernel
diagnostics; they are in the `Environment`, while the others are in the
`State`).
I also observed that the `reportDiag` in `elabAsync` (but not in
`elabSync`) duplicated the reporting, so without `elab.Async true` you
get the message twice. To fix this, `reportDiag` now resets the
diagnostics. This should avoid reporting counts twice in general (at
least within a linear use of the state).
---------
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This PR removes vestigial syntax definitions in
`Lean.Elab.Tactic.Do.VCGen` that when imported undefine the `mvcgen`
tactic. Now it should be possible to import Mathlib and still use
`mvcgen`.
This PR adds a few more `*.by_wp` "adequacy theorems" that allows to
prove facts about programs in `ReaderM` and `ExceptM` using the `Std.Do`
framework.
This PR adds a `HPow \a Int \a` field to `Lean.Grind.Field`, and
sufficient axioms to connect it to the operations, so that in future we
can reason about exponents in `grind`. To avoid collisions, we also move
the `HPow \a Nat \a` field in `Semiring` from the extends clause to a
field. Finally, we add some failing tests about normalizing exponents.
This PR makes cdot function expansion take hygiene information into
account, fixing "parenthesis capturing" errors that can make erroneous
cdots trigger cdot expansion in conjunction with macros. For example,
given
```lean
macro "baz% " t:term : term => `(1 + ($t))
```
it used to be that `baz% ·` would expand to `1 + fun x => x`, but now
the parentheses in `($t)` do not capture the cdot. We also fix an
oversight where cdot function expansion ignored the fact that type
ascriptions and tuples were supposed to delimit expansion, and also now
the quotation prechecker ignores the identifier in `hygieneInfo`. (#9491
added the hygiene information to the parenthesis and cdot syntaxes.)
This fixes a bug discovered by [Google
DeepMind](https://storage.googleapis.com/deepmind-media/DeepMind.com/Blog/imo-2024-solutions/P1/index.html),
which made use of `useλy . x=>y.rec λS p=>?_`. The `use` tactic from
Mathlib wrapped the provided term in a type ascription, and so this was
equivalent to `use fun x => λy x x=>y.rec λS p=>?_`. (Note that cdot
function expansion is not able to take into account *where* the cdots
are located, and it is syntactically valid to insert an identifier into
the binder list like this. If we ever want to address this in the
future, we could have cdots expand into a special term that wraps an
identifier that evaluates to a local, but which would cause errors in
other contexts.)
Design note: we put the `hygieneInfo` on the open parenthesis rather
than at the end, since that way the hygiene information is available
even when there are parsing errors. This is important since we rely on
being able to elaborate partial syntax to get elab info (e.g. in `(a.`
to get completion info). Note that syntax matchers check that the
`hygieneInfo` is actually present, so such partial syntax would not be
matched.
This PR adds a feature where `structure` constructors can override the
inferred binder kinds of the type's parameters. In the following, the
`(p)` binder on `toLp` causes `p` to be an explicit parameter to
`WithLp.toLp`:
```lean
structure WithLp (p : Nat) (V : Type) where toLp (p) ::
ofLp : V
```
This reflects the syntax of the feature added in #7742 for overriding
binder kinds of structure projections. Similarly, only those parameters
in the header of the `structure` may be updated; it is an error to try
to update binder kinds of parameters included via `variable`.
Closes#9072.
Fixes a possible bug from stale caches when creating the type of the
constructor.
This PR resolves an issue where the `Meta.Context.configKey` field is
private but we still want to use the constructor of the structure for
setting other fields, which would be prevented by the module system
checks:
```lean
structure Context where
private config : Config := {}
private configKey : UInt64 := config.toKey
...
def ContextInfo.runMetaM (info : ContextInfo) (lctx : LocalContext) (x : MetaM α) : IO α := do
-- cannot call private constructor of `Meta.Context`!
(·.1) <$> info.runCoreM (x.run { lctx := lctx } { mctx := info.mctx })
```
Instead, the private field is extracted into an (existing) structure
that applies its default value:
```lean
/-- Configuration with key produced by `Config.toKey`. -/
structure ConfigWithKey where
private mk ::
config : Config := {}
key : UInt64 := config.toKey
structure Context where
keyedConfig : ConfigWithKey := default
```
Thus `Context`'s constructor remains public without exposing a way to
set `key` directly.
This PR fixes a kernel type mismatch that occurs when using `grind` on
goals containing non-standard `OfNat.ofNat` terms. For example, in issue
#9477, the `0` in the theorem `range_lower` has the form:
```lean
(@OfNat.ofNat
(Std.PRange.Bound (Std.PRange.RangeShape.lower (Std.PRange.RangeShape.mk Std.PRange.BoundShape.closed Std.PRange.BoundShape.open)) Nat)
(nat_lit 0)
(instOfNatNat (nat_lit 0)))
```
instead of the more standard form:
```lean
(@OfNat.ofNat
Nat
(nat_lit 0)
(instOfNatNat (nat_lit 0)))
```
Closes#9477
This PR improves the `evalInt?` function, which is used to evaluate
configuration parameters from the `ToInt` type class. This PR also adds
a new `evalNat?` function for handling the `IsCharP` type class, and
introduces a configuration option:
```
grind (exp := <num>)
```
This option controls the maximum exponent size considered during
expression evaluation. Previously, `evalInt?` used `whnf`, which could
run out of stack space when reducing terms such as `2^1024`.
closes#9427
This PR adds `binrel%` macros for `!=` and `≠` notation defined in
`Init.Core`. This allows the elaborator to insert coercions on both
sides of the relation, instead of committing to the type on the left
hand side.
I first discovered this bug while working on Brouwer's fixed point
theorem. See the discussion on Zulip at [#lean4 > Elaboration of
`≠` @
💬](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Elaboration.20of.20.60.E2.89.A0.60/near/526236907).
This PR replaces the proof of the simplification lemma `Nat.zero_mod`
with
`rfl` since it is, by design, a definitional equality. This solves an
issue
whereby the lemma could not be used by the simplifier when in 'dsimp'
mode.
Closes#9389
---------
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
This PR introduces tactic `mleave` that leaves the `SPred` proof mode by
eta expanding through its abstractions and applying some mild
simplifications. This is useful to apply automation such as `grind`
afterwards.
Relates to #9363.
This PR adds support in the `mintro` tactic for introducing `let`/`have`
binders in stateful targets, akin to `intro`. This is useful when
specifications introduce such let bindings.
Closes#9365.
This PR makes `PProdN.reduceProjs` also look for projection functions.
Previously, all redexes were created by the functions in `PProdN`, which
used primitive projections. But with `mkAdmProj` the projection
functions creep in via the types of the `admissible_pprod_fst` theorem.
So let's just reduce both of them.
Fixes#9462.
The `isRef` check being removed here used to be an optimization, because
this structure only tracked whether ref counting operations need to be
inserted at all. Now the structure also tracks whether the value needs
to be checked for being a scalar or not, which is something that can be
refined by a `cases` arm, since inductive types can have a mix of scalar
and non-scalar constructors.
This PR fixes an issue that caused some `deriving` handlers to fail when
the name of the type being declared matched that of a declaration in an
open namespace.
Closes#9366
This PR improves the 'Go to Definition' UX, specifically:
- Using 'Go to Definition' on a type class projection will now extract
the specific instances that were involved and provide them as locations
to jump to. For example, using 'Go to Definition' on the `toString` of
`toString 0` will yield results for `ToString.toString` and `ToString
Nat`.
- Using 'Go to Definition' on a macro that produces syntax with type
class projections will now also extract the specific instances that were
involved and provide them as locations to jump to. For example, using
'Go to Definition' on the `+` of `1 + 1` will yield results for
`HAdd.hAdd`, `HAdd α α α` and `Add Nat`.
- Using 'Go to Declaration' will now provide all the results of 'Go to
Definition' in addition to the elaborator and the parser that were
involved. For example, using 'Go to Declaration' on the `+` of `1 + 1`
will yield results for `HAdd.hAdd`, `HAdd α α α`, `Add Nat`,
``macro_rules | `($x + $y) => ...`` and `infixl:65 " + " => HAdd.hAdd`.
- Using 'Go to Type Definition' on a value with a type that contains
multiple constants will now provide 'Go to Definition' results for each
constant. For example, using 'Go to Type Definition' on `x` for `x :
Array Nat` will yield results for `Array` and `Nat`.
### Details
'Go to Definition' for type class projections was first implemented by
#1767, but there were still a couple of shortcomings with the
implementation. E.g. in order to jump to the instance in `toString 0`,
one had to add another space within the application and then use 'Go to
Definition' on that, or macros would block instances from being
displayed. Then, when the .ilean format was added, most 'Go to
Definition' requests were already handled using the .ileans in the
watchdog process, and so the file worker never received them to handle
them with the semantic information that it has available.
This PR resolves most of the issues with the previous implementation and
refactors the 'Go to Definition' control flow so that 'Go to Definition'
requests are always handled by the file worker, with the watchdog merely
using its .ilean position information to update the positions in the
response to a more up-to-date state. This is necessary because the file
worker obtains its position information from the .oleans, which need to
be rebuilt in order to be up-to-date, while the watchdog always receives
.ilean update notifications from each active file worker with the
current position information in the editor.
Finally, all of the 'Go to Definition' code is refactored to be easier
to maintain.
### Breaking changes
`InfoTree.hoverableInfoAt?` has been generalized to
`InfoTree.hoverableInfoAtM?` and now takes a general `filter` argument
instead of several boolean flags, as was the case before.
This PR removes uses of `Lean.RBMap` in Lean itself.
Furthermore some massaging of the import graph is done in order to avoid
having `Std.Data.TreeMap.AdditionalOperations` (which is quite
expensive) be the critical path for a large chunk of Lean. In particular
we can build `Lean.Meta.Simp` and `Lean.Meta.Grind` without it thanks to
these changes.
We did previously not conduct this change as `Std.TreeMap` was not
outperforming `Lean.RBMap` yet, however this has changed with the new
code generator.
This PR addresses the lean crash (stack overflow) with nested induction
and the generation of the `SizeOf` spec lemmas, reported at #9018.
It does not address the underlying issue that in these cases, the
generated SizeOf code does not match the the SizeOf function found by
instance search, and thus the generation fails.
This seem hard to fix: `mkSizeOfMinors` would have to recognize that
given, say, `List (Id Tree)`, the derived instance (assuming there was
one for `Tree`) is not the same as for `List Tree`.
The problem seems just about as hard as getting derived SizeOf right in
the presence of nested induction and non-canonical SizeOf instances.
This PR fixes the behavior of `String.prev`, aligning the runtime
implementation with the reference implementation. In particular, the
following statements hold now:
- `(s.prev p).byteIdx` is at least `p.byteIdx - 4` and at most
`p.byteIdx - 1`
- `s.prev 0 = 0`
- `s.prev` is monotone
Closes#9439
This PR adds the number of jobs run to the final message Lake produces
on a successfully run of `lake build`.
**Examples**
```
Build completed successfully (1 job).
Build completed successfully (6 jobs).
```
This PR adds the `libPrefixOnWindows` package and library configuration
option. When enabled, Lake will prefix static and shared libraries with
`lib` on Windows (i.e., the same way it does on Unix).
This PR changes the Lake local cache infrastructure to restore
executables and shared and static libraries from the cache. This means
they keep their expected names, which some use cases still rely on.
This PR adds a hint to the "invalid projection" message suggesting the
correct nested projection for expressions of the form `t.n` where `t` is
a tuple and `n > 2`.
This feature was originally proposed by @nomeata in #8986.
This PR improves the error messages produced by the `split` tactic,
including suggesting syntax fixes and related tactics with which it
might be confused.
Note that, to avoid clashing with the new error message styling
conventions used in these messages, this PR also updates the formatting
of the message produced by `throwTacticEx`.
Closes#6224
This PR changes `IRType.boxed` to map `erased` to `tobject` rather than
`object`, since `erased` has a representation of a boxed scalar 0 when
we are forced to represent it at runtime. This case does not occur at
all in the Lean codebase.
This PR updates the formatting of, and adds explanations for, "unknown
identifier" errors as well as "failed to infer type" errors for binders
and definitions.
It attempts to ameliorate some of the confusion encountered in #1592 by
modifying the wording of the "header is elaborated before body is
processed" note and adding further discussion and examples of this
behavior in the corresponding error explanation.
An earlier PR (#9017) replaced certain subarray functions such as
`Subarray.foldl` with generic slice functions `Slice.foldl`. For
backward compatibility reasons, This PR reintroduces `Subarray.foldl`
etc. as aliases for the `Slice` versions.
This PR adds Lake tests for builds involving the Lean module system and
fixes some bugs encountered in the process. In particular, it fixes the
parsing of private imports and how Lake handles the `import all` of a
private import.
This PR fixes some issues with the Lake tests on Windows and macOS. It
also avoids downloading Mathlib in the `init` test, which was currently
doing this after changes to the `math-lax` template in #8866.
To skip the Mathlib download in `init`, an undocumented `--offline`
option was added`. This option is currently meant for internal use only.
This PR increases the number of cases where `isArrowProposition` returns
a result other than `.undef`. This function is used to implement the
`isProof` predicate, which is invoked on every subterm visited by
`simp`.
This PR adds improves the "invalid named argument" error message in
function applications and match patterns by providing clickable hints
with valid argument names. In so doing, it also fixes an issue where
this error message would erroneously flag valid match-pattern argument
names.
This PR adds support for compilation of `casesOn` for subsingletons. We
rely on the elaborator's type checking to restrict this to inductives in
`Prop` that can actually eliminate into `Type n`. This does not yet
cover other recursors of these types (or of inductives not in `Prop` for
that matter).
This PR implements a simple optimization: dependent implications are no
longer treated as E-matching theorems in `grind`. In
`grind_bitvec2.lean`, this change saves around 3 seconds, as many
dependent implications are generated. Example:
```lean
∀ (h : i + 1 ≤ w), x.abs.getLsbD i = x.abs[i]
```
This PR adds a benchmark to our suite, specifically targeting the fact
that local hypotheses
are currently not indexed in simp and can thus cause significant
slowdowns compared to having them
as external declarations.
This PR splits up `Module.recBuildLean` into smaller functions and
optimizes the implementation of `Module.cacheOutputArtifacts` for the
new compiler. Now, all functions within `Lake.Build.Module` take Lean
<1s to compile.
This PR updates Lake to resolve the `.olean` files for transitive
imports for Lean through the `modules` field of `lean --setup`. This
enables means the Lean can now directly use the `.olean` files from the
Lake cache without needed to locate them at a specific hierarchical
path.
Resolving transitive imports still has a performance penalty, but it is
now much less.
This is mostly a refactoring that replaces other analyses with type
information, but due to the introduction of `tagged` it also has the
side effect of eliminating ref counting ops entirely for types that
always have a tagged scalar representation, e.g. `Unit`.
This PR fixes a bug at `mkCongrSimpCore?`. It fixes the issue reported
by @joehendrix at #9388.
The fix is just commit: afc4ba617f. The
rest of the PR is just cleaning up the file.
closes#9388
This PR fixes an unsafe trick where a sentinel for a hash table of Exprs
(keyed by pointer) is created by constructing a value whose runtime
representation can never be a valid Expr. The value chosen for this
purpose was Unit.unit, which violates the inference that Expr has no
scalar constructors. Instead, we change this to a freshly allocated Unit
× Unit value.
A micro-benchmark for plain, mostly first-order rewriting of simp:
This uses axiom to make it independent of specific optimization (e.g.
for `Nat`).
It generates a “list” of 128 `b`s followed by 128 `a` and uses
bubble-sort to to sort it and compares it against the expected output.
This PR changes the dependency cloning mechanism in lake so the log
message that lake is cloning a
dependency occurs before it is finished doing so (and instead before it
starts). This has been a
huge source of confusion for users that don't understand why lake seems
to be just stuck for no
reason when setting up a new project, the output now is:
```
λ lake +lean4 new math math
info: downloading mathlib `lean-toolchain` file
info: math: no previous manifest, creating one from scratch
info: leanprover-community/mathlib: cloning https://github.com/leanprover-community/mathlib4
<hang>
info: leanprover-community/mathlib: checking out revision 'cd11c28c6a0d514a41dd7be9a862a9c8815f8599'
```
This PR fixes a performance issue that occurs when generating equation
lemmas for functions that use match-expressions containing several
literals. This issue was exposed by #9322 and arises from a combination
of factors:
1. Literal values are compiled into a chain of dependent if-then-else
expressions.
2. Dependent if-then-else expressions are significantly more expensive
to simplify than regular ones.
3. The `split` tactic selects a target, splits it, and then invokes
`simp` on the resulting subgoals. Moreover, `simp` traverses the entire
goal bottom-up and does not stop after reaching the target.
This PR addresses the issue by introducing a custom simproc that avoids
recursively simplifying nested if-then-else expressions. It does **not**
alter the user-facing behavior of the `split` tactic because such a
change would be highly disruptive. Instead, the PR adds a new flag,
`backward.split` to control the behavior of the user-facing `split`
tactic. It is currently set to `true`, i.e., the old behavior is still
the default one. In a future PR, we should set this flag to `false` by
default and begin repairing all affected proofs.
closes#9322
This PR modifies the encoding from `Nat` to `Int` used in `grind
cutsat`. It is simpler, more extensible, and similar to the generic
`ToInt`. After update stage0, we will be able to delete the leftovers.
This PR correctly populates the `xType` field of the `IR.FnBody.case`
constructor. It turns out that there is no obvious consequence for this
being incorrect, because it is conservatively recomputed by the `Boxing`
pass.
This PR changes the implementation of `trace.Compiler.result` to use the
decls as they are provided rather than looking them up in the LCNF mono
environment extension, which was seemingly done to save the trouble of
re-normalizing fvar IDs before printing the decl. This means that the
`._closed` decls created by the `extractClosed` pass will now be
included in the output, which was definitely confusing before if you
didn't know what was happening.
This currently relies on the encoding pun of Nat.zero as the first
tagged constructor of Nat. Since Nat.succ is lowered to addition, it
makes sense to also lower Nat.zero to a zero literal. This might also
expose more optimization opportunities in the future.
This PR fixes IR constructor argument lowering to correctly handle an
irrelevant argument being passed for a relevant parameter in all cases.
This happened because constructor argument lowering (incompletely)
reimplemented general LCNF-to-IR argument lowering, and the fix is to
just adopt the generic helper functions. This is probably due to an
incomplete refactoring when the new compiler was still on a branch.
This PR uses the `mkCongrSimpForConst?` API in `simp` to reduce the
number of times the same congruence lemma is generated. Before this PR,
`grind` would spend `1.5`s creating congruence theorems during
normalization in the `grind_bitvec2.lean` benchmark. It now spends
`0.6`s. This PR should make an even bigger difference after we merge
#9300.
This PR removes the unnecessary requirement of `BEq α` for
`Array.any_push`, `Array.any_push'`, `Array.all_push`, `Array.all_push'`
as well as `Vector.any_push` and `Vector.all_push`.
This PR replaces the `reduceCtorEq` simproc used in `grind` by a much
more efficient one. The default one use in `simp` is just overhead
because the `grind` normalizer is already normalizing arithmetic.
In a separate PR, we will push performance improvements to the default
`reduceCtorEq`.
This PR fixes `toISO8601String` to produce a string that conforms to the
ISO 8601 format specification. The previous implementation separated the
minutes and seconds fragments with a `.` instead of a `:` and included
timezone offsets without the hour and minute fragments separated by a
`:`.
Closes#9235
This PR moves the implementation of `lean_add_extern`/`addExtern` from
C++ into Lean. I believe is the last C++ helper function from the
library/compiler directory being relied upon by the new compiler. I put
it into its own file and duplicated some code because this function
needs to execute in CoreM, whereas the other IR functions live in their
own monad stack. After the C++ compiler is removed, we can move the IR
functions into CoreM.
This PR optimizes support for `Decidable` instances in `grind`. Because
`Decidable` is a subsingleton, the canonicalizer no longer wastes time
normalizing such instances, a significant performance bottleneck in
benchmarks like `grind_bitvec2.lean`. In addition, the
congruence-closure module now handles `Decidable` instances, and can
solve examples such as:
```lean
example (p q : Prop) (h₁ : Decidable p) (h₂ : Decidable (p ∧ q)) : (p ↔ q) → h₁ ≍ h₂ := by
grind
```
This PR adds support for `.mdata` in LCNF mono types (and then drops it
at the IR type level instead). This better matches the behavior of
extern decls in the C++ code of the old compiler, which is still being
used to create extern decls at the moment and will soon be replaced.
This is covered by existing tests.
This PR fixes the bug that `collectAxioms` didn't collect axioms
referenced by other axioms. One of the results of this bug is that
axioms collected from a theorem proved by `native_decide` may not
include `Lean.trustCompiler`.
Closes#8840.
This PR demotes the builtin elaborators for `Std.Do.PostCond.total` and
`Std.Do.Triple` into macros, following the DefEq improvements of #9015.
Co-authored-by: Sebastian Graf <sg@lean-fro.org>
This PR makes `isDefEq` detect more stuck definitional equalities
involving smart unfoldings. Specifically, if `t =?= defn ?m` and `defn`
matches on its argument, then this equality is stuck on `?m`. Prior to
this change, we would not see this dependency and simply return `false`.
Fixes#8766.
Co-authored-by: Kyle Miller <kmill31415@gmail.com>
This PR improves the `congr` tactic so that it can handle function
applications with fewer arguments than the arity of the head function.
This also fixes a bug where `congr` could not make progress with
`Set`-valued functions in Mathlib, since `Set` was being unfolded and
making such functions have an apparently higher arity.
This addresses issue #2128 for the `congr` tactic, but not `simp` and
others.
This PR adds theorem `BitVec.clzAuxRec_eq_clzAuxRec_of_getLsbD_false` as
a more general statement than `BitVec.clzAuxRec_eq_clzAuxRec_of_le`,
replacing the latter in the bitblaster too.
This PR makes the logic and tactics of `Std.Do` universe polymorphic, at
the cost of a few definitional properties arising from the switch from
`Prop` to `ULift Prop` in the base case `SPred []`.
Co-authored-by: Sebastian Graf <sg@lean-fro.org>
This PR migrates usages of `Std.Range` to the new polymorphic ranges.
This PR unfortunately increases the transitive imports for
frequently-used parts of `Init` because the ranges now rely on iterators
in order to provide their functionality for types other than `Nat`.
However, iteration over ranges in compiled code is as efficient as
before in the examples I checked. This is because of a special
`IteratorLoop` implementation provided in the PR for this purpose.
There were two issues that were uncovered during migration:
* In `IndPredBelow.lean`, migrating the last remaining range causes
`compilerTest1.lean` to break. I have minimized the issue and came to
the conclusion it's a compiler bug. Therefore, I have not replaced said
old range usage yet (see #9186).
* In `BRecOn.lean`, we are publicly importing the ranges. Making this
import private should theoretically work, but there seems to be a
problem with the module system, causing the build to panic later in
`Init.Data.Grind.Poly` (see #9185).
* In `FuzzyMatching.lean`, inlining fails with the new ranges, which
would have led to significant slowdown. Therefore, I have not migrated
this file either.
This PR adds a benchmark for the rewriting engine of bv_decide, based on
a problem extracted from
SMT-LIB. Note that this problem has significant elaboration time itself
due to its sheer size though
the overall execution time is split approximately 50:50 between
elaboration and rewriting.
This PR improves the startup time for `grind ring` by generating the
required type classes on demand. This optimization is particularly
relevant for files that make hundreds of calls to `grind`, such as
`tests/lean/run/grind_bitvec2.lean`. For example, before this change,
`grind` spent 6.87 seconds synthesizing type classes, compared to 3.92
seconds after this PR.
We can probably remove `lcUnreachable` once we delete the old compiler,
but for now it makes more sense to move it earlier, since LCNF already
has `Code.unreachable`.
This PR changes the `toMono` pass to consider the type of an application
and erase all arguments corresponding to erased params. This enables a
lightweight form of relevance analysis by changing the mono type of a
decl. I would have liked to unify this with the behavior for
constructors, but my attempt to give constructors the same behavior in
#9222 (which was in preparation for this PR) had a minor performance
regression that is really incidental to the change. Still, I decided to
hold off on it for the time being. In the future, we can hopefully
extend this to constructors, extern decls, etc.
This PR removes code that has the false assumption that LCNF local vars
can occur in types. There are other comments in `ElimDead.lean`
asserting that this is not possible, so this must have been a change
early in the development of the new compiler.
This PR makes the LCNF `elimDeadBranches` pass handle unsafe decls a bit
more carefully. Now the result of an unsafe decl will only become ⊤ if
there is value flow from a recursive call.
These are used by the checker for `.ctor`, but I don't think that that
unboxed types will reuse `.ctor`, whose implementation details are
intimately connected to our runtime representation of objects.
This PR changes the `getLiteral` helper function of `elimDeadBranches`
to correctly handle inductives with constructors. This function is not
used as often as it could be, which makes this issue rare to hit outside
of targeted test cases.
This PR extends the `Eq` simproc used in `grind`. It covers more cases
now. It also adds 3 reducible declarations to the list of declarations
to unfold.
This PR implements `exists` normalization using a simproc instead of
rewriting rules in grind. This is the first part of the PR, after update
stage0, we must remove the normalization theorems.
This PR changes the compiler's specialization analysis to consider
higher-order params that are rebundled in a way that only changes their
`Prop` arguments to be fixed. This means that they get specialized with
a mere `@[specialize]`, rather than the compiler having to opt-in to
more aggressive parameter-specific specialization.
This PR implements `forall` normalization using a simproc instead of
rewriting rules in `grind`. This is the first part of the PR, after
update stage0, we must remove the normalization theorems.
This PR fixes stealing of `⇓` syntax by the new notation for total
postconditions by demoting it to non-builtin syntax and scoping it to
`Std.Do`.
Co-authored-by: Sebastian Graf <sg@lean-fro.org>
This PR tries to improve the E-matching pattern inference for `grind`.
That said, we still need better tools for annotating and maintaining
`grind` annotations in libraries.
closes#9125
This PR removes the `Subarray`-specific `toArray`, `foldlM` and `foldl`
methods and instead provides these operations on `Std.Slice`, which are
implemented with the `ToIterator` instance of the slice. Calling
`subarray.toArray` etc. still works, since `Subarray` is an abbreviation
for `Slice _`.
Because the benchmarks are not so clear, to be safe, I will merge this
only after the release. In contrast to the ranges, the iteration over
slices is not quite as efficient as the old `Subarray`-specific
implementation, which would require either more optimizations in the
iterator library (special `IteratorLoop` and `IteratorCollect`
implementations) or better unboxing support by the compiler.
This PR makes the `pullInstances` pass avoid pulling any instance
expressions containing erased propositions, because we don't correctly
represent the dependencies that remain after erasure.
This PR disables the use of the header produced by `lake setup-file` in
the server for now. It will be re-enabled once Lake takes into account
the header given by the server when processing workspace modules.
Without that, `setup-file` header can produce odd behavior when the file
on disk and in an editor disagree on whether the file participates in
the module system.
This PR fixes `undefined symbol: lean::mpz::divexact(lean::mpz const&,
lean::mpz const&)` when building without `LEAN_USE_GMP`
This fixes a regression in #8089
This PR makes `mvcgen` split ifs rather than applying specifications.
Doing so fixes a bug reported by Rish.
Co-authored-by: Sebastian Graf <sg@lean-fro.org>
This PR resolves a defeq diamond, which caused a problem in Mathlib:
```
import Mathlib
example (R : Type) [I : Ring R] :
@AddCommGroup.toGrindIntModule R (@Ring.toAddCommGroup R I) =
@Lean.Grind.Ring.instIntModule R (@Ring.toGrindRing R I) := rfl -- fails
```
This PR fixes two issues with Lake's process of creating static
archives.
Lake now always recreates static archives by first deleting any existing
one and then recreating it. `ar rcs` does not remove delete files, so
running it when the archive already exists can leave behind "ghost"
symbols of removed object files.
Second, Lake now use `T` rather than `--thin` to create thin archives.
While `--thin` is the recommended spelling, older versions of LLVM `ar`
do not support it. Thus, either choice produces tradeoffs. `T` is chosen
to make Lake consistent with the Lean core's own (Make) build scripts.
This PR enforces the non-inlining of _override impls in the base phase
of LCNF compilation. The current situation allows for constructor/cases
mismatches to be exposed to the simplifier, which triggers an assertion
failure. The reason this didn't show up sooner for Expr is that Expr has
a custom extern implementation of its computed field getter.
Fixes#9156.
This test was originally checked in for a panic in the pretty printer,
but at some point the output of every LCNF simp pass was added to
#guard_msgs output. Since this is printing LCNF built by the stage0
compiler, this causes a lot of unnecessary churn.
This PR changes the key Lake uses for the `,ir` artifact in the content
hash data structure to `r`, maintaining the convention of single
character key names.
This PR fixes the syntax of `grind` modifiers to use `patternIgnore` for
cases where both unicode and ascii variants are matched. This fixes an
issue where several variants of grind syntax weren't accepted (e.g.
`@[grind ← gen]`). Additionally, this reduces the chance that we get
another syntax matching bootstrap hell.
This PR wraps `simpLemma` and `grindLemma` in `ppGroup` to make sure
that the modifiers aren't printed separately from the term / identifier.
Example:
```
simp only [very_long_lemma_oh_no_can_you_please_stop_we're_getting_to_the_limit, ←
wait_this_is_rewritten_backwards_oh_uhh_where's_the_arrow_you_ask?_oh_wait_it's_up_there!]
==>
simp only [very_long_lemma_oh_no_can_you_please_stop_we're_getting_to_the_limit,
← wait_this_is_rewritten_backwards_and_wow_it's_very_clear_and_obvious]
```
This PR tightens the IR typing rules around applications of closures.
When re-reading some code, I realized that the code in `mkPartialApp`
has a clear typo—`.object` and `type` should be swapped. However, it
doesn't matter, because later IR passes smooth out the mismatch here. It
makes more sense to be strict up-front and require applications of
closures to always return an `.object`.
This PR removes a rather ugly hack in the module system, exposing the
bodies of theorems whose type mention `WellFounded`.
The original motivation was that reducing well-founded definitions (e.g.
in `by rfl`) requires reducing proofs, so they need to be available.
But reducing proofs is generally fraught with peril, and we have been
nudging our users away from using it for a while, e.g. in #5182. Since
the module system is opt-in and users will gradually migrate to it, it
may be reasonable to expect them to avoid reducing well-founded
recursion in the process
This way we don't need hacks like this (which, without evidence, I
believe would be incomplete anyways) and we get the nice guarantee that
within the module system, theorems bodies are always private.
This PR removes some unnecessary `Decidable*` instance arguments by
using lemmas in the `Classical` namespace instead of the `Decidable`
namespace.
This might lead to some additional dependency on classical axioms, but
large parts of the standard library are relying on them either way.
This PR ensures that the state is reverted when compilation using the
new compiler fails. This is especially important for noncomputable
sections where the compiler might generate half-compiled functions which
may then be erroneously used while compiling other functions.
This PR generalizes the `a^(m+n)` grind normalizer to any semirings.
Example:
```
variable [Field R]
example (M : R) (h₀ : M ≠ 0) {n : Nat} (hn : n > 0) : M ^ n / M = M ^ (n - 1) := by
cases n <;> grind
```
This PR adds support for representing more inductive as enums,
summarized up as extending support to those that fail to be enums
because of parameters or irrelevant fields. While this is nice to have,
it is actually motivated by correctness of a future desired
optimization. The existing type representation is unsound if we
implement `object`/`tobject` distinction between values guaranteed to be
an object pointer and those that may also be a tagged scalar. In
particular, types like the ones added in this PR's tests would have all
of their constructors encoded via tagged values, but under the natural
extension of the existing rules of type representation they would be
considered `object` rather than `tobject`.
This PR converts the `lowerEnumToScalarType?` cache to a cache of IR
types of named types. This is more sensible than just focusing on the
enum optimization, and due to uniform representation of polymorphism we
have to compile `Constant T1` and `Constant T2` to the same
representation.
Bumps
[dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
from 10 to 11.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dawidd6/action-download-artifact/releases">dawidd6/action-download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v11</h2>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v10...v11">https://github.com/dawidd6/action-download-artifact/compare/v10...v11</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ac66b43f0e"><code>ac66b43</code></a>
node_modules: upgrade</li>
<li><a
href="9b54a0a70c"><code>9b54a0a</code></a>
Update README.md</li>
<li>See full diff in <a
href="https://github.com/dawidd6/action-download-artifact/compare/v10...v11">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This PR changes ToIR to call `lowerEnumToScalarType?` with
`ConstructorVal.induct` rather than the name of the constructor itself.
This was an oversight in some refactoring of code in the new compiler
before landing it. It should not affect runtime of compiled code (due to
the extra tagging/untagging being optimized by LLVM), but it does make
IR for the interpreter slightly more efficient.
This PR fixes spacing in the `grind` attribute and tactic syntax.
Previously `@[grind]` was incorrectly pretty-printed as `@[grind ]`, and
`grind [...] on_failure ...` was pretty-printed `grind [...]on_failure
...`. Fixes that `on_failure` was reserved as keyword.
This PR moves the construction of the `Option.SomeLtNone.lt` (and `le`)
relation, in which `some` is less than `none`, to
`Init.Data.Option.Basic` and moves well-foundedness proofs for
`Option.lt` and `Option.SomeLtNone.lt` into `Init.Data.Option.Lemmas`.
This PR improves the “expected type mismatch” error message by omitting
the type's types when they are defeq, and putting them into separate
lines when not.
I found it rather tediuos to parse the error message when the expected
type is long, because I had to find the `:` in the middle of a large
expression somewhere. Also, when both are of sort `Prop` or `Type` it
doesn't add much value to print the sort (and it’s only one hover away
anyways).
This PR further improves release automation, automatically incorporating
material from `nightly-testing` and `bump/v4.X.0` branches in the bump
PRs to downstream repositories.
This PR adjusts the experimental module system to not import the IR of
non-`meta` declarations. It does this by replacing such IR with opaque
foreign declarations on export and adjusting the new compiler
accordingly.
This PR should not be merged before the new compiler.
Based on #8664.
This PR fixes a bug introduce by #9081 where the source file was dropped
from the module input trace and some entries were dropped from the
module job log.
This PR moves the constructor layout code from C++ to Lean. When
writing the new compiler, we just reused the existing C++ code,
even though it was a bit inconvenient, because we wanted to
ensure that constructor layout always matched the existing
compiler.
This fixes#2589 by handling struct field types just like any
other type being lowered, and thus applying the trivial structure
optimization in the process. Originally, I wanted to port the
code to Lean without any functional changes, but I found that
it took less code to just implement it "correctly" and get this
fix as a consequence than to emulate the bugs of the existing
C++ implementation.
This PR ensures that `mspec` uses the configured transparency setting
and makes `mvcgen` use default transparency when calling `mspec`.
Co-authored-by: Sebastian Graf <sg@lean-fro.org>
make -C build/release -j "$(nproc)"testARGS=-R testname'
```
## Testing stage 2
When requested to test stage 2, build it as follows:
```
make -C build/release stage2 -j$(nproc)
```
Stage 2 is *not* automatically invalidated by changes to `src/` which allows for faster iteration
when fixing a specific file in the stage 2 build but for invalidating any files that already passed
the stage 2 build as well as for final validation,
```
make -C build/release/stage2 clean-stdlib
```
must be run manually before building.
## New features
When asked to implement new features:
* begin by reviewing existing relevant code and tests
* write comprehensive tests first (expecting that these will initially fail)
* and then iterate on the implementation until the tests pass.
## Success Criteria
*Never* report success on a task unless you have verified both a clean build without errors, and that the relevant tests pass.
## Build System Safety
**NEVER manually delete build directories** (build/, stage0/, stage1/, etc.) even when builds fail.
- ONLY use the project's documented build command: `make -j$(nproc) -C build/release`
- If a build is broken, ask the user before attempting any manual cleanup
## stage0 Is a Copy of src
**Never manually edit files under `stage0/`.** The `stage0/` directory is a snapshot of `src/` produced by `make update-stage0`. To change anything in stage0 (CMakeLists.txt, C++ source, etc.), edit the corresponding file in `src/` and let `update-stage0` propagate it.
## LSP and IDE Diagnostics
After rebuilding, LSP diagnostics may be stale until the user interacts with files. Trust command-line test results over IDE diagnostics.
## Update prompting when the user is frustrated
If the user expresses frustration with you, stop and ask them to help update this `.claude/CLAUDE.md` file with missing guidance.
## Creating pull requests
Follow the commit convention in `doc/dev/commit_convention.md`.
**Title format:**`<type>: <subject>` where type is one of: `feat`, `fix`, `doc`, `style`, `refactor`, `test`, `chore`, `perf`.
Subject should use imperative present tense ("add" not "added"), no capitalization, no trailing period.
**Body format:** The first paragraph must start with "This PR". This paragraph is automatically incorporated into release notes. Use imperative present tense. Include motivation and contrast with previous behavior when relevant. Do NOT use markdown headings (`## Summary`, `## Test plan`, etc.) in PR bodies.
Example:
```
feat: add optional binder limit to `mkPatternFromTheorem`
This PR adds a `num?` parameter to `mkPatternFromTheorem` to control how many
leading quantifiers are stripped when creating a pattern.
```
**Changelog labels:** Add one `changelog-*` label to categorize the PR for release notes:
-`changelog-language` - Language features and metaprograms
-`changelog-tactics` - User facing tactics
-`changelog-server` - Language server, widgets, and IDE extensions
-`changelog-pp` - Pretty printing
-`changelog-library` - Library
-`changelog-compiler` - Compiler, runtime, and FFI
-`changelog-lake` - Lake
-`changelog-doc` - Documentation
-`changelog-ffi` - FFI changes
-`changelog-other` - Other changes
-`changelog-no` - Do not include this PR in the release changelog
If you're unsure which label applies, it's fine to omit the label and let reviewers add it.
## Module System for `src/` Files
Files in `src/Lean/`, `src/Std/`, and `src/lake/Lake/` must have both `module` and `prelude` (CI enforces `^prelude$` on its own line). With `prelude`, nothing is auto-imported — you must explicitly import `Init.*` modules for standard library features. Check existing files in the same directory for the pattern, e.g.:
```lean
module
prelude
importInit.While-- needed for while/repeat
importInit.Data.String.TakeDrop-- needed for String.startsWith
publicimportLean.Compiler.NameMangling-- public if types are used in public signatures
```
Files outside these directories (e.g. `tests/`, `script/`) use just `module`.
## CI Log Retrieval
When CI jobs fail, investigate immediately - don't wait for other jobs to complete. Individual job logs are often available even while other jobs are still running. Try `gh run view <run-id> --log` or `gh run view <run-id> --log-failed`, or use `gh run view <run-id> --job=<job-id>` to target the specific failed job. Sleeping is fine when asked to monitor CI and no failures exist yet, but once any job fails, investigate that failure immediately.
## Copyright Headers
New files require a copyright header. To get the year right, always run `date +%Y` rather than relying on memory. The copyright holder should be the author or their current employer — check other recent files by the same author in the repository to determine the correct entity (e.g., "Lean FRO, LLC", "Amazon.com, Inc. or its affiliates").
Test files (in `tests/`) do not need copyright headers.
For subsequent RCs (`-rc2`, etc.) and stable releases, just update the version number in the existing release notes file title.
See `doc/dev/release_checklist.md` section "Writing the release notes" for full details.
## Process
1. Run `script/release_checklist.py {version}` to check the current status
2. **CRITICAL: If preliminary lean4 checks fail, STOP immediately and alert the user**
- Check for: release branch exists, CMake version correct, tag exists, release page exists, release notes file exists
- **IMPORTANT**: The release page is created AUTOMATICALLY by CI after pushing the tag - DO NOT create it manually
- **IMPORTANT**: For -rc1 releases, release notes must be created before proceeding
- Do NOT create any PRs or proceed with repository updates if these checks fail
3. Create a todo list tracking all repositories that need updates
4. **CRITICAL RULE: You can ONLY run `release_steps.py` for a repository if `release_checklist.py` explicitly says to do so**
- The checklist output will say "Run `script/release_steps.py {version} {repo_name}` to create it"
- If a repository shows "🟡 Dependencies not ready", you CANNOT create a PR for it yet
- You MUST rerun `release_checklist.py` before attempting to create PRs for any new repositories
5. For each repository that the checklist says needs updating:
- Run `script/release_steps.py {version} {repo_name}` to create the PR
- Mark it complete when the PR is created
6. After creating PRs, notify the user which PRs need review and merging
7. **MANDATORY: Rerun `release_checklist.py` to check current status**
- Do this after creating each batch of PRs
- Do this after the user reports PRs have been merged
- NEVER assume a repository is ready without checking the checklist output
8. As PRs are merged and tagged, dependent repositories will become ready
9. Continue the cycle: run checklist → create PRs for ready repos → wait for merges → repeat
10. Continue until all repositories are updated and the release is complete
## Important Notes
- **NEVER merge PRs autonomously** - always wait for the user to merge PRs themselves
- The `release_steps.py` script is idempotent - it's safe to rerun
- The `release_checklist.py` script is idempotent - it's safe to rerun
- Some repositories depend on others (e.g., mathlib4 depends on batteries, aesop, etc.)
- Wait for user to merge PRs before dependent repos can be updated
- Alert user if anything unusual or scary happens
- Use appropriate timeouts for long-running builds (verso can take 10+ minutes)
- ProofWidgets4 uses semantic versioning (v0.0.X) - it's okay to create and push the next sequential tag yourself when needed for a release
## PR Status Reporting
Every time you run `release_checklist.py`, you MUST:
1. Parse the output to identify ALL open PRs mentioned (lines with "✅ PR with title ... exists")
2. Provide a summary to the user listing ALL open PRs that need review
3. Group them by status:
- PRs for repositories that are blocked by dependencies (show these but note they're blocked)
- PRs for repositories that are ready to merge (highlight these)
4. Format the summary clearly with PR numbers and URLs
This summary should be provided EVERY time you run the checklist, not just after creating new PRs.
The user needs to see the complete picture of what's waiting for review.
## Checking PR Status When Asked
When the user asks for "status" or you need to report on PRs between checklist runs:
- **ALWAYS check actual PR state** using `gh pr view <number> --repo <repo> --json state,mergedAt`
- Do NOT rely on cached CI results or previous checklist output
- The user may have merged PRs since your last check
- Report which PRs are MERGED, which are OPEN with CI status, and which are still pending
- After discovering merged PRs, rerun `release_checklist.py` to advance the release process
## Nightly Infrastructure
The nightly build system uses branches and tags across two repositories:
- `leanprover/lean4` has **branches** `nightly` and `nightly-with-mathlib` tracking the latest nightly builds
- `leanprover/lean4-nightly` has **dated tags** like `nightly-2026-01-23`
When a nightly succeeds with mathlib, all three should point to the same commit. Don't confuse these: branches are in the main lean4 repo, dated tags are in lean4-nightly.
## CI Failures: Investigate Immediately
**CRITICAL: If the checklist reports `❌ CI: X check(s) failing` for any PR, investigate immediately.**
Do NOT:
- Report it as "CI in progress" or "some checks pending"
- Wait for the remaining checks to finish before investigating
- Assume it's a transient failure without checking
DO:
1. Run `gh pr checks <number> --repo <owner>/<repo>` to see which specific check failed
2. Run `gh run view <run-id> --repo <owner>/<repo> --log-failed` to see the failure output
3. Diagnose the failure and report clearly to the user: what failed and why
4. Propose a fix if one is obvious (e.g., subverso version mismatch, transient elan install error)
The checklist now distinguishes `❌ X check(s) failing, Y still in progress` from `🔄 Y check(s) in progress`.
Any `❌` in CI status requires immediate investigation — do not move on.
## Waiting for CI or Merges
Use `gh pr checks --watch` to block until a PR's CI checks complete (no polling needed).
Run these as background bash commands so you get notified when they finish:
description: Profile Lean programs with demangled names using samply and Firefox Profiler. Use when the user asks to profile a Lean binary or investigate performance.
Requires `samply` (`cargo install samply`) and `python3`.
## Agent Notes
- The pipeline is interactive (serves to browser at the end). When running non-interactively, run the steps manually instead of using the wrapper script.
- The three steps are: `samply record --save-only`, `symbolicate_profile.py`, then `serve_profile.py`.
-`lean_demangle.py` works standalone as a stdin filter (like `c++filt`) for quick name lookups.
- The `--raw` flag on `lean_demangle.py` gives exact demangled names without postprocessing (keeps `._redArg`, `._lam_0` suffixes as-is).
- Use `PROFILE_KEEP=1` to keep the temp directory for later inspection.
- The demangled profile is a standard Firefox Profiler JSON. Function names live in `threads[i].stringArray`, indexed by `threads[i].funcTable.name`.
description: Extract Zulip thread HTML dumps into readable plain text. Use when the user provides a Zulip HTML file or asks to parse/read/convert/summarize a Zulip thread.
---
# Zulip Thread Extractor
Run the bundled script to convert a Zulip HTML page dump into plain text.
echo "... and Batteries has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
if [[ -n "$MATHLIB_REMOTE_TAGS" ]]; then
echo "... and Mathlib has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE=""
if [[ -n "$MATHLIB_REMOTE_TAGS" ]]; then
echo "... and Mathlib has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
else
echo "... but Mathlib does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE="- ❗ Mathlib CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Mathlib CI should run now."
fi
else
echo "... but Batteries does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE="- ❗ Batteries CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Batteries CI should run now."
echo "... but Mathlib does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE="- ❗ Mathlib CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Mathlib CI should run now."
fi
else
echo "The most recently nightly tag on this branch has SHA: $NIGHTLY_SHA"
@@ -195,12 +216,13 @@ jobs:
if [[ -n "$MESSAGE" ]]; then
# Check if force-mathlib-ci label is present
# Use GITHUB_TOKEN for read-only label fetch (MATHLIB4_COMMENT_BOT is only for posting comments)
Since version 4, Lean is a partially bootstrapped program: most parts of the
Lean is a bootstrapped program: the
frontend and compiler are written in Lean itself and thus need to be built before
building Lean itself - which is needed to again build those parts. This cycle is
broken by using pre-built C files checked into the repository (which ultimately
go back to a point where the Lean compiler was not written in Lean) in place of
these Lean inputs and then compiling everything in multiple stages up to a fixed
point. The build directory is organized in these stages:
point. The build directory is organized into these stages:
```bash
stage0/
@@ -72,6 +72,14 @@ update the archived C source code of the stage 0 compiler in `stage0/src`.
The github repository will automatically update stage0 on `master` once
`src/stdlib_flags.h` and `stage0/src/stdlib_flags.h` are out of sync.
To trigger this, modify `stage0/src/stdlib_flags.h` (e.g., by adding or changing
a comment). When `update-stage0` runs, it will overwrite `stage0/src/stdlib_flags.h`
with the contents of `src/stdlib_flags.h`, bringing them back in sync.
NOTE: A full rebuild of stage 1 will only be triggered when the *committed* contents of `stage0/` are changed.
Thus if you change files in it manually instead of through `update-stage0-commit` (see below) or fetching updates from git, you either need to commit those changes first or run `make -C build/release clean-stdlib`.
The same is true for further stages except that a rebuild of them is retriggered on any committed change, not just to a specific directory.
Thus when debugging e.g. stage 2 failures, you can resume the build from these failures on but you may want to explicitly call `clean-stdlib` to either observe changes from `.olean` files of modules that built successfully or to check that you did not break modules that built successfully at some prior point.
If you have write access to the lean4 repository, you can also manually
trigger that process, for example to be able to use new features in the compiler itself.
@@ -82,18 +90,18 @@ gh workflow run update-stage0.yml
```
Leaving stage0 updates to the CI automation is preferable, but should you need
to do it locally, you can use `make update-stage0-commit` in `build/release` to
update `stage0` from `stage1` or `make -C stageN update-stage0-commit` to
to do it locally, you can use `make -C build/release update-stage0-commit` to
update `stage0` from `stage1` or `make -C build/release/stageN update-stage0-commit` to
update from another stage. This command will automatically stage the updated files
and introduce a commit,so make sure to commit your work before that.
and introduce a commit,so make sure to commit your work before that.
If you rebased the branch (either onto a newer version of `master`, or fixing
up some commits prior to the stage0 update, recreate the stage0 update commits.
up some commits prior to the stage0 update), recreate the stage0 update commits.
The script `script/rebase-stage0.sh` can be used for that.
The CI should prevent PRs with changes to stage0 (besides `stdlib_flags.h`)
from entering `master` through the (squashing!) merge queue, and label such PRs
with the `changes-stage0` label. Such PRs should have a cleanedup history,
with the `changes-stage0` label. Such PRs should have a cleaned-up history,
with separate stage0 update commits; then coordinate with the admins to merge
your PR using rebase merge, bypassing the merge queue.
NOTE: The current interface was designed for internal use in Lean and should be considered **unstable**.
It will be refined and extended in the future.
The Lean FFI documentation is now part of the [Lean language reference](https://lean-lang.org/doc/reference/latest/).
As Lean is written partially in Lean itself and partially in C++, it offers efficient interoperability between the two languages (or rather, between Lean and any language supporting C interfaces).
This support is however currently limited to transferring Lean data types; in particular, it is not possible yet to pass or return compound data structures such as C `struct`s by value from or to Lean.
There are two primary attributes for interoperating with other languages:
*`@[extern "sym"] constant leanSym : ...` binds a Lean declaration to the external symbol `sym`.
It can also be used with `def` to provide an internal definition, but ensuring consistency of both definitions is up to the user.
*`@[export sym] def leanSym : ...` exports `leanSym` under the unmangled symbol name `sym`.
For simple examples of how to call foreign code from Lean and vice versa, see <https://github.com/leanprover/lean4/blob/master/src/lake/examples/ffi> and <https://github.com/leanprover/lean4/blob/master/src/lake/examples/reverse-ffi>, respectively.
## The Lean ABI
The Lean Application Binary Interface (ABI) describes how the signature of a Lean declaration is encoded as a native calling convention.
It is based on the standard C ABI and calling convention of the target platform.
For a Lean declaration marked with either `@[extern "sym"]` or `@[export sym]` for some symbol name `sym`, let `α₁ → ... → αₙ → β` be the normalized declaration's type.
If `n` is 0, the corresponding C declaration is
```c
externssym;
```
where `s` is the C translation of `β` as specified in the next section.
In the case of an `@[extern]` definition, the symbol's value is guaranteed to be initialized only after calling the Lean module's initializer or that of an importing module; see [Initialization](#initialization).
If `n` is greater than 0, the corresponding C declaration is
```c
ssym(t₁,...,tₘ);
```
where the parameter types `tᵢ` are the C translation of the `αᵢ` as in the next section.
In the case of `@[extern]` all *irrelevant* types are removed first; see next section.
### Translating Types from Lean to C
* The integer types `UInt8`, ..., `UInt64`, `USize` are represented by the C types `uint8_t`, ..., `uint64_t`, `size_t`, respectively
*`Char` is represented by `uint32_t`
*`Float` is represented by `double`
* An *enum* inductive type of at least 2 and at most 2^32 constructors, each of which with no parameters, is represented by the first type of `uint8_t`, `uint16_t`, `uint32_t` that is sufficient to represent all constructor indices.
For example, the type `Bool` is represented as `uint8_t` with values `0` for `false` and `1` for `true`.
*`Decidable α` is represented the same way as `Bool`
* An inductive type with a *trivial structure*, that is,
* it is none of the types described above
* it is not marked `unsafe`
* it has a single constructor with a single parameter of *relevant* type
is represented by the representation of that parameter's type.
For example, `{ x : α // p }`, the `Subtype` structure of a value of type `α` and an irrelevant proof, is represented by the representation of `α`.
Similarly, the signed integer types `Int8`, ..., `Int64`, `ISize` are also represented by the unsigned C types `uint8_t`, ..., `uint64_t`, `size_t`, respectively, because they have a trivial structure.
* `Nat` and `Int` are represented by `lean_object *`.
Their runtime values is either a pointer to an opaque bignum object or, if the lowest bit of the "pointer" is 1 (`lean_is_scalar`), an encoded unboxed natural number or integer (`lean_box`/`lean_unbox`).
* A universe `Sort u`, type constructor `... → Sort u`, or proposition `p : Prop` is *irrelevant* and is either statically erased (see above) or represented as a `lean_object *` with the runtime value `lean_box(0)`
* Any other type is represented by `lean_object *`.
Its runtime value is a pointer to an object of a subtype of `lean_object` (see the "Inductive types" section below) or the unboxed value `lean_box(cidx)` for the `cidx`th constructor of an inductive type if this constructor does not have any relevant parameters.
Example: the runtime value of `u : Unit` is always `lean_box(0)`.
#### Inductive types
For inductive types which are in the fallback `lean_object *` case above and not trivial constructors, the type is stored as a `lean_ctor_object`, and `lean_is_ctor` will return true. A `lean_ctor_object` stores the constructor index in the header, and the fields are stored in the `m_objs` portion of the object.
The memory order of the fields is derived from the types and order of the fields in the declaration. They are ordered as follows:
* Non-scalar fields stored as `lean_object *`
* Fields of type `USize`
* Other scalar fields, in decreasing order by size
Within each group the fields are ordered in declaration order. **Warning**: Trivial wrapper types still count toward a field being treated as non-scalar for this purpose.
* To access fields of the first kind, use `lean_ctor_get(val, i)` to get the `i`th non-scalar field.
* To access `USize` fields, use `lean_ctor_get_usize(val, n+i)` to get the `i`th usize field and `n` is the total number of fields of the first kind.
* To access other scalar fields, use `lean_ctor_get_uintN(val, off)` or `lean_ctor_get_usize(val, off)` as appropriate. Here `off` is the byte offset of the field in the structure, starting at `n*sizeof(void*)` where `n` is the number of fields of the first two kinds.
For example, a structure such as
```lean
structure S where
ptr_1 : Array Nat
usize_1 : USize
sc64_1 : UInt64
ptr_2 : { x : UInt64 // x > 0 } -- wrappers don't count as scalars
sc64_2 : Float -- `Float` is 64 bit
sc8_1 : Bool
sc16_1 : UInt16
sc8_2 : UInt8
sc64_3 : UInt64
usize_2 : USize
ptr_3 : Char -- trivial wrapper around `UInt32`
sc32_1 : UInt32
sc16_2 : UInt16
```
would get re-sorted into the following memory order:
By default, all `lean_object *` parameters of an `@[extern]` function are considered *owned*, i.e. the external code is passed a "virtual RC token" and is responsible for passing this token along to another consuming function (exactly once) or freeing it via `lean_dec`.
To reduce reference counting overhead, parameters can be marked as *borrowed* by prefixing their type with `@&`.
Borrowed objects must only be passed to other non-consuming functions (arbitrarily often) or converted to owned values using `lean_inc`.
In `lean.h`, the `lean_object *` aliases `lean_obj_arg` and `b_lean_obj_arg` are used to mark this difference on the C side.
Return values and `@[export]` parameters are always owned at the moment.
## Initialization
When including Lean code as part of a larger program, modules must be *initialized* before accessing any of their declarations.
Module initialization entails
* initialization of all "constants" (nullary functions), including closed terms lifted out of other functions
* execution of all `[init]` functions
* execution of all `[builtin_init]` functions, if the `builtin` parameter of the module initializer has been set
The module initializer is automatically run with the `builtin` flag for executables compiled from Lean code and for "plugins" loaded with `lean --plugin`.
For all other modules imported by `lean`, the initializer is run without `builtin`.
Thus `[init]` functions are run iff their module is imported, regardless of whether they have native code available or not, while `[builtin_init]` functions are only run for native executable or plugins, regardless of whether their module is imported or not.
`lean` uses built-in initializers for e.g. registering basic parsers that should be available even without importing their module (which is necessary for bootstrapping).
The initializer for module `A.B` is called `initialize_A_B` and will automatically initialize any imported modules.
Module initializers are idempotent (when run with the same `builtin` flag), but not thread-safe.
**Important for process-related functionality**: If your application needs to use process-related functions from libuv, such as `Std.Internal.IO.Process.getProcessTitle` and `Std.Internal.IO.Process.setProcessTitle`, you must call `lean_setup_args(argc, argv)` (which returns a potentially modified `argv` that must be used in place of the original) **before** calling `lean_initialize()` or `lean_initialize_runtime_module()`. This sets up process handling capabilities correctly, which is essential for certain system-level operations that Lean's runtime may depend on.
Together with initialization of the Lean runtime, you should execute code like the following exactly once before accessing any Lean declarations:
argv = lean_setup_args(argc, argv); // if using process-related functionality
lean_initialize_runtime_module();
//lean_initialize(); // necessary (and replaces `lean_initialize_runtime_module`) if you (indirectly) access the `Lean` package
lean_object * res;
// use same default as for Lean executables
uint8_t builtin = 1;
res = initialize_A_B(builtin, lean_io_mk_world());
if (lean_io_result_is_ok(res)) {
lean_dec_ref(res);
} else {
lean_io_result_show_error(res);
lean_dec(res);
return ...; // do not access Lean declarations if initialization failed
}
res = initialize_C(builtin, lean_io_mk_world());
if (lean_io_result_is_ok(res)) {
...
//lean_init_task_manager(); // necessary if you (indirectly) use `Task`
lean_io_mark_end_initialization();
```
In addition, any other thread not spawned by the Lean runtime itself must be initialized for Lean use by calling
```c
void lean_initialize_thread();
```
and should be finalized in order to free all thread-local resources by calling
```c
void lean_finalize_thread();
```
## `@[extern]` in the Interpreter
The interpreter can run Lean declarations for which symbols are available in loaded shared libraries, which includes `@[extern]` declarations.
Thus to e.g. run `#eval` on such a declaration, you need to
1. compile (at least) the module containing the declaration and its dependencies into a shared library, and then
1. pass this library to `lean --load-dynlib=` to run code `import`ing this module.
Note that it is not sufficient to load the foreign library containing the external symbol because the interpreter depends on code that is emitted for each `@[extern]` declaration.
Thus it is not possible to interpret an `@[extern]` declaration in the same file.
See [`tests/compiler/foreign`](https://github.com/leanprover/lean4/tree/master/tests/compiler/foreign/) for an example.
If you want to make changes to Lean itself, start by [building Lean](../make/index.md) from a clean checkout to make sure that everything is set up correctly.
After that, read on below to find out how to set up your editor for changing the Lean source code, followed by further sections of the development manual where applicable such as on the [test suite](testing.md) and [commit convention](commit_convention.md).
After that, read on below to find out how to set up your editor for changing the Lean source code,
followed by further sections of the development manual where applicable
such as on the [test suite](../../tests/README.md) and [commit convention](commit_convention.md).
If you are planning to make any changes that may affect the compilation of Lean itself, e.g. changes to the parser, elaborator, or compiler, you should first read about the [bootstrapping pipeline](bootstrap.md).
You should not edit the `stage0` directory except using the commands described in that section when necessary.
## Development Setup
You can use any of the [supported editors](../setup.md) for editing the Lean source code.
If you set up `elan` as below, opening `src/` as a *workspace folder* should ensure that stage 0 (i.e. the stage that first compiles `src/`) will be used for files in that directory.
You can use any of the [supported editors](https://lean-lang.org/install/manual/) for editing the Lean source code.
Please see below for specific instructions for VS Code.
### Dev setup using elan
@@ -61,13 +63,17 @@ you can then put `my_name/lean4:my-tag` in your `lean-toolchain` file in a proje
### VS Code
There is a `lean.code-workspace` file that correctly sets up VS Code with workspace roots for the stage0/stage1 setup described above as well as with other settings.
You should always load it when working on Lean, such as by invoking
There is a `.vscode/` directory that correctly sets up VS Code with settings, tasks, and recommended extensions.
Simply open the repository folder in VS Code, such as by invoking
```
code lean.code-workspace
code .
```
on the command line.
You can use the `Refresh File Dependencies` command as in other projects to rebuild modules from inside VS Code but be aware that this does not trigger any non-Lake build targets.
In particular, after updating `stage0/` (or fetching an update to it), you will want to invoke `make` directly to rebuild `stage0/bin/lean` as described in [building Lean](../make/index.md).
You should then run the `Restart Server` command to update all open files and the server watchdog process as well.
### `ccache`
Lean's build process uses [`ccache`](https://ccache.dev/) if it is
@@ -95,3 +101,19 @@ on to `nightly-with-manual` branch. (It is fine to force push after rebasing.)
CI will generate a branch of the reference manual called `lean-pr-testing-NNNN`
in `leanprover/reference-manual`. This branch uses the toolchain for your PR,
and will report back to the Lean PR with results from Mathlib CI.
### Avoiding rebuilds for downstream projects
If you want to test changes to Lean on downstream projects and would like to avoid rebuilding modules you have already built/fetched using the project's configured Lean toolchain, you can often do so as long as your build of Lean is close enough to that Lean toolchain (compatible .olean format including structure of all relevant environment extensions).
To override the toolchain without rebuilding for a single command, for example `lake build` or `lake lean`, you can use the prefix
```
LEAN_GITHASH=$(lean --githash) lake +lean4 ...
```
Alternatively, use
```
export LEAN_GITHASH=$(lean --githash)
export ELAN_TOOLCHAIN=lean4
```
to persist these changes for the lifetime of the current shell, which will affect any processes spawned from it such as VS Code started via `code .`.
If you use a setup where you cannot directly start your editor from the command line, such as VS Code Remote, you might want to consider using [direnv](https://direnv.net/) together with an editor extension for it instead so that you can put the lines above into `.envrc`.
After [building Lean](../make/index.md) you can run all the tests using
```
cd build/release
make test ARGS=-j4
```
Change the 4 to the maximum number of parallel tests you want to
allow. The best choice is the number of CPU cores on your machine as
the tests are mostly CPU bound. You can find the number of processors
on linux using `nproc` and on Windows it is the `NUMBER_OF_PROCESSORS`
environment variable.
You can run tests after [building a specific stage](bootstrap.md) by
adding the `-C stageN` argument. The default when run as above is stage 1. The
Lean tests will automatically use that stage's corresponding Lean
executables
Running `make test` will not pick up new test files; run
```bash
cmake build/release/stage1
```
to update the list of tests.
You can also use `ctest` directly if you are in the right folder. So
to run stage1 tests with a 300 second timeout run this:
```bash
cd build/release/stage1
ctest -j 4 --output-on-failure --timeout 300
```
Useful `ctest` flags are `-R <name of test>` to run a single test, and
`--rerun-failed` to run all tests that failed during the last run.
You can also pass `ctest` flags via `make test ARGS="--rerun-failed"`.
To get verbose output from ctest pass the `--verbose` command line
option. Test output is normally suppressed and only summary
information is displayed. This option will show all test output.
## Test Suite Organization
All these tests are included by [src/shell/CMakeLists.txt](https://github.com/leanprover/lean4/blob/master/src/shell/CMakeLists.txt):
- [`tests/lean`](https://github.com/leanprover/lean4/tree/master/tests/lean/): contains tests that come equipped with a
.lean.expected.out file. The driver script [`test_single.sh`](https://github.com/leanprover/lean4/tree/master/tests/lean/test_single.sh) runs
each test and checks the actual output (*.produced.out) with the
checked in expected output.
- [`tests/lean/run`](https://github.com/leanprover/lean4/tree/master/tests/lean/run/): contains tests that are run through the lean
command line one file at a time. These tests only look for error
codes and do not check the expected output even though output is
produced, it is ignored.
- [`tests/lean/interactive`](https://github.com/leanprover/lean4/tree/master/tests/lean/interactive/): are designed to test server requests at a
given position in the input file. Each .lean file contains comments
that indicate how to simulate a client request at that position.
using a `--^` point to the line position. Example:
```lean,ignore
open Foo in
theorem tst2 (h : a ≤ b) : a + 2 ≤ b + 2 :=
Bla.
--^ textDocument/completion
```
In this example, the test driver [`test_single.sh`](https://github.com/leanprover/lean4/tree/master/tests/lean/interactive/test_single.sh) will simulate an
auto-completion request at `Bla.`. The expected output is stored in
a .lean.expected.out in the json format that is part of the
- [`tests/plugin`](https://github.com/leanprover/lean4/tree/master/tests/plugin/): tests that compiled Lean code can be loaded into
`lean` via the `--plugin` command line option.
## Writing Good Tests
Every test file should contain:
* an initial `/-! -/` module docstring summarizing the test's purpose
* a module docstring for each test section that describes what is tested
and, if not 100% clear, why that is the desirable behavior
At the time of writing, most tests do not follow these new guidelines yet.
For an example of a conforming test, see [`tests/lean/1971.lean`](https://github.com/leanprover/lean4/tree/master/tests/lean/1971.lean).
## Fixing Tests
When the Lean source code or the standard library are modified, some of the
tests break because the produced output is slightly different, and we have
to reflect the changes in the `.lean.expected.out` files.
We should not blindly copy the new produced output since we may accidentally
miss a bug introduced by recent changes.
The test suite contains commands that allow us to see what changed in a convenient way.
First, we must install [meld](http://meldmerge.org/). On Ubuntu, we can do it by simply executing
```
sudo apt-get install meld
```
Now, suppose `bad_class.lean` test is broken. We can see the problem by going to [`tests/lean`](https://github.com/leanprover/lean4/tree/master/tests/lean) directory and
executing
```
./test_single.sh -i bad_class.lean
```
When the `-i` option is provided, `meld` is automatically invoked
whenever there is discrepancy between the produced and expected
outputs. `meld` can also be used to repair the problems.
In Emacs, we can also execute `M-x lean4-diff-test-file` to check/diff the file of the current buffer.
To mass-copy all `.produced.out` files to the respective `.expected.out` file, use `tests/lean/copy-produced`.
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](../dev/index.md).
We strongly suggest that new users instead follow the [Quickstart](../quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
We strongly suggest that new users instead follow the [Installation Instructions](https://lean-lang.org/install/) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
renderedStatement:="Std.DHashMap.Raw.Const.get.{u, v} {α : Type u} {β : Type v} [BEq α] [Hashable α] (m : Std.DHashMap.Raw α fun x => β)\n (a : α) (h : a ∈ m) : β"
renderedStatement:="Std.DHashMap.Raw.Const.get.{u, v} {α : Type u} {β : Type v} [BEq α] [Hashable α]\n (m : Std.DHashMap.Raw α fun x => β) (a : α) (h : a ∈ m) : β",
description:="Operations that take as input an associative container and return a 'single' piece of information (e.g., `GetElem` or `isEmpty`, but not `toList`)."
.text"The Lean standard library contains a fully-featured string library, centered around the types `String` and `String.Slice`.",
.text"`String` is defined as the subtype of `ByteArray` of valid UTF-8 strings. A `String.Slice` is a `String` together with a start and end position.",
.text"`String` is equivalent to `List Char`, but it has a more efficient runtime representation. While the logical model based on `ByteArray` is overwritten in the runtime, the runtime implementation is very similar to the logical model, with the main difference being that the length of a string in Unicode code points is cached in the runtime implementation.",
.text"We are considering removing this feature in the future (i.e., deprecating `String.length`), as the number of UTF-8 codepoints in a string is not particularly useful, and if needed it can be computed in linear time using `s.positions.count`."
.text"The Lean standard library contains a number of functions that take one or more strings and slices and return a string or a slice.",
.text"If possible, these functions should avoid allocating a new string, and return a slice of their input(s) instead.",
.text"Usually, for every operation `f`, there will be functions `String.f` and `String.Slice.f`, where `String.f s` is defined as `String.Slice.f s.toSlice`.",
.text"In particular, functions that transform strings and slices should live in the `String` and `String.Slice` namespaces even if they involve a `String.Pos`/`String.Slice.Pos` (like `String.sliceTo`), for reasons that will become clear shortly.",
.h3"Transforming positions",
.text"Since positions on strings and slices are dependent on the string or slice, whenever users transform a string/slice, they will be interested in interpreting positions on the original string/slice as positions on the result, or vice versa.",
.text"Consequently, every operation that transforms a string or slice should come with a corresponding set of transformations between positions, usually in both directions, possibly with one of the directions being conditional.",
.text"For example, given a string `s` and a position `p` on `s`, we have the slice `s.sliceFrom p`, which is the slice from `p` to the end of `s`. A position on `s.sliceFrom p` can always be interpreted as a position on `s`. This is the \"backwards\" transformation. Conversely, a position `q` on `s` can be interpreted as a position on `s.sliceFrom p` as long as `p ≤ q`. This is the conditional forwards direction.",
.text"The convention for naming these transformations is that the forwards transformation should have the same name as the transformation on strings/slices, but it should be located in the `String.Pos` or `String.Slice.Pos` namespace, depending on the type of the starting position (so that dot notation is possible for the forward direction). The backwards transformation should have the same name as the operation on strings/slices, but with an `of` prefix, and live in the same namespace as the forwards transformation (so in general dot notation will not be available).",
.text"So, in the `sliceFrom` example, the forward direction would be called `String.Pos.sliceFrom`, while the backwards direction should be called `String.Pos.ofSliceFrom` (not `String.Slice.Pos.ofSliceFrom`).",
.text"If one of the directions is conditional, it should have a corresponding panicking operation that does not require a proof; in our example this would be `String.Pos.sliceFrom!`.",
.text"Sometimes there is a name clash for the panicking operations if the operation on strings is already panicking. For example, there are both `String.slice` and `String.slice!`. If the original operation is already panicking, we only provide panicking transformation operations. But now `String.Pos.slice!` could refer both to the panicking forwards transformation associated with `String.slice`, and also to the (only) forwards transformation associated with `String.slice!`. In this situation, we use an `orPanic` suffix to disambiguate. So the panicking forwards operation associated with `String.slice` is called `String.Pos.sliceOrPanic`, and the forwards operation associated with `String.slice!` is called `String.Pos.slice!`."
* The functions `Lean.Environment.importModules` and `Lean.Environment.finalizeImport` have been extended with a new parameter `loadExts : Bool := false` that enables environment extension state loading.
Their previous behavior corresponds to setting the flag to `true` but is only safe to do in combination with `enableInitializersExecution`; see also the `importModules` docstring.
The new default value `false` ensures the functions can be used correctly multiple times within the same process when environment extension access is not needed.
The wrapper function `Lean.Environment.withImportModules` now always calls `importModules` with `loadExts := false` as it is incompatible with extension loading.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.