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 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
cbfc9313affad45012ebd5ac40b338ee829009b1. 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 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 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 `@[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.
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 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 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 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>
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 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 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 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 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]
```