This PR modifies the app elaborator to beta reduce arguments while
substituting them into expected types for later arguments. This makes it
consistent with `inferType` and `instantiateMVars`, which both beta
reduce substitutions. In particular, this change ensures that the app
elaborator behaves as if it creates metavariables for each parameter and
assigns elaborated arguments to the metavariables. **Breaking change:**
tactic proofs may need to be modified to remove unnecessary steps, e.g.
`dsimp only` steps that were previously for beta reductions.
This PR enforces that Verso docstring extensions should always be meta
at attribute application time, giving better error messages, and ensures
that the generated argument parser helper is also meta and has the same
visibility.
This PR adds two new fields to `DoOps`, `splitMonadApp?` and
`mkMonadApp`, so that callers of `elabDoWith` can use indexed monads
like `Measure α` (where `Measure : (α : Type u) → [MeasureSpace α] →
Type u` carries instance arguments) that the default `m α` decomposition
cannot handle. The existing behavior moves into `DoOps.default`.
`splitMonadApp?` replaces the hard-coded `.app m α` step inside the
`extractMonadInfo` recursion, and `mkMonadApp` replaces the hard-coded
`mkApp m α` used to construct the monadic type.
---------
Co-authored-by: Sebastian Graf <sg@lean-fro.org>
This PR renames the `do` elaborator's `mkMonadicType` to `mkMonadApp`,
aligning it with the existing `mkPureApp` / `mkBindApp` naming
convention in `DoOps`.
Co-authored-by: Sebastian Graf <sg@lean-fro.org>
This PR generates specialized code for invoking `dec` on values whose
shape is known. This puts branch prediction pressure off
`lean_dec_ref_cold` as the shape of the constructor should now be
compiled into the executable.
If we're using the downloaded LLVM release and building stage2/stage3,
we need to also copy stage1 to stage2/stage3 respectively before
continuing the build. Previously, the CI did not do this in every case.
Now we do it unconditionally because the overhead is small enough.
This PR is part 2 to #13779. It completes the transition of the
configuration evaluation metaprograms into being builtin elaborators.
After this, building stage1 will not invoke the interpreter when
generating configuration evaluators. A tradeoff is that changes to
ConfigEval will not affect stage1 builds, but these changes ought to be
infrequent.
This PR makes the command elaborators for configuration evaluation
metaprogramming be builtins, to avoid bootstrapping ABI issues in core
Lean due to the interpreter evaluating large parts of the elaborator
before all builtin initializers are run. (This is part 1; #13780 will be
applied after a stage0 update.)
This PR eliminates the use of `liftCommandElabM` from the coinductive
module.
Context: `liftCommandElabM` was decided to be deprecated in issue
#10674.
This PR eliminates the use of `liftCommandElabM` in the `@[ext]`
attribute, since it is unnecessary — all the computations can stay in
`TermElabM`.
Context: `liftCommandElabM` was decided to be deprecated in issue
#10674.
This PR moves the `evalSuggest` combinator and trace-handler dispatch
from a hardcoded `match` on syntax kinds to the existing
`tryTacticElabAttribute` registration mechanism, bringing `try?`'s
extensibility model in line with normal tactics and interactive `grind`.
Each built-in combinator (`<;>`, `first`, `paren`, `try`, `attempt_all`,
`attempt_all_par`, `first_par`, `seq1`) and trace handler (`grind?`,
`simp?`, `simp_all?`, `exact?`) is now registered as
`@[builtin_try_tactic <kind>]`. `evalSuggestImpl` becomes a thin
attribute-driven dispatcher mirroring `evalTactic`/`evalGrindTactic`.
The post-run "no unsolved goals in terminal mode" check is no longer
applied centrally by the dispatcher. Handlers that may leave goals
open (`simp?`, `simp_all?`, the atomic fallback) call the new
`checkTerminalGoals` helper themselves; handlers that close the goal
by construction (`grind?`, `exact?`) and combinators that delegate via
`evalSuggest` need no explicit call.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR makes `try?`'s `expandUserTactic` walk the info tree for
`TryThisInfo`
nodes (introduced in #10524) instead of parsing the rendered `Try this:`
message
text. The previous approach scraped lines prefixed with ` [apply] ` from
the
message log, which would break the moment that wire format changed.
The user tactic is run under `withSaveInfoContext` so the in-flight
trees come
out wrapped with a `PartialContextInfo.commandCtx`, which is what
`InfoTree.foldInfo` needs in order to descend; the structured
suggestions can
then be read directly from the `TryThisInfo` nodes that
`TryThis.addSuggestion`
already pushes. The prior manual `Core.setMessageLog` save/restore dance
is no
longer needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR fixes premise selection silently dropping relevant premises when
the goal was reached via `induction`.
`MVarId.getRelevantConstants` and `MVarId.getConstants` walked the raw
goal type returned by `getType`, which after `induction` is `?motive
arg` with `?motive` an assigned-but-unsubstituted metavariable. The
constant fold treats the metavariable as an opaque leaf, so every
constant in the goal predicate is lost. Instantiating metavariables
first recovers them.
Thanks to Xavier Généreux for the report.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR does some refactoring of the function application elaborator,
and it improves `trace.Elab.app` tracing. It also improves asymptotic
complexity by more carefully substituting arguments into the function's
type and by changing how named argument dependency suppression is
implemented. For dot notation, it now constructs base projections
directly rather than using the app elaborator. It fixes a bug in the eta
args feature where more explicit arguments would be turned into implicit
arguments than expected, and it improves expected type propagation by
following the rules from the main app elaborator.
This PR refines MePo premise selection so that (1) candidates are
restricted to theorems, matching the convention already used by
`SineQuaNon` and `SymbolFrequency`, and (2) the result is ordered
lexicographically by `(iteration, score)` rather than by score alone.
Before the theorem filter, `mepoSelector` returned functions, recursors,
and casts (e.g. `Int.add`, `Eq.ndrec`, `cast`, `proof_irrel`) alongside
real premises. With it, those go away and the obvious lemmas — e.g.
`Int.add_comm` for `a + b = b + a` — rank well above the remaining
noise.
The `(iteration, score)` ordering preserves the iteration priority of
the original Meng–Paulson MePo: an iter-1 premise scoring 0.6 always
ranks above an iter-2 premise scoring 1.0, since later iterations score
against a strictly larger `relevant` set and a higher threshold, so
their raw scores are not comparable.
Thanks to Xavier Généreux for the report. Further tuning of the score
function (the remaining problem: small generic theorems still score 1.0)
is tracked in https://github.com/leanprover/lean4/issues/13749.
Depends on https://github.com/leanprover/lean4/pull/13747.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR an intermittent test failure in the Lake environment test caused
by its reuse of the hello test's configuration. The tests are now
properly independent.
This PR closes https://github.com/leanprover/lean4/issues/13770 by
including `Config.zetaUnused` in `Config.toKey`. Without this, two
configs that differ only in `zetaUnused` share a `WHNF`/`isDefEq` cache
key, so reductions performed under one setting can be returned for the
other. The new bit sits at position 22, immediately above `zetaHave`.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR fixes a long-standing bug in `Meta.Config.toKey` and
`Context.setTransparency` where `TransparencyMode` was packed into only
2 bits of the cache key, even though it has 5 constructors (`.all`,
`.default`, `.reducible`, `.instances`, `.none`). The `.none` case
(value `4`, i.e. `0b100`) overlapped with the `foApprox` bit, so
configurations differing only in transparency vs. `foApprox` could
collide in the `isDefEq`/`WHNF` cache, and `Context.setTransparency`
corrupted the neighbouring bit when switching to/from `.none`.
The fix widens the transparency field to 3 bits and shifts every
subsequent flag up by one. Split out from
https://github.com/leanprover/lean4/pull/13637 where the same fix was
needed anyway to accommodate a 6th transparency constructor.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR fixes the MePo premise selector returning its lowest-scoring
premises instead of its best ones.
Since https://github.com/leanprover/lean4/pull/10917 `mepo` returns
suggestions in score-descending order, but `mepoSelector` still applied
a `.reverse` that predated that change. The `.reverse` flipped the order
to score-ascending, so the subsequent `.take config.maxSuggestions` kept
the `maxSuggestions` worst premises.
Thanks to Xavier Généreux for the report.
🤖 Prepared with Claude Code
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR removes the `addInfo` flag from `elabSetOption` introduced in
#11313, instead allowing callers to use `withEnableInfoTree` to control
whether infotrees are added.
This PR adds `MessageData.withExprHover`, for creating messages that
show information about an expression when hovered over. A
`withExprHoverM` variant captures the current local context.
This PR fixes an issue where the `pp.universes` option would cause
constants with no universes to not use unexpanders or dot notation. For
example, `p ↔ q` would pretty print as `Iff p q` even though `Iff` has
no universe levels.
This PR improves `Expr.instantiateBetaRevRange` to be more efficient in
the common case where lambda functions are not being instantiated, and
it increases expression sharing in applications.
The motivation is that we would like to use this function more
pervasively in elaboration, so that users do not need to write `dsimp
only` as frequently in applications that involve higher-order functions,
plus `inferType` uses it so there is a UX inconsistency when the
elaborator is not using it.
This PR adds new incremental module serialization functions that
save/load a single module at a time with explicit sharing via dep
regions and compactor state, generalizing the existing batch
saveModuleDataParts API.
Two sharing mechanisms that can be mixed:
- `CompactedRegion` dep regions for sharing with loaded regions
- `CompactorState` for same-process chaining (pre-loaded `m_obj_table`)
This PR adds the missing `ByteArray` push and `set!` lemmas that are
still carried locally in `ZipForStd.ByteArray` downstream.
These lemmas provide one coherent API layer for reasoning about
`ByteArray` pushes and `set!` updates on top of the existing upstream
append, extract, and size lemmas. Previous downstream code had to keep
local compatibility lemmas for these common proof steps.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR adds `Dyadic.divAtPrec a b prec`, returning the greatest dyadic
with precision at most `prec` which is less than or equal to `a/b` (and
`0` when `b = 0`). Mirroring the existing `invAtPrec`, the
characterising lemmas `divAtPrec_mul_le` and `lt_divAtPrec_add_inc_mul`
are also provided.
Compared to composing `invAtPrec` with multiplication, `divAtPrec`
rounds `a/b` down uniformly (no sign-dependent rounding flip), states
the precision at the output rather than requiring callers to back-solve
from `‖a‖`, and fuses the bignum division with renormalisation.
`invAtPrec` remains the right primitive when the reciprocal is reused.
Closes https://github.com/leanprover/lean4/issues/13653.
🤖 Prepared with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR changes the separator between the plugin file name and the
initialization function in `--plugin` from `:` to `=`. This prevents
clashes with the `:` in drive prefixes on Windows.
This PR replaces the previous tactic configuration system with a
significantly more efficient one that supports custom configuration
syntaxes and processing. On a simple benchmark, configuration evaluation
takes 6.2% of the time it used to. The `declare_config_elab` command
generates a configuration elaborator that now directly constructs
configuration objects; previously it relied on `Meta.evalExpr'`, which
involved running a configuration through the full term elaboration,
compilation, and evaluation processes. The generated configuration
elaborators now also have the capability to do direct `Syntax`
evaluation in common cases, skipping term elaboration. Furthermore, the
elaborator accepts configurations more liberally: any user-defined
syntax that has the form of an `optConfig`-style configuration or
configuration item (including, e.g., `namedArgument`s) is accepted.
Import `Lean.Elab.ConfigEval` to use the system; see this module for
some documentation in addition to the docstrings in
`Lean.Elab.ConfigEval.Commands`. Furthermore, the `simp` tactic now also
has `(user.optionName := ...)` user configuration options, which can be
declared using a global `tactic.simp.user.optionName` option; use
`getUserConfigOption` and `withUserConfig` to access and set these in
metaprograms.
Other features:
- `declare_config_elab` creates a function that exposes an `init`
parameter for the configuration that will be modified. It also now has a
`where` clause, enabling defining custom handlers for specific keys.
- Elaborators can be given additional binders, to make parameterized
elaborators. This is used by `simp` and `grind ` to support multiple
default configurations with the correct expected type for `(config :=
...)` elaboration.
- The `EvalTerm` class supports direct evaluation of `Syntax`, skipping
term elaboration. The system will attempt to automatically derive this
class when generating the elaborator.
- In case `EvalTerm` does not recognize the term, then the syntax is
elaborated to an expression and an `EvalExpr` instance is applied to
evaluate the expression. The system will similarly automatically derive
these instances if possible.
- Automatic derivation is *transitive*. It is able to seek instances
through other instances; e.g. if it needs an `EvalTerm (List T)`
instance it will be able to reduce this to seeking an `EvalTerm T`
instance.
- The system is designed to be flexible, and the various components can
be combined to construct a configuration elaborator. There are also now
`declare_core_config_elab` and `declare_term_config_elab` for
conveniently generating elaborators for `CoreM` and `TermElabM`. The
difference is that the first takes an explicit flag for whether to log
exceptions, and the second uses the current `errToSorry` state.
**Warning:** if you use the `TermElabM` one from `TacticM`, it will be
unaware of the current `recover` state. The only differences between
these macros are the ways error recovery is handled per monad.
Other changes:
- `#reduce` tactic configuration now makes use of this system and has
more options
- The module `Lean.Elab.Tactic.ConfigSetter` is removed; the
`declare_config_elab`-family macros subsume its functionality.
- The module `Lean.Elab.Tactic.Config` is deprecated and will be
removed; migration notes appear in the module docs there. Import
`Lean.Elab.ConfigEval` instead.
- One of the mvcgen benchmarks got significantly slower, but it turned
out to be caused by the new tactic configuration elaboration no longer
resetting the MetaM caches. Adding an explicit `resetCache` into the
test driver fixed the benchmark.
### Notes for metaprogram authors
If you are using the module system, you just need a `meta import
Lean.Elab.ConfigEval` to use the macros, and it should serve as a
drop-in replacement to the previous system so long as
1. your configuration type is a `structure` with no parameters, indices,
or universes (only `Type` is supported);
2. default values are self-contained and not dependent on other fields;
and
3. all fields have types that are composed from `Option`, `List`,
`Array`, `String`, `DataValue`, and inductive types in `Type` with no
parameters or indices, whose fields are similarly composed.
The macros synthesize a self-contained configuration elaboration
procedure, analyzing the `EvalTerm` and `EvalExpr` instances that are
currently available or can be automatically derived. These are the
components of the system:
- `EvalTerm` instances provide `Term → TermElabM α` functions for
evaluation of raw syntax; these handle the common cases where an option
value is a identifier, application, or other simple expression. They are
responsible for adding TermInfo when info is enabled, to support hovers.
One can invoke derivation of a `EvalTerm T` instance with the
`ensure_eval_term_instance T` command (after `open scoped
Lean.Elab.ConfigEval`).
- `EvalExpr` instances provide `Expr → TermElabM α` functions for
evaluation of elaborated expressions; these handle cases where an option
value may require reduction to evaluate. Similarly, one can invoke
derivation of an `EvalExpr T` instance with the
`ensure_eval_expr_instance T` command. If needed, there's also
`derive_eval_expr_instance_using_meta_eval T` for creating a
`Meta.evalExpr'`-based evaluator.
- Functions like `ConfigEval.evalExprWithElab` compose `EvalTerm` and
`EvalExpr` instances into a single procedure that first attempts
`EvalTerm`, and, if that fails, applies the standard term elaborator and
then attempts `EvalExpr`. This way term elaboration can be skipped in
all but uncommon cases.
- Configuration item interpretation is through `ConfigEval.foldConfigM`,
which is a procedure with a lax specification for what counts as a
configuration item, calling the provided function on each recognized
configuration item. The idea is:
- Null nodes are lists of configurations
- One-argument nodes are considered to be wrappers like `optConfig` or
`configItem`
- Two-argument nodes of the form `("+"<|>"-") (atom<|>ident)` are
considered to be boolean options
- Five-argument nodes of the form `"(" (atom<|>ident) ":=" syntax ")"`
are considered to be general configuration items. (It only checks for
the presence of `(` and that there are two-to-five arguments.)
- Bare atoms are considered to be positive boolean options
- Configuration evaluation then uses `EvalConfigItem.set` on each item
produced by the fold, for an `EvalConfigItem` structure defined for the
given configuration type. The `def_eval_config_item` command can be used
to generate this structure. It analyzes which `EvalTerm` and `EvalExpr`
instances exist and derives missing ones, then builds an efficient
procedure to process configuration items and apply evaluators.
- Lastly, there are the `declare_core_config_elab`,
`declare_term_config_elab`, `declare_config_elab`, and
`declare_command_config_elab` macros for conveniently running the
`def_eval_config_item` command and constructing a self-contained
elaboration function.
The derivation procedures analyze which `EvalTerm`/`EvalExpr` instances
already exist and only derive the "leaf" instances that are necessary to
construct `EvalTerm` and `EvalExpr` instances. The derived instances are
made `private local` — since configuration elaborators are meant to be
self-contained, we decided not to let the additional instances be a side
effect of the macros. The instances can be globally added by manually
using the `ensure_*` commands.
The macros support making parameterized elaborators with arbitrary
additional binders. See `make_elab_grind_config` and
`make_elab_simp_config` in core Lean for examples of generating a single
elaborator that's used with multiple default value configurations.
To see how to create a key handler that matches all configuration keys
with a given prefix, see `make_elab_simp_config`.
There is a todo item at `Lean.Elab.ConfigEval.ReflectConfigItems` for
reflecting configurations back to syntax, which is not yet supported.
### Performance evaluation
A legacy configuration parser was temporarily added to
`Lean.Elab.Tactic.Grind.Config` using `declare_term_config_elab_legacy
elabGrindConfigLegacy Grind.Config`, and then this file was used for
measuring elaboration time:
```lean
import Lean
open Lean Elab Meta Tactic Parser
def cfgs : Array Syntax := Unhygienic.run do
return #[
← `(Tactic.optConfig| ),
← `(Tactic.optConfig| +clean),
← `(Tactic.optConfig| +trace +markInstances -lookahead -useSorry),
← `(Tactic.optConfig| (trace := true) (markInstances := true) (lookahead := false) (useSorry := false)),
← `(Tactic.optConfig| -trace (splits := 20) +revert (maxSuggestions := some 3) (ematch := 2)),
← `(Tactic.optConfig| (gen := 5) -reducible +splitImp -funCC),
← `(Tactic.optConfig| (config := { trace := true, lookahead := false, maxSuggestions := some 3 })),
]
def testGrindElab (cfgs : Array Syntax) (n : Nat) : TacticM Unit := do
profileitM Exception "test grind elab" (← getOptions) do
let mut ematch := 0
for _ in [0:n] do
for cfg in cfgs do
let c ← Tactic.elabGrindConfig cfg
ematch := ematch + c.ematch
logInfo m!"sum = {ematch}"
def testGrindElabLegacy (cfgs : Array Syntax) (n : Nat) : TacticM Unit := do
profileitM Exception "test grind elab legacy" (← getOptions) do
let mut ematch := 0
for _ in [0:n] do
for cfg in cfgs do
let c ← Tactic.elabGrindConfigLegacy cfg
ematch := ematch + c.ematch
logInfo m!"sum = {ematch}"
def runTest (info : Bool) (test : TacticM Unit) : TermElabM Unit := do
withEnableInfoTree info do
let mvar ← mkFreshExprMVar none
discard <| Tactic.run mvar.mvarId! test
set_option maxHeartbeats 0
set_option profiler true
set_option profiler.threshold 1
def iters : Nat := 1000
#eval runTest false <| testGrindElab cfgs iters
#eval runTest true <| testGrindElab cfgs iters
#eval runTest false <| testGrindElabLegacy cfgs iters
#eval runTest true <| testGrindElabLegacy cfgs iters
```
A representative output is
```
test grind elab took 315ms
test grind elab took 333ms
test grind elab legacy took 5.22s
test grind elab legacy took 5.33s
```
Computing `(315.0 + 333.0) / (5220 + 5330)` and rounding up to the
nearest tenth gives the 6.2% figure.
---
The #13426 draft PR includes some LSP modifications to support
completions for `simp` user configuration options.
This PR upstreams `unusedDecidableInType` linter from mathlib.
Stacked on top of #11313.
---------
Co-authored-by: thorimur <thomasmurrills@gmail.com>
Co-authored-by: thorimur <68410468+thorimur@users.noreply.github.com>
This PR improves the logic and performance of the
`checkImpossibleInstance` function to detect more arguments that are
impossible to
infer for typeclass synthesis. It also improves the formatting of the
error messages for `checkImpossibleInstance` and `checkNonClassInstance`
to be more readable.
This integrates [independent (temporarily merged)
work](https://github.com/leanprover-community/batteries/pull/1717) on
these former Batteries linters which has been reverted in Batteries
because of the unprecedented upstreaming of these linters.
We also disable these checks (if the declaration contains any `sorry`s
so that partially completing instances is still possible without being
terrorized by obvious errors. We also swap the order of the checks, such
that now `checkNonClassInstance` is called first - it would be wrong to
warn for synthesis impossibility if the return type isn't even
synthesizable because it is not class-valued.
Co-authored by: @thorimur
---------
Co-authored-by: Wojciech Rozowski <wojciech@lean-fro.org>
This PR fixes a regression introduced in #7166 where, after fixed and
varying
parameters were allowed to be reordered, three places in
`Lean.Elab.Structural.FindRecArg` still indexed the concatenation `xs ++
ys`
with `recArgInfo.recArgPos` even though `recArgPos` refers to the
original
parameter order. With fixed parameters interleaved with the structural
argument, this picked the wrong element: error messages named the wrong
parameter, and `argsInGroup`'s nested-inductive recognition silently
rejected
otherwise-valid mutual definitions.
All three sites now use `recArgInfo.fixedParamPerm.buildArgs xs ys` so
the
index matches `recArgPos` and `indicesPos`.
Closes#13729.
This PR improves hovers and completions for compound field names in
structure instance notation. Previously a field like `x.fst` would only
have information associated to `x` attached to the entire syntax, but
now `x` and `fst` are treated separately.
Additionally, the `trace.Elab.struct` trace class is now
`trace.Elab.structInst`, and the messages have been cleaned up and
reorganized. Furthermore, `ExceptToTraceResult` has an `Expr` instance
that shows a failure emoji when there are synthetic sorries. Lastly,
`Syntax.identComponents` has an early return for names with at most one
component, saving a re-parsing step.
This PR fixes toml_escape so it does not emit moreLeancArgs = [""] when
internal leanc flags are both empty (the combined placeholder was only
whitespace). This led GCC to see an extra empty argv entry and fail with
a confusing linker error.
Co-authored-by: Cursor <cursoragent@cursor.com>
This PR resurrects the tests about cancellation of `try?` tactics.
They were flaky before. By introducing an option
(`debug.tactic.try.onlyUserSuggestions`) to make these tests not run
`exact?` as part of `try?`, and thus be generally faster and use less
memory, the flakiness seems to have disappeared, at least in
non-`master` testing. We’ll see.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>