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>