This PR extends the `simp` tactic in `sym =>` mode to support local
hypotheses in the extra theorem list.
`simp myVariant [h]` now resolves `h` against the local context first,
falling back to global constants. Local hypotheses are converted to
rewrite rules via `mkTheoremFromExpr`, which applies the `eq_true`/
`eq_false`/`propext` adapter from #13041.
- Add `ExtraTheorem` inductive (`.const` / `.fvar`) for cache keying
- Add `resolveExtraTheorems` that checks the local context before
globals
- Update `addExtraTheorems`, `mkDefaultMethods`, `elabVariant`
signatures
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR extends `mkTheoremFromDecl` and `mkTheoremFromExpr` to handle
theorems whose conclusion is not an equality, enabling `Sym.simp` to use
a broader class of lemmas as rewrite rules.
Adaptations:
- `¬ p` → `p = False` via `eq_false`
- `p ↔ q` → `p = q` via `propext`
- `p` (proposition) → `p = True` via `eq_true`
Conjunctions (`p ∧ q`) are not handled here since the `SymM` E-graph
aggressively splits them via case analysis.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR adds validation to the `register_sym_simp` command:
- Reject duplicate variant names
- Validate `pre`/`post` syntax by elaborating them via `elabSymSimproc`
in a minimal `GrindTacticM` context, catching unknown theorem names
and unknown theorem set references at registration time
Adds `withGrindTacticM` helper for running `GrindTacticM` from
`CommandElabM`,
and `validateOptionSimprocSyntax` for optional syntax validation.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR adds the `simp` tactic to the `sym =>` interactive mode,
completing
the `Sym.simp` interactive infrastructure.
The `simp` tactic supports:
- `simp` — default variant with `@[sym_simp]` theorem set, `simpControl
>> simpArrowTelescope` pre, `evalGround >> thms.rewrite` post
- `simp myVariant` — named variant registered via `register_sym_simp`
- `simp [thm₁, thm₂]` — default variant with extra rewrite theorems
appended to `post`
- `simp myVariant [thm₁, thm₂]` — named variant with extra theorems
Per-variant persistent caching: each unique (variant name, extra theorem
list)
combination gets its own `Sym.Simp.State` cache, shared across
invocations
within a `sym =>` block. Test 10 verifies cache hits using
`trace.sym.simp.debug.cache`.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR adjusts the results of `inferInstanceAs` and the `def` `deriving` handler to conform to recently strengthened restrictions on reducibility. This change ensures that when deriving or inferring an instance for a semireducible type definition, the definition's RHS is not leaked when the instance is reduced at lower than semireducible transparency.
More specifically, given the "source type" and "target type" (the given and expected type for `inferInstanceAs`, the right-hand side and applied left-hand side of the `def` for `deriving`), we synthesize an instance for the source type and then unfold and rewrap its components (fields, nested instances) as necessary to make them compatible with the target type. The individual steps are represented by the following options, which all default to enabled and can be disabled to help with porting:
- `backward.inferInstanceAs.wrap`: master switch for instance adjustment in both `inferInstanceAs` and the default `deriving` handler
- `backward.inferInstanceAs.wrap.reuseSubInstances`: reuse existing instances for the target type for sub-instance fields to avoid non-defeq instance diamonds
- `backward.inferInstanceAs.wrap.instances`: wrap non-reducible instances in auxiliary definitions
- `backward.inferInstanceAs.wrap.data`: wrap data fields in auxiliary definitions (proof fields are always wrapped)
This PR is an extension and rewrite of prior work in Mathlib: https://github.com/leanprover-community/mathlib4/pull/36420
Last(?) part of fix for #9077🤖 Prepared with Claude Code
# Breaking changes
Proofs that relied on the prior "defeq abuse" of these instance or that depended on their specific structure may need adjustments. As `inferInstanceAs A` now needs to know the source and target types exactly before it can continue, it cannot be used anymore as a synonym for `(inferInstance : A)`, use the latter instead when source and target type are identical.
This PR adds the `register_sym_simp` command for declaring named
`Sym.simp`
variants with `pre`/`post` simproc chains and optional config overrides.
```
register_sym_simp myVariant where
pre := telescope
post := ground >> rewrite [thm1, thm2] with self
maxSteps := 50000
```
- `SymSimpVariant` structure storing `pre?`/`post?` syntax (elaborated
at use
time in `GrindTacticM`) and `Config` overrides
- `SimpleScopedEnvExtension` for persistent cross-module variant storage
- `register_sym_simp` command syntax with `sym_simp_field` category
- Command elaborator with syntax quotation matching and duplicate field
detection
- `getSymSimpVariant?` lookup function
- `deriving Inhabited` on `Simp.Config` for extension support
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR adds `r == e` guards to the `norm_eq_var` and
`norm_eq_var_const` branches of `Int.Linear.simpEq?`. Without these
guards, `simpEq?` returns a non-trivial proof for already-normalized
equations like `x = -1`, causing `exists_prop_congr` to fire repeatedly
and build an infinitely growing term.
The existing `Nat.simpCnstrPos?` already had the equivalent guard (`if r
!= lhs then ... else return none`).
Closes#12812
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a nondeterministic crash in `grind` caused by a
`BEq`/`Hashable` invariant
violation in the congruence table. `congrHash` uses each expression's
own `funCC` flag to
compute its hash (one-level decomposition for `funCC = true`, full
recursive decomposition
for `funCC = false`), but `isCongruent` only checked the stored
expression's flag. When two
expressions with mismatched `funCC` flags accidentally hash-collided
(via pointer-based
`ptrAddrUnsafe` hashing), `isCongruent` could declare them congruent
despite different
argument counts, leading to an assertion failure in `mkCongrProof`.
The fix requires matching `funCC` flags in `isCongruent`. The PR also
fixes the debug
invariant checker (`checkParents`) to skip `funCC` parents and adds a
regression test for
funCC congruence.
Observed as a nondeterministic crash in Mathlib at
`Analysis/ODE/PicardLindelof.lean`.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes an issue where `grind` could prove each conjunct
individually but failed on the conjunction. The root cause:
`solverAction`'s `.propagated` path calls `processNewFacts` which drains
the `newFacts` queue, but the resulting propagation cascade (congruence
closure, or-propagation, `propagateForallPropDown`) can call
`addNewRawFact`, enqueuing to the separate `newRawFacts` queue. These
raw facts were never drained.
The fix moves `Solvers.mkAction` from `Types.lean` to `Intro.lean` where
it can compose the core solver action with `assertAll`, unconditionally
draining `newRawFacts` after every solver step.
Closes#12581
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds named theorem sets for `Sym.simp` with associated
attributes, following the same pattern as `Meta.simp`'s
`register_simp_attr`.
- `register_sym_simp_attr my_set` creates a named set with its own
`PersistentEnvExtension` and attribute
- `@[my_set] theorem ...` adds a rewrite theorem
- `@[my_set] def ...` adds equation theorems from the definition
- `builtin_initialize symSimpExtension` registers a default
`@[sym_simp]` set
- `getSymSimpTheorems` / `getSymSimpExtension?` retrieve theorem sets at
tactic time
New files:
- `Sym/Simp/Attr.lean`: attribute logic (`mkSymSimpAttr`,
`registerSymSimpAttr`)
- `Sym/Simp/RegisterCommand.lean`: `register_sym_simp_attr` macro
Tests:
- `tests/pkg/sym_simp_attr/`: package test with user-defined set
(`my_sym_simp`)
- `tests/elab/sym_simp_set.lean`: tests for the builtin `@[sym_simp]`
set
This PR removes the custom `M`/`State` monad from structural recursion
elaboration, replacing it with plain `MetaM`. This simplifies the code
and makes the control flow more explicit, in preparation for #12987
which
introduces named `_f` auxiliary definitions for structural recursion.
Key changes:
- Remove `State`/`M` types from `Structural.Basic`, use `MetaM`
throughout
- Extract `withRecFunsAsAxioms` helper for adding recursive functions as
temporary axioms
- Split `tryAllArgs` into `findRecArgCandidates` (analysis) and
`tryCandidates` (backtracking execution)
- Move `withoutModifyingEnv` into each phase that needs it
- For inductive predicates, return matchers from `mkIndPredBRecOnF`
instead of accumulating in state
- Pass `fnTypes` explicitly to `mkBRecOnMotive` instead of re-inferring
This is a pure refactoring with no behavior changes (except matcher
numbering in `inductive_pred` test due to changed
`saveState`/`restoreState` boundaries).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR further enforces that all modules used in compile-time execution
must be meta imported in preparation for enabling
https://github.com/leanprover/lean4/pull/10291
# Breaking changes
Metaprograms that call `compileDecl` directly may now need to call
`markMeta` first where appropriate, possibly based on the value of
`isMarkedMeta` of existing decls. `addAndCompile` should be split into
`addDecl` and `compileDecl` for this in order to insert the call in
between.
This PR enables support for respecting user provided borrow annotations.
This allows user to mark arguments of their definitions or local
functions with `(x : @&Ty)` and have the borrow inference try its best
to preserve this annotation, thus potentially reducing RC pressure. Note
that in some cases this might not be possible. For example, the compiler
prioritizes preserving tail calls over preserving borrow annotations. A
precise reasoning of why the compiler chose to make its inference
decisions can be obtained with `trace.Compiler.inferBorrow`.
The implementation consists of two parts:
1. A propagator in ToLCNF. This is required because the elaborator does
not place the borrow annotations in the function binders themselves but
just in type annotations of let binders/global declarations while LCNF
expects them in the lambda variable binders themselves. Thus ToLCNF now
implements a (very weak but strong enough for this purpose) propagator
of the borrow annotations of a type annotation into the variable binders
of the term affected by the annotations
2. A weakening of the InferBorrow heuristic. It now has a set of
"forced" and "non-forced" reasons to mark a variable as owned instead of
borrowed. If a variable is user annotated as borrowed, it will only be
marked as owned if the reason is a forced one, e.g. preservation of tail
calls.
This PR speeds up some benchmarks when run as tests by lowering their
workload. It also stops testing some of the more expensive benchmarks
that can't be easily made smaller.
The ultimate goal of this work is to turn production of `.ir` files into
separate build step so that it does not block non-`meta` imports and can
be skipped entirely when not needed. This PR implements the main logic
of this new `leanir` compiler executable and runs it after `lean` inside
the same Lake build step but leaves its use disabled behind a
`compiler.postponeCompile` flag until further Lake adjustments move it
to a separate facet so that its use can be actually beneficial.
---------
Co-authored-by: Joscha <joscha@plugh.de>
This PR adds per-result `contextDependent` tracking to `Sym.Simp.Result`
and splits the simplifier cache into persistent (context-independent)
and transient (context-dependent, cleared on binder entry). This
replaces the coarse `wellBehavedMethods` flag.
Key changes:
- Add `contextDependent : Bool := false` to `Result.rfl` and
`Result.step`
- Split `State.cache` into `persistentCache` and `transientCache`
- Remove `wellBehavedMethods` from `Methods`
- Replace `withoutModifyingCacheIfNotWellBehaved` with
`withFreshTransientCache`
- Change `DischargeResult` to an inductive (`.failed`/`.solved`)
- Add `dischargeAssumption` (context-dependent discharger for testing)
- Add `sym.simp.debug.cache` trace class
- Propagate `contextDependent` through all combinators (congruence,
transitivity, control flow, arrows, rewriting)
- Add `mkRflResult`/`mkRflResultCD` to avoid dynamic allocation of rfl
results
- Fix `isRfl` to ignore `contextDependent` (was silently broken by the
extra field)
Propagation invariant: when combining sub-results, `cd` is the
disjunction of ALL sub-results' flags — including `.rfl` results. If
`simp` returned `.rfl (contextDependent := true)`, it means `simp` might
take a completely different code path in another local context, so all
downstream results must be marked context-dependent.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR introduces the `URI` data type.
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 fixes an issue where the `induction` and `cases` tactics would
swallow diagnostics (such as unsolved goals errors) when the `using`
clause contains a nested tactic.
Closes#12815
This PR fixes the interaction between `cbv_opaque` and
`inline`/`always_inline` annotations, to make sure that inlined
definitions marked as `cbv_opaque` are not unfolded during the
preprocessing stage of `cbv` tactic.
This PR makes `#print` show the full internal private name (including
module prefix) in the declaration signature when `pp.privateNames` is
set to true. Previously, `pp.privateNames` only affected names in the
body but the signature always stripped the private prefix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a series of errors in docstrings.
This includes:
- incorrect gramar
- errant reference to "dependent" in the non-dependent `HashMap` files
- reference to expression metavariables as universe level metavariables
- outdated reference to `usizeSz` instead of `USize.size`
- syntax errors in code examples
- a broken link to a paper
---------
Co-authored-by: Derrik Petrin <derrik.petrin@pm.me>
This PR removes the obsolete `Lean.Environment.replay` from
`src/Lean/Replay.lean` and replaces it with the improved version from
`src/LeanChecker/Replay.lean`, which includes fixes for duplicate
theorem handling and Quot/Eq dependency ordering. The primed names
(`Replay'`, `replay'`) are renamed back to `Replay` and `replay`.
A test for the original issue (nested inductives failing with `replay`)
is added as `tests/elab/issue12819.lean`.
Closes#12819🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR adds a `sym =>` tactic that enters an interactive symbolic
simulation
mode built on `grind`. Unlike `grind =>`, it does not eagerly introduce
hypotheses or apply by-contradiction, giving users explicit control over
`intro`, `apply`, and `internalize` steps.
New tactics available in `sym =>` mode:
- `intro` / `intros`: introduce binders and internalize into the E-graph
by
default. Use `intro~` or `intro (internalize := false)` to skip
internalization.
- `apply t`: apply backward rules with caching for `repeat`.
- `internalize` / `internalize_all`: internalize hypotheses into the
E-graph.
- `by_contra`: apply proof by contradiction, negating the target.
Satellite solvers (`lia`, `ring`, `linarith`) automatically introduce
remaining
binders and apply by-contradiction in `sym =>` mode, matching their
behavior in
default tactic mode. All existing `grind =>` tactics (`finish`,
`instantiate`,
`cases`, etc.) also work in `sym =>` mode. The sym-specific tactics are
guarded
and rejected in regular `grind =>` mode.
```lean
example (x : Nat) : myP x → myQ x := by
sym [myP_myQ] =>
intro h
finish
example (x y z : Nat) : x > 1 → x + y + z > 0 := by
sym =>
lia
```
This PR fixes an issue where `realizeConst` would generate auxiliary
declarations
(like `_sparseCasesOn`) using the original defining module's private
name prefix
rather than the realizing module's prefix. When two modules
independently realized
the same imported constant, they produced identically-named auxiliary
declarations,
causing "environment already contains" errors on diamond import.
The fix re-privatizes the constant name under the current module before
passing it
to `withDeclNameForAuxNaming`, ensuring each realizing module generates
distinctly
named auxiliary declarations.
Fixes#12825
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR fixes a regression introduced in Lean 4.29.0-rc2 where `simp` no
longer simplifies inside type class instance arguments due to the
`backward.isDefEq.respectTransparency` change. This breaks proofs where
a term like `(a :: l).length` appears both in the main expression and
inside implicit instance arguments (e.g., determining a `BitVec` width).
**The problem:** After `simp only [List.length_cons]`, the main
expression has `l.length + 1` but instances still have `(a ::
l).length`. Since `simp` no longer simplifies inside instances, and
`isDefEq` won't unfold `List.length` at the default transparency,
subsequent lemma applications fail.
**Reproducer** (from Son Ho, reported by Sebastian Ullrich):
```lean
theorem BitVec.getElem!_eq_testBit_toNat {w : Nat} (x : BitVec w) (i : Nat) :
x[i]! = x.toNat.testBit i := by sorry
example (l : List Nat) (a : Nat) (j : Nat) :
(0#((a :: l).length))[j]! = (0#((a :: l).length)).toNat.testBit j := by
simp only [List.length_cons]
simp only [BitVec.getElem!_eq_testBit_toNat] -- works in 4.28.0-rc1, fails in 4.29.0-rc6
```
**The fix:** Mark `List.length` as `@[implicit_reducible]`, allowing
`isDefEq` to unfold it when checking implicit arguments. Several proofs
that previously needed a trailing `rfl` after `simp` now close directly,
since `simp` can see through `List.length` in more positions.
**Longer term:** The root cause is that `GetElem` carries complex proof
obligations in its type class instances, making implicit arguments
sensitive to definitional equality of collection sizes. We are
considering a redesign with a noncomputable `GetElemV` variant based on
`Nonempty` that avoids these casts entirely, but that is a larger change
planned for a future release.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR changes the Lake `CacheMap` data structure to track the
platform-dependence of outputs. Platform-independent packages will no
longer include platform-dependent mappings in the output files produced
by `lake build -o`.
This PR fixes some process signals that were incorrectly numbered.
From what I can tell, the code used signals and signal numbers for
Alpha/SPARC, not x86/ARM. The test was also broken and always green,
hiding the mistake.
This PR changes the interaction between `@[cbv_opaque]` and
`@[cbv_eval]`
attributes in the `cbv` tactic. Previously, `@[cbv_opaque]` completely
blocked
all reduction including `@[cbv_eval]` rewrite rules. Now, `@[cbv_eval]`
rules
can fire on `@[cbv_opaque]` constants, allowing users to provide custom
rewrite
rules without exposing the full definition. Equation theorems, unfold
theorems,
and kernel reduction remain suppressed for opaque constants.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR introduces the `Headers` data type, that provides a good and
convenient abstraction for parsing, querying, and encoding HTTP/1.1
headers.
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 fixes a segfault when running `idbgClientLoop`. `@[extern]`
expects that the function doesn't include erased arguments in the
signature; however, `@[export]` exports the function with all arguments,
including erased ones. This causes a function signature mismatch between
`idbgClientLoopImpl` and `idbgClientLoop`, causing segfaults. However,
instead of solving the deeper problem that `@[extern]` - `@[export]`
pairs can cause such problems, this PR removes the erased arguments from
`idbgClientLoopImpl` and replaces occurrences of `α` with `NonScalar`.
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 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 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>