Lean 4.23.0-rc2 (2025-08-15)
For this release, 610 changes landed. In addition to the 95 feature additions and 139 fixes listed below there were 61 refactoring changes, 12 documentation improvements, 71 performance improvements, and 232 other changes.
Highlights
Lean v4.23.0 release brings significant performance improvements, better error messages,
and a plethora of bug fixes, refinements, and consolidations in grind
, the compiler, and other components of Lean.
In terms of user experience, noteworthy new features are:
-
Improved 'Go to Definition' navigation (#9040)
-
Using 'Go to Definition' on a type class projection now extracts the specific instances that were involved and provides them as locations to jump to. For example, using 'Go to Definition' on the
toString
oftoString 0
yields results forToString.toString
andToString Nat
. -
Using 'Go to Definition' on a macro that produces syntax with type class projections now also extracts the specific instances that were involved and provides them as locations to jump to. For example, using 'Go to Definition' on the
+
of1 + 1
yields results forHAdd.hAdd
,HAdd α α α
andAdd Nat
. -
Using 'Go to Declaration' now provides all the results of 'Go to Definition' in addition to the elaborator and the parser that were involved. For example, using 'Go to Declaration' on the
+
of1 + 1
yields results forHAdd.hAdd
,HAdd α α α
,Add Nat
,macro_rules | `($x + $y) => ...
andinfixl:65 " + " => HAdd.hAdd
. -
Using 'Go to Type Definition' on a value with a type that contains multiple constants now provides 'Go to Definition' results for each constant. For example, using 'Go to Type Definition' on
x
forx : Array Nat
yields results forArray
andNat
.
-
-
Interactive code-action hints for errors:
-
for "invalid named argument" error, suggest valid argument names (#9315)
-
for "invalid case name" error, suggest valid case names (#9316)
-
for "fields missing" error in structure instances, suggest to insert all the missing fields (#9317)
You can try all of these in the Lean playground.
-
Breaking Changes
-
#9800 improves the delta deriving handler, giving it the ability to process definitions with binders, as well as the ability to recursively unfold definitions. Breaking change: the derived instance's name uses the
instance
command's name generator, and the new instance is added to the current namespace. -
#9040 improves the 'Go to Definition' UX. Breaking change:
InfoTree.hoverableInfoAt?
has been generalized toInfoTree.hoverableInfoAtM?
and now takes a generalfilter
argument instead of several boolean flags, as was the case before. -
#9594 optimizes
Lean.Name.toString
, giving a 10% instruction benefit.Crucially this is a breaking change as the old
Lean.Name.toString
method used to support a method for identifying tokens. This method is now available asLean.Name.toStringWithToken
in order to allow for specialization of the (highly common)toString
code path which sets this function to just returnfalse
. -
#9729 introduces a canonical way to endow a type with an order structure. Breaking changes:
-
The requirements of the
lt_of_le_of_lt
/le_trans
lemmas forVector
,List
andArray
are simplified. They now require anIsLinearOrder
instance. The new requirements are logically equivalent to the old ones, but theIsLinearOrder
instance is not automatically inferred from the smaller typeclasses. -
Hypotheses of type
Std.Total (¬ · < · : α → α → Prop)
are replaced with the equivalent classStd.Asymm (· < · : α → α → Prop)
. Breakage should be limited because there is now an instance that derives the latter from the former. -
In
Init.Data.List.MinMax
, multiple theorem signatures are modified, replacing explicit parameters for antisymmetry, totality,min_ex_or
etc. with corresponding instance parameters.
-
Language
-
#6732 adds support for the
clear
tactic in conversion mode. -
#8666 adjusts the experimental module system to not import the IR of non-
meta
declarations. It does this by replacing such IR with opaque foreign declarations on export and adjusting the new compiler accordingly. -
#8842 fixes the bug that
collectAxioms
didn't collect axioms referenced by other axioms. One of the results of this bug is that axioms collected from a theorem proved bynative_decide
may not includeLean.trustCompiler
. -
#9015 makes
isDefEq
detect more stuck definitional equalities involving smart unfoldings. Specifically, ift =?= defn ?m
anddefn
matches on its argument, then this equality is stuck on?m
. Prior to this change, we would not see this dependency and simply returnfalse
. -
#9084 adds
binrel%
macros for!=
and≠
notation defined inInit.Core
. This allows the elaborator to insert coercions on both sides of the relation, instead of committing to the type on the left hand side. -
#9090 fixes a bug in
whnfCore
where it would fail to reduce applications of recursors/auxiliary defs. -
#9097 ensures that
mspec
uses the configured transparency setting and makesmvcgen
use default transparency when callingmspec
. -
#9099 improves the “expected type mismatch” error message by omitting the type's types when they are defeq, and putting them into separate lines when not.
-
#9103 prevents truncation of
panic!
messages containing null bytes. -
#9108 fixes an issue that may have caused inline expressions in messages to be unnecessarily rendered on a separate line.
-
#9113 improves the
grind
doc string and tries to make it more approachable to new user. -
#9130 fixes unexpected occurrences of the
Grind.offset
gadget in ground patterns. See new test -
#9131 adds a
usedLetOnly
parameter toLocalContext.mkLambda
andLocalContext.mkForall
, to parallel theMetavarContext
versions. -
#9133 adds support for
a^(m+n)
in thegrind
normalizer. -
#9143 removes a rather ugly hack in the module system, exposing the bodies of theorems whose type mention
WellFounded
. -
#9146 adds "safe" polynomial operations to
grind ring
. The use the usual combinators:withIncRecDepth
andcheckSystem
. -
#9149 generalizes the
a^(m+n)
grind normalizer to any semirings. Example:variable [Field R]
-
#9150 adds a missing case in the
toPoly
function used ingrind
. -
#9153 improves the linarith
markVars
, and ensures it does not produce spurious issue messages. -
#9168 resolves a defeq diamond, which caused a problem in Mathlib:
import Mathlib
-
#9172 fixes a bug at
matchEqBwdPat
. The type may contain pattern variables. -
#9173 fixes an incompatibility in the experimental module system when trying to combine wellfounded recursion with public exposed definitions.
-
#9176 makes
mvcgen
split ifs rather than applying specifications. Doing so fixes a bug reported by Rish. -
#9182 tries to improve the E-matching pattern inference for
grind
. That said, we still need better tools for annotating and maintaininggrind
annotations in libraries. -
#9184 fixes stealing of
⇓
syntax by the new notation for total postconditions by demoting it to non-builtin syntax and scoping it toStd.Do
. -
#9191 lets the equation compiler unfold abstracted proofs again if they would otherwise hide recursive calls.
This fixes #8939.
-
#9193 fixes the unexpected kernel projection issue reported by issue #9187
-
#9194 makes the logic and tactics of
Std.Do
universe polymorphic, at the cost of a few definitional properties arising from the switch fromProp
toULift Prop
in the base caseSPred []
. -
#9196 implements
forall
normalization using a simproc instead of rewriting rules ingrind
. This is the first part of the PR, after update stage0, we must remove the normalization theorems. -
#9200 implements
exists
normalization using a simproc instead of rewriting rules in grind. This is the first part of the PR, after update stage0, we must remove the normalization theorems. -
#9202 extends the
Eq
simproc used ingrind
. It covers more cases now. It also adds 3 reducible declarations to the list of declarations to unfold. -
#9214 implements support for local and scoped
grind_pattern
commands. -
#9225 improves the
congr
tactic so that it can handle function applications with fewer arguments than the arity of the head function. This also fixes a bug wherecongr
could not make progress withSet
-valued functions in Mathlib, sinceSet
was being unfolded and making such functions have an apparently higher arity. -
#9228 improves the startup time for
grind ring
by generating the required type classes on demand. This optimization is particularly relevant for files that make hundreds of calls togrind
, such astests/lean/run/grind_bitvec2.lean
. For example, before this change,grind
spent 6.87 seconds synthesizing type classes, compared to 3.92 seconds after this PR. -
#9241 ensures that the type class instances used to implement the
ToInt
adapter (ingrind cutsat
) are generated on demand. -
#9244 improves the instance generation in the
grind linarith
module. -
#9251 demotes the builtin elaborators for
Std.Do.PostCond.total
andStd.Do.Triple
into macros, following the DefEq improvements of #9015. -
#9267 optimizes support for
Decidable
instances ingrind
. BecauseDecidable
is a subsingleton, the canonicalizer no longer wastes time normalizing such instances, a significant performance bottleneck in benchmarks likegrind_bitvec2.lean
. In addition, the congruence-closure module now handlesDecidable
instances, and can solve examples such as:example (p q : Prop) (h₁ : Decidable p) (h₂ : Decidable (p ∧ q)) : (p ↔ q) → h₁ ≍ h₂ := by grind
-
#9271 improves the performance of the formula normalizer used in
grind
. -
#9287 rewords the "application type mismatch" error message so that the argument and its type precede the application expression.
-
#9293 replaces the
reduceCtorEq
simproc used ingrind
by a much more efficient one. The default one use insimp
is just overhead because thegrind
normalizer is already normalizing arithmetic. In a separate PR, we will push performance improvements to the defaultreduceCtorEq
. -
#9305 uses the
mkCongrSimpForConst?
API insimp
to reduce the number of times the same congruence lemma is generated. Before this PR,grind
would spend1.5
s creating congruence theorems during normalization in thegrind_bitvec2.lean
benchmark. It now spends0.6
s. should make an even bigger difference after we merge #9300. -
#9315 adds improves the "invalid named argument" error message in function applications and match patterns by providing clickable hints with valid argument names. In so doing, it also fixes an issue where this error message would erroneously flag valid match-pattern argument names.
-
#9316 adds clickable code-action hints to the "invalid case name" error message.
-
#9317 adds to the "fields missing" error message for structure instance notation a code-action hint that inserts all missing fields.
-
#9324 improves the functions for checking whether two terms are disequal in
grind
-
#9325 optimizes the Boolean disequality propagator used in
grind
. -
#9326 optimizes
propagateEqUp
used ingrind
. -
#9340 modifies the encoding from
Nat
toInt
used ingrind cutsat
. It is simpler, more extensible, and similar to the genericToInt
. After update stage0, we will be able to delete the leftovers. -
#9351 optimizes the
grind
preprocessing steps by skipping steps when the term is already present in the hash-consing table. -
#9358 adds support for generating lattice-theoretic (co)induction proof principles for predicates defined via
mutual
blocks usinginductive_fixpoint
/coinductive_fixpoint
constructs. -
#9367 implements a minor optimization to the
grind
preprocessor. -
#9369 optimizes the
grind
preprocessor by skipping unnecessary steps when possible. -
#9371 fixes an issue that caused some
deriving
handlers to fail when the name of the type being declared matched that of a declaration in an open namespace. -
#9372 fixes a performance issue that occurs when generating equation lemmas for functions that use match-expressions containing several literals. This issue was exposed by #9322 and arises from a combination of factors:
-
Literal values are compiled into a chain of dependent if-then-else expressions.
-
Dependent if-then-else expressions are significantly more expensive to simplify than regular ones.
-
The
split
tactic selects a target, splits it, and then invokessimp
on the resulting subgoals. Moreover,simp
traverses the entire goal bottom-up and does not stop after reaching the target.
-
-
#9385 replaces the
isDefEq
test in thesimpEq
simproc used ingrind
. It is too expensive. -
#9386 improves a confusing error message that occurred when attempting to project from a zero-field structure.
-
#9387 adds a hint to the "invalid projection" message suggesting the correct nested projection for expressions of the form
t.n
wheret
is a tuple andn > 2
. -
#9395 fixes a bug at
mkCongrSimpCore?
. It fixes the issue reported by @joehendrix at #9388. The fix is just commit: afc4ba617fe2ca5828e0e252558d893d7791d56b. The rest of the PR is just cleaning up the file. -
#9398 avoids the expensive
inferType
call insimpArith
. It also cleans up some of the code and removes anti-patterns. -
#9408 implements a simple optimization: dependent implications are no longer treated as E-matching theorems in
grind
. Ingrind_bitvec2.lean
, this change saves around 3 seconds, as many dependent implications are generated. Example:∀ (h : i + 1 ≤ w), x.abs.getLsbD i = x.abs[i]
-
#9414 increases the number of cases where
isArrowProposition
returns a result other than.undef
. This function is used to implement theisProof
predicate, which is invoked on every subterm visited bysimp
. -
#9421 fixes a bug that caused error explanations to "steal" the Infoview's container in the Lean web editor.
-
#9423 updates the formatting of, and adds explanations for, "unknown identifier" errors as well as "failed to infer type" errors for binders and definitions.
-
#9424 improves the error messages produced by the
split
tactic, including suggesting syntax fixes and related tactics with which it might be confused. -
#9443 makes cdot function expansion take hygiene information into account, fixing "parenthesis capturing" errors that can make erroneous cdots trigger cdot expansion in conjunction with macros. For example, given
macro "baz% " t:term : term => `(1 + ($t))
it used to be that
baz% ·
would expand to1 + fun x => x
, but now the parentheses in($t)
do not capture the cdot. We also fix an oversight where cdot function expansion ignored the fact that type ascriptions and tuples were supposed to delimit expansion, and also now the quotation prechecker ignores the identifier inhygieneInfo
. (#9491 added the hygiene information to the parenthesis and cdot syntaxes.) -
#9447 ensures that
mvcgen
not only tries to close stateful subgoals by assumption, but also pure Lean goals. -
#9448 addresses the lean crash (stack overflow) with nested induction and the generation of the
SizeOf
spec lemmas, reported at #9018. -
#9451 adds support in the
mintro
tactic for introducinglet
/have
binders in stateful targets, akin tointro
. This is useful when specifications introduce such let bindings. -
#9454 introduces tactic
mleave
that leaves theSPred
proof mode by eta expanding through its abstractions and applying some mild simplifications. This is useful to apply automation such asgrind
afterwards. -
#9464 makes
PProdN.reduceProjs
also look for projection functions. Previously, all redexes were created by the functions inPProdN
, which used primitive projections. But withmkAdmProj
the projection functions creep in via the types of theadmissible_pprod_fst
theorem. So let's just reduce both of them. -
#9472 fixes another issue at the
congr_simp
theorems that was affecting Mathlib. Many thanks to Johan Commelin for creating the mwe. -
#9476 fixes the bridge between
Nat
andInt
ingrind cutsat
. -
#9479 improves the
evalInt?
function, which is used to evaluate configuration parameters from theToInt
type class. also adds a newevalNat?
function for handling theIsCharP
type class, and introduces a configuration option:grind (exp := <num>)
This option controls the maximum exponent size considered during expression evaluation. Previously,
evalInt?
usedwhnf
, which could run out of stack space when reducing terms such as2^1024
. -
#9480 adds a feature where
structure
constructors can override the inferred binder kinds of the type's parameters. In the following, the(p)
binder ontoLp
causesp
to be an explicit parameter toWithLp.toLp
:structure WithLp (p : Nat) (V : Type) where toLp (p) :: ofLp : V
This reflects the syntax of the feature added in #7742 for overriding binder kinds of structure projections. Similarly, only those parameters in the header of the
structure
may be updated; it is an error to try to update binder kinds of parameters included viavariable
. -
#9481 fixes a kernel type mismatch that occurs when using
grind
on goals containing non-standardOfNat.ofNat
terms. For example, in issue #9477, the0
in the theoremrange_lower
has the form:(@OfNat.ofNat (Std.PRange.Bound (Std.PRange.RangeShape.lower (Std.PRange.RangeShape.mk Std.PRange.BoundShape.closed Std.PRange.BoundShape.open)) Nat) (nat_lit 0) (instOfNatNat (nat_lit 0)))
instead of the more standard form:
(@OfNat.ofNat Nat (nat_lit 0) (instOfNatNat (nat_lit 0)))
-
#9487 fixes an incorrect proof term constructed by
grind linarith
, as reported in #9485. -
#9491 adds hygiene info to paren/tuple/typeAscription syntaxes, which will be used to implement hygienic cdot function expansion in #9443.
-
#9496 improves the error messages produced by the
set_option
command. -
#9500 adds a
HPow \a Int \a
field toLean.Grind.Field
, and sufficient axioms to connect it to the operations, so that in future we can reason about exponents ingrind
. To avoid collisions, we also move theHPow \a Nat \a
field inSemiring
from the extends clause to a field. Finally, we add some failing tests about normalizing exponents. -
#9505 removes vestigial syntax definitions in
Lean.Elab.Tactic.Do.VCGen
that when imported undefine themvcgen
tactic. Now it should be possible to import Mathlib and still usemvcgen
. -
#9506 adds a few missing simp lemmas to
mleave
. -
#9507 makes
mvcgen
mintro
let/have bindings. -
#9509 surfaces kernel diagnostics even in
example
. -
#9512 makes
mframe
,mspec
andmvcgen
respect hygiene. Inaccessible stateful hypotheses can now be named with a new tacticmrename_i
that works analogously torename_i
. -
#9516 ensures that private declarations made inaccessible by the module system are noted in the relevant error messages
-
#9518 ensures previous "is marked as private" messages are still triggered under the module system
-
#9520 corrects the changes to
Lean.Grind.Field
made in #9500. -
#9522 uses
withAbstractAtoms
to prevent the kernel from accidentally reducing the atoms in the arith normlizer while typechecking. This PR also setsimplicitDefEqProofs := false
in thegrind
normalizer -
#9532 generalizes
Process.output
andProcess.run
with an optionalString
argument that can be piped tostdin
. -
#9551 fixes the error position for the "dependent elimination failed" error for the
cases
tactic. -
#9553 fixes a bug introduced in #7830 where if the cursor is at the indicated position
example (as bs : List Nat) : (as.append bs).length = as.length + bs.length := by induction as with | nil => -- cursor | cons b bs ih =>
then the Infoview would show "no goals" rather than the
nil
goal. The PR also fixes a separate bug where placing the cursor on the next line after theinduction
/cases
tactics like ininduction as with | nil => sorry | cons b bs ih => sorry I -- < cursor
would report the original goal in the goal list. Furthermore, there are numerous improvements to error recovery (including
allGoals
-type logic for pre-tactics) and the visible tactic states when there are errors. AddsTactic.throwOrLogErrorAt
/Tactic.throwOrLogError
for throwing or logging errors depending on the recovery state. -
#9571 restores the feature where in
induction
/cases
forNat
, thezero
andsucc
labels are hoverable. This was added in #1660, but broken in #3629 and #3655 when custom eliminators were added. In general, if a custom eliminatorT.elim
for an inductive typeT
has an alternativefoo
, andT.foo
is a constant, then thefoo
label will haveT.foo
hover information. -
#9574 adds the option
abstractProof
to control whethergrind
automatically creates an auxiliary theorem for the generated proof or not. -
#9575 optimizes the proof terms generated by
grind ring
. For example, before this PR, the kernel took 2.22 seconds (on a M4 Max) to type-check the proof in the benchmarkgrind_ring_5.lean
; it now takes only 0.63 seconds. -
#9578 fixes an issue in
grind
's disequality proof construction. The issue occurs when an equality is merged with theFalse
equivalence class, but it is not the root of its congruence class, and its congruence root has not yet been merged into theFalse
equivalence class yet. -
#9579 ensures
ite
anddite
are to selected as E-matching patterns. They are bad patterns because the then/else branches are only internalized aftergrind
decided whether the condition isTrue
/False
. -
#9592 updates the styling and wording of error messages produced in inductive type declarations and anonymous constructor notation, including hints for inferable constructor visibility updates.
-
#9595 improves the error message displayed when writing an invalid projection on a free variable of function type.
-
#9606 adds notes to the deprecation warning when the replacement constant has a different type, visibility, and/or namespace.
-
#9625 improves trace messages around wf_preprocess.
-
#9628 introduces a
mutual_induct
variant of the generated (co)induction proof principle for mutually defined (co)inductive predicates. Unlike the standard (co)induction principle (which projects conclusions separately for each predicate),mutual_induct
produces a conjunction of all conclusions. -
#9633 updates various error messages produced by or associated with built-in tactics and adapts their formatting to current conventions.
-
#9634 modifies dot identifier notation so that
(.a : T)
resolvesT.a
with respect to the root namespace, like for generalized field notation. This lets the notation refer to private names, follow aliases, and also use open namespaces. The LSP completions are improved to follow how dot ident notation is resolved, but it doesn't yet take into account aliases or open namespaces. -
#9637 improves the readability of the "maximum universe level offset exceeded" error message.
-
#9646 uses a more simple approach to proving the unfolding theorem for a function defined by well-founded recursion. Instead of looping a bunch of tactics, it uses simp in single-pass mode to (try to) exactly undo the changes done in
WF.Fix
, using a dedicated theorem that pushes the extra argument in for each matcher (orcasesOn
). -
#9649 fixes an issue where a macro unfolding to multiple commands would not be accepted inside
mutual
-
#9653 adds error explanations for two common errors caused by large elimination from
Prop
. To support this functionality, "nested" named errors thrown by sub-tactics are now able to display their error code and explanation. -
#9666 addresses an outstanding feature in the module system to automatically mark
let rec
andwhere
helper declarations as private unless they are defined in a public context such as under@[expose]
. -
#9670 add constructors
.intCast k
and.natCast k
toCommRing.Expr
. We need them because terms such asNat.cast (R := α) 1
and(1 : α)
are not definitionally equal. This is pervaise in Mathlib for the numerals0
and1
. -
#9671 fixes support for
SMul.smul
ingrind ring
.SMul.smul
applications are now normalized. Example:example (x : BitVec 2) : x - 2 • x + x = 0 := by grind
-
#9675 adds support for
Fin.val
ingrind cutsat
. Examples:example (a b : Fin 2) (n : Nat) : n = 1 → ↑(a + b) ≠ n → a ≠ 0 → b = 0 → False := by grind
-
#9676 adds normalizers for nonstandard arithmetic instances. The types
Nat
andInt
have built-in support ingrind
, which uses the standard instances for these types and assumes they are the ones in use. However, users may define their own alternative instances that are definitionally equal to the standard ones. normalizes such instances using simprocs. This situation actually occurs in Mathlib. Example:class Distrib (R : Type _) extends Mul R where
-
#9679 produces a warning for redundant
grind
arguments. -
#9682 fixes a regression introduced by an optimization in the
unfoldReducible
step used by thegrind
normalizer. It also ensures that projection functions are not reduced, as they are folded in a later step. -
#9686 applies
clear
to implementation detail local declarations during thegrind
preprocessing steps. -
#9699 adds propagation rules for functions that take singleton types. This feature is useful for discharging verification conditions produced by
mvcgen
. For example:example (h : (fun (_ : Unit) => x + 1) = (fun _ => 1 + y)) : x = y := by grind
-
#9700 fixes assertion violations when
checkInvariants
is enabled ingrind
-
#9701 switches to a non-verloading local
Std.Do.Triple
notation in SpecLemmas.lean to work around a stage2 build failure. -
#9702 fixes an issue in the
match
elaborator where pattern variables like__x
would not have the kindimplDetail
in the local context. NowkindOfBinderName
isLocalDeclKind.ofBinderName
. -
#9704 optimizes the proof terms produced by
grind cutsat
. Additional performance improvements will be merged later. -
#9706 combines
Poly.combine_k
andPoly.mul_k
steps used in thegrind cutsat
proof terms. -
#9710 improves some of the proof terms produced by
grind ring
andgrind cutsat
. -
#9714 adds a version of
CommRing.Expr.toPoly
optimized for kernel reduction. We use this function not only to implementgrind ring
, but also to interface the ring module withgrind cutsat
. -
#9716 moves the validation of cross-package
import all
to Lake and the syntax validation of import keywords (public
,meta
, andall
) to the two import parsers. -
#9728 fixes #9724
-
#9735 extends the propagation rule implemented in #9699 to constant functions.
-
#9736 implements the option
mvcgen +jp
to employ a slightly lossy VC encoding for join points that prevents exponential VC blowup incurred by naïve splitting on control flow. -
#9754 make
mleave
applyat *
and improve its simp set in order to discharge some more trivialities (#9581). -
#9755 implements a
mrevert ∀n
tactic that "eta-reduces" the stateful goal and is adjoint tomintro ∀x1 ... ∀xn
. -
#9767 fixes equality congruence proof terms contructed by
grind
. -
#9772 fixes a bug in the projection over constructor propagator used in
grind
. It may construct type incorrect terms when a equivalence class contains heterogeneous equalities. -
#9776 combines the simplification and unfold-reducible-constants steps in
grind
to ensure that no potential normalization steps are missed. -
#9780 extends the test suite for
grind
working category theory, to help debug outstanding problems in Mathlib. -
#9781 ensures that
mvcgen
is hygienic. The goals it generates should now introduce all locals inaccessibly. -
#9785 splits out an implementation detail of MVarId.getMVarDependencies into a top-level function. Aesop was relying on the function defined in the where clause, which is no longer possible after #9759.
-
#9798 introduces
Lean.realizeValue
, a new metaprogramming API for parallelism-aware caching ofMetaM
computations -
#9800 improves the delta deriving handler, giving it the ability to process definitions with binders, as well as the ability to recursively unfold definitions. Furthermore, delta deriving now tries all explicit non-out-param arguments to a class, and it can handle "mixin" instance arguments. The
deriving
syntax has been changed to accept general terms, which makes it possible to derive specific instances with for examplederiving OfNat _ 1
orderiving Module R
. The class is allowed to be a pi type, to add additional hypotheses; here is a Mathlib example:def Sym (α : Type*) (n : ℕ) := { s : Multiset α // Multiset.card s = n } deriving [DecidableEq α] → DecidableEq _
This underscore stands for where
Sym α n
may be inserted, which is necessary when→
is used. Thederiving instance
command can refer to scoped variables when delta deriving as well. Breaking change: the derived instance's name uses theinstance
command's name generator, and the new instance is added to the current namespace. -
#9804 allows trailing comma in the argument list of
simp?
,dsimp?
,simpa
, etc... Previously, it was only allowed in the non?
variants ofsimp
,dsimp
,simp_all
. -
#9807 adds
Std.List.Zipper.pref
to the simp set ofmleave
. -
#9809 adds a script for analyzing
grind
E-matching annotations. The script is useful for detecting matching loops. We plan to add user-facing commands for running the script in the future. -
#9813 fixes an unexpected bound variable panic in
unfoldReducible
used ingrind
. -
#9814 skips the
normalizeLevels
preprocessing step ingrind
when it is not needed. -
#9818 fixes a bug where the
DecidableEq
deriving handler did not take universe levels into account for enumerations (inductive types whose constructors all have no fields). Closes #9541. -
#9819 makes the
unsafe t
term create an auxiliary opaque declaration, rather than an auxiliary definition with opaque reducibility hints. -
#9831 adds a delaborator for
Std.Range
notation. -
#9832 adds simp lemmas
SPred.entails_<n>
to replaceSPred.entails_cons
which was disfunctional as a simp lemma due to #8074. -
#9833 works around a DefEq bug in
mspec
involving delayed assignments. -
#9834 fixes a bug in
mvcgen
triggered by excess state arguments to thewp
application, a situation which arises when working withStateT
primitives. -
#9841 migrates the ⌜p⌝ notation for embedding pure p : Prop into SPred σs to expand into a simple, first-order expression SPred.pure p that can be supported by e-matching in grind.
-
#9843 makes
mvcgen
produce deterministic case labels for the generated VCs. Invariants will be namedinv<n>
and every other VC will be namedvc<n>.*
, where the*
part serves as a loose indication of provenance. -
#9852 removes the
inShareCommon
quick filter used ingrind
preprocessing steps.shareCommon
is no longer used only for fully preprocessed terms. -
#9853 adds
Nat
andInt
numeral normalizers ingrind
. -
#9857 ensures
grind
can E-match patterns containing universe polymorphic ground sub-patterns. For example, givenset_option pp.universes true in attribute [grind?] Id.run_pure
the pattern
Id.run_pure.{u_1}: [@Id.run.{u_1} #1 (@pure.{u_1, u_1} `[Id.{u_1}] `[Applicative.toPure.{u_1, u_1}] _ #0)]
contains two nested universe polymorphic ground patterns
-
Id.{u_1}
-
Applicative.toPure.{u_1, u_1}
-
-
#9860 fixes E-matching theorem activation in
grind
. -
#9865 adds improved support for proof-by-reflection to the kernel type checker. It addresses the performance issue exposed by #9854. With this PR, whenever the kernel type-checks an argument of the form
eagerReduce _
, it enters "eager-reduction" mode. In this mode, the kernel is more eager to reduce terms. The neweagerReduce _
hint is often used to wrapEq.refl true
. The new hint should not negatively impact any existing Lean package. -
#9867 fixes a nondeterministic behavior in
grind ring
. -
#9880 ensures a local forall is activated at most once per pattern in
grind
. -
#9883 refines the warning message for redundant
grind
arguments. It is not based on the actual inferred pattern instead provided kind. -
#9885 is initially motivated by noticing
Lean.Grind.Preorder.toLE
appearing in long Mathlib typeclass searches; this change will prevent these searches. These changes are also helpful preparation for potentially dropping the customLean.Grind.*
typeclasses, and unifying with the new typeclasses introduced in #9729.
Library
-
#7450 implements
Nat.dfold
, a dependent analogue ofNat.fold
. -
#9096 removes some unnecessary
Decidable*
instance arguments by using lemmas in theClassical
namespace instead of theDecidable
namespace. -
#9121 allows
grind
to case on the universe variants ofProd
. -
#9129 fixes simp lemmas about boolean equalities to say
(!x) = y
instead of(!decide (x = y)) = true
-
#9135 allows the result type of
forIn
,foldM
andfold
on pure iterators (Iter
) to be in a different universe than the iterators. -
#9142 changes
Fin.reverseInduction
from using well-founded recursion to usinglet rec
, which makes it have better definitional equality. Co-authored by @digama0. See the test below:namespace Fin
-
#9145 fixes two typos.
-
#9176 makes
mvcgen
split ifs rather than applying specifications. Doing so fixes a bug reported by Rish. -
#9194 makes the logic and tactics of
Std.Do
universe polymorphic, at the cost of a few definitional properties arising from the switch fromProp
toULift Prop
in the base caseSPred []
. -
#9249 adds theorem
BitVec.clzAuxRec_eq_clzAuxRec_of_getLsbD_false
as a more general statement thanBitVec.clzAuxRec_eq_clzAuxRec_of_le
, replacing the latter in the bitblaster too. -
#9260 removes uses of
Lean.RBMap
in Lean itself. -
#9263 fixes
toISO8601String
to produce a string that conforms to the ISO 8601 format specification. The previous implementation separated the minutes and seconds fragments with a.
instead of a:
and included timezone offsets without the hour and minute fragments separated by a:
. -
#9285 removes the unnecessary requirement of
BEq α
forArray.any_push
,Array.any_push'
,Array.all_push
,Array.all_push'
as well asVector.any_push
andVector.all_push
. -
#9301 adds a
simp
and agrind
annotation onZipper
-related theorems to improve reasoning aboutStd.Do
invariants. -
#9391 replaces the proof of the simplification lemma
Nat.zero_mod
withrfl
since it is, by design, a definitional equality. This solves an issue whereby the lemma could not be used by the simplifier when in 'dsimp' mode. -
#9441 fixes the behavior of
String.prev
, aligning the runtime implementation with the reference implementation. In particular, the following statements hold now:-
(s.prev p).byteIdx
is at leastp.byteIdx - 4
and at mostp.byteIdx - 1
-
s.prev 0 = 0
-
s.prev
is monotone
-
-
#9449 fix the behavior of
String.next
on the scalar boundary (2 ^ 63 - 1
on 64-bit platforms). -
#9451 adds support in the
mintro
tactic for introducinglet
/have
binders in stateful targets, akin tointro
. This is useful when specifications introduce such let bindings. -
#9454 introduces tactic
mleave
that leaves theSPred
proof mode by eta expanding through its abstractions and applying some mild simplifications. This is useful to apply automation such asgrind
afterwards. -
#9504 adds a few more
*.by_wp
"adequacy theorems" that allows to prove facts about programs inReaderM
andExceptM
using theStd.Do
framework. -
#9528 adds
List.zipWithM
andArray.zipWithM
. -
#9529 upstreams some helper instances for
NameSet
from Batteries. -
#9538 adds two lemmas related to
Iter.toArray
. -
#9577 adds lemmas about
UIntX.toBitVec
andUIntX.ofBitVec
and^
. -
#9586 adds componentwise algebraic operations on
Vector α n
, and relevant instances. -
#9594 optimizes
Lean.Name.toString
, giving a 10% instruction benefit. -
#9609 adds
@[grind =]
toProd.lex_def
. Note thatomega
has special handling forProd.Lex
, and this is needed forgrind
's cutsat module to achieve parity. -
#9616 introduces checks to make sure that the IO functions produce errors when inputs contain NUL bytes (instead of ignoring everything after the first NUL byte).
-
#9620 adds the separate directions of
List.pairwise_iff_forall_sublist
as named lemmas. -
#9621 renames
Xor
toXorOp
, to matchAndOp
, etc. -
#9622 adds a missing lemma about
List.sum
, and a grind annotation. -
#9701 switches to a non-verloading local
Std.Do.Triple
notation in SpecLemmas.lean to work around a stage2 build failure. -
#9721 tags more
SInt
andUInt
lemmas withint_toBitVec
sobv_decide
can handle casts between them and negation. -
#9729 introduces a canonical way to endow a type with an order structure. The basic operations (
LE
,LT
,Min
,Max
, and in later PRsBEq
,Ord
, ...) and any higher-level property (a preorder, a partial order, a linear order etc.) are then put in relation toLE
as necessary. The PR providesIsLinearOrder
instances for many core types and updates the signatures of some lemmas. -
#9732 re-implements
IO.waitAny
using Lean instead of C++. This is to reduce the size and complexity oftask_manager
in order to ease future refactorings. -
#9736 implements the option
mvcgen +jp
to employ a slightly lossy VC encoding for join points that prevents exponential VC blowup incurred by naïve splitting on control flow. -
#9739 removes the
instance
attribute fromlexOrd
that was accidentally applied inStd.Classes.Ord.Basic
. -
#9757 adds
grind
annotations for keyStd.Do.SPred
lemmas. -
#9782 corrects the
Inhabited
instance ofStdGen
to use a valid initial state for the pseudorandom number generator. Previously, thedefault
generator had the property thatProd.snd (stdNext default) = default
, so it would produce only constant sequences. -
#9787 adds a simp lemma
PostCond.const_apply
. -
#9792 adds
@[expose]
to two definitions withwhere
clauses that Batteries proves theorems about. -
#9799 fixes the #9410 issue.
-
#9805 improves the API for invariants and postconditions and as such introduces a few breaking changes to the existing pre-release API around
Std.Do
. It also adds Markus Himmel'spairsSumToZero
example as a test case. -
#9832 adds simp lemmas
SPred.entails_<n>
to replaceSPred.entails_cons
which was disfunctional as a simp lemma due to #8074. -
#9841 migrates the ⌜p⌝ notation for embedding pure p : Prop into SPred σs to expand into a simple, first-order expression SPred.pure p that can be supported by e-matching in grind.
-
#9848 adds
@[spec]
lemmas forforIn
andforIn'
atStd.PRange
. -
#9850 add a delaborator for
Std.PRange
notation.
Compiler
-
#8691 ensures that the state is reverted when compilation using the new compiler fails. This is especially important for noncomputable sections where the compiler might generate half-compiled functions which may then be erroneously used while compiling other functions.
-
#9134 changes ToIR to call
lowerEnumToScalarType?
withConstructorVal.induct
rather than the name of the constructor itself. This was an oversight in some refactoring of code in the new compiler before landing it. It should not affect runtime of compiled code (due to the extra tagging/untagging being optimized by LLVM), but it does make IR for the interpreter slightly more efficient. -
#9144 adds support for representing more inductive as enums, summarized up as extending support to those that fail to be enums because of parameters or irrelevant fields. While this is nice to have, it is actually motivated by correctness of a future desired optimization. The existing type representation is unsound if we implement
object
/tobject
distinction between values guaranteed to be an object pointer and those that may also be a tagged scalar. In particular, types like the ones added in this PR's tests would have all of their constructors encoded via tagged values, but under the natural extension of the existing rules of type representation they would be consideredobject
rather thantobject
. -
#9154 tightens the IR typing rules around applications of closures. When re-reading some code, I realized that the code in
mkPartialApp
has a clear typo—.object
andtype
should be swapped. However, it doesn't matter, because later IR passes smooth out the mismatch here. It makes more sense to be strict up-front and require applications of closures to always return an.object
. -
#9159 enforces the non-inlining of _override impls in the base phase of LCNF compilation. The current situation allows for constructor/cases mismatches to be exposed to the simplifier, which triggers an assertion failure. The reason this didn't show up sooner for Expr is that Expr has a custom extern implementation of its computed field getter.
-
#9177 makes the
pullInstances
pass avoid pulling any instance expressions containing erased propositions, because we don't correctly represent the dependencies that remain after erasure. -
#9198 changes the compiler's specialization analysis to consider higher-order params that are rebundled in a way that only changes their
Prop
arguments to be fixed. This means that they get specialized with a mere@[specialize]
, rather than the compiler having to opt-in to more aggressive parameter-specific specialization. -
#9207 makes the offending declaration clickable in the error message produced when something should be marked
noncomputable
. -
#9209 changes the
getLiteral
helper function ofelimDeadBranches
to correctly handle inductives with constructors. This function is not used as often as it could be, which makes this issue rare to hit outside of targeted test cases. -
#9218 makes the LCNF
elimDeadBranches
pass handle unsafe decls a bit more carefully. Now the result of an unsafe decl will only become ⊤ if there is value flow from a recursive call. -
#9221 removes code that has the false assumption that LCNF local vars can occur in types. There are other comments in
ElimDead.lean
asserting that this is not possible, so this must have been a change early in the development of the new compiler. -
#9224 changes the
toMono
pass to consider the type of an application and erase all arguments corresponding to erased params. This enables a lightweight form of relevance analysis by changing the mono type of a decl. I would have liked to unify this with the behavior for constructors, but my attempt to give constructors the same behavior in #9222 (which was in preparation for this PR) had a minor performance regression that is really incidental to the change. Still, I decided to hold off on it for the time being. In the future, we can hopefully extend this to constructors, extern decls, etc. -
#9266 adds support for
.mdata
in LCNF mono types (and then drops it at the IR type level instead). This better matches the behavior of extern decls in the C++ code of the old compiler, which is still being used to create extern decls at the moment and will soon be replaced. -
#9268 moves the implementation of
lean_add_extern
/addExtern
from C++ into Lean. I believe is the last C++ helper function from the library/compiler directory being relied upon by the new compiler. I put it into its own file and duplicated some code because this function needs to execute in CoreM, whereas the other IR functions live in their own monad stack. After the C++ compiler is removed, we can move the IR functions into CoreM. -
#9275 removes the old compiler written in C++.
-
#9279 fixes the
compiler.extract_closed
option after migrating it to Lean (and adds a test so it would be caught in the future). -
#9310 fixes IR constructor argument lowering to correctly handle an irrelevant argument being passed for a relevant parameter in all cases. This happened because constructor argument lowering (incompletely) reimplemented general LCNF-to-IR argument lowering, and the fix is to just adopt the generic helper functions. This is probably due to an incomplete refactoring when the new compiler was still on a branch.
-
#9336 changes the implementation of
trace.Compiler.result
to use the decls as they are provided rather than looking them up in the LCNF mono environment extension, which was seemingly done to save the trouble of re-normalizing fvar IDs before printing the decl. This means that the._closed
decls created by theextractClosed
pass will now be included in the output, which was definitely confusing before if you didn't know what was happening. -
#9344 correctly populates the
xType
field of theIR.FnBody.case
constructor. It turns out that there is no obvious consequence for this being incorrect, because it is conservatively recomputed by theBoxing
pass. -
#9393 fixes an unsafe trick where a sentinel for a hash table of Exprs (keyed by pointer) is created by constructing a value whose runtime representation can never be a valid Expr. The value chosen for this purpose was Unit.unit, which violates the inference that Expr has no scalar constructors. Instead, we change this to a freshly allocated Unit × Unit value.
-
#9411 adds support for compilation of
casesOn
for subsingletons. We rely on the elaborator's type checking to restrict this to inductives inProp
that can actually eliminate intoType n
. This does not yet cover other recursors of these types (or of inductives not inProp
for that matter). -
#9703 changes the LCNF
elimDeadBranches
pass so that it considers all non-Nat
literal types to be⊤
. It turns out that fixing this to correctly handle all of these types with the current abstract value representation is surprisingly nontrivial, and it's better to just land the fix first. -
#9720 removes an error which implicitly assumes that the sort of type dependency between erased types present in the test being added can not occur. It would be difficult to refine the error using only the information present in LCNF types, and it is of very little ongoing value (I don't recall it ever finding an actual problem), so it makes more sense to delete it.
-
#9827 changes the lowering of
Quot.lcInv
(the compiler-internal form ofQuot.lift
) intoMono
to support overapplication. -
#9847 adds a check for reursive decls in this bespoke inlining path, which fixes a regression from the old compiler.
-
#9864 adds new variants of
Array.getInternal
andArray.get!Internal
that return their argument borrowed, i.e. without a reference count increment. These are intended for use by the compiler in cases where it can determine that the array will continue to hold a valid reference to the element for the returned value's lifetime.
Pretty Printing
-
#8391 adds an unexpander for
Vector.mk
that unexpandsVector.mk #[...] _
to#v[...]
.-- previously: #check #v[1, 2, 3] -- { toArray := #[1, 2, 3], size_toArray := ⋯ } : Vector Nat 3 -- now: #check #v[1, 2, 3] -- #v[1, 2, 3] : Vector Nat 3
-
#9475 fixes the way some syntaxes are pretty printed due to missing whitespace advice.
-
#9494 fixes an issue that caused some error messages to attempt to display hovers for nonexistent identifiers.
-
#9555 allows hints in message data to specify custom preview spans that extend beyond the edit region specified by the code action.
-
#9778 modifies the pretty printing of anonymous metavariables to use the index rather than the internal name. This leads to smaller numerical suffixes in
?m.123
since the indices are numbered within a given metavariable context rather than across an entire file, hence each command gets its own numbering. This does not yet affect pretty printing of universe level metavariables.
Documentation
-
#9093 adds a missing docstring for
ToFormat.toFormat
. -
#9152 fixes an obsolete docstring for
registerDerivingHandler
-
#9593 simplifies the docstring for
propext
significantly.
Server
-
#9040 improves the 'Go to Definition' UX, specifically:
-
Using 'Go to Definition' on a type class projection will now extract the specific instances that were involved and provide them as locations to jump to. For example, using 'Go to Definition' on the
toString
oftoString 0
will yield results forToString.toString
andToString Nat
. -
Using 'Go to Definition' on a macro that produces syntax with type class projections will now also extract the specific instances that were involved and provide them as locations to jump to. For example, using 'Go to Definition' on the
+
of1 + 1
will yield results forHAdd.hAdd
,HAdd α α α
andAdd Nat
. -
Using 'Go to Declaration' will now provide all the results of 'Go to Definition' in addition to the elaborator and the parser that were involved. For example, using 'Go to Declaration' on the
+
of1 + 1
will yield results forHAdd.hAdd
,HAdd α α α
,Add Nat
,macro_rules | `($x + $y) => ...
andinfixl:65 " + " => HAdd.hAdd
. -
Using 'Go to Type Definition' on a value with a type that contains multiple constants will now provide 'Go to Definition' results for each constant. For example, using 'Go to Type Definition' on
x
forx : Array Nat
will yield results forArray
andNat
.
-
-
#9163 disables the use of the header produced by
lake setup-file
in the server for now. It will be re-enabled once Lake takes into account the header given by the server when processing workspace modules. Without that,setup-file
header can produce odd behavior when the file on disk and in an editor disagree on whether the file participates in the module system. -
#9563 performs some micro optimizations on fuzzy matching for a
~20%
instructions win. -
#9784 ensures the editor progress bar better reflects the actual progress of parallel elaboration.
Lake
-
#9053 updates Lake to resolve the
.olean
files for transitive imports for Lean through themodules
field oflean --setup
. This enables means the Lean can now directly use the.olean
files from the Lake cache without needed to locate them at a specific hierarchical path. -
#9101 fixes a bug introduce by #9081 where the source file was dropped from the module input trace and some entries were dropped from the module job log.
-
#9162 changes the key Lake uses for the
,ir
artifact in the content hash data structure tor
, maintaining the convention of single character key names. -
#9165 fixes two issues with Lake's process of creating static archives.
-
#9332 changes the dependency cloning mechanism in lake so the log message that lake is cloning a dependency occurs before it is finished doing so (and instead before it starts). This has been a huge source of confusion for users that don't understand why lake seems to be just stuck for no reason when setting up a new project, the output now is:
λ lake +lean4 new math math info: downloading mathlib `lean-toolchain` file info: math: no previous manifest, creating one from scratch info: leanprover-community/mathlib: cloning https://github.com/leanprover-community/mathlib4 <hang> info: leanprover-community/mathlib: checking out revision 'cd11c28c6a0d514a41dd7be9a862a9c8815f8599'
-
#9434 changes the Lake local cache infrastructure to restore executables and shared and static libraries from the cache. This means they keep their expected names, which some use cases still rely on.
-
#9435 adds the
libPrefixOnWindows
package and library configuration option. When enabled, Lake will prefix static and shared libraries withlib
on Windows (i.e., the same way it does on Unix). -
#9436 adds the number of jobs run to the final message Lake produces on a successfully run of
lake build
. -
#9478 adds proper Lake support for
meta import
. Module IR is now tracked in traces and in the pre-resolved modules Lake passes tolean --setup
. -
#9525 fixes Lake's handling of a module system
import all
. Previously, Lake treatedimport all
the same a non-moduleimport
, importing all private data in the transitive import tree. Lake now distinguishes the two, withimport all M
just importing the private data ofM
. The direct private imports ofM
are followed, but they are not promoted. -
#9559 changes
lake setup-file
to use the server-provided header for workspace modules. -
#9604 restricts Lake's production of thin archives to only the Windows core build (i.e.,
bootstrap = true
). The unbundledar
usually used for core builds on macOS does not support--thin
, so we avoid using it unless necessary. -
#9677 adds build times to each build step of the build monitor (under
-v
or in CI) and delays exiting on a--no-build
until after the build monitor finishes. Thus, a--no-build
failure will now report which targets blocked Lake by needing a rebuild. -
#9697 fixes the handling in
lake lean
andlake setup-file
of a library source file with multiple dots (e.g.,src/Foo.Bar.lean
). -
#9698 adjusts the formatting type classes for
lake query
to no longer require both a text and JSON form and instead work with any combination of the two. The classes have also been renamed. In addition, the query formatting of a text module header has been improved to only produce valid headers.
Other
-
#9106 fixes
undefined symbol: lean::mpz::divexact(lean::mpz const&, lean::mpz const&)
when building withoutLEAN_USE_GMP
-
#9114 further improves release automation, automatically incorporating material from
nightly-testing
andbump/v4.X.0
branches in the bump PRs to downstream repositories. -
#9659 fixes compatibility of the
trace.profiler.output
option with newer versions of Firefox Profiler